Version 3.23.17

Performance and stability improvements on all platforms.

git-svn-id: http://v8.googlecode.com/svn/trunk@18218 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 7759b08..39a6854 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-12-03: Version 3.23.17
+
+        Performance and stability improvements on all platforms.
+
+
 2013-12-02: Version 3.23.16
 
         Array builtins need to be prevented from changing frozen objects, and
diff --git a/build/standalone.gypi b/build/standalone.gypi
index b1aec36..1f91f9e 100644
--- a/build/standalone.gypi
+++ b/build/standalone.gypi
@@ -273,7 +273,6 @@
           'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES',
           'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES',      # -fvisibility=hidden
           'GCC_THREADSAFE_STATICS': 'NO',           # -fno-threadsafe-statics
-          'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES',    # -Werror
           'GCC_VERSION': 'com.apple.compilers.llvmgcc42',
           'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES',  # -Wnewline-eof
           'GCC_WARN_NON_VIRTUAL_DESTRUCTOR': 'YES', # -Wnon-virtual-dtor
@@ -292,6 +291,13 @@
             '-Wno-unused-parameter',
           ],
         },
+        'conditions': [
+          ['werror==""', {
+            'xcode_settings': {'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO'},
+          }, {
+            'xcode_settings': {'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES'},
+          }],
+        ],
         'target_conditions': [
           ['_type!="static_library"', {
             'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-search_paths_first']},
diff --git a/include/v8-profiler.h b/include/v8-profiler.h
index 0882d64..0ed6c5d 100644
--- a/include/v8-profiler.h
+++ b/include/v8-profiler.h
@@ -425,8 +425,12 @@
    * Starts tracking of heap objects population statistics. After calling
    * this method, all heap objects relocations done by the garbage collector
    * are being registered.
+   *
+   * |track_allocations| parameter controls whether stack trace of each
+   * allocation in the heap will be recorded and reported as part of
+   * HeapSnapshot.
    */
-  void StartTrackingHeapObjects();
+  void StartTrackingHeapObjects(bool track_allocations = false);
 
   /**
    * Adds a new time interval entry to the aggregated statistics array. The
@@ -479,13 +483,15 @@
    * Starts recording JS allocations immediately as they arrive and tracking of
    * heap objects population statistics.
    */
-  void StartRecordingHeapAllocations();
+  V8_DEPRECATED("Use StartTrackingHeapObjects instead",
+                void StartRecordingHeapAllocations());
 
   /**
    * Stops recording JS allocations and tracking of heap objects population
    * statistics, cleans all collected heap objects population statistics data.
    */
-  void StopRecordingHeapAllocations();
+  V8_DEPRECATED("Use StopTrackingHeapObjects instead",
+                void StopRecordingHeapAllocations());
 
 
  private:
diff --git a/src/api.cc b/src/api.cc
index 562985c..aee9e3a 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -2131,18 +2131,18 @@
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ON_BAILOUT(isolate, "v8::Message::Get()", return Local<String>());
   ENTER_V8(isolate);
-  HandleScope scope(reinterpret_cast<Isolate*>(isolate));
+  EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
   i::Handle<i::String> raw_result = i::MessageHandler::GetMessage(isolate, obj);
   Local<String> result = Utils::ToLocal(raw_result);
-  return scope.Close(result);
+  return scope.Escape(result);
 }
 
 
 v8::Handle<Value> Message::GetScriptResourceName() const {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ENTER_V8(isolate);
-  HandleScope scope(reinterpret_cast<Isolate*>(isolate));
+  EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
   i::Handle<i::JSMessageObject> message =
       i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
   // Return this.script.name.
@@ -2151,14 +2151,14 @@
                                                        isolate));
   i::Handle<i::Object> resource_name(i::Script::cast(script->value())->name(),
                                      isolate);
-  return scope.Close(Utils::ToLocal(resource_name));
+  return scope.Escape(Utils::ToLocal(resource_name));
 }
 
 
 v8::Handle<Value> Message::GetScriptData() const {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ENTER_V8(isolate);
-  HandleScope scope(reinterpret_cast<Isolate*>(isolate));
+  EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
   i::Handle<i::JSMessageObject> message =
       i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
   // Return this.script.data.
@@ -2166,21 +2166,21 @@
       i::Handle<i::JSValue>::cast(i::Handle<i::Object>(message->script(),
                                                        isolate));
   i::Handle<i::Object> data(i::Script::cast(script->value())->data(), isolate);
-  return scope.Close(Utils::ToLocal(data));
+  return scope.Escape(Utils::ToLocal(data));
 }
 
 
 v8::Handle<v8::StackTrace> Message::GetStackTrace() const {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ENTER_V8(isolate);
-  HandleScope scope(reinterpret_cast<Isolate*>(isolate));
+  EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
   i::Handle<i::JSMessageObject> message =
       i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
   i::Handle<i::Object> stackFramesObj(message->stack_frames(), isolate);
   if (!stackFramesObj->IsJSArray()) return v8::Handle<v8::StackTrace>();
   i::Handle<i::JSArray> stackTrace =
       i::Handle<i::JSArray>::cast(stackFramesObj);
-  return scope.Close(Utils::StackTraceToLocal(stackTrace));
+  return scope.Escape(Utils::StackTraceToLocal(stackTrace));
 }
 
 
@@ -2300,14 +2300,14 @@
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ON_BAILOUT(isolate, "v8::Message::GetSourceLine()", return Local<String>());
   ENTER_V8(isolate);
-  HandleScope scope(reinterpret_cast<Isolate*>(isolate));
+  EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
   EXCEPTION_PREAMBLE(isolate);
   i::Handle<i::Object> result = CallV8HeapFunction("GetSourceLine",
                                                    Utils::OpenHandle(this),
                                                    &has_pending_exception);
   EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::String>());
   if (result->IsString()) {
-    return scope.Close(Utils::ToLocal(i::Handle<i::String>::cast(result)));
+    return scope.Escape(Utils::ToLocal(i::Handle<i::String>::cast(result)));
   } else {
     return Local<String>();
   }
@@ -2331,11 +2331,11 @@
 Local<StackFrame> StackTrace::GetFrame(uint32_t index) const {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ENTER_V8(isolate);
-  HandleScope scope(reinterpret_cast<Isolate*>(isolate));
+  EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
   i::Handle<i::JSArray> self = Utils::OpenHandle(this);
   i::Object* raw_object = self->GetElementNoExceptionThrown(isolate, index);
   i::Handle<i::JSObject> obj(i::JSObject::cast(raw_object));
-  return scope.Close(Utils::StackFrameToLocal(obj));
+  return scope.Escape(Utils::StackFrameToLocal(obj));
 }
 
 
@@ -2415,39 +2415,39 @@
 Local<String> StackFrame::GetScriptName() const {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ENTER_V8(isolate);
-  HandleScope scope(reinterpret_cast<Isolate*>(isolate));
+  EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
   i::Handle<i::JSObject> self = Utils::OpenHandle(this);
   i::Handle<i::Object> name = GetProperty(self, "scriptName");
   if (!name->IsString()) {
     return Local<String>();
   }
-  return scope.Close(Local<String>::Cast(Utils::ToLocal(name)));
+  return scope.Escape(Local<String>::Cast(Utils::ToLocal(name)));
 }
 
 
 Local<String> StackFrame::GetScriptNameOrSourceURL() const {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ENTER_V8(isolate);
-  HandleScope scope(reinterpret_cast<Isolate*>(isolate));
+  EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
   i::Handle<i::JSObject> self = Utils::OpenHandle(this);
   i::Handle<i::Object> name = GetProperty(self, "scriptNameOrSourceURL");
   if (!name->IsString()) {
     return Local<String>();
   }
-  return scope.Close(Local<String>::Cast(Utils::ToLocal(name)));
+  return scope.Escape(Local<String>::Cast(Utils::ToLocal(name)));
 }
 
 
 Local<String> StackFrame::GetFunctionName() const {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ENTER_V8(isolate);
-  HandleScope scope(reinterpret_cast<Isolate*>(isolate));
+  EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
   i::Handle<i::JSObject> self = Utils::OpenHandle(this);
   i::Handle<i::Object> name = GetProperty(self, "functionName");
   if (!name->IsString()) {
     return Local<String>();
   }
-  return scope.Close(Local<String>::Cast(Utils::ToLocal(name)));
+  return scope.Escape(Local<String>::Cast(Utils::ToLocal(name)));
 }
 
 
@@ -4158,7 +4158,7 @@
   ENTER_V8(isolate);
   i::Logger::TimerEventScope timer_scope(
       isolate, i::Logger::TimerEventScope::v8_execute);
-  HandleScope scope(reinterpret_cast<Isolate*>(isolate));
+  EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
   i::Handle<i::JSFunction> function = Utils::OpenHandle(this);
   STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
   i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
@@ -4166,7 +4166,7 @@
   i::Handle<i::Object> returned =
       i::Execution::New(function, argc, args, &has_pending_exception);
   EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<v8::Object>());
-  return scope.Close(Utils::ToLocal(i::Handle<i::JSObject>::cast(returned)));
+  return scope.Escape(Utils::ToLocal(i::Handle<i::JSObject>::cast(returned)));
 }
 
 
@@ -7069,7 +7069,7 @@
   if (!isolate->IsInitialized()) return Local<Value>();
   ON_BAILOUT(isolate, "v8::Debug::GetMirror()", return Local<Value>());
   ENTER_V8(isolate);
-  v8::HandleScope scope(reinterpret_cast<Isolate*>(isolate));
+  v8::EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
   i::Debug* isolate_debug = isolate->debug();
   isolate_debug->Load();
   i::Handle<i::JSObject> debug(isolate_debug->debug_context()->global_object());
@@ -7081,11 +7081,10 @@
   const int kArgc = 1;
   v8::Handle<v8::Value> argv[kArgc] = { obj };
   EXCEPTION_PREAMBLE(isolate);
-  v8::Handle<v8::Value> result = v8_fun->Call(Utils::ToLocal(debug),
-                                              kArgc,
-                                              argv);
+  v8::Local<v8::Value> result =
+      v8_fun->Call(Utils::ToLocal(debug), kArgc, argv);
   EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
-  return scope.Close(result);
+  return scope.Escape(result);
 }
 
 
@@ -7497,8 +7496,9 @@
 }
 
 
-void HeapProfiler::StartTrackingHeapObjects() {
-  reinterpret_cast<i::HeapProfiler*>(this)->StartHeapObjectsTracking();
+void HeapProfiler::StartTrackingHeapObjects(bool track_allocations) {
+  reinterpret_cast<i::HeapProfiler*>(this)->StartHeapObjectsTracking(
+      track_allocations);
 }
 
 
@@ -7537,12 +7537,12 @@
 
 
 void HeapProfiler::StartRecordingHeapAllocations() {
-  reinterpret_cast<i::HeapProfiler*>(this)->StartHeapAllocationsRecording();
+  reinterpret_cast<i::HeapProfiler*>(this)->StartHeapObjectsTracking(true);
 }
 
 
 void HeapProfiler::StopRecordingHeapAllocations() {
-  reinterpret_cast<i::HeapProfiler*>(this)->StopHeapAllocationsRecording();
+  reinterpret_cast<i::HeapProfiler*>(this)->StopHeapObjectsTracking();
 }
 
 
diff --git a/src/api.h b/src/api.h
index 9197baf..5f19380 100644
--- a/src/api.h
+++ b/src/api.h
@@ -308,12 +308,12 @@
 
 template <class T>
 v8::internal::Handle<T> v8::internal::Handle<T>::EscapeFrom(
-    v8::HandleScope* scope) {
+    v8::EscapableHandleScope* scope) {
   v8::internal::Handle<T> handle;
   if (!is_null()) {
     handle = *this;
   }
-  return Utils::OpenHandle(*scope->Close(Utils::ToLocal(handle)), true);
+  return Utils::OpenHandle(*scope->Escape(Utils::ToLocal(handle)), true);
 }
 
 
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index d63bc65..cc2dbdc 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -193,7 +193,7 @@
 }
 
 
-void BinaryOpStub::InitializeInterfaceDescriptor(
+void BinaryOpICStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
   static Register registers[] = { r1, r0 };
@@ -1666,7 +1666,7 @@
   StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
   CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
-  BinaryOpStub::GenerateAheadOfTime(isolate);
+  BinaryOpICStub::GenerateAheadOfTime(isolate);
 }
 
 
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 88421af..5508803 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -2298,7 +2298,7 @@
   patch_site.EmitJumpIfSmi(scratch1, &smi_case);
 
   __ bind(&stub_call);
-  BinaryOpStub stub(op, mode);
+  BinaryOpICStub stub(op, mode);
   CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
          expr->BinaryOperationFeedbackId());
   patch_site.EmitPatchInfo();
@@ -2307,7 +2307,6 @@
   __ bind(&smi_case);
   // Smi case. This code works the same way as the smi-smi case in the type
   // recording binary operation stub, see
-  // BinaryOpStub::GenerateSmiSmiOperation for comments.
   switch (op) {
     case Token::SAR:
       __ GetLeastBitsFromSmi(scratch1, right, 5);
@@ -2376,7 +2375,7 @@
                                      Token::Value op,
                                      OverwriteMode mode) {
   __ pop(r1);
-  BinaryOpStub stub(op, mode);
+  BinaryOpICStub stub(op, mode);
   JumpPatchSite patch_site(masm_);    // unbound, signals no inlined smi code.
   CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
          expr->BinaryOperationFeedbackId());
@@ -4416,7 +4415,7 @@
   // Record position before stub call.
   SetSourcePosition(expr->position());
 
-  BinaryOpStub stub(Token::ADD, NO_OVERWRITE);
+  BinaryOpICStub stub(Token::ADD, NO_OVERWRITE);
   CallIC(stub.GetCode(isolate()),
          RelocInfo::CODE_TARGET,
          expr->CountBinOpFeedbackId());
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index dd3840a..ea247b3 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -1503,7 +1503,7 @@
 
 
 void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
-                                  StrictModeFlag strict_mode) {
+                                  ExtraICState extra_ic_state) {
   // ----------- S t a t e -------------
   //  -- r0    : value
   //  -- r1    : receiver
@@ -1513,7 +1513,7 @@
 
   // Get the receiver from the stack and probe the stub cache.
   Code::Flags flags = Code::ComputeFlags(
-      Code::HANDLER, MONOMORPHIC, strict_mode,
+      Code::HANDLER, MONOMORPHIC, extra_ic_state,
       Code::NORMAL, Code::STORE_IC);
 
   masm->isolate()->stub_cache()->GenerateProbe(
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 7b605f7..6119b24 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -272,7 +272,8 @@
 void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
   stream->Add(" = ");
   base_object()->PrintTo(stream);
-  stream->Add(" + %d", offset());
+  stream->Add(" + ");
+  offset()->PrintTo(stream);
 }
 
 
@@ -1084,7 +1085,7 @@
   LOperand* receiver = UseRegisterAtStart(instr->receiver());
   LOperand* function = UseRegisterAtStart(instr->function());
   LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
-  return AssignEnvironment(DefineSameAsFirst(result));
+  return AssignEnvironment(DefineAsRegister(result));
 }
 
 
@@ -1116,11 +1117,11 @@
 
 
 LInstruction* LChunkBuilder::DoInnerAllocatedObject(
-    HInnerAllocatedObject* inner_object) {
-  LOperand* base_object = UseRegisterAtStart(inner_object->base_object());
-  LInnerAllocatedObject* result =
-    new(zone()) LInnerAllocatedObject(base_object);
-  return DefineAsRegister(result);
+    HInnerAllocatedObject* instr) {
+  LOperand* base_object = UseRegisterAtStart(instr->base_object());
+  LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
+  return DefineAsRegister(
+      new(zone()) LInnerAllocatedObject(base_object, offset));
 }
 
 
@@ -1473,7 +1474,7 @@
     if (instr->HasPowerOf2Divisor()) {
       ASSERT(!right->CanBeZero());
       LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
-                                     UseOrConstant(right));
+                                     UseConstant(right));
       LInstruction* result = DefineAsRegister(mod);
       return (left->CanBeNegative() &&
               instr->CheckFlag(HValue::kBailoutOnMinusZero))
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index 19e26ba..cfafc06 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -1798,19 +1798,19 @@
 };
 
 
-class LInnerAllocatedObject V8_FINAL: public LTemplateInstruction<1, 1, 0> {
+class LInnerAllocatedObject V8_FINAL: public LTemplateInstruction<1, 2, 0> {
  public:
-  explicit LInnerAllocatedObject(LOperand* base_object) {
+  LInnerAllocatedObject(LOperand* base_object, LOperand* offset) {
     inputs_[0] = base_object;
+    inputs_[1] = offset;
   }
 
-  LOperand* base_object() { return inputs_[0]; }
-  int offset() { return hydrogen()->offset(); }
+  LOperand* base_object() const { return inputs_[0]; }
+  LOperand* offset() const { return inputs_[1]; }
 
   virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
 
-  DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "sub-allocated-object")
-  DECLARE_HYDROGEN_ACCESSOR(InnerAllocatedObject)
+  DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
 };
 
 
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 4e1cc2f..e4d816a 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2047,8 +2047,7 @@
 
 
 void LCodeGen::DoThrow(LThrow* instr) {
-  Register input_reg = EmitLoadRegister(instr->value(), ip);
-  __ push(input_reg);
+  __ push(ToRegister(instr->value()));
   ASSERT(ToRegister(instr->context()).is(cp));
   CallRuntime(Runtime::kThrow, 1, instr);
 
@@ -2186,7 +2185,7 @@
   ASSERT(ToRegister(instr->right()).is(r0));
   ASSERT(ToRegister(instr->result()).is(r0));
 
-  BinaryOpStub stub(instr->op(), NO_OVERWRITE);
+  BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
   // Block literal pool emission to ensure nop indicating no inlined smi code
   // is in the correct position.
   Assembler::BlockConstPoolScope block_const_pool(masm());
@@ -3496,12 +3495,13 @@
 void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
   Register receiver = ToRegister(instr->receiver());
   Register function = ToRegister(instr->function());
+  Register result = ToRegister(instr->result());
   Register scratch = scratch0();
 
   // If the receiver is null or undefined, we have to pass the global
   // object as a receiver to normal functions. Values have to be
   // passed unchanged to builtins and strict-mode functions.
-  Label global_object, receiver_ok;
+  Label global_object, result_in_receiver;
 
   // Do not transform the receiver to object for strict mode
   // functions.
@@ -3511,11 +3511,11 @@
          FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
   __ tst(scratch,
          Operand(1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize)));
-  __ b(ne, &receiver_ok);
+  __ b(ne, &result_in_receiver);
 
   // Do not transform the receiver to object for builtins.
   __ tst(scratch, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
-  __ b(ne, &receiver_ok);
+  __ b(ne, &result_in_receiver);
 
   // Normal function. Replace undefined or null with global receiver.
   __ LoadRoot(scratch, Heap::kNullValueRootIndex);
@@ -3530,13 +3530,21 @@
   DeoptimizeIf(eq, instr->environment());
   __ CompareObjectType(receiver, scratch, scratch, FIRST_SPEC_OBJECT_TYPE);
   DeoptimizeIf(lt, instr->environment());
-  __ jmp(&receiver_ok);
+  __ b(&result_in_receiver);
 
   __ bind(&global_object);
-  __ ldr(receiver, GlobalObjectOperand());
-  __ ldr(receiver,
-         FieldMemOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
-  __ bind(&receiver_ok);
+  __ ldr(result, GlobalObjectOperand());
+  __ ldr(result,
+         FieldMemOperand(result, JSGlobalObject::kGlobalReceiverOffset));
+  if (result.is(receiver)) {
+    __ bind(&result_in_receiver);
+  } else {
+    Label result_ok;
+    __ b(&result_ok);
+    __ bind(&result_in_receiver);
+    __ mov(result, receiver);
+    __ bind(&result_ok);
+  }
 }
 
 
@@ -4170,7 +4178,13 @@
 void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
   Register result = ToRegister(instr->result());
   Register base = ToRegister(instr->base_object());
-  __ add(result, base, Operand(instr->offset()));
+  if (instr->offset()->IsConstantOperand()) {
+    LConstantOperand* offset = LConstantOperand::cast(instr->offset());
+    __ add(result, base, Operand(ToInteger32(offset)));
+  } else {
+    Register offset = ToRegister(instr->offset());
+    __ add(result, base, offset);
+  }
 }
 
 
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 60c28da..265265d 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -1547,7 +1547,7 @@
   Handle<Code> code =
       isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
                                                kind_,
-                                               extra_state_);
+                                               extra_state());
   __ Jump(code, RelocInfo::CODE_TARGET);
 }
 
@@ -1938,7 +1938,7 @@
   Label* index_out_of_range_label = &index_out_of_range;
 
   if (kind_ == Code::CALL_IC &&
-      (CallICBase::StringStubState::decode(extra_state_) ==
+      (CallICBase::StringStubState::decode(extra_state()) ==
        DEFAULT_STRING_STUB)) {
     index_out_of_range_label = &miss;
   }
@@ -2004,7 +2004,7 @@
   Label index_out_of_range;
   Label* index_out_of_range_label = &index_out_of_range;
   if (kind_ == Code::CALL_IC &&
-      (CallICBase::StringStubState::decode(extra_state_) ==
+      (CallICBase::StringStubState::decode(extra_state()) ==
        DEFAULT_STRING_STUB)) {
     index_out_of_range_label = &miss;
   }
@@ -2466,7 +2466,7 @@
   // Get the receiver from the stack.
   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
 
-  CallInterceptorCompiler compiler(this, arguments(), r2, extra_state_);
+  CallInterceptorCompiler compiler(this, arguments(), r2, extra_state());
   compiler.Compile(masm(), object, holder, name, &lookup, r1, r3, r4, r0,
                    &miss);
 
diff --git a/src/ast.cc b/src/ast.cc
index 85482fa..aeb767e 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -580,35 +580,6 @@
 }
 
 
-void Assignment::RecordTypeFeedback(TypeFeedbackOracle* oracle,
-                                    Zone* zone) {
-  Property* prop = target()->AsProperty();
-  ASSERT(prop != NULL);
-  TypeFeedbackId id = AssignmentFeedbackId();
-  is_uninitialized_ = oracle->StoreIsUninitialized(id);
-  if (is_uninitialized_) return;
-
-  is_pre_monomorphic_ = oracle->StoreIsPreMonomorphic(id);
-  is_monomorphic_ = oracle->StoreIsMonomorphicNormal(id);
-  ASSERT(!is_pre_monomorphic_ || !is_monomorphic_);
-  receiver_types_.Clear();
-  if (prop->key()->IsPropertyName()) {
-    Literal* lit_key = prop->key()->AsLiteral();
-    ASSERT(lit_key != NULL && lit_key->value()->IsString());
-    Handle<String> name = Handle<String>::cast(lit_key->value());
-    oracle->StoreReceiverTypes(this, name, &receiver_types_);
-  } else if (is_monomorphic_) {
-    // Record receiver type for monomorphic keyed stores.
-    receiver_types_.Add(oracle->StoreMonomorphicReceiverType(id), zone);
-    store_mode_ = oracle->GetStoreMode(id);
-  } else if (oracle->StoreIsKeyedPolymorphic(id)) {
-    receiver_types_.Reserve(kMaxKeyedPolymorphism, zone);
-    oracle->CollectKeyedReceiverTypes(id, &receiver_types_);
-    store_mode_ = oracle->GetStoreMode(id);
-  }
-}
-
-
 bool Call::ComputeTarget(Handle<Map> type, Handle<String> name) {
   // If there is an interceptor, we can't compute the target for a direct call.
   if (type->has_named_interceptor()) return false;
@@ -711,20 +682,21 @@
 
 void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle,
                               CallKind call_kind) {
-  is_monomorphic_ = oracle->CallIsMonomorphic(this);
+  is_monomorphic_ = oracle->CallIsMonomorphic(CallFeedbackId());
   Property* property = expression()->AsProperty();
   if (property == NULL) {
     // Function call.  Specialize for monomorphic calls.
-    if (is_monomorphic_) target_ = oracle->GetCallTarget(this);
+    if (is_monomorphic_) target_ = oracle->GetCallTarget(CallFeedbackId());
   } else if (property->key()->IsPropertyName()) {
     // Method call.  Specialize for the receiver types seen at runtime.
     Literal* key = property->key()->AsLiteral();
     ASSERT(key != NULL && key->value()->IsString());
     Handle<String> name = Handle<String>::cast(key->value());
-    check_type_ = oracle->GetCallCheckType(this);
+    check_type_ = oracle->GetCallCheckType(CallFeedbackId());
     receiver_types_.Clear();
     if (check_type_ == RECEIVER_MAP_CHECK) {
-      oracle->CallReceiverTypes(this, name, call_kind, &receiver_types_);
+      oracle->CallReceiverTypes(CallFeedbackId(),
+          name, arguments()->length(), call_kind, &receiver_types_);
       is_monomorphic_ = is_monomorphic_ && receiver_types_.length() > 0;
     } else {
       holder_ = GetPrototypeForPrimitiveCheck(check_type_, oracle->isolate());
@@ -745,17 +717,19 @@
     }
   } else {
     if (is_monomorphic_) {
-      keyed_array_call_is_holey_ = oracle->KeyedArrayCallIsHoley(this);
+      keyed_array_call_is_holey_ =
+          oracle->KeyedArrayCallIsHoley(CallFeedbackId());
     }
   }
 }
 
 
 void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  allocation_info_cell_ = oracle->GetCallNewAllocationInfoCell(this);
-  is_monomorphic_ = oracle->CallNewIsMonomorphic(this);
+  allocation_info_cell_ =
+      oracle->GetCallNewAllocationInfoCell(CallNewFeedbackId());
+  is_monomorphic_ = oracle->CallNewIsMonomorphic(CallNewFeedbackId());
   if (is_monomorphic_) {
-    target_ = oracle->GetCallNewTarget(this);
+    target_ = oracle->GetCallNewTarget(CallNewFeedbackId());
     Object* value = allocation_info_cell_->value();
     ASSERT(!value->IsTheHole());
     if (value->IsAllocationSite()) {
@@ -767,9 +741,9 @@
 
 
 void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  receiver_type_ = oracle->ObjectLiteralStoreIsMonomorphic(this)
-      ? oracle->GetObjectLiteralStoreMap(this)
-      : Handle<Map>::null();
+  TypeFeedbackId id = key()->LiteralFeedbackId();
+  receiver_type_ = oracle->ObjectLiteralStoreIsMonomorphic(id)
+      ? oracle->GetObjectLiteralStoreMap(id) : Handle<Map>::null();
 }
 
 
diff --git a/src/ast.h b/src/ast.h
index 3febc16..0bbb904 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -2142,7 +2142,6 @@
 
   // Type feedback information.
   TypeFeedbackId AssignmentFeedbackId() { return reuse(id()); }
-  void RecordTypeFeedback(TypeFeedbackOracle* oracle, Zone* zone);
   virtual bool IsMonomorphic() V8_OVERRIDE { return is_monomorphic_; }
   bool IsUninitialized() { return is_uninitialized_; }
   bool IsPreMonomorphic() { return is_pre_monomorphic_; }
@@ -2155,6 +2154,10 @@
   virtual KeyedAccessStoreMode GetStoreMode() V8_OVERRIDE {
     return store_mode_;
   }
+  void set_is_uninitialized(bool b) { is_uninitialized_ = b; }
+  void set_is_monomorphic(bool b) { is_monomorphic_ = b; }
+  void set_is_pre_monomorphic(bool b) { is_pre_monomorphic_ = b; }
+  void set_store_mode(KeyedAccessStoreMode mode) { store_mode_ = mode; }
 
  protected:
   Assignment(Isolate* isolate,
diff --git a/src/builtins.cc b/src/builtins.cc
index bc6dceb..f9c2708 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1412,12 +1412,14 @@
 
 
 static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
-  StoreIC::GenerateMegamorphic(masm, kNonStrictMode);
+  StoreIC::GenerateMegamorphic(masm,
+                               StoreIC::ComputeExtraICState(kNonStrictMode));
 }
 
 
 static void Generate_StoreIC_Megamorphic_Strict(MacroAssembler* masm) {
-  StoreIC::GenerateMegamorphic(masm, kStrictMode);
+  StoreIC::GenerateMegamorphic(masm,
+                               StoreIC::ComputeExtraICState(kStrictMode));
 }
 
 
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index 03b8c18..e52ec65 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -469,7 +469,8 @@
 
   ASSERT(FLAG_allocation_site_pretenuring || (size == object_size));
   if (FLAG_allocation_site_pretenuring) {
-    BuildCreateAllocationMemento(object, object_size, allocation_site);
+    BuildCreateAllocationMemento(
+        object, Add<HConstant>(object_size), allocation_site);
   }
 
   environment()->Push(object);
@@ -894,20 +895,21 @@
 
 
 template <>
-HValue* CodeStubGraphBuilder<BinaryOpStub>::BuildCodeInitializedStub() {
-  BinaryOpStub* stub = casted_stub();
-  HValue* left = GetParameter(0);
-  HValue* right = GetParameter(1);
+HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() {
+  BinaryOpIC::State state = casted_stub()->state();
 
-  Handle<Type> left_type = stub->GetLeftType(isolate());
-  Handle<Type> right_type = stub->GetRightType(isolate());
-  Handle<Type> result_type = stub->GetResultType(isolate());
+  HValue* left = GetParameter(BinaryOpICStub::kLeft);
+  HValue* right = GetParameter(BinaryOpICStub::kRight);
+
+  Handle<Type> left_type = state.GetLeftType(isolate());
+  Handle<Type> right_type = state.GetRightType(isolate());
+  Handle<Type> result_type = state.GetResultType(isolate());
 
   ASSERT(!left_type->Is(Type::None()) && !right_type->Is(Type::None()) &&
-         (stub->HasSideEffects(isolate()) || !result_type->Is(Type::None())));
+         (state.HasSideEffects() || !result_type->Is(Type::None())));
 
   HValue* result = NULL;
-  if (stub->operation() == Token::ADD &&
+  if (state.op() == Token::ADD &&
       (left_type->Maybe(Type::String()) || right_type->Maybe(Type::String())) &&
       !left_type->Is(Type::String()) && !right_type->Is(Type::String())) {
     // For the generic add stub a fast case for string addition is performance
@@ -918,16 +920,16 @@
       if_leftisstring.Then();
       {
         Push(BuildBinaryOperation(
-                    stub->operation(), left, right,
+                    state.op(), left, right,
                     handle(Type::String(), isolate()), right_type,
-                    result_type, stub->fixed_right_arg()));
+                    result_type, state.fixed_right_arg()));
       }
       if_leftisstring.Else();
       {
         Push(BuildBinaryOperation(
-                    stub->operation(), left, right,
+                    state.op(), left, right,
                     left_type, right_type, result_type,
-                    stub->fixed_right_arg()));
+                    state.fixed_right_arg()));
       }
       if_leftisstring.End();
       result = Pop();
@@ -937,32 +939,32 @@
       if_rightisstring.Then();
       {
         Push(BuildBinaryOperation(
-                    stub->operation(), left, right,
+                    state.op(), left, right,
                     left_type, handle(Type::String(), isolate()),
-                    result_type, stub->fixed_right_arg()));
+                    result_type, state.fixed_right_arg()));
       }
       if_rightisstring.Else();
       {
         Push(BuildBinaryOperation(
-                    stub->operation(), left, right,
+                    state.op(), left, right,
                     left_type, right_type, result_type,
-                    stub->fixed_right_arg()));
+                    state.fixed_right_arg()));
       }
       if_rightisstring.End();
       result = Pop();
     }
   } else {
     result = BuildBinaryOperation(
-            stub->operation(), left, right,
+            state.op(), left, right,
             left_type, right_type, result_type,
-            stub->fixed_right_arg());
+            state.fixed_right_arg());
   }
 
   // If we encounter a generic argument, the number conversion is
   // observable, thus we cannot afford to bail out after the fact.
-  if (!stub->HasSideEffects(isolate())) {
+  if (!state.HasSideEffects()) {
     if (result_type->Is(Type::Smi())) {
-      if (stub->operation() == Token::SHR) {
+      if (state.op() == Token::SHR) {
         // TODO(olivf) Replace this by a SmiTagU Instruction.
         // 0x40000000: this number would convert to negative when interpreting
         // the register as signed value;
@@ -980,8 +982,8 @@
 
   // Reuse the double box of one of the operands if we are allowed to (i.e.
   // chained binops).
-  if (stub->CanReuseDoubleBox()) {
-    HValue* operand = (stub->mode() == OVERWRITE_LEFT) ? left : right;
+  if (state.CanReuseDoubleBox()) {
+    HValue* operand = (state.mode() == OVERWRITE_LEFT) ? left : right;
     IfBuilder if_heap_number(this);
     if_heap_number.IfNot<HIsSmiAndBranch>(operand);
     if_heap_number.Then();
@@ -997,7 +999,7 @@
 }
 
 
-Handle<Code> BinaryOpStub::GenerateCode(Isolate* isolate) {
+Handle<Code> BinaryOpICStub::GenerateCode(Isolate* isolate) {
   return DoGenerateCode(isolate, this);
 }
 
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 3f26e3f..3fb6153 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -217,479 +217,32 @@
 }
 
 
-void BinaryOpStub::PrintBaseName(StringStream* stream) {
-  const char* op_name = Token::Name(op_);
-  const char* ovr = "";
-  if (mode_ == OVERWRITE_LEFT) ovr = "_ReuseLeft";
-  if (mode_ == OVERWRITE_RIGHT) ovr = "_ReuseRight";
-  stream->Add("BinaryOpStub_%s%s", op_name, ovr);
-}
-
-
-void BinaryOpStub::PrintState(StringStream* stream) {
-  stream->Add("(");
-  stream->Add(StateToName(left_state_));
-  stream->Add("*");
-  if (fixed_right_arg_.has_value) {
-    stream->Add("%d", fixed_right_arg_.value);
-  } else {
-    stream->Add(StateToName(right_state_));
-  }
-  stream->Add("->");
-  stream->Add(StateToName(result_state_));
-  stream->Add(")");
-}
-
-
-Maybe<Handle<Object> > BinaryOpStub::Result(Handle<Object> left,
-                                            Handle<Object> right,
-                                            Isolate* isolate) {
-  Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object());
-  Builtins::JavaScript func = BinaryOpIC::TokenToJSBuiltin(op_);
-  Object* builtin = builtins->javascript_builtin(func);
-  Handle<JSFunction> builtin_function =
-      Handle<JSFunction>(JSFunction::cast(builtin), isolate);
-  bool caught_exception;
-  Handle<Object> result = Execution::Call(isolate, builtin_function, left,
-      1, &right, &caught_exception);
-  return Maybe<Handle<Object> >(!caught_exception, result);
-}
-
-
-void BinaryOpStub::Initialize() {
-  fixed_right_arg_.has_value = false;
-  left_state_ = right_state_ = result_state_ = NONE;
-}
-
-
-void BinaryOpStub::Generate(Token::Value op,
-                            State left,
-                            State right,
-                            State result,
-                            OverwriteMode mode,
-                            Isolate* isolate) {
-  BinaryOpStub stub(INITIALIZED);
-  stub.op_ = op;
-  stub.left_state_ = left;
-  stub.right_state_ = right;
-  stub.result_state_ = result;
-  stub.mode_ = mode;
-  stub.GetCode(isolate);
-}
-
-
-void BinaryOpStub::Generate(Token::Value op,
-                            State left,
-                            int right,
-                            State result,
-                            OverwriteMode mode,
-                            Isolate* isolate) {
-  BinaryOpStub stub(INITIALIZED);
-  stub.op_ = op;
-  stub.left_state_ = left;
-  stub.fixed_right_arg_.has_value = true;
-  stub.fixed_right_arg_.value = right;
-  stub.right_state_ = SMI;
-  stub.result_state_ = result;
-  stub.mode_ = mode;
-  stub.GetCode(isolate);
-}
-
-
-void BinaryOpStub::GenerateAheadOfTime(Isolate* isolate) {
-  Token::Value binop[] = {Token::SUB, Token::MOD, Token::DIV, Token::MUL,
-                          Token::ADD, Token::SAR, Token::BIT_OR, Token::BIT_AND,
-                          Token::BIT_XOR, Token::SHL, Token::SHR};
-  for (unsigned i = 0; i < ARRAY_SIZE(binop); i++) {
-    BinaryOpStub stub(UNINITIALIZED);
-    stub.op_ = binop[i];
-    stub.GetCode(isolate);
-  }
-
-  // TODO(olivf) We should investigate why adding stubs to the snapshot is so
-  // expensive at runtime. When solved we should be able to add most binops to
-  // the snapshot instead of hand-picking them.
-  // Generated list of commonly used stubs
-  Generate(Token::ADD, INT32, INT32, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::ADD, INT32, INT32, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::ADD, INT32, INT32, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::ADD, INT32, INT32, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::ADD, INT32, NUMBER, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::ADD, INT32, SMI, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::ADD, INT32, SMI, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::ADD, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::ADD, NUMBER, INT32, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::ADD, NUMBER, NUMBER, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::ADD, NUMBER, SMI, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::ADD, SMI, INT32, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::ADD, SMI, INT32, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::ADD, SMI, INT32, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::ADD, SMI, NUMBER, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::ADD, SMI, SMI, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::ADD, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_AND, INT32, INT32, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_AND, INT32, INT32, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_AND, INT32, INT32, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_AND, INT32, SMI, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_AND, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_AND, INT32, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_AND, NUMBER, INT32, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_AND, NUMBER, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_AND, NUMBER, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_AND, SMI, INT32, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_AND, SMI, INT32, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_AND, SMI, NUMBER, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_AND, SMI, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_OR, INT32, INT32, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_OR, INT32, SMI, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_OR, INT32, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_OR, INT32, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_OR, NUMBER, SMI, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_OR, NUMBER, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_OR, NUMBER, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_OR, SMI, INT32, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_XOR, INT32, INT32, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_XOR, INT32, INT32, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_XOR, INT32, INT32, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_XOR, INT32, NUMBER, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_XOR, INT32, SMI, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::BIT_XOR, NUMBER, INT32, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_XOR, NUMBER, SMI, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_XOR, NUMBER, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_XOR, SMI, INT32, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_XOR, SMI, INT32, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_XOR, SMI, INT32, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_XOR, SMI, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::DIV, INT32, INT32, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::DIV, INT32, INT32, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::DIV, INT32, NUMBER, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::DIV, INT32, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::DIV, INT32, SMI, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::DIV, INT32, SMI, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::DIV, NUMBER, INT32, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::DIV, NUMBER, INT32, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::DIV, NUMBER, NUMBER, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::DIV, NUMBER, SMI, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::DIV, NUMBER, SMI, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::DIV, SMI, INT32, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::DIV, SMI, INT32, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::DIV, SMI, INT32, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::DIV, SMI, NUMBER, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::DIV, SMI, SMI, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::DIV, SMI, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::DIV, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::DIV, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::MOD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::MOD, SMI, 16, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::MOD, SMI, 2, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::MOD, SMI, 2048, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::MOD, SMI, 32, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::MOD, SMI, 4, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::MOD, SMI, 4, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::MOD, SMI, 8, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::MOD, SMI, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::MOD, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::MUL, INT32, INT32, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, INT32, INT32, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, INT32, NUMBER, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, INT32, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::MUL, INT32, SMI, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, INT32, SMI, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::MUL, INT32, SMI, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, NUMBER, INT32, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::MUL, NUMBER, NUMBER, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::MUL, NUMBER, SMI, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::MUL, SMI, INT32, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, SMI, INT32, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::MUL, SMI, INT32, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, SMI, NUMBER, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::MUL, SMI, SMI, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, SMI, SMI, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, SMI, SMI, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::MUL, SMI, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::MUL, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::MUL, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SAR, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SAR, INT32, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::SAR, INT32, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SAR, NUMBER, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::SAR, NUMBER, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SAR, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::SAR, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SHL, INT32, SMI, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::SHL, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SHL, INT32, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::SHL, INT32, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SHL, NUMBER, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SHL, SMI, SMI, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::SHL, SMI, SMI, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::SHL, SMI, SMI, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SHL, SMI, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::SHL, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::SHL, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SHR, INT32, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::SHR, INT32, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::SHR, INT32, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SHR, NUMBER, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::SHR, NUMBER, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::SHR, NUMBER, SMI, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SHR, SMI, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::SHR, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::SHR, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SUB, INT32, INT32, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::SUB, INT32, INT32, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::SUB, INT32, NUMBER, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::SUB, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SUB, INT32, SMI, INT32, OVERWRITE_LEFT, isolate);
-  Generate(Token::SUB, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SUB, NUMBER, INT32, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::SUB, NUMBER, INT32, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::SUB, NUMBER, NUMBER, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SUB, NUMBER, SMI, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SUB, SMI, INT32, INT32, NO_OVERWRITE, isolate);
-  Generate(Token::SUB, SMI, NUMBER, NUMBER, NO_OVERWRITE, isolate);
-  Generate(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
-  Generate(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
-  Generate(Token::SUB, SMI, SMI, SMI, NO_OVERWRITE, isolate);
-  Generate(Token::SUB, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
-  Generate(Token::SUB, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
-}
-
-
-bool BinaryOpStub::can_encode_arg_value(int32_t value) const {
-  return op_ == Token::MOD && value > 0 && IsPowerOf2(value) &&
-         FixedRightArgValueBits::is_valid(WhichPowerOf2(value));
-}
-
-
-int BinaryOpStub::encode_arg_value(int32_t value) const {
-  ASSERT(can_encode_arg_value(value));
-  return WhichPowerOf2(value);
-}
-
-
-int32_t BinaryOpStub::decode_arg_value(int value)  const {
-  return 1 << value;
-}
-
-
-int BinaryOpStub::encode_token(Token::Value op) const {
-  ASSERT(op >= FIRST_TOKEN && op <= LAST_TOKEN);
-  return op - FIRST_TOKEN;
-}
-
-
-Token::Value BinaryOpStub::decode_token(int op) const {
-  int res = op + FIRST_TOKEN;
-  ASSERT(res >= FIRST_TOKEN && res <= LAST_TOKEN);
-  return static_cast<Token::Value>(res);
-}
-
-
-const char* BinaryOpStub::StateToName(State state) {
-  switch (state) {
-    case NONE:
-      return "None";
-    case SMI:
-      return "Smi";
-    case INT32:
-      return "Int32";
-    case NUMBER:
-      return "Number";
-    case STRING:
-      return "String";
-    case GENERIC:
-      return "Generic";
-  }
-  return "";
-}
-
-
-void BinaryOpStub::UpdateStatus(Handle<Object> left,
-                                Handle<Object> right,
-                                Maybe<Handle<Object> > result) {
-  int old_state = GetExtraICState();
-
-  UpdateStatus(left, &left_state_);
-  UpdateStatus(right, &right_state_);
-
-  int32_t value;
-  bool new_has_fixed_right_arg =
-      right->ToInt32(&value) && can_encode_arg_value(value) &&
-      (left_state_ == SMI || left_state_ == INT32) &&
-      (result_state_ == NONE || !fixed_right_arg_.has_value);
-
-  fixed_right_arg_ = Maybe<int32_t>(new_has_fixed_right_arg, value);
-
-  if (result.has_value) UpdateStatus(result.value, &result_state_);
-
-  State max_input = Max(left_state_, right_state_);
-
-  if (!has_int_result() && op_ != Token::SHR &&
-      max_input <= NUMBER && max_input > result_state_) {
-    result_state_ = max_input;
-  }
-
-  ASSERT(result_state_ <= (has_int_result() ? INT32 : NUMBER) ||
-         op_ == Token::ADD);
-
-  // Reset overwrite mode unless we can actually make use of it, or may be able
-  // to make use of it at some point in the future.
-  if ((mode_ == OVERWRITE_LEFT && left_state_ > NUMBER) ||
-      (mode_ == OVERWRITE_RIGHT && right_state_ > NUMBER) ||
-      result_state_ > NUMBER) {
-    mode_ = NO_OVERWRITE;
-  }
-
-  if (old_state == GetExtraICState()) {
-    // Tagged operations can lead to non-truncating HChanges
-    if (left->IsUndefined() || left->IsBoolean()) {
-      left_state_ = GENERIC;
-    } else if (right->IsUndefined() || right->IsBoolean()) {
-      right_state_ = GENERIC;
-    } else {
-      // Since the fpu is to precise, we might bail out on numbers which
-      // actually would truncate with 64 bit precision.
-      ASSERT(!CpuFeatures::IsSupported(SSE2) &&
-             result_state_ <= INT32);
-      result_state_ = NUMBER;
+// static
+void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) {
+  // Generate the uninitialized versions of the stub.
+  for (int op = Token::BIT_OR; op <= Token::MOD; ++op) {
+    for (int mode = NO_OVERWRITE; mode <= OVERWRITE_RIGHT; ++mode) {
+      BinaryOpICStub stub(static_cast<Token::Value>(op),
+                          static_cast<OverwriteMode>(mode));
+      stub.GetCode(isolate);
     }
   }
+
+  // Generate special versions of the stub.
+  BinaryOpIC::State::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
 }
 
 
-void BinaryOpStub::UpdateStatus(Handle<Object> object,
-                                State* state) {
-  bool is_truncating = (op_ == Token::BIT_AND || op_ == Token::BIT_OR ||
-                        op_ == Token::BIT_XOR || op_ == Token::SAR ||
-                        op_ == Token::SHL || op_ == Token::SHR);
-  v8::internal::TypeInfo type = v8::internal::TypeInfo::FromValue(object);
-  if (object->IsBoolean() && is_truncating) {
-    // Booleans are converted by truncating by HChange.
-    type = TypeInfo::Integer32();
-  }
-  if (object->IsUndefined()) {
-    // Undefined will be automatically truncated for us by HChange.
-    type = is_truncating ? TypeInfo::Integer32() : TypeInfo::Double();
-  }
-  State int_state = SmiValuesAre32Bits() ? NUMBER : INT32;
-  State new_state = NONE;
-  if (type.IsSmi()) {
-    new_state = SMI;
-  } else if (type.IsInteger32()) {
-    new_state = int_state;
-  } else if (type.IsNumber()) {
-    new_state = NUMBER;
-  } else if (object->IsString() && operation() == Token::ADD) {
-    new_state = STRING;
-  } else {
-    new_state = GENERIC;
-  }
-  if ((new_state <= NUMBER && *state >  NUMBER) ||
-      (new_state >  NUMBER && *state <= NUMBER && *state != NONE)) {
-    new_state = GENERIC;
-  }
-  *state = Max(*state, new_state);
+void BinaryOpICStub::PrintState(StringStream* stream) {
+  state_.Print(stream);
 }
 
 
-Handle<Type> BinaryOpStub::StateToType(State state,
-                                       Isolate* isolate) {
-  Handle<Type> t = handle(Type::None(), isolate);
-  switch (state) {
-    case NUMBER:
-      t = handle(Type::Union(t, handle(Type::Double(), isolate)), isolate);
-      // Fall through.
-    case INT32:
-      t = handle(Type::Union(t, handle(Type::Signed32(), isolate)), isolate);
-      // Fall through.
-    case SMI:
-      t = handle(Type::Union(t, handle(Type::Smi(), isolate)), isolate);
-      break;
-
-    case STRING:
-      t = handle(Type::Union(t, handle(Type::String(), isolate)), isolate);
-      break;
-    case GENERIC:
-      return handle(Type::Any(), isolate);
-      break;
-    case NONE:
-      break;
-  }
-  return t;
-}
-
-
-Handle<Type> BinaryOpStub::GetLeftType(Isolate* isolate) const {
-  return StateToType(left_state_, isolate);
-}
-
-
-Handle<Type> BinaryOpStub::GetRightType(Isolate* isolate) const {
-  return StateToType(right_state_, isolate);
-}
-
-
-Handle<Type> BinaryOpStub::GetResultType(Isolate* isolate) const {
-  if (HasSideEffects(isolate)) return StateToType(NONE, isolate);
-  if (result_state_ == GENERIC && op_ == Token::ADD) {
-    return handle(Type::Union(handle(Type::Number(), isolate),
-                              handle(Type::String(), isolate)), isolate);
-  }
-  ASSERT(result_state_ != GENERIC);
-  if (result_state_ == NUMBER && op_ == Token::SHR) {
-    return handle(Type::Unsigned32(), isolate);
-  }
-  return StateToType(result_state_, isolate);
+// static
+void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate,
+                                         const BinaryOpIC::State& state) {
+  BinaryOpICStub stub(state);
+  stub.GetCode(isolate);
 }
 
 
@@ -1166,6 +719,13 @@
 
 
 // static
+void BinaryOpICStub::InstallDescriptors(Isolate* isolate) {
+  BinaryOpICStub stub(Token::ADD, NO_OVERWRITE);
+  InstallDescriptor(isolate, &stub);
+}
+
+
+// static
 void NewStringAddStub::InstallDescriptors(Isolate* isolate) {
   NewStringAddStub stub(STRING_ADD_CHECK_NONE, NOT_TENURED);
   InstallDescriptor(isolate, &stub);
diff --git a/src/code-stubs.h b/src/code-stubs.h
index a852a5c..f2de616 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -41,7 +41,7 @@
 #define CODE_STUB_LIST_ALL_PLATFORMS(V)  \
   V(CallFunction)                        \
   V(CallConstruct)                       \
-  V(BinaryOp)                            \
+  V(BinaryOpIC)                          \
   V(StringAdd)                           \
   V(NewStringAdd)                        \
   V(SubString)                           \
@@ -126,9 +126,6 @@
   CODE_STUB_LIST_ARM(V)              \
   CODE_STUB_LIST_MIPS(V)
 
-// Mode to overwrite BinaryExpression values.
-enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
-
 // Stub is base classes of all stubs.
 class CodeStub BASE_EMBEDDED {
  public:
@@ -1061,177 +1058,56 @@
 };
 
 
-class BinaryOpStub: public HydrogenCodeStub {
+class BinaryOpICStub V8_FINAL : public HydrogenCodeStub {
  public:
-  BinaryOpStub(Token::Value op, OverwriteMode mode)
-      : HydrogenCodeStub(UNINITIALIZED), op_(op), mode_(mode) {
-    ASSERT(op <= LAST_TOKEN && op >= FIRST_TOKEN);
-    Initialize();
-  }
+  BinaryOpICStub(Token::Value op, OverwriteMode mode)
+      : HydrogenCodeStub(UNINITIALIZED), state_(op, mode) {}
 
-  explicit BinaryOpStub(ExtraICState state)
-      : op_(decode_token(OpBits::decode(state))),
-        mode_(OverwriteModeField::decode(state)),
-        fixed_right_arg_(
-            Maybe<int>(HasFixedRightArgBits::decode(state),
-                decode_arg_value(FixedRightArgValueBits::decode(state)))),
-        left_state_(LeftStateField::decode(state)),
-        right_state_(fixed_right_arg_.has_value
-            ? ((fixed_right_arg_.value <= Smi::kMaxValue) ? SMI : INT32)
-            : RightStateField::decode(state)),
-        result_state_(ResultStateField::decode(state)) {
-    // We don't deserialize the SSE2 Field, since this is only used to be able
-    // to include SSE2 as well as non-SSE2 versions in the snapshot. For code
-    // generation we always want it to reflect the current state.
-    ASSERT(!fixed_right_arg_.has_value ||
-           can_encode_arg_value(fixed_right_arg_.value));
-  }
-
-  static const int FIRST_TOKEN = Token::BIT_OR;
-  static const int LAST_TOKEN = Token::MOD;
+  explicit BinaryOpICStub(const BinaryOpIC::State& state) : state_(state) {}
 
   static void GenerateAheadOfTime(Isolate* isolate);
+
   virtual void InitializeInterfaceDescriptor(
-      Isolate* isolate, CodeStubInterfaceDescriptor* descriptor);
-  static void InitializeForIsolate(Isolate* isolate) {
-    BinaryOpStub binopStub(UNINITIALIZED);
-    binopStub.InitializeInterfaceDescriptor(
-        isolate, isolate->code_stub_interface_descriptor(CodeStub::BinaryOp));
+      Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) V8_OVERRIDE;
+
+  static void InstallDescriptors(Isolate* isolate);
+
+  virtual Code::Kind GetCodeKind() const V8_OVERRIDE {
+    return Code::BINARY_OP_IC;
   }
 
-  virtual Code::Kind GetCodeKind() const { return Code::BINARY_OP_IC; }
-  virtual InlineCacheState GetICState() {
-    if (Max(left_state_, right_state_) == NONE) {
-      return ::v8::internal::UNINITIALIZED;
-    }
-    if (Max(left_state_, right_state_) == GENERIC) return MEGAMORPHIC;
-    return MONOMORPHIC;
+  virtual InlineCacheState GetICState() V8_OVERRIDE {
+    return state_.GetICState();
+  }
+
+  virtual ExtraICState GetExtraICState() V8_OVERRIDE {
+    return state_.GetExtraICState();
   }
 
   virtual void VerifyPlatformFeatures(Isolate* isolate) V8_OVERRIDE {
     ASSERT(CpuFeatures::VerifyCrossCompiling(SSE2));
   }
 
-  virtual ExtraICState GetExtraICState() {
-    bool sse_field = Max(result_state_, Max(left_state_, right_state_)) > SMI &&
-                     CpuFeatures::IsSafeForSnapshot(SSE2);
+  virtual Handle<Code> GenerateCode(Isolate* isolate) V8_OVERRIDE;
 
-    return OpBits::encode(encode_token(op_))
-         | LeftStateField::encode(left_state_)
-         | RightStateField::encode(fixed_right_arg_.has_value
-                                       ? NONE : right_state_)
-         | ResultStateField::encode(result_state_)
-         | HasFixedRightArgBits::encode(fixed_right_arg_.has_value)
-         | FixedRightArgValueBits::encode(fixed_right_arg_.has_value
-                                              ? encode_arg_value(
-                                                  fixed_right_arg_.value)
-                                              : 0)
-         | SSE2Field::encode(sse_field)
-         | OverwriteModeField::encode(mode_);
-  }
+  const BinaryOpIC::State& state() const { return state_; }
 
-  bool CanReuseDoubleBox() {
-    return result_state_ <= NUMBER && result_state_ > SMI &&
-      ((left_state_ > SMI && left_state_ <= NUMBER &&
-        mode_ == OVERWRITE_LEFT) ||
-       (right_state_ > SMI && right_state_ <= NUMBER &&
-        mode_ == OVERWRITE_RIGHT));
-  }
+  virtual void PrintState(StringStream* stream) V8_OVERRIDE;
 
-  bool HasSideEffects(Isolate* isolate) const {
-    Handle<Type> left = GetLeftType(isolate);
-    Handle<Type> right = GetRightType(isolate);
-    return left->Maybe(Type::Receiver()) || right->Maybe(Type::Receiver());
-  }
-
-  virtual Handle<Code> GenerateCode(Isolate* isolate);
-
-  Maybe<Handle<Object> > Result(Handle<Object> left,
-                         Handle<Object> right,
-                         Isolate* isolate);
-
-  Token::Value operation() const { return op_; }
-  OverwriteMode mode() const { return mode_; }
-  Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
-
-  Handle<Type> GetLeftType(Isolate* isolate) const;
-  Handle<Type> GetRightType(Isolate* isolate) const;
-  Handle<Type> GetResultType(Isolate* isolate) const;
-
-  void UpdateStatus(Handle<Object> left,
-                    Handle<Object> right,
-                    Maybe<Handle<Object> > result);
-
-  void PrintState(StringStream* stream);
+  // Parameters accessed via CodeStubGraphBuilder::GetParameter()
+  static const int kLeft = 0;
+  static const int kRight = 1;
 
  private:
-  explicit BinaryOpStub(InitializationState state) : HydrogenCodeStub(state),
-                                                     op_(Token::ADD),
-                                                     mode_(NO_OVERWRITE) {
-    Initialize();
-  }
-  void Initialize();
+  static void GenerateAheadOfTime(Isolate* isolate,
+                                  const BinaryOpIC::State& state);
 
-  enum State { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
+  virtual Major MajorKey() V8_OVERRIDE { return BinaryOpIC; }
+  virtual int NotMissMinorKey() V8_OVERRIDE { return GetExtraICState(); }
 
-  // We truncate the last bit of the token.
-  STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 5));
-  class LeftStateField:         public BitField<State, 0,  3> {};
-  // When fixed right arg is set, we don't need to store the right state.
-  // Thus the two fields can overlap.
-  class HasFixedRightArgBits:   public BitField<bool, 4, 1> {};
-  class FixedRightArgValueBits: public BitField<int,  5, 4> {};
-  class RightStateField:        public BitField<State, 5, 3> {};
-  class ResultStateField:       public BitField<State, 9, 3> {};
-  class SSE2Field:              public BitField<bool, 12, 1> {};
-  class OverwriteModeField:     public BitField<OverwriteMode, 13, 2> {};
-  class OpBits:                 public BitField<int, 15,  5> {};
+  BinaryOpIC::State state_;
 
-  virtual CodeStub::Major MajorKey() { return BinaryOp; }
-  virtual int NotMissMinorKey() { return GetExtraICState(); }
-
-  static Handle<Type> StateToType(State state,
-                                  Isolate* isolate);
-
-  static void Generate(Token::Value op,
-                       State left,
-                       int right,
-                       State result,
-                       OverwriteMode mode,
-                       Isolate* isolate);
-
-  static void Generate(Token::Value op,
-                       State left,
-                       State right,
-                       State result,
-                       OverwriteMode mode,
-                       Isolate* isolate);
-
-  void UpdateStatus(Handle<Object> object,
-                    State* state);
-
-  bool can_encode_arg_value(int32_t value) const;
-  int encode_arg_value(int32_t value) const;
-  int32_t decode_arg_value(int value)  const;
-  int encode_token(Token::Value op) const;
-  Token::Value decode_token(int op) const;
-
-  bool has_int_result() const {
-    return op_ == Token::BIT_XOR || op_ == Token::BIT_AND ||
-           op_ == Token::BIT_OR || op_ == Token::SAR || op_ == Token::SHL;
-  }
-
-  const char* StateToName(State state);
-
-  void PrintBaseName(StringStream* stream);
-
-  Token::Value op_;
-  OverwriteMode mode_;
-
-  Maybe<int> fixed_right_arg_;
-  State left_state_;
-  State right_state_;
-  State result_state_;
+  DISALLOW_COPY_AND_ASSIGN(BinaryOpICStub);
 };
 
 
diff --git a/src/debug.cc b/src/debug.cc
index 23495c8..25be003 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -3640,7 +3640,7 @@
 
 
 v8::Handle<v8::String> MessageImpl::GetJSON() const {
-  v8::HandleScope scope(
+  v8::EscapableHandleScope scope(
       reinterpret_cast<v8::Isolate*>(event_data_->GetIsolate()));
 
   if (IsEvent()) {
@@ -3656,7 +3656,7 @@
     if (caught_exception || !json->IsString()) {
       return v8::Handle<v8::String>();
     }
-    return scope.Close(v8::Utils::ToLocal(Handle<String>::cast(json)));
+    return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json)));
   } else {
     return v8::Utils::ToLocal(response_json_);
   }
diff --git a/src/factory.cc b/src/factory.cc
index 01f5854..483e6a6 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -854,7 +854,7 @@
                                  const char* message,
                                  Vector< Handle<Object> > args) {
   // Instantiate a closeable HandleScope for EscapeFrom.
-  v8::HandleScope scope(reinterpret_cast<v8::Isolate*>(isolate()));
+  v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate()));
   Handle<FixedArray> array = NewFixedArray(args.length());
   for (int i = 0; i < args.length(); i++) {
     array->set(i, *args[i]);
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 35977e6..63bbd2f 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -296,7 +296,7 @@
             "perform array index dehoisting")
 DEFINE_bool(analyze_environment_liveness, true,
             "analyze liveness of environment slots and zap dead values")
-DEFINE_bool(load_elimination, false, "use load elimination")
+DEFINE_bool(load_elimination, true, "use load elimination")
 DEFINE_bool(check_elimination, false, "use check elimination")
 DEFINE_bool(dead_code_elimination, true, "use dead code elimination")
 DEFINE_bool(fold_constants, true, "use constant folding")
diff --git a/src/frames.cc b/src/frames.cc
index 912c822..9549c2d 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -984,14 +984,16 @@
       // to construct a stack trace, the receiver is always in a stack slot.
       opcode = static_cast<Translation::Opcode>(it.Next());
       ASSERT(opcode == Translation::STACK_SLOT ||
-             opcode == Translation::LITERAL);
+             opcode == Translation::LITERAL ||
+             opcode == Translation::CAPTURED_OBJECT ||
+             opcode == Translation::DUPLICATED_OBJECT);
       int index = it.Next();
 
       // Get the correct receiver in the optimized frame.
       Object* receiver = NULL;
       if (opcode == Translation::LITERAL) {
         receiver = data->LiteralArray()->get(index);
-      } else {
+      } else if (opcode == Translation::STACK_SLOT) {
         // Positive index means the value is spilled to the locals
         // area. Negative means it is stored in the incoming parameter
         // area.
@@ -1007,6 +1009,12 @@
               ? this->receiver()
               : this->GetParameter(parameter_index);
         }
+      } else {
+        // TODO(3029): Materializing a captured object (or duplicated
+        // object) is hard, we return undefined for now. This breaks the
+        // produced stack trace, as constructor frames aren't marked as
+        // such anymore.
+        receiver = isolate()->heap()->undefined_value();
       }
 
       Code* code = function->shared()->code();
diff --git a/src/globals.h b/src/globals.h
index db80a7e..2f526a8 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -187,8 +187,13 @@
 # define V8_INTPTR_C(x)   (x ## LL)
 # define V8_PTR_PREFIX    "I64"
 #elif V8_HOST_ARCH_64_BIT
-# define V8_UINT64_C(x)   (x ## UL)
-# define V8_INT64_C(x)    (x ## L)
+# if V8_OS_MACOSX
+#  define V8_UINT64_C(x)   (x ## ULL)
+#  define V8_INT64_C(x)    (x ## LL)
+# else
+#  define V8_UINT64_C(x)   (x ## UL)
+#  define V8_INT64_C(x)    (x ## L)
+# endif
 # define V8_INTPTR_C(x)   (x ## L)
 # define V8_PTR_PREFIX    "l"
 #else
@@ -208,13 +213,12 @@
 #define V8PRIuPTR V8_PTR_PREFIX "u"
 
 // Fix for Mac OS X defining uintptr_t as "unsigned long":
-#if defined(__APPLE__) && defined(__MACH__)
+#if V8_OS_MACOSX
 #undef V8PRIxPTR
 #define V8PRIxPTR "lx"
 #endif
 
-#if (defined(__APPLE__) && defined(__MACH__)) || \
-    defined(__FreeBSD__) || defined(__OpenBSD__)
+#if V8_OS_MACOSX || defined(__FreeBSD__) || defined(__OpenBSD__)
 #define USING_BSD_ABI
 #endif
 
diff --git a/src/handles.h b/src/handles.h
index 5bc5779..7fef919 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -83,7 +83,7 @@
 
   // Closes the given scope, but lets this handle escape. See
   // implementation in api.h.
-  inline Handle<T> EscapeFrom(v8::HandleScope* scope);
+  inline Handle<T> EscapeFrom(v8::EscapableHandleScope* scope);
 
 #ifdef DEBUG
   enum DereferenceCheckMode { INCLUDE_DEFERRED_CHECK, NO_DEFERRED_CHECK };
diff --git a/src/heap-profiler.cc b/src/heap-profiler.cc
index 6f99360..3d8e336 100644
--- a/src/heap-profiler.cc
+++ b/src/heap-profiler.cc
@@ -98,9 +98,14 @@
 }
 
 
-void HeapProfiler::StartHeapObjectsTracking() {
-  snapshots_->StartHeapObjectsTracking();
+void HeapProfiler::StartHeapObjectsTracking(bool track_allocations) {
+  snapshots_->StartHeapObjectsTracking(track_allocations);
   is_tracking_object_moves_ = true;
+  ASSERT(!is_tracking_allocations_);
+  if (track_allocations) {
+    heap()->DisableInlineAllocation();
+    is_tracking_allocations_ = true;
+  }
 }
 
 
@@ -111,6 +116,10 @@
 
 void HeapProfiler::StopHeapObjectsTracking() {
   snapshots_->StopHeapObjectsTracking();
+  if (is_tracking_allocations_) {
+    heap()->EnableInlineAllocation();
+    is_tracking_allocations_ = false;
+  }
 }
 
 
@@ -158,18 +167,4 @@
 }
 
 
-void HeapProfiler::StartHeapAllocationsRecording() {
-  StartHeapObjectsTracking();
-  heap()->DisableInlineAllocation();
-  is_tracking_allocations_ = true;
-}
-
-
-void HeapProfiler::StopHeapAllocationsRecording() {
-  StopHeapObjectsTracking();
-  heap()->EnableInlineAllocation();
-  is_tracking_allocations_ = false;
-}
-
-
 } }  // namespace v8::internal
diff --git a/src/heap-profiler.h b/src/heap-profiler.h
index 866a678..13e605b 100644
--- a/src/heap-profiler.h
+++ b/src/heap-profiler.h
@@ -53,7 +53,7 @@
       v8::ActivityControl* control,
       v8::HeapProfiler::ObjectNameResolver* resolver);
 
-  void StartHeapObjectsTracking();
+  void StartHeapObjectsTracking(bool track_allocations);
   void StopHeapObjectsTracking();
 
   SnapshotObjectId PushHeapObjectsStats(OutputStream* stream);
@@ -78,9 +78,6 @@
   bool is_tracking_object_moves() const { return is_tracking_object_moves_; }
   bool is_tracking_allocations() const { return is_tracking_allocations_; }
 
-  void StartHeapAllocationsRecording();
-  void StopHeapAllocationsRecording();
-
   int FindUntrackedObjects() {
     return snapshots_->FindUntrackedObjects();
   }
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index b77414b..271f95c 100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -752,9 +752,10 @@
 }
 
 
-void HeapSnapshotsCollection::StartHeapObjectsTracking() {
+void HeapSnapshotsCollection::StartHeapObjectsTracking(bool track_allocations) {
   ids_.UpdateHeapObjectsMap();
-  if (allocation_tracker_ == NULL) {
+  ASSERT(allocation_tracker_ == NULL);
+  if (track_allocations) {
     allocation_tracker_ = new AllocationTracker(&ids_, names());
   }
 }
diff --git a/src/heap-snapshot-generator.h b/src/heap-snapshot-generator.h
index 8fa840c..e55513f 100644
--- a/src/heap-snapshot-generator.h
+++ b/src/heap-snapshot-generator.h
@@ -296,7 +296,7 @@
   SnapshotObjectId PushHeapObjectsStats(OutputStream* stream) {
     return ids_.PushHeapObjectsStats(stream);
   }
-  void StartHeapObjectsTracking();
+  void StartHeapObjectsTracking(bool track_allocations);
   void StopHeapObjectsTracking();
 
   HeapSnapshot* NewSnapshot(const char* name, unsigned uid);
diff --git a/src/hydrogen-check-elimination.cc b/src/hydrogen-check-elimination.cc
index bf8257c..bbd3042 100644
--- a/src/hydrogen-check-elimination.cc
+++ b/src/hydrogen-check-elimination.cc
@@ -127,6 +127,23 @@
       new_entry->check_ = NULL;
       new_entry->maps_ = old_entry->maps_->Copy(phase_->zone());
     }
+    if (succ->predecessors()->length() == 1) {
+      HControlInstruction* end = succ->predecessors()->at(0)->end();
+      if (end->IsCompareMap() && end->SuccessorAt(0) == succ) {
+        // Learn on the true branch of if(CompareMap(x)).
+        HCompareMap* cmp = HCompareMap::cast(end);
+        HValue* object = cmp->value()->ActualValue();
+        HCheckTableEntry* entry = copy->Find(object);
+        if (entry == NULL) {
+          copy->Insert(object, cmp->map());
+        } else {
+          MapSet list = new(phase_->zone()) UniqueSet<Map>();
+          list->Add(cmp->map(), phase_->zone());
+          entry->maps_ = list;
+        }
+      }
+      // TODO(titzer): is it worthwhile to learn on false branch too?
+    }
     return copy;
   }
 
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index e93d340..9f96202 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -3505,7 +3505,7 @@
       HInnerAllocatedObject::New(zone,
                                  context(),
                                  dominator_allocate,
-                                 dominator_size_constant,
+                                 dominator_size,
                                  type());
   dominated_allocate_instr->InsertBefore(this);
   DeleteAndReplaceWith(dominated_allocate_instr);
@@ -3601,11 +3601,9 @@
 void HAllocate::CreateFreeSpaceFiller(int32_t free_space_size) {
   ASSERT(filler_free_space_size_ == NULL);
   Zone* zone = block()->zone();
-  int32_t dominator_size =
-      HConstant::cast(dominating_allocate_->size())->GetInteger32Constant();
   HInstruction* free_space_instr =
       HInnerAllocatedObject::New(zone, context(), dominating_allocate_,
-      dominator_size, type());
+      dominating_allocate_->size(), type());
   free_space_instr->InsertBefore(this);
   HConstant* filler_map = HConstant::New(
       zone,
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 52e3ba0..d4beb6e 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -5609,21 +5609,21 @@
 };
 
 
-class HInnerAllocatedObject V8_FINAL: public HTemplateInstruction<1> {
+class HInnerAllocatedObject V8_FINAL : public HTemplateInstruction<2> {
  public:
   static HInnerAllocatedObject* New(Zone* zone,
                                     HValue* context,
                                     HValue* value,
-                                    int offset,
+                                    HValue* offset,
                                     HType type = HType::Tagged()) {
     return new(zone) HInnerAllocatedObject(value, offset, type);
   }
 
   HValue* base_object() { return OperandAt(0); }
-  int offset() { return offset_; }
+  HValue* offset() { return OperandAt(1); }
 
   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
-    return Representation::Tagged();
+    return index == 0 ? Representation::Tagged() : Representation::Integer32();
   }
 
   virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
@@ -5631,15 +5631,16 @@
   DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
 
  private:
-  HInnerAllocatedObject(HValue* value, int offset, HType type = HType::Tagged())
-      : HTemplateInstruction<1>(type), offset_(offset) {
+  HInnerAllocatedObject(HValue* value,
+                        HValue* offset,
+                        HType type = HType::Tagged())
+      : HTemplateInstruction<2>(type) {
     ASSERT(value->IsAllocate());
     SetOperandAt(0, value);
+    SetOperandAt(1, offset);
     set_type(type);
     set_representation(Representation::Tagged());
   }
-
-  int offset_;
 };
 
 
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index b6498b1..900e07e 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -2237,25 +2237,8 @@
                         length_field);
 
   if (mode == TRACK_ALLOCATION_SITE) {
-    BuildCreateAllocationMemento(array,
-                                 JSArray::kSize,
-                                 allocation_site_payload);
-    if (FLAG_allocation_site_pretenuring) {
-      // TODO(mvstanton): move this code into BuildCreateAllocationMemento when
-      // constructed arrays also pay attention to pretenuring.
-      HObjectAccess access =
-          HObjectAccess::ForAllocationSiteOffset(
-              AllocationSite::kMementoCreateCountOffset);
-      HValue* create_info = Add<HLoadNamedField>(allocation_site_payload,
-                                                 access);
-      HInstruction* new_create_info =
-          AddUncasted<HAdd>(create_info, graph()->GetConstant1());
-      new_create_info->ClearFlag(HValue::kCanOverflow);
-      HStoreNamedField* store = Add<HStoreNamedField>(allocation_site_payload,
-                                                      access, new_create_info);
-      // No write barrier needed to store a smi.
-      store->SkipWriteBarrier();
-    }
+    BuildCreateAllocationMemento(
+        array, Add<HConstant>(JSArray::kSize), allocation_site_payload);
   }
 
   int elements_location = JSArray::kSize;
@@ -2263,9 +2246,10 @@
     elements_location += AllocationMemento::kSize;
   }
 
-  HValue* elements = Add<HInnerAllocatedObject>(array, elements_location);
+  HInnerAllocatedObject* elements = Add<HInnerAllocatedObject>(
+      array, Add<HConstant>(elements_location));
   Add<HStoreNamedField>(array, HObjectAccess::ForElementsPointer(), elements);
-  return static_cast<HInnerAllocatedObject*>(elements);
+  return elements;
 }
 
 
@@ -2495,7 +2479,8 @@
 
   // Create an allocation site info if requested.
   if (mode == TRACK_ALLOCATION_SITE) {
-    BuildCreateAllocationMemento(object, JSArray::kSize, allocation_site);
+    BuildCreateAllocationMemento(
+        object, Add<HConstant>(JSArray::kSize), allocation_site);
   }
 
   if (length > 0) {
@@ -2588,18 +2573,31 @@
 }
 
 
-HValue* HGraphBuilder::BuildCreateAllocationMemento(HValue* previous_object,
-                                                    int previous_object_size,
-                                                    HValue* alloc_site) {
-  ASSERT(alloc_site != NULL);
-  HInnerAllocatedObject* alloc_memento = Add<HInnerAllocatedObject>(
+void HGraphBuilder::BuildCreateAllocationMemento(
+    HValue* previous_object,
+    HValue* previous_object_size,
+    HValue* allocation_site) {
+  ASSERT(allocation_site != NULL);
+  HInnerAllocatedObject* allocation_memento = Add<HInnerAllocatedObject>(
       previous_object, previous_object_size);
-  Handle<Map> alloc_memento_map =
-      isolate()->factory()->allocation_memento_map();
-  AddStoreMapConstant(alloc_memento, alloc_memento_map);
-  HObjectAccess access = HObjectAccess::ForAllocationMementoSite();
-  Add<HStoreNamedField>(alloc_memento, access, alloc_site);
-  return alloc_memento;
+  AddStoreMapConstant(
+      allocation_memento, isolate()->factory()->allocation_memento_map());
+  Add<HStoreNamedField>(
+      allocation_memento,
+      HObjectAccess::ForAllocationMementoSite(),
+      allocation_site);
+  if (FLAG_allocation_site_pretenuring) {
+    HValue* memento_create_count = Add<HLoadNamedField>(
+        allocation_site, HObjectAccess::ForAllocationSiteOffset(
+            AllocationSite::kMementoCreateCountOffset));
+    memento_create_count = AddUncasted<HAdd>(
+        memento_create_count, graph()->GetConstant1());
+    HStoreNamedField* store = Add<HStoreNamedField>(
+        allocation_site, HObjectAccess::ForAllocationSiteOffset(
+            AllocationSite::kMementoCreateCountOffset), memento_create_count);
+    // No write barrier needed to store a smi.
+    store->SkipWriteBarrier();
+  }
 }
 
 
@@ -8860,8 +8858,10 @@
       case Token::MOD: {
         if (fixed_right_arg.has_value) {
           if (right->IsConstant()) {
-            ASSERT_EQ(fixed_right_arg.value,
-                      HConstant::cast(right)->Integer32Value());
+            HConstant* c_right = HConstant::cast(right);
+            if (c_right->HasInteger32Value()) {
+              ASSERT_EQ(fixed_right_arg.value, c_right->Integer32Value());
+            }
           } else {
             HConstant* fixed_right = Add<HConstant>(
                 static_cast<int>(fixed_right_arg.value));
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 6a6aef0..61e98b2 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -1718,9 +1718,9 @@
       Handle<Type> type,
       HIfContinuation* continuation);
 
-  HValue* BuildCreateAllocationMemento(HValue* previous_object,
-                                       int previous_object_size,
-                                       HValue* payload);
+  void BuildCreateAllocationMemento(HValue* previous_object,
+                                    HValue* previous_object_size,
+                                    HValue* payload);
 
   HInstruction* BuildConstantMapCheck(Handle<JSObject> constant,
                                       CompilationInfo* info);
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index f0dcf71..0481814 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -330,7 +330,7 @@
 }
 
 
-void BinaryOpStub::InitializeInterfaceDescriptor(
+void BinaryOpICStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
   static Register registers[] = { edx, eax };
@@ -2961,9 +2961,9 @@
   CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
   if (Serializer::enabled()) {
     PlatformFeatureScope sse2(SSE2);
-    BinaryOpStub::GenerateAheadOfTime(isolate);
+    BinaryOpICStub::GenerateAheadOfTime(isolate);
   } else {
-    BinaryOpStub::GenerateAheadOfTime(isolate);
+    BinaryOpICStub::GenerateAheadOfTime(isolate);
   }
 }
 
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 649a58b..3c5d4aa 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -2245,7 +2245,7 @@
 
   __ bind(&stub_call);
   __ mov(eax, ecx);
-  BinaryOpStub stub(op, mode);
+  BinaryOpICStub stub(op, mode);
   CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
          expr->BinaryOperationFeedbackId());
   patch_site.EmitPatchInfo();
@@ -2330,7 +2330,7 @@
                                      Token::Value op,
                                      OverwriteMode mode) {
   __ pop(edx);
-  BinaryOpStub stub(op, mode);
+  BinaryOpICStub stub(op, mode);
   JumpPatchSite patch_site(masm_);    // unbound, signals no inlined smi code.
   CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
          expr->BinaryOperationFeedbackId());
@@ -4414,7 +4414,7 @@
   __ bind(&stub_call);
   __ mov(edx, eax);
   __ mov(eax, Immediate(Smi::FromInt(1)));
-  BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
+  BinaryOpICStub stub(expr->binary_op(), NO_OVERWRITE);
   CallIC(stub.GetCode(isolate()),
          RelocInfo::CODE_TARGET,
          expr->CountBinOpFeedbackId());
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 0b85829..2973beb 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -1435,16 +1435,15 @@
 
 
 void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
-                                  StrictModeFlag strict_mode) {
+                                  ExtraICState extra_ic_state) {
   // ----------- S t a t e -------------
   //  -- eax    : value
   //  -- ecx    : name
   //  -- edx    : receiver
   //  -- esp[0] : return address
   // -----------------------------------
-
   Code::Flags flags = Code::ComputeFlags(
-      Code::HANDLER, MONOMORPHIC, strict_mode,
+      Code::HANDLER, MONOMORPHIC, extra_ic_state,
       Code::NORMAL, Code::STORE_IC);
   masm->isolate()->stub_cache()->GenerateProbe(
       masm, flags, edx, ecx, ebx, no_reg);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 739f042..f26eeac 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2356,7 +2356,7 @@
   ASSERT(ToRegister(instr->right()).is(eax));
   ASSERT(ToRegister(instr->result()).is(eax));
 
-  BinaryOpStub stub(instr->op(), NO_OVERWRITE);
+  BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
   CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
   __ nop();  // Signals no inlined code.
 }
@@ -4426,7 +4426,13 @@
 void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
   Register result = ToRegister(instr->result());
   Register base = ToRegister(instr->base_object());
-  __ lea(result, Operand(base, instr->offset()));
+  if (instr->offset()->IsConstantOperand()) {
+    LConstantOperand* offset = LConstantOperand::cast(instr->offset());
+    __ lea(result, Operand(base, ToInteger32(offset)));
+  } else {
+    Register offset = ToRegister(instr->offset());
+    __ lea(result, Operand(base, offset, times_1, 0));
+  }
 }
 
 
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 678c0ca..aa35e9d 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -302,7 +302,8 @@
 void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
   stream->Add(" = ");
   base_object()->PrintTo(stream);
-  stream->Add(" + %d", offset());
+  stream->Add(" + ");
+  offset()->PrintTo(stream);
 }
 
 
@@ -1201,11 +1202,11 @@
 
 
 LInstruction* LChunkBuilder::DoInnerAllocatedObject(
-    HInnerAllocatedObject* inner_object) {
-  LOperand* base_object = UseRegisterAtStart(inner_object->base_object());
-  LInnerAllocatedObject* result =
-    new(zone()) LInnerAllocatedObject(base_object);
-  return DefineAsRegister(result);
+    HInnerAllocatedObject* instr) {
+  LOperand* base_object = UseRegisterAtStart(instr->base_object());
+  LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
+  return DefineAsRegister(
+      new(zone()) LInnerAllocatedObject(base_object, offset));
 }
 
 
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index b429120..ea4fef8 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -1801,19 +1801,19 @@
 };
 
 
-class LInnerAllocatedObject V8_FINAL: public LTemplateInstruction<1, 1, 0> {
+class LInnerAllocatedObject V8_FINAL: public LTemplateInstruction<1, 2, 0> {
  public:
-  explicit LInnerAllocatedObject(LOperand* base_object) {
+  LInnerAllocatedObject(LOperand* base_object, LOperand* offset) {
     inputs_[0] = base_object;
+    inputs_[1] = offset;
   }
 
-  LOperand* base_object() { return inputs_[0]; }
-  int offset() { return hydrogen()->offset(); }
+  LOperand* base_object() const { return inputs_[0]; }
+  LOperand* offset() const { return inputs_[1]; }
 
   virtual void PrintDataTo(StringStream* stream);
 
-  DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "sub-allocated-object")
-  DECLARE_HYDROGEN_ACCESSOR(InnerAllocatedObject)
+  DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
 };
 
 
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index ba57d7e..f4f3b2b 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -1639,7 +1639,7 @@
   Handle<Code> code =
       isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
                                                kind_,
-                                               extra_state_);
+                                               extra_state());
   __ jmp(code, RelocInfo::CODE_TARGET);
 }
 
@@ -2033,7 +2033,7 @@
   Label* index_out_of_range_label = &index_out_of_range;
 
   if (kind_ == Code::CALL_IC &&
-      (CallICBase::StringStubState::decode(extra_state_) ==
+      (CallICBase::StringStubState::decode(extra_state()) ==
        DEFAULT_STRING_STUB)) {
     index_out_of_range_label = &miss;
   }
@@ -2099,7 +2099,7 @@
   Label* index_out_of_range_label = &index_out_of_range;
 
   if (kind_ == Code::CALL_IC &&
-      (CallICBase::StringStubState::decode(extra_state_) ==
+      (CallICBase::StringStubState::decode(extra_state()) ==
        DEFAULT_STRING_STUB)) {
     index_out_of_range_label = &miss;
   }
@@ -2589,7 +2589,7 @@
   // Get the receiver from the stack.
   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
 
-  CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_);
+  CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state());
   compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax,
                    &miss);
 
diff --git a/src/ic.cc b/src/ic.cc
index 6ee728a..08df226 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1205,7 +1205,7 @@
 
   Handle<Type> type = CurrentTypeOf(object, isolate());
   Handle<JSObject> holder(lookup->holder());
-  LoadStubCompiler compiler(isolate(), cache_holder, kind());
+  LoadStubCompiler compiler(isolate(), kNoExtraICState, cache_holder, kind());
 
   switch (lookup->type()) {
     case FIELD: {
@@ -2317,76 +2317,464 @@
 }
 
 
-const char* BinaryOpIC::GetName(TypeInfo type_info) {
-  switch (type_info) {
-    case UNINITIALIZED: return "Uninitialized";
-    case SMI: return "Smi";
-    case INT32: return "Int32";
-    case NUMBER: return "Number";
-    case ODDBALL: return "Oddball";
-    case STRING: return "String";
-    case GENERIC: return "Generic";
-    default: return "Invalid";
+BinaryOpIC::State::State(ExtraICState extra_ic_state) {
+  // We don't deserialize the SSE2 Field, since this is only used to be able
+  // to include SSE2 as well as non-SSE2 versions in the snapshot. For code
+  // generation we always want it to reflect the current state.
+  op_ = static_cast<Token::Value>(
+      FIRST_TOKEN + OpField::decode(extra_ic_state));
+  mode_ = OverwriteModeField::decode(extra_ic_state);
+  fixed_right_arg_ = Maybe<int>(
+      HasFixedRightArgField::decode(extra_ic_state),
+      1 << FixedRightArgValueField::decode(extra_ic_state));
+  left_kind_ = LeftKindField::decode(extra_ic_state);
+  if (fixed_right_arg_.has_value) {
+    right_kind_ = Smi::IsValid(fixed_right_arg_.value) ? SMI : INT32;
+  } else {
+    right_kind_ = RightKindField::decode(extra_ic_state);
+  }
+  result_kind_ = ResultKindField::decode(extra_ic_state);
+  ASSERT_LE(FIRST_TOKEN, op_);
+  ASSERT_LE(op_, LAST_TOKEN);
+}
+
+
+ExtraICState BinaryOpIC::State::GetExtraICState() const {
+  bool sse2 = (Max(result_kind_, Max(left_kind_, right_kind_)) > SMI &&
+               CpuFeatures::IsSafeForSnapshot(SSE2));
+  ExtraICState extra_ic_state =
+      SSE2Field::encode(sse2) |
+      OpField::encode(op_ - FIRST_TOKEN) |
+      OverwriteModeField::encode(mode_) |
+      LeftKindField::encode(left_kind_) |
+      ResultKindField::encode(result_kind_) |
+      HasFixedRightArgField::encode(fixed_right_arg_.has_value);
+  if (fixed_right_arg_.has_value) {
+    extra_ic_state = FixedRightArgValueField::update(
+        extra_ic_state, WhichPowerOf2(fixed_right_arg_.value));
+  } else {
+    extra_ic_state = RightKindField::update(extra_ic_state, right_kind_);
+  }
+  return extra_ic_state;
+}
+
+
+// static
+void BinaryOpIC::State::GenerateAheadOfTime(
+    Isolate* isolate, void (*Generate)(Isolate*, const State&)) {
+  // TODO(olivf) We should investigate why adding stubs to the snapshot is so
+  // expensive at runtime. When solved we should be able to add most binops to
+  // the snapshot instead of hand-picking them.
+  // Generated list of commonly used stubs
+#define GENERATE(op, left_kind, right_kind, result_kind, mode)  \
+  do {                                                          \
+    State state(op, mode);                                      \
+    state.left_kind_ = left_kind;                               \
+    state.fixed_right_arg_.has_value = false;                   \
+    state.right_kind_ = right_kind;                             \
+    state.result_kind_ = result_kind;                           \
+    Generate(isolate, state);                                   \
+  } while (false)
+  GENERATE(Token::ADD, INT32, INT32, INT32, NO_OVERWRITE);
+  GENERATE(Token::ADD, INT32, INT32, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::ADD, INT32, INT32, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::ADD, INT32, INT32, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::ADD, INT32, NUMBER, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::ADD, INT32, SMI, INT32, NO_OVERWRITE);
+  GENERATE(Token::ADD, INT32, SMI, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::ADD, INT32, SMI, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::ADD, NUMBER, INT32, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::ADD, NUMBER, SMI, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::ADD, SMI, INT32, INT32, NO_OVERWRITE);
+  GENERATE(Token::ADD, SMI, INT32, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::ADD, SMI, INT32, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::ADD, SMI, NUMBER, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::ADD, SMI, SMI, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::ADD, SMI, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_AND, INT32, INT32, INT32, NO_OVERWRITE);
+  GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_AND, INT32, INT32, SMI, NO_OVERWRITE);
+  GENERATE(Token::BIT_AND, INT32, INT32, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_AND, INT32, SMI, INT32, NO_OVERWRITE);
+  GENERATE(Token::BIT_AND, INT32, SMI, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_AND, INT32, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_AND, NUMBER, INT32, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_AND, NUMBER, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::BIT_AND, NUMBER, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_AND, SMI, INT32, INT32, NO_OVERWRITE);
+  GENERATE(Token::BIT_AND, SMI, INT32, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_AND, SMI, NUMBER, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_AND, SMI, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_OR, INT32, INT32, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_OR, INT32, SMI, INT32, NO_OVERWRITE);
+  GENERATE(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_OR, INT32, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::BIT_OR, INT32, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, NO_OVERWRITE);
+  GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_OR, NUMBER, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::BIT_OR, NUMBER, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_OR, SMI, INT32, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_XOR, INT32, INT32, INT32, NO_OVERWRITE);
+  GENERATE(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_XOR, INT32, INT32, SMI, NO_OVERWRITE);
+  GENERATE(Token::BIT_XOR, INT32, INT32, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_XOR, INT32, NUMBER, SMI, NO_OVERWRITE);
+  GENERATE(Token::BIT_XOR, INT32, SMI, INT32, NO_OVERWRITE);
+  GENERATE(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::BIT_XOR, NUMBER, INT32, INT32, NO_OVERWRITE);
+  GENERATE(Token::BIT_XOR, NUMBER, SMI, INT32, NO_OVERWRITE);
+  GENERATE(Token::BIT_XOR, NUMBER, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::BIT_XOR, SMI, INT32, INT32, NO_OVERWRITE);
+  GENERATE(Token::BIT_XOR, SMI, INT32, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_XOR, SMI, INT32, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_XOR, SMI, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::DIV, INT32, INT32, INT32, NO_OVERWRITE);
+  GENERATE(Token::DIV, INT32, INT32, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::DIV, INT32, NUMBER, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::DIV, INT32, NUMBER, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::DIV, INT32, SMI, INT32, NO_OVERWRITE);
+  GENERATE(Token::DIV, INT32, SMI, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::DIV, NUMBER, INT32, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::DIV, NUMBER, INT32, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::DIV, NUMBER, SMI, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::DIV, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::DIV, SMI, INT32, INT32, NO_OVERWRITE);
+  GENERATE(Token::DIV, SMI, INT32, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::DIV, SMI, INT32, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::DIV, SMI, NUMBER, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::DIV, SMI, SMI, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::DIV, SMI, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::DIV, SMI, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::DIV, SMI, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::MOD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::MOD, SMI, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::MOD, SMI, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::MUL, INT32, INT32, INT32, NO_OVERWRITE);
+  GENERATE(Token::MUL, INT32, INT32, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::MUL, INT32, NUMBER, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::MUL, INT32, NUMBER, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::MUL, INT32, SMI, INT32, NO_OVERWRITE);
+  GENERATE(Token::MUL, INT32, SMI, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::MUL, INT32, SMI, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::MUL, NUMBER, INT32, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::MUL, NUMBER, NUMBER, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::MUL, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::MUL, NUMBER, SMI, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::MUL, SMI, INT32, INT32, NO_OVERWRITE);
+  GENERATE(Token::MUL, SMI, INT32, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::MUL, SMI, INT32, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::MUL, SMI, NUMBER, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::MUL, SMI, SMI, INT32, NO_OVERWRITE);
+  GENERATE(Token::MUL, SMI, SMI, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::MUL, SMI, SMI, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::MUL, SMI, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::MUL, SMI, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::MUL, SMI, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::SAR, INT32, SMI, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::SAR, INT32, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::SAR, INT32, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::SAR, NUMBER, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::SAR, NUMBER, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::SAR, SMI, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::SAR, SMI, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::SHL, INT32, SMI, INT32, NO_OVERWRITE);
+  GENERATE(Token::SHL, INT32, SMI, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::SHL, INT32, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::SHL, INT32, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::SHL, NUMBER, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::SHL, SMI, SMI, INT32, NO_OVERWRITE);
+  GENERATE(Token::SHL, SMI, SMI, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::SHL, SMI, SMI, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::SHL, SMI, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::SHL, SMI, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::SHL, SMI, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::SHR, INT32, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::SHR, INT32, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::SHR, INT32, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::SHR, NUMBER, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::SHR, NUMBER, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::SHR, NUMBER, SMI, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::SHR, SMI, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::SHR, SMI, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::SHR, SMI, SMI, SMI, OVERWRITE_RIGHT);
+  GENERATE(Token::SUB, INT32, INT32, INT32, NO_OVERWRITE);
+  GENERATE(Token::SUB, INT32, INT32, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::SUB, INT32, NUMBER, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::SUB, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::SUB, INT32, SMI, INT32, OVERWRITE_LEFT);
+  GENERATE(Token::SUB, INT32, SMI, INT32, OVERWRITE_RIGHT);
+  GENERATE(Token::SUB, NUMBER, INT32, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::SUB, NUMBER, INT32, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::SUB, NUMBER, SMI, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::SUB, SMI, INT32, INT32, NO_OVERWRITE);
+  GENERATE(Token::SUB, SMI, NUMBER, NUMBER, NO_OVERWRITE);
+  GENERATE(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_LEFT);
+  GENERATE(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT);
+  GENERATE(Token::SUB, SMI, SMI, SMI, NO_OVERWRITE);
+  GENERATE(Token::SUB, SMI, SMI, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::SUB, SMI, SMI, SMI, OVERWRITE_RIGHT);
+#undef GENERATE
+#define GENERATE(op, left_kind, fixed_right_arg_value, result_kind, mode) \
+  do {                                                                    \
+    State state(op, mode);                                                \
+    state.left_kind_ = left_kind;                                         \
+    state.fixed_right_arg_.has_value = true;                              \
+    state.fixed_right_arg_.value = fixed_right_arg_value;                 \
+    state.right_kind_ = SMI;                                              \
+    state.result_kind_ = result_kind;                                     \
+    Generate(isolate, state);                                             \
+  } while (false)
+  GENERATE(Token::MOD, SMI, 2, SMI, NO_OVERWRITE);
+  GENERATE(Token::MOD, SMI, 4, SMI, NO_OVERWRITE);
+  GENERATE(Token::MOD, SMI, 4, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::MOD, SMI, 8, SMI, NO_OVERWRITE);
+  GENERATE(Token::MOD, SMI, 16, SMI, OVERWRITE_LEFT);
+  GENERATE(Token::MOD, SMI, 32, SMI, NO_OVERWRITE);
+  GENERATE(Token::MOD, SMI, 2048, SMI, NO_OVERWRITE);
+#undef GENERATE
+}
+
+
+Handle<Type> BinaryOpIC::State::GetResultType(Isolate* isolate) const {
+  Kind result_kind = result_kind_;
+  if (HasSideEffects()) {
+    result_kind = NONE;
+  } else if (result_kind == GENERIC && op_ == Token::ADD) {
+    return handle(Type::Union(handle(Type::Number(), isolate),
+                              handle(Type::String(), isolate)), isolate);
+  } else if (result_kind == NUMBER && op_ == Token::SHR) {
+    return handle(Type::Unsigned32(), isolate);
+  }
+  ASSERT_NE(GENERIC, result_kind);
+  return KindToType(result_kind, isolate);
+}
+
+
+void BinaryOpIC::State::Print(StringStream* stream) const {
+  stream->Add("(%s", Token::Name(op_));
+  if (mode_ == OVERWRITE_LEFT) stream->Add("_ReuseLeft");
+  else if (mode_ == OVERWRITE_RIGHT) stream->Add("_ReuseRight");
+  stream->Add(":%s*", KindToString(left_kind_));
+  if (fixed_right_arg_.has_value) {
+    stream->Add("%d", fixed_right_arg_.value);
+  } else {
+    stream->Add("%s", KindToString(right_kind_));
+  }
+  stream->Add("->%s)", KindToString(result_kind_));
+}
+
+
+void BinaryOpIC::State::Update(Handle<Object> left,
+                               Handle<Object> right,
+                               Handle<Object> result) {
+  ExtraICState old_extra_ic_state = GetExtraICState();
+
+  left_kind_ = UpdateKind(left, left_kind_);
+  right_kind_ = UpdateKind(right, right_kind_);
+
+  int32_t fixed_right_arg_value = 0;
+  bool has_fixed_right_arg =
+      op_ == Token::MOD &&
+      right->ToInt32(&fixed_right_arg_value) &&
+      fixed_right_arg_value > 0 &&
+      IsPowerOf2(fixed_right_arg_value) &&
+      FixedRightArgValueField::is_valid(fixed_right_arg_value) &&
+      (left_kind_ == SMI || left_kind_ == INT32) &&
+      (result_kind_ == NONE || !fixed_right_arg_.has_value);
+  fixed_right_arg_ = Maybe<int32_t>(has_fixed_right_arg,
+                                    fixed_right_arg_value);
+
+  result_kind_ = UpdateKind(result, result_kind_);
+
+  if (!Token::IsTruncatingBinaryOp(op_)) {
+    Kind input_kind = Max(left_kind_, right_kind_);
+    if (result_kind_ < input_kind && input_kind <= NUMBER) {
+      result_kind_ = input_kind;
+    }
+  }
+
+  // Reset overwrite mode unless we can actually make use of it, or may be able
+  // to make use of it at some point in the future.
+  if ((mode_ == OVERWRITE_LEFT && left_kind_ > NUMBER) ||
+      (mode_ == OVERWRITE_RIGHT && right_kind_ > NUMBER) ||
+      result_kind_ > NUMBER) {
+    mode_ = NO_OVERWRITE;
+  }
+
+  if (old_extra_ic_state == GetExtraICState()) {
+    // Tagged operations can lead to non-truncating HChanges
+    if (left->IsUndefined() || left->IsBoolean()) {
+      left_kind_ = GENERIC;
+    } else if (right->IsUndefined() || right->IsBoolean()) {
+      right_kind_ = GENERIC;
+    } else {
+      // Since the X87 is too precise, we might bail out on numbers which
+      // actually would truncate with 64 bit precision.
+      ASSERT(!CpuFeatures::IsSupported(SSE2));
+      ASSERT(result_kind_ < NUMBER);
+      result_kind_ = NUMBER;
+    }
   }
 }
 
 
+BinaryOpIC::State::Kind BinaryOpIC::State::UpdateKind(Handle<Object> object,
+                                                      Kind kind) const {
+  Kind new_kind = GENERIC;
+  bool is_truncating = Token::IsTruncatingBinaryOp(op());
+  if (object->IsBoolean() && is_truncating) {
+    // Booleans will be automatically truncated by HChange.
+    new_kind = INT32;
+  } else if (object->IsUndefined()) {
+    // Undefined will be automatically truncated by HChange.
+    new_kind = is_truncating ? INT32 : NUMBER;
+  } else if (object->IsSmi()) {
+    new_kind = SMI;
+  } else if (object->IsHeapNumber()) {
+    double value = Handle<HeapNumber>::cast(object)->value();
+    new_kind = TypeInfo::IsInt32Double(value) ? INT32 : NUMBER;
+  } else if (object->IsString() && op() == Token::ADD) {
+    new_kind = STRING;
+  }
+  if (new_kind == INT32 && SmiValuesAre32Bits()) {
+    new_kind = NUMBER;
+  }
+  if (kind != NONE &&
+      ((new_kind <= NUMBER && kind > NUMBER) ||
+       (new_kind > NUMBER && kind <= NUMBER))) {
+    new_kind = GENERIC;
+  }
+  return Max(kind, new_kind);
+}
+
+
+// static
+const char* BinaryOpIC::State::KindToString(Kind kind) {
+  switch (kind) {
+    case NONE: return "None";
+    case SMI: return "Smi";
+    case INT32: return "Int32";
+    case NUMBER: return "Number";
+    case STRING: return "String";
+    case GENERIC: return "Generic";
+  }
+  UNREACHABLE();
+  return NULL;
+}
+
+
+// static
+Handle<Type> BinaryOpIC::State::KindToType(Kind kind, Isolate* isolate) {
+  Type* type = NULL;
+  switch (kind) {
+    case NONE: type = Type::None(); break;
+    case SMI: type = Type::Smi(); break;
+    case INT32: type = Type::Signed32(); break;
+    case NUMBER: type = Type::Number(); break;
+    case STRING: type = Type::String(); break;
+    case GENERIC: type = Type::Any(); break;
+  }
+  return handle(type, isolate);
+}
+
+
 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) {
-  ExtraICState extra_ic_state = target()->extended_extra_ic_state();
-  BinaryOpStub stub(extra_ic_state);
+  State state(target()->extended_extra_ic_state());
 
-  Handle<Type> left_type = stub.GetLeftType(isolate());
-  Handle<Type> right_type = stub.GetRightType(isolate());
-  bool smi_was_enabled = left_type->Maybe(Type::Smi()) &&
-                         right_type->Maybe(Type::Smi());
+  // Compute the actual result using the builtin for the binary operation.
+  Object* builtin = isolate()->js_builtins_object()->javascript_builtin(
+      TokenToJSBuiltin(state.op()));
+  Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate());
+  bool caught_exception;
+  Handle<Object> result = Execution::Call(
+      isolate(), function, left, 1, &right, &caught_exception);
+  if (caught_exception) return Failure::Exception();
 
-  Maybe<Handle<Object> > result = stub.Result(left, right, isolate());
-  if (!result.has_value) return Failure::Exception();
+  // Compute the new state.
+  State old_state = state;
+  state.Update(left, right, result);
+
+  // Install the new stub.
+  BinaryOpICStub stub(state);
+  set_target(*stub.GetCode(isolate()));
 
   if (FLAG_trace_ic) {
-    char buffer[100];
-    NoAllocationStringAllocator allocator(buffer,
-                                        static_cast<unsigned>(sizeof(buffer)));
+    char buffer[150];
+    NoAllocationStringAllocator allocator(
+        buffer, static_cast<unsigned>(sizeof(buffer)));
     StringStream stream(&allocator);
-    stream.Add("[");
-    stub.PrintName(&stream);
-
-    stub.UpdateStatus(left, right, result);
-
+    stream.Add("[BinaryOpIC");
+    old_state.Print(&stream);
     stream.Add(" => ");
-    stub.PrintState(&stream);
-    stream.Add(" ");
+    state.Print(&stream);
+    stream.Add(" @ %p <- ", static_cast<void*>(*target()));
     stream.OutputToStdOut();
-    PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate())));
     JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
     PrintF("]\n");
-  } else {
-    stub.UpdateStatus(left, right, result);
   }
 
-  Handle<Code> code = stub.GetCode(isolate());
-  set_target(*code);
-
-  left_type = stub.GetLeftType(isolate());
-  right_type = stub.GetRightType(isolate());
-  bool enable_smi = left_type->Maybe(Type::Smi()) &&
-                    right_type->Maybe(Type::Smi());
-
-  if (!smi_was_enabled && enable_smi) {
+  // Patch the inlined smi code as necessary.
+  if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
     PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
-  } else if (smi_was_enabled && !enable_smi) {
+  } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
     PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK);
   }
 
-  ASSERT(result.has_value);
-  return static_cast<MaybeObject*>(*result.value);
+  return *result;
 }
 
 
 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) {
   HandleScope scope(isolate);
-  Handle<Object> left = args.at<Object>(0);
-  Handle<Object> right = args.at<Object>(1);
+  Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft);
+  Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight);
   BinaryOpIC ic(isolate);
   return ic.Transition(left, right);
 }
diff --git a/src/ic.h b/src/ic.h
index b1a47e2..fa7ed6d 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -595,7 +595,7 @@
   }
   static void GenerateMiss(MacroAssembler* masm);
   static void GenerateMegamorphic(MacroAssembler* masm,
-                                  StrictModeFlag strict_mode);
+                                  ExtraICState extra_ic_state);
   static void GenerateNormal(MacroAssembler* masm);
   static void GenerateRuntimeSetProperty(MacroAssembler* masm,
                                          StrictModeFlag strict_mode);
@@ -810,25 +810,114 @@
 };
 
 
+// Mode to overwrite BinaryExpression values.
+enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
+
 // Type Recording BinaryOpIC, that records the types of the inputs and outputs.
 class BinaryOpIC: public IC {
  public:
-  enum TypeInfo {
-    UNINITIALIZED,
-    SMI,
-    INT32,
-    NUMBER,
-    ODDBALL,
-    STRING,  // Only used for addition operation.
-    GENERIC
+  class State V8_FINAL BASE_EMBEDDED {
+   public:
+    explicit State(ExtraICState extra_ic_state);
+
+    State(Token::Value op, OverwriteMode mode)
+        : op_(op), mode_(mode), left_kind_(NONE), right_kind_(NONE),
+          result_kind_(NONE) {
+      ASSERT_LE(FIRST_TOKEN, op);
+      ASSERT_LE(op, LAST_TOKEN);
+    }
+
+    InlineCacheState GetICState() const {
+      if (Max(left_kind_, right_kind_) == NONE) {
+        return ::v8::internal::UNINITIALIZED;
+      }
+      if (Max(left_kind_, right_kind_) == GENERIC) {
+        return ::v8::internal::MEGAMORPHIC;
+      }
+      if (Min(left_kind_, right_kind_) == GENERIC) {
+        return ::v8::internal::GENERIC;
+      }
+      return ::v8::internal::MONOMORPHIC;
+    }
+
+    ExtraICState GetExtraICState() const;
+
+    static void GenerateAheadOfTime(
+        Isolate*, void (*Generate)(Isolate*, const State&));
+
+    bool CanReuseDoubleBox() const {
+      return (result_kind_ > SMI && result_kind_ <= NUMBER) &&
+          ((mode_ == OVERWRITE_LEFT &&
+            left_kind_ > SMI && left_kind_ <= NUMBER) ||
+           (mode_ == OVERWRITE_RIGHT &&
+            right_kind_ > SMI && right_kind_ <= NUMBER));
+    }
+
+    bool HasSideEffects() const {
+      return Max(left_kind_, right_kind_) == GENERIC;
+    }
+
+    bool UseInlinedSmiCode() const {
+      return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_);
+    }
+
+    static const int FIRST_TOKEN = Token::BIT_OR;
+    static const int LAST_TOKEN = Token::MOD;
+
+    Token::Value op() const { return op_; }
+    OverwriteMode mode() const { return mode_; }
+    Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
+
+    Handle<Type> GetLeftType(Isolate* isolate) const {
+      return KindToType(left_kind_, isolate);
+    }
+    Handle<Type> GetRightType(Isolate* isolate) const {
+      return KindToType(right_kind_, isolate);
+    }
+    Handle<Type> GetResultType(Isolate* isolate) const;
+
+    void Print(StringStream* stream) const;
+
+    void Update(Handle<Object> left,
+                Handle<Object> right,
+                Handle<Object> result);
+
+   private:
+    enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
+
+    Kind UpdateKind(Handle<Object> object, Kind kind) const;
+
+    static const char* KindToString(Kind kind);
+    static Handle<Type> KindToType(Kind kind, Isolate* isolate);
+    static bool KindMaybeSmi(Kind kind) {
+      return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
+    }
+
+    // We truncate the last bit of the token.
+    STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4));
+    class OpField:                 public BitField<int, 0, 4> {};
+    class OverwriteModeField:      public BitField<OverwriteMode, 4, 2> {};
+    class SSE2Field:               public BitField<bool, 6, 1> {};
+    class ResultKindField:         public BitField<Kind, 7, 3> {};
+    class LeftKindField:           public BitField<Kind, 10,  3> {};
+    // When fixed right arg is set, we don't need to store the right kind.
+    // Thus the two fields can overlap.
+    class HasFixedRightArgField:   public BitField<bool, 13, 1> {};
+    class FixedRightArgValueField: public BitField<int,  14, 4> {};
+    class RightKindField:          public BitField<Kind, 14, 3> {};
+
+    Token::Value op_;
+    OverwriteMode mode_;
+    Kind left_kind_;
+    Kind right_kind_;
+    Kind result_kind_;
+    Maybe<int> fixed_right_arg_;
   };
 
   explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { }
 
   static Builtins::JavaScript TokenToJSBuiltin(Token::Value op);
 
-  static const char* GetName(TypeInfo type_info);
-
   MUST_USE_RESULT MaybeObject* Transition(Handle<Object> left,
                                           Handle<Object> right);
 };
diff --git a/src/isolate.cc b/src/isolate.cc
index 941ac42..25bc546 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -1323,11 +1323,6 @@
 }
 
 
-void Isolate::TraceException(bool flag) {
-  FLAG_trace_exception = flag;  // TODO(isolates): This is an unfortunate use.
-}
-
-
 bool Isolate::OptionalRescheduleException(bool is_bottom_call) {
   ASSERT(has_pending_exception());
   PropagatePendingExceptionToExternalTryCatch();
@@ -2109,7 +2104,7 @@
                                    DONT_TRACK_ALLOCATION_SITE, 0);
     stub.InitializeInterfaceDescriptor(
         this, code_stub_interface_descriptor(CodeStub::FastCloneShallowArray));
-    BinaryOpStub::InitializeForIsolate(this);
+    BinaryOpICStub::InstallDescriptors(this);
     CompareNilICStub::InitializeForIsolate(this);
     ToBooleanStub::InitializeForIsolate(this);
     ArrayConstructorStubBase::InstallDescriptors(this);
diff --git a/src/isolate.h b/src/isolate.h
index e80cd45..7ba3088 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -785,9 +785,6 @@
   // result in the target out parameter.
   void ComputeLocation(MessageLocation* target);
 
-  // Override command line flag.
-  void TraceException(bool flag);
-
   // Out of resource exception helpers.
   Failure* StackOverflow();
   Failure* TerminateExecution();
diff --git a/src/log.cc b/src/log.cc
index e123231..a508e87 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -1838,12 +1838,7 @@
     case Code::FUNCTION:
     case Code::OPTIMIZED_FUNCTION:
       return;  // We log this later using LogCompiledFunctions.
-    case Code::BINARY_OP_IC: {
-      BinaryOpStub stub(code_object->extended_extra_ic_state());
-      description = stub.GetName().Detach();
-      tag = Logger::STUB_TAG;
-      break;
-    }
+    case Code::BINARY_OP_IC:
     case Code::COMPARE_IC:  // fall through
     case Code::COMPARE_NIL_IC:   // fall through
     case Code::TO_BOOLEAN_IC:  // fall through
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index bd42161..4c3708c 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -718,8 +718,8 @@
     Isolate* isolate) {
   WriteInt32ToHeapNumberStub stub1(a1, v0, a2, a3);
   WriteInt32ToHeapNumberStub stub2(a2, v0, a3, a0);
-  stub1.GetCode(isolate)->set_is_pregenerated(true);
-  stub2.GetCode(isolate)->set_is_pregenerated(true);
+  stub1.GetCode(isolate);
+  stub2.GetCode(isolate);
 }
 
 
@@ -1261,7 +1261,7 @@
 }
 
 
-void BinaryOpStub::InitializeInterfaceDescriptor(
+void BinaryOpICStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
   static Register registers[] = { a1, a0 };
@@ -1735,7 +1735,7 @@
   StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
   CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
-  BinaryOpStub::GenerateAheadOfTime(isolate);
+  BinaryOpICStub::GenerateAheadOfTime(isolate);
 }
 
 
@@ -1754,16 +1754,13 @@
   if (!stub.FindCodeInCache(&store_buffer_overflow_code, isolate)) {
       store_buffer_overflow_code = *stub.GetCode(isolate);
   }
-  save_doubles_code->set_is_pregenerated(true);
-  store_buffer_overflow_code->set_is_pregenerated(true);
   isolate->set_fp_stubs_generated(true);
 }
 
 
 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
   CEntryStub stub(1, kDontSaveFPRegs);
-  Handle<Code> code = stub.GetCode(isolate);
-  code->set_is_pregenerated(true);
+  stub.GetCode(isolate);
 }
 
 
@@ -5481,10 +5478,10 @@
 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
     Isolate* isolate) {
   StoreBufferOverflowStub stub1(kDontSaveFPRegs);
-  stub1.GetCode(isolate)->set_is_pregenerated(true);
+  stub1.GetCode(isolate);
   // Hydrogen code stubs need stub2 at snapshot time.
   StoreBufferOverflowStub stub2(kSaveFPRegs);
-  stub2.GetCode(isolate)->set_is_pregenerated(true);
+  stub2.GetCode(isolate);
 }
 
 
@@ -5981,12 +5978,12 @@
   for (int i = 0; i <= to_index; ++i) {
     ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
     T stub(kind);
-    stub.GetCode(isolate)->set_is_pregenerated(true);
+    stub.GetCode(isolate);
     if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE ||
         (!FLAG_track_allocation_sites &&
          (kind == initial_kind || kind == initial_holey_kind))) {
       T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES);
-      stub1.GetCode(isolate)->set_is_pregenerated(true);
+      stub1.GetCode(isolate);
     }
   }
 }
@@ -6008,11 +6005,11 @@
   for (int i = 0; i < 2; i++) {
     // For internal arrays we only need a few things.
     InternalArrayNoArgumentConstructorStub stubh1(kinds[i]);
-    stubh1.GetCode(isolate)->set_is_pregenerated(true);
+    stubh1.GetCode(isolate);
     InternalArraySingleArgumentConstructorStub stubh2(kinds[i]);
-    stubh2.GetCode(isolate)->set_is_pregenerated(true);
+    stubh2.GetCode(isolate);
     InternalArrayNArgumentsConstructorStub stubh3(kinds[i]);
-    stubh3.GetCode(isolate)->set_is_pregenerated(true);
+    stubh3.GetCode(isolate);
   }
 }
 
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index a56fbb1..3ce2ab5 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -2319,7 +2319,7 @@
   patch_site.EmitJumpIfSmi(scratch1, &smi_case);
 
   __ bind(&stub_call);
-  BinaryOpStub stub(op, mode);
+  BinaryOpICStub stub(op, mode);
   CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
          expr->BinaryOperationFeedbackId());
   patch_site.EmitPatchInfo();
@@ -2328,7 +2328,6 @@
   __ bind(&smi_case);
   // Smi case. This code works the same way as the smi-smi case in the type
   // recording binary operation stub, see
-  // BinaryOpStub::GenerateSmiSmiOperation for comments.
   switch (op) {
     case Token::SAR:
       __ Branch(&stub_call);
@@ -2402,7 +2401,7 @@
                                      OverwriteMode mode) {
   __ mov(a0, result_register());
   __ pop(a1);
-  BinaryOpStub stub(op, mode);
+  BinaryOpICStub stub(op, mode);
   JumpPatchSite patch_site(masm_);    // unbound, signals no inlined smi code.
   CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
          expr->BinaryOperationFeedbackId());
@@ -4474,7 +4473,7 @@
   // Record position before stub call.
   SetSourcePosition(expr->position());
 
-  BinaryOpStub stub(Token::ADD, NO_OVERWRITE);
+  BinaryOpICStub stub(Token::ADD, NO_OVERWRITE);
   CallIC(stub.GetCode(isolate()),
          RelocInfo::CODE_TARGET,
          expr->CountBinOpFeedbackId());
diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc
index 37af8a6..4c1ddbd 100644
--- a/src/mips/ic-mips.cc
+++ b/src/mips/ic-mips.cc
@@ -1514,7 +1514,7 @@
 
 
 void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
-                                  StrictModeFlag strict_mode) {
+                                  ExtraICState extra_ic_state) {
   // ----------- S t a t e -------------
   //  -- a0    : value
   //  -- a1    : receiver
@@ -1524,7 +1524,7 @@
 
   // Get the receiver from the stack and probe the stub cache.
   Code::Flags flags = Code::ComputeFlags(
-      Code::HANDLER, MONOMORPHIC, strict_mode,
+      Code::HANDLER, MONOMORPHIC, extra_ic_state,
       Code::NORMAL, Code::STORE_IC);
   masm->isolate()->stub_cache()->GenerateProbe(
       masm, flags, a1, a2, a3, t0, t1, t2);
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index 3fb08ef..9f3c088 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -1841,8 +1841,7 @@
 
 
 void LCodeGen::DoThrow(LThrow* instr) {
-  Register input_reg = EmitLoadRegister(instr->value(), at);
-  __ push(input_reg);
+  __ push(ToRegister(instr->value()));
   ASSERT(ToRegister(instr->context()).is(cp));
   CallRuntime(Runtime::kThrow, 1, instr);
 
@@ -2000,7 +1999,7 @@
   ASSERT(ToRegister(instr->right()).is(a0));
   ASSERT(ToRegister(instr->result()).is(v0));
 
-  BinaryOpStub stub(instr->op(), NO_OVERWRITE);
+  BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
   CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
   // Other arch use a nop here, to signal that there is no inlined
   // patchable code. Mips does not need the nop, since our marker
@@ -3373,12 +3372,13 @@
 void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
   Register receiver = ToRegister(instr->receiver());
   Register function = ToRegister(instr->function());
+  Register result = ToRegister(instr->result());
   Register scratch = scratch0();
 
   // If the receiver is null or undefined, we have to pass the global
   // object as a receiver to normal functions. Values have to be
   // passed unchanged to builtins and strict-mode functions.
-  Label global_object, receiver_ok;
+  Label global_object, result_in_receiver;
 
   // Do not transform the receiver to object for strict mode
   // functions.
@@ -3392,7 +3392,7 @@
                   1 <<  (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize);
   int32_t native_mask = 1 << (SharedFunctionInfo::kNative + kSmiTagSize);
   __ And(scratch, scratch, Operand(strict_mode_function_mask | native_mask));
-  __ Branch(&receiver_ok, ne, scratch, Operand(zero_reg));
+  __ Branch(&result_in_receiver, ne, scratch, Operand(zero_reg));
 
   // Normal function. Replace undefined or null with global receiver.
   __ LoadRoot(scratch, Heap::kNullValueRootIndex);
@@ -3407,13 +3407,21 @@
   __ GetObjectType(receiver, scratch, scratch);
   DeoptimizeIf(lt, instr->environment(),
                scratch, Operand(FIRST_SPEC_OBJECT_TYPE));
-  __ Branch(&receiver_ok);
+  __ Branch(&result_in_receiver);
 
   __ bind(&global_object);
-  __ lw(receiver, GlobalObjectOperand());
-  __ lw(receiver,
-         FieldMemOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
-  __ bind(&receiver_ok);
+  __ lw(result, GlobalObjectOperand());
+  __ lw(result,
+         FieldMemOperand(result, JSGlobalObject::kGlobalReceiverOffset));
+  if (result.is(receiver)) {
+    __ bind(&result_in_receiver);
+  } else {
+    Label result_ok;
+    __ Branch(&result_ok);
+    __ bind(&result_in_receiver);
+    __ mov(result, receiver);
+    __ bind(&result_ok);
+  }
 }
 
 
@@ -4093,7 +4101,13 @@
 void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
   Register result = ToRegister(instr->result());
   Register base = ToRegister(instr->base_object());
-  __ Addu(result, base, Operand(instr->offset()));
+  if (instr->offset()->IsConstantOperand()) {
+    LConstantOperand* offset = LConstantOperand::cast(instr->offset());
+    __ Addu(result, base, Operand(ToInteger32(offset)));
+  } else {
+    Register offset = ToRegister(instr->offset());
+    __ Addu(result, base, offset);
+  }
 }
 
 
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 4b161d6..a441ba5 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -277,7 +277,8 @@
 void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
   stream->Add(" = ");
   base_object()->PrintTo(stream);
-  stream->Add(" + %d", offset());
+  stream->Add(" + ");
+  offset()->PrintTo(stream);
 }
 
 
@@ -1087,7 +1088,7 @@
   LOperand* receiver = UseRegisterAtStart(instr->receiver());
   LOperand* function = UseRegisterAtStart(instr->function());
   LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
-  return AssignEnvironment(DefineSameAsFirst(result));
+  return AssignEnvironment(DefineAsRegister(result));
 }
 
 
@@ -1119,11 +1120,11 @@
 
 
 LInstruction* LChunkBuilder::DoInnerAllocatedObject(
-    HInnerAllocatedObject* inner_object) {
-  LOperand* base_object = UseRegisterAtStart(inner_object->base_object());
-  LInnerAllocatedObject* result =
-    new(zone()) LInnerAllocatedObject(base_object);
-  return DefineAsRegister(result);
+    HInnerAllocatedObject* instr) {
+  LOperand* base_object = UseRegisterAtStart(instr->base_object());
+  LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
+  return DefineAsRegister(
+      new(zone()) LInnerAllocatedObject(base_object, offset));
 }
 
 
@@ -1454,7 +1455,7 @@
     if (instr->HasPowerOf2Divisor()) {
       ASSERT(!right->CanBeZero());
       LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
-                                     UseOrConstant(right));
+                                     UseConstant(right));
       LInstruction* result = DefineAsRegister(mod);
       return (left->CanBeNegative() &&
               instr->CheckFlag(HValue::kBailoutOnMinusZero))
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 2996c78..dbb78ea 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -1778,19 +1778,19 @@
 };
 
 
-class LInnerAllocatedObject V8_FINAL: public LTemplateInstruction<1, 1, 0> {
+class LInnerAllocatedObject V8_FINAL: public LTemplateInstruction<1, 2, 0> {
  public:
-  explicit LInnerAllocatedObject(LOperand* base_object) {
+  LInnerAllocatedObject(LOperand* base_object, LOperand* offset) {
     inputs_[0] = base_object;
+    inputs_[1] = offset;
   }
 
-  LOperand* base_object() { return inputs_[0]; }
-  int offset() { return hydrogen()->offset(); }
+  LOperand* base_object() const { return inputs_[0]; }
+  LOperand* offset() const { return inputs_[1]; }
 
   virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
 
-  DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "sub-allocated-object")
-  DECLARE_HYDROGEN_ACCESSOR(InnerAllocatedObject)
+  DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
 };
 
 
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index ea1c9a5..3d4617a 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -1533,7 +1533,7 @@
   Handle<Code> code =
       isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
                                                kind_,
-                                               extra_state_);
+                                               extra_state());
   __ Jump(code, RelocInfo::CODE_TARGET);
 }
 
@@ -1923,7 +1923,7 @@
   Label* index_out_of_range_label = &index_out_of_range;
 
   if (kind_ == Code::CALL_IC &&
-      (CallICBase::StringStubState::decode(extra_state_) ==
+      (CallICBase::StringStubState::decode(extra_state()) ==
        DEFAULT_STRING_STUB)) {
     index_out_of_range_label = &miss;
   }
@@ -1987,7 +1987,7 @@
   Label index_out_of_range;
   Label* index_out_of_range_label = &index_out_of_range;
   if (kind_ == Code::CALL_IC &&
-      (CallICBase::StringStubState::decode(extra_state_) ==
+      (CallICBase::StringStubState::decode(extra_state()) ==
        DEFAULT_STRING_STUB)) {
     index_out_of_range_label = &miss;
   }
@@ -2463,7 +2463,7 @@
   // Get the receiver from the stack.
   __ lw(a1, MemOperand(sp, argc * kPointerSize));
 
-  CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
+  CallInterceptorCompiler compiler(this, arguments(), a2, extra_state());
   compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
                    &miss);
 
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index cb68b89..eec5baf 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -152,13 +152,13 @@
     KeyedLoadStubCompiler ic_compiler(isolate(), flag);
     ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
   } else if (kind == Code::STORE_IC) {
-    StrictModeFlag strict_mode = StoreIC::GetStrictMode(extra_ic_state);
-    StoreStubCompiler ic_compiler(isolate(), strict_mode);
+    StoreStubCompiler ic_compiler(isolate(), extra_ic_state);
     ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
   } else {
     ASSERT(kind == Code::KEYED_STORE_IC);
-    StrictModeFlag strict_mode = StoreIC::GetStrictMode(extra_ic_state);
-    KeyedStoreStubCompiler ic_compiler(isolate(), strict_mode, STANDARD_STORE);
+    ASSERT(STANDARD_STORE ==
+           KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state));
+    KeyedStoreStubCompiler ic_compiler(isolate(), extra_ic_state);
     ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
   }
 
@@ -236,7 +236,7 @@
   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
 
-  KeyedStoreStubCompiler compiler(isolate(), strict_mode, store_mode);
+  KeyedStoreStubCompiler compiler(isolate(), extra_state);
   Handle<Code> code = compiler.CompileStoreElement(receiver_map);
 
   Map::UpdateCodeCache(receiver_map, name, code);
@@ -647,7 +647,7 @@
   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
 
-  KeyedStoreStubCompiler compiler(isolate_, strict_mode, store_mode);
+  KeyedStoreStubCompiler compiler(isolate_, extra_state);
   Handle<Code> code = compiler.CompileStoreElementPolymorphic(receiver_maps);
   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
   return code;
@@ -1129,7 +1129,7 @@
 
 
 CallKind CallStubCompiler::call_kind() {
-  return CallICBase::Contextual::decode(extra_state_)
+  return CallICBase::Contextual::decode(extra_state())
       ? CALL_AS_FUNCTION
       : CALL_AS_METHOD;
 }
@@ -1577,11 +1577,11 @@
     stub = KeyedStoreFastElementStub(
         is_jsarray,
         elements_kind,
-        store_mode_).GetCode(isolate());
+        store_mode()).GetCode(isolate());
   } else {
     stub = KeyedStoreElementStub(is_jsarray,
                                  elements_kind,
-                                 store_mode_).GetCode(isolate());
+                                 store_mode()).GetCode(isolate());
   }
 
   __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
@@ -1707,19 +1707,19 @@
           elements_kind,
           transitioned_map->elements_kind(),
           is_js_array,
-          store_mode_).GetCode(isolate());
+          store_mode()).GetCode(isolate());
     } else {
       if (receiver_map->has_fast_elements() ||
           receiver_map->has_external_array_elements()) {
         cached_stub = KeyedStoreFastElementStub(
             is_js_array,
             elements_kind,
-            store_mode_).GetCode(isolate());
+            store_mode()).GetCode(isolate());
       } else {
         cached_stub = KeyedStoreElementStub(
             is_js_array,
             elements_kind,
-            store_mode_).GetCode(isolate());
+            store_mode()).GetCode(isolate());
       }
     }
     ASSERT(!cached_stub.is_null());
@@ -1746,10 +1746,9 @@
                                    Code::Kind kind,
                                    ExtraICState extra_state,
                                    InlineCacheHolderFlag cache_holder)
-    : StubCompiler(isolate),
+    : StubCompiler(isolate, extra_state),
       arguments_(argc),
       kind_(kind),
-      extra_state_(extra_state),
       cache_holder_(cache_holder) {
 }
 
@@ -1817,7 +1816,7 @@
                                        Handle<Name> name) {
   int argc = arguments_.immediate();
   Code::Flags flags = Code::ComputeMonomorphicFlags(
-      kind_, extra_state_, cache_holder_, type, argc);
+      kind_, extra_state(), cache_holder_, type, argc);
   return GetCodeWithFlags(flags, name);
 }
 
diff --git a/src/stub-cache.h b/src/stub-cache.h
index c70b1ff..ebf0bd3 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -364,8 +364,10 @@
 // The stub compilers compile stubs for the stub cache.
 class StubCompiler BASE_EMBEDDED {
  public:
-  explicit StubCompiler(Isolate* isolate)
-      : isolate_(isolate), masm_(isolate, NULL, 256), failure_(NULL) { }
+  explicit StubCompiler(Isolate* isolate,
+                        ExtraICState extra_ic_state = kNoExtraICState)
+      : isolate_(isolate), extra_ic_state_(extra_ic_state),
+        masm_(isolate, NULL, 256), failure_(NULL) { }
 
   // Functions to compile either CallIC or KeyedCallIC.  The specific kind
   // is extracted from the code flags.
@@ -489,6 +491,8 @@
   Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
   Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name);
 
+  ExtraICState extra_state() { return extra_ic_state_; }
+
   MacroAssembler* masm() { return &masm_; }
   void set_failure(Failure* failure) { failure_ = failure; }
 
@@ -504,6 +508,7 @@
 
  private:
   Isolate* isolate_;
+  const ExtraICState extra_ic_state_;
   MacroAssembler masm_;
   Failure* failure_;
 };
@@ -516,8 +521,11 @@
  public:
   BaseLoadStoreStubCompiler(Isolate* isolate,
                             Code::Kind kind,
+                            ExtraICState extra_ic_state = kNoExtraICState,
                             InlineCacheHolderFlag cache_holder = OWN_MAP)
-      : StubCompiler(isolate), kind_(kind), cache_holder_(cache_holder) {
+      : StubCompiler(isolate, extra_ic_state),
+        kind_(kind),
+        cache_holder_(cache_holder) {
     InitializeRegisters();
   }
   virtual ~BaseLoadStoreStubCompiler() { }
@@ -589,7 +597,6 @@
   }
   void JitEvent(Handle<Name> name, Handle<Code> code);
 
-  virtual ExtraICState extra_state() { return kNoExtraICState; }
   virtual Register receiver() = 0;
   virtual Register name() = 0;
   virtual Register scratch1() = 0;
@@ -609,9 +616,11 @@
 class LoadStubCompiler: public BaseLoadStoreStubCompiler {
  public:
   LoadStubCompiler(Isolate* isolate,
+                   ExtraICState extra_ic_state = kNoExtraICState,
                    InlineCacheHolderFlag cache_holder = OWN_MAP,
                    Code::Kind kind = Code::LOAD_IC)
-      : BaseLoadStoreStubCompiler(isolate, kind, cache_holder) { }
+      : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state,
+                                  cache_holder) { }
   virtual ~LoadStubCompiler() { }
 
   Handle<Code> CompileLoadField(Handle<Type> type,
@@ -708,8 +717,10 @@
 class KeyedLoadStubCompiler: public LoadStubCompiler {
  public:
   KeyedLoadStubCompiler(Isolate* isolate,
+                        ExtraICState extra_ic_state = kNoExtraICState,
                         InlineCacheHolderFlag cache_holder = OWN_MAP)
-      : LoadStubCompiler(isolate, cache_holder, Code::KEYED_LOAD_IC) { }
+      : LoadStubCompiler(isolate, extra_ic_state, cache_holder,
+                         Code::KEYED_LOAD_IC) { }
 
   Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
 
@@ -732,10 +743,9 @@
 class StoreStubCompiler: public BaseLoadStoreStubCompiler {
  public:
   StoreStubCompiler(Isolate* isolate,
-                    StrictModeFlag strict_mode,
+                    ExtraICState extra_ic_state,
                     Code::Kind kind = Code::STORE_IC)
-      : BaseLoadStoreStubCompiler(isolate, kind),
-        strict_mode_(strict_mode) { }
+      : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state) {}
 
   virtual ~StoreStubCompiler() { }
 
@@ -826,16 +836,11 @@
   virtual Register scratch1() { return registers_[3]; }
   virtual Register scratch2() { return registers_[4]; }
   virtual Register scratch3() { return registers_[5]; }
-  StrictModeFlag strict_mode() { return strict_mode_; }
-  virtual ExtraICState extra_state() {
-    return StoreIC::ComputeExtraICState(strict_mode_);
-  }
 
  protected:
   static Register* registers();
 
  private:
-  StrictModeFlag strict_mode_;
   friend class BaseLoadStoreStubCompiler;
 };
 
@@ -843,10 +848,8 @@
 class KeyedStoreStubCompiler: public StoreStubCompiler {
  public:
   KeyedStoreStubCompiler(Isolate* isolate,
-                         StrictModeFlag strict_mode,
-                         KeyedAccessStoreMode store_mode)
-      : StoreStubCompiler(isolate, strict_mode, Code::KEYED_STORE_IC),
-        store_mode_(store_mode) { }
+                         ExtraICState extra_ic_state)
+      : StoreStubCompiler(isolate, extra_ic_state, Code::KEYED_STORE_IC) {}
 
   Handle<Code> CompileStoreElement(Handle<Map> receiver_map);
 
@@ -859,11 +862,12 @@
   static void GenerateStoreDictionaryElement(MacroAssembler* masm);
 
  protected:
-  virtual ExtraICState extra_state() {
-    return KeyedStoreIC::ComputeExtraICState(strict_mode(), store_mode_);
-  }
   static Register* registers();
 
+  KeyedAccessStoreMode store_mode() {
+    return KeyedStoreIC::GetKeyedAccessStoreMode(extra_state());
+  }
+
  private:
   Register transition_map() {
     return registers()[3];
@@ -872,7 +876,6 @@
   virtual void GenerateNameCheck(Handle<Name> name,
                                  Register name_reg,
                                  Label* miss);
-  KeyedAccessStoreMode store_mode_;
   friend class BaseLoadStoreStubCompiler;
 };
 
@@ -1000,7 +1003,6 @@
 
   const ParameterCount arguments_;
   const Code::Kind kind_;
-  const ExtraICState extra_state_;
   const InlineCacheHolderFlag cache_holder_;
 };
 
diff --git a/src/token.h b/src/token.h
index 992adaa..39bcc24 100644
--- a/src/token.h
+++ b/src/token.h
@@ -213,6 +213,10 @@
     return COMMA <= op && op <= MOD;
   }
 
+  static bool IsTruncatingBinaryOp(Value op) {
+    return BIT_OR <= op && op <= ROR;
+  }
+
   static bool IsCompareOp(Value op) {
     return EQ <= op && op <= IN;
   }
diff --git a/src/type-info.cc b/src/type-info.cc
index e4eb7db..6e3a4f6 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -197,30 +197,29 @@
 }
 
 
-bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) {
-  Handle<Object> value = GetInfo(expr->CallFeedbackId());
+bool TypeFeedbackOracle::CallIsMonomorphic(TypeFeedbackId id) {
+  Handle<Object> value = GetInfo(id);
   return value->IsMap() || value->IsAllocationSite() || value->IsJSFunction() ||
       value->IsSmi() ||
       (value->IsCode() && Handle<Code>::cast(value)->ic_state() == MONOMORPHIC);
 }
 
 
-bool TypeFeedbackOracle::KeyedArrayCallIsHoley(Call* expr) {
-  Handle<Object> value = GetInfo(expr->CallFeedbackId());
+bool TypeFeedbackOracle::KeyedArrayCallIsHoley(TypeFeedbackId id) {
+  Handle<Object> value = GetInfo(id);
   Handle<Code> code = Handle<Code>::cast(value);
   return KeyedArrayCallStub::IsHoley(code);
 }
 
 
-bool TypeFeedbackOracle::CallNewIsMonomorphic(CallNew* expr) {
-  Handle<Object> info = GetInfo(expr->CallNewFeedbackId());
+bool TypeFeedbackOracle::CallNewIsMonomorphic(TypeFeedbackId id) {
+  Handle<Object> info = GetInfo(id);
   return info->IsAllocationSite() || info->IsJSFunction();
 }
 
 
-bool TypeFeedbackOracle::ObjectLiteralStoreIsMonomorphic(
-    ObjectLiteral::Property* prop) {
-  Handle<Object> map_or_code = GetInfo(prop->key()->LiteralFeedbackId());
+bool TypeFeedbackOracle::ObjectLiteralStoreIsMonomorphic(TypeFeedbackId id) {
+  Handle<Object> map_or_code = GetInfo(id);
   return map_or_code->IsMap();
 }
 
@@ -285,22 +284,21 @@
 }
 
 
-void TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr,
+void TypeFeedbackOracle::StoreReceiverTypes(TypeFeedbackId id,
                                             Handle<String> name,
                                             SmallMapList* types) {
   Code::Flags flags = Code::ComputeFlags(
       Code::HANDLER, MONOMORPHIC, kNoExtraICState,
       Code::NORMAL, Code::STORE_IC);
-  CollectReceiverTypes(expr->AssignmentFeedbackId(), name, flags, types);
+  CollectReceiverTypes(id, name, flags, types);
 }
 
 
-void TypeFeedbackOracle::CallReceiverTypes(Call* expr,
+void TypeFeedbackOracle::CallReceiverTypes(TypeFeedbackId id,
                                            Handle<String> name,
+                                           int arity,
                                            CallKind call_kind,
                                            SmallMapList* types) {
-  int arity = expr->arguments()->length();
-
   // Note: Currently we do not take string extra ic data into account
   // here.
   ContextualMode contextual_mode = call_kind == CALL_AS_FUNCTION
@@ -311,12 +309,12 @@
 
   Code::Flags flags = Code::ComputeMonomorphicFlags(
       Code::CALL_IC, extra_ic_state, OWN_MAP, Code::NORMAL, arity);
-  CollectReceiverTypes(expr->CallFeedbackId(), name, flags, types);
+  CollectReceiverTypes(id, name, flags, types);
 }
 
 
-CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) {
-  Handle<Object> value = GetInfo(expr->CallFeedbackId());
+CheckType TypeFeedbackOracle::GetCallCheckType(TypeFeedbackId id) {
+  Handle<Object> value = GetInfo(id);
   if (!value->IsSmi()) return RECEIVER_MAP_CHECK;
   CheckType check = static_cast<CheckType>(Smi::cast(*value)->value());
   ASSERT(check != RECEIVER_MAP_CHECK);
@@ -324,8 +322,8 @@
 }
 
 
-Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(Call* expr) {
-  Handle<Object> info = GetInfo(expr->CallFeedbackId());
+Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(TypeFeedbackId id) {
+  Handle<Object> info = GetInfo(id);
   if (info->IsAllocationSite()) {
     return Handle<JSFunction>(isolate_->global_context()->array_function());
   } else {
@@ -334,8 +332,8 @@
 }
 
 
-Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(CallNew* expr) {
-  Handle<Object> info = GetInfo(expr->CallNewFeedbackId());
+Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(TypeFeedbackId id) {
+  Handle<Object> info = GetInfo(id);
   if (info->IsAllocationSite()) {
     return Handle<JSFunction>(isolate_->global_context()->array_function());
   } else {
@@ -344,15 +342,15 @@
 }
 
 
-Handle<Cell> TypeFeedbackOracle::GetCallNewAllocationInfoCell(CallNew* expr) {
-  return GetInfoCell(expr->CallNewFeedbackId());
+Handle<Cell> TypeFeedbackOracle::GetCallNewAllocationInfoCell(
+    TypeFeedbackId id) {
+  return GetInfoCell(id);
 }
 
 
-Handle<Map> TypeFeedbackOracle::GetObjectLiteralStoreMap(
-    ObjectLiteral::Property* prop) {
-  ASSERT(ObjectLiteralStoreIsMonomorphic(prop));
-  return Handle<Map>::cast(GetInfo(prop->key()->LiteralFeedbackId()));
+Handle<Map> TypeFeedbackOracle::GetObjectLiteralStoreMap(TypeFeedbackId id) {
+  ASSERT(ObjectLiteralStoreIsMonomorphic(id));
+  return Handle<Map>::cast(GetInfo(id));
 }
 
 
@@ -410,28 +408,26 @@
                                     Handle<Type>* right,
                                     Handle<Type>* result,
                                     Maybe<int>* fixed_right_arg,
-                                    Token::Value operation) {
+                                    Token::Value op) {
   Handle<Object> object = GetInfo(id);
   if (!object->IsCode()) {
     // For some binary ops we don't have ICs, e.g. Token::COMMA, but for the
-    // operations covered by the BinaryOpStub we should always have them.
-    ASSERT(!(operation >= BinaryOpStub::FIRST_TOKEN &&
-             operation <= BinaryOpStub::LAST_TOKEN));
+    // operations covered by the BinaryOpIC we should always have them.
+    ASSERT(op < BinaryOpIC::State::FIRST_TOKEN ||
+           op > BinaryOpIC::State::LAST_TOKEN);
     *left = *right = *result = handle(Type::None(), isolate_);
+    *fixed_right_arg = Maybe<int>();
     return;
   }
   Handle<Code> code = Handle<Code>::cast(object);
-  ASSERT(code->is_binary_op_stub());
+  ASSERT_EQ(Code::BINARY_OP_IC, code->kind());
+  BinaryOpIC::State state(code->extended_extra_ic_state());
+  ASSERT_EQ(op, state.op());
 
-  BinaryOpStub stub(code->extended_extra_ic_state());
-
-  // Sanity check.
-  ASSERT(stub.operation() == operation);
-
-  *left = stub.GetLeftType(isolate());
-  *right = stub.GetRightType(isolate());
-  *result = stub.GetResultType(isolate());
-  *fixed_right_arg = stub.fixed_right_arg();
+  *left = state.GetLeftType(isolate());
+  *right = state.GetRightType(isolate());
+  *result = state.GetResultType(isolate());
+  *fixed_right_arg = state.fixed_right_arg();
 }
 
 
@@ -449,13 +445,11 @@
 
 Handle<Type> TypeFeedbackOracle::CountType(TypeFeedbackId id) {
   Handle<Object> object = GetInfo(id);
-  Handle<Type> unknown(Type::None(), isolate_);
-  if (!object->IsCode()) return unknown;
+  if (!object->IsCode()) return handle(Type::None(), isolate_);
   Handle<Code> code = Handle<Code>::cast(object);
-  if (!code->is_binary_op_stub()) return unknown;
-
-  BinaryOpStub stub(code->extended_extra_ic_state());
-  return stub.GetLeftType(isolate());
+  ASSERT_EQ(Code::BINARY_OP_IC, code->kind());
+  BinaryOpIC::State state(code->extended_extra_ic_state());
+  return state.GetLeftType(isolate());
 }
 
 
@@ -486,6 +480,28 @@
 }
 
 
+void TypeFeedbackOracle::AssignmentReceiverTypes(
+    TypeFeedbackId id, Handle<String> name, SmallMapList* receiver_types) {
+  receiver_types->Clear();
+  StoreReceiverTypes(id, name, receiver_types);
+}
+
+
+void TypeFeedbackOracle::KeyedAssignmentReceiverTypes(
+    TypeFeedbackId id, SmallMapList* receiver_types,
+    KeyedAccessStoreMode* store_mode) {
+  receiver_types->Clear();
+  if (StoreIsMonomorphicNormal(id)) {
+    // Record receiver type for monomorphic keyed stores.
+    receiver_types->Add(StoreMonomorphicReceiverType(id), zone());
+  } else if (StoreIsKeyedPolymorphic(id)) {
+    receiver_types->Reserve(kMaxKeyedPolymorphism, zone());
+    CollectKeyedReceiverTypes(id, receiver_types);
+  }
+  *store_mode = GetStoreMode(id);
+}
+
+
 void TypeFeedbackOracle::CountReceiverTypes(
     TypeFeedbackId id, SmallMapList* receiver_types) {
   receiver_types->Clear();
diff --git a/src/type-info.h b/src/type-info.h
index 05c76f2..a0d3215 100644
--- a/src/type-info.h
+++ b/src/type-info.h
@@ -218,20 +218,9 @@
 
 
 // Forward declarations.
-// TODO(rossberg): these should all go away eventually.
-class Assignment;
-class Call;
-class CallNew;
-class CaseClause;
 class CompilationInfo;
-class CountOperation;
-class Expression;
-class ForInStatement;
 class ICStub;
-class Property;
 class SmallMapList;
-class ObjectLiteral;
-class ObjectLiteralProperty;
 
 
 class TypeFeedbackOracle: public ZoneObject {
@@ -245,14 +234,14 @@
   bool LoadIsUninitialized(TypeFeedbackId id);
   bool LoadIsPreMonomorphic(TypeFeedbackId id);
   bool LoadIsPolymorphic(TypeFeedbackId id);
-  bool StoreIsUninitialized(TypeFeedbackId ast_id);
-  bool StoreIsMonomorphicNormal(TypeFeedbackId ast_id);
-  bool StoreIsPreMonomorphic(TypeFeedbackId ast_id);
-  bool StoreIsKeyedPolymorphic(TypeFeedbackId ast_id);
-  bool CallIsMonomorphic(Call* expr);
-  bool KeyedArrayCallIsHoley(Call* expr);
-  bool CallNewIsMonomorphic(CallNew* expr);
-  bool ObjectLiteralStoreIsMonomorphic(ObjectLiteralProperty* prop);
+  bool StoreIsUninitialized(TypeFeedbackId id);
+  bool StoreIsMonomorphicNormal(TypeFeedbackId id);
+  bool StoreIsPreMonomorphic(TypeFeedbackId id);
+  bool StoreIsKeyedPolymorphic(TypeFeedbackId id);
+  bool CallIsMonomorphic(TypeFeedbackId aid);
+  bool KeyedArrayCallIsHoley(TypeFeedbackId id);
+  bool CallNewIsMonomorphic(TypeFeedbackId id);
+  bool ObjectLiteralStoreIsMonomorphic(TypeFeedbackId id);
 
   // TODO(1571) We can't use ForInStatement::ForInType as the return value due
   // to various cycles in our headers.
@@ -263,21 +252,22 @@
   Handle<Map> LoadMonomorphicReceiverType(TypeFeedbackId id);
   Handle<Map> StoreMonomorphicReceiverType(TypeFeedbackId id);
 
-  KeyedAccessStoreMode GetStoreMode(TypeFeedbackId ast_id);
+  KeyedAccessStoreMode GetStoreMode(TypeFeedbackId id);
 
   void LoadReceiverTypes(TypeFeedbackId id,
                          Handle<String> name,
                          SmallMapList* types);
-  void StoreReceiverTypes(Assignment* expr,
+  void StoreReceiverTypes(TypeFeedbackId id,
                           Handle<String> name,
                           SmallMapList* types);
-  void CallReceiverTypes(Call* expr,
+  void CallReceiverTypes(TypeFeedbackId id,
                          Handle<String> name,
+                         int arity,
                          CallKind call_kind,
                          SmallMapList* types);
-  void CollectKeyedReceiverTypes(TypeFeedbackId ast_id,
+  void CollectKeyedReceiverTypes(TypeFeedbackId id,
                                  SmallMapList* types);
-  void CollectPolymorphicStoreReceiverTypes(TypeFeedbackId ast_id,
+  void CollectPolymorphicStoreReceiverTypes(TypeFeedbackId id,
                                             SmallMapList* types);
 
   void PropertyReceiverTypes(TypeFeedbackId id,
@@ -287,6 +277,12 @@
   void KeyedPropertyReceiverTypes(TypeFeedbackId id,
                                   SmallMapList* receiver_types,
                                   bool* is_string);
+  void AssignmentReceiverTypes(TypeFeedbackId id,
+                               Handle<String> name,
+                               SmallMapList* receiver_types);
+  void KeyedAssignmentReceiverTypes(TypeFeedbackId id,
+                                    SmallMapList* receiver_types,
+                                    KeyedAccessStoreMode* store_mode);
   void CountReceiverTypes(TypeFeedbackId id,
                           SmallMapList* receiver_types);
 
@@ -296,12 +292,12 @@
 
   void CollectPolymorphicMaps(Handle<Code> code, SmallMapList* types);
 
-  CheckType GetCallCheckType(Call* expr);
-  Handle<JSFunction> GetCallTarget(Call* expr);
-  Handle<JSFunction> GetCallNewTarget(CallNew* expr);
-  Handle<Cell> GetCallNewAllocationInfoCell(CallNew* expr);
+  CheckType GetCallCheckType(TypeFeedbackId id);
+  Handle<JSFunction> GetCallTarget(TypeFeedbackId id);
+  Handle<JSFunction> GetCallNewTarget(TypeFeedbackId id);
+  Handle<Cell> GetCallNewAllocationInfoCell(TypeFeedbackId id);
 
-  Handle<Map> GetObjectLiteralStoreMap(ObjectLiteralProperty* prop);
+  Handle<Map> GetObjectLiteralStoreMap(TypeFeedbackId id);
 
   bool LoadIsBuiltin(TypeFeedbackId id, Builtins::Name builtin_id);
   bool LoadIsStub(TypeFeedbackId id, ICStub* stub);
@@ -332,12 +328,12 @@
   Isolate* isolate() const { return isolate_; }
 
  private:
-  void CollectReceiverTypes(TypeFeedbackId ast_id,
+  void CollectReceiverTypes(TypeFeedbackId id,
                             Handle<String> name,
                             Code::Flags flags,
                             SmallMapList* types);
 
-  void SetInfo(TypeFeedbackId ast_id, Object* target);
+  void SetInfo(TypeFeedbackId id, Object* target);
 
   void BuildDictionary(Handle<Code> code);
   void GetRelocInfos(Handle<Code> code, ZoneList<RelocInfo>* infos);
@@ -350,10 +346,10 @@
 
   // Returns an element from the backing store. Returns undefined if
   // there is no information.
-  Handle<Object> GetInfo(TypeFeedbackId ast_id);
+  Handle<Object> GetInfo(TypeFeedbackId id);
 
   // Return the cell that contains type feedback.
-  Handle<Cell> GetInfoCell(TypeFeedbackId ast_id);
+  Handle<Cell> GetInfoCell(TypeFeedbackId id);
 
  private:
   Handle<Context> native_context_;
diff --git a/src/typing.cc b/src/typing.cc
index d9420ad..8487c05 100644
--- a/src/typing.cc
+++ b/src/typing.cc
@@ -387,31 +387,35 @@
 
 
 void AstTyper::VisitAssignment(Assignment* expr) {
-  // TODO(rossberg): Can we clean this up?
-  if (expr->is_compound()) {
-    // Collect type feedback.
-    Expression* target = expr->target();
-    Property* prop = target->AsProperty();
-    if (prop != NULL) {
-      RECURSE(Visit(expr->target()));
-      expr->RecordTypeFeedback(oracle(), zone());
+  // Collect type feedback.
+  Property* prop = expr->target()->AsProperty();
+  if (prop != NULL) {
+    TypeFeedbackId id = expr->AssignmentFeedbackId();
+    expr->set_is_uninitialized(oracle()->StoreIsUninitialized(id));
+    if (!expr->IsUninitialized()) {
+      expr->set_is_pre_monomorphic(oracle()->StoreIsPreMonomorphic(id));
+      expr->set_is_monomorphic(oracle()->StoreIsMonomorphicNormal(id));
+      ASSERT(!expr->IsPreMonomorphic() || !expr->IsMonomorphic());
+      if (prop->key()->IsPropertyName()) {
+        Literal* lit_key = prop->key()->AsLiteral();
+        ASSERT(lit_key != NULL && lit_key->value()->IsString());
+        Handle<String> name = Handle<String>::cast(lit_key->value());
+        oracle()->AssignmentReceiverTypes(id, name, expr->GetReceiverTypes());
+      } else {
+        KeyedAccessStoreMode store_mode;
+        oracle()->KeyedAssignmentReceiverTypes(
+            id, expr->GetReceiverTypes(), &store_mode);
+        expr->set_store_mode(store_mode);
+      }
     }
-
-    RECURSE(Visit(expr->binary_operation()));
-
-    NarrowType(expr, expr->binary_operation()->bounds());
-  } else {
-    // Collect type feedback.
-    if (expr->target()->IsProperty()) {
-      expr->RecordTypeFeedback(oracle(), zone());
-    }
-
-    RECURSE(Visit(expr->target()));
-    RECURSE(Visit(expr->value()));
-
-    NarrowType(expr, expr->value()->bounds());
   }
 
+  Expression* rhs =
+      expr->is_compound() ? expr->binary_operation() : expr->value();
+  RECURSE(Visit(expr->target()));
+  RECURSE(Visit(rhs));
+  NarrowType(expr, rhs->bounds());
+
   VariableProxy* proxy = expr->target()->AsVariableProxy();
   if (proxy != NULL && proxy->var()->IsStackAllocated()) {
     store_.Seq(variable_index(proxy->var()), Effect(expr->bounds()));
diff --git a/src/version.cc b/src/version.cc
index d4f7feb..fee352e 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      16
+#define BUILD_NUMBER      17
 #define PATCH_LEVEL       0
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc
index 49bd78d..bc875d6 100644
--- a/src/x64/assembler-x64.cc
+++ b/src/x64/assembler-x64.cc
@@ -1395,92 +1395,59 @@
 }
 
 
-void Assembler::movl(Register dst, const Operand& src) {
+void Assembler::emit_mov(Register dst, const Operand& src, int size) {
   EnsureSpace ensure_space(this);
-  emit_optional_rex_32(dst, src);
+  emit_rex(dst, src, size);
   emit(0x8B);
   emit_operand(dst, src);
 }
 
 
-void Assembler::movl(Register dst, Register src) {
+void Assembler::emit_mov(Register dst, Register src, int size) {
   EnsureSpace ensure_space(this);
   if (src.low_bits() == 4) {
-    emit_optional_rex_32(src, dst);
+    emit_rex(src, dst, size);
     emit(0x89);
     emit_modrm(src, dst);
   } else {
-    emit_optional_rex_32(dst, src);
+    emit_rex(dst, src, size);
     emit(0x8B);
     emit_modrm(dst, src);
   }
 }
 
 
-void Assembler::movl(const Operand& dst, Register src) {
+void Assembler::emit_mov(const Operand& dst, Register src, int size) {
   EnsureSpace ensure_space(this);
-  emit_optional_rex_32(src, dst);
+  emit_rex(src, dst, size);
   emit(0x89);
   emit_operand(src, dst);
 }
 
 
-void Assembler::movl(const Operand& dst, Immediate value) {
+void Assembler::emit_mov(Register dst, Immediate value, int size) {
   EnsureSpace ensure_space(this);
-  emit_optional_rex_32(dst);
+  emit_rex(dst, size);
+  if (size == kInt64Size) {
+    emit(0xC7);
+    emit_modrm(0x0, dst);
+  } else {
+    ASSERT(size == kInt32Size);
+    emit(0xB8 + dst.low_bits());
+  }
+  emit(value);
+}
+
+
+void Assembler::emit_mov(const Operand& dst, Immediate value, int size) {
+  EnsureSpace ensure_space(this);
+  emit_rex(dst, size);
   emit(0xC7);
   emit_operand(0x0, dst);
   emit(value);
 }
 
 
-void Assembler::movl(Register dst, Immediate value) {
-  EnsureSpace ensure_space(this);
-  emit_optional_rex_32(dst);
-  emit(0xB8 + dst.low_bits());
-  emit(value);
-}
-
-
-void Assembler::movq(Register dst, const Operand& src) {
-  EnsureSpace ensure_space(this);
-  emit_rex_64(dst, src);
-  emit(0x8B);
-  emit_operand(dst, src);
-}
-
-
-void Assembler::movq(Register dst, Register src) {
-  EnsureSpace ensure_space(this);
-  if (src.low_bits() == 4) {
-    emit_rex_64(src, dst);
-    emit(0x89);
-    emit_modrm(src, dst);
-  } else {
-    emit_rex_64(dst, src);
-    emit(0x8B);
-    emit_modrm(dst, src);
-  }
-}
-
-
-void Assembler::movq(Register dst, Immediate value) {
-  EnsureSpace ensure_space(this);
-  emit_rex_64(dst);
-  emit(0xC7);
-  emit_modrm(0x0, dst);
-  emit(value);  // Only 32-bit immediates are possible, not 8-bit immediates.
-}
-
-
-void Assembler::movq(const Operand& dst, Register src) {
-  EnsureSpace ensure_space(this);
-  emit_rex_64(src, dst);
-  emit(0x89);
-  emit_operand(src, dst);
-}
-
-
 void Assembler::movq(Register dst, void* value, RelocInfo::Mode rmode) {
   // This method must not be used with heap object references. The stored
   // address is not GC safe. Use the handle version instead.
@@ -1504,12 +1471,8 @@
 }
 
 
-void Assembler::movq(const Operand& dst, Immediate value) {
-  EnsureSpace ensure_space(this);
-  emit_rex_64(dst);
-  emit(0xC7);
-  emit_operand(0, dst);
-  emit(value);
+void Assembler::movq(Register dst, uint64_t value) {
+  movq(dst, static_cast<int64_t>(value));
 }
 
 
diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h
index 709b61b..1f1316f 100644
--- a/src/x64/assembler-x64.h
+++ b/src/x64/assembler-x64.h
@@ -530,6 +530,10 @@
 };
 
 
+#define ASSEMBLER_INSTRUCTION_LIST(V)  \
+  V(mov)
+
+
 class Assembler : public AssemblerBase {
  private:
   // We check before assembling an instruction that there is sufficient
@@ -658,6 +662,24 @@
   // Some mnemonics, such as "and", are the same as C++ keywords.
   // Naming conflicts with C++ keywords are resolved by adding a trailing '_'.
 
+#define DECLARE_INSTRUCTION(instruction)                \
+  template<class P1, class P2>                          \
+  void instruction##p(P1 p1, P2 p2) {                   \
+    emit_##instruction(p1, p2, kPointerSize);           \
+  }                                                     \
+                                                        \
+  template<class P1, class P2>                          \
+  void instruction##l(P1 p1, P2 p2) {                   \
+    emit_##instruction(p1, p2, kInt32Size);             \
+  }                                                     \
+                                                        \
+  template<class P1, class P2>                          \
+  void instruction##q(P1 p1, P2 p2) {                   \
+    emit_##instruction(p1, p2, kInt64Size);             \
+  }
+  ASSEMBLER_INSTRUCTION_LIST(DECLARE_INSTRUCTION)
+#undef DECLARE_INSTRUCTION
+
   // Insert the smallest number of nop instructions
   // possible to align the pc offset to a multiple
   // of m, where m must be a power of 2.
@@ -695,30 +717,15 @@
   void movw(const Operand& dst, Register src);
   void movw(const Operand& dst, Immediate imm);
 
-  void movl(Register dst, Register src);
-  void movl(Register dst, const Operand& src);
-  void movl(const Operand& dst, Register src);
-  void movl(const Operand& dst, Immediate imm);
-  // Load a 32-bit immediate value, zero-extended to 64 bits.
-  void movl(Register dst, Immediate imm32);
-
-  // Move 64 bit register value to 64-bit memory location.
-  void movq(const Operand& dst, Register src);
-  // Move 64 bit memory location to 64-bit register value.
-  void movq(Register dst, const Operand& src);
-  void movq(Register dst, Register src);
-  // Sign extends immediate 32-bit value to 64 bits.
-  void movq(Register dst, Immediate x);
   // Move the offset of the label location relative to the current
   // position (after the move) to the destination.
   void movl(const Operand& dst, Label* src);
 
-  // Move sign extended immediate to memory location.
-  void movq(const Operand& dst, Immediate value);
   // Loads a pointer into a register with a relocation mode.
   void movq(Register dst, void* ptr, RelocInfo::Mode rmode);
   // Loads a 64-bit immediate into a register.
   void movq(Register dst, int64_t value);
+  void movq(Register dst, uint64_t value);
   void movq(Register dst, Handle<Object> handle, RelocInfo::Mode rmode);
 
   void movsxbq(Register dst, const Operand& src);
@@ -1590,6 +1597,25 @@
   // numbers have a high bit set.
   inline void emit_optional_rex_32(const Operand& op);
 
+  template<class P1>
+  void emit_rex(P1 p1, int size) {
+    if (size == kInt64Size) {
+      emit_rex_64(p1);
+    } else {
+      ASSERT(size == kInt32Size);
+      emit_optional_rex_32(p1);
+    }
+  }
+
+  template<class P1, class P2>
+  void emit_rex(P1 p1, P2 p2, int size) {
+    if (size == kInt64Size) {
+      emit_rex_64(p1, p2);
+    } else {
+      ASSERT(size == kInt32Size);
+      emit_optional_rex_32(p1, p2);
+    }
+  }
 
   // Emit the ModR/M byte, and optionally the SIB byte and
   // 1- or 4-byte offset for a memory operand.  Also encodes
@@ -1675,6 +1701,12 @@
   // record reloc info for current pc_
   void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
 
+  void emit_mov(Register dst, const Operand& src, int size);
+  void emit_mov(Register dst, Register src, int size);
+  void emit_mov(const Operand& dst, Register src, int size);
+  void emit_mov(Register dst, Immediate value, int size);
+  void emit_mov(const Operand& dst, Immediate value, int size);
+
   friend class CodePatcher;
   friend class EnsureSpace;
   friend class RegExpMacroAssemblerX64;
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 6f35a21..0c9a0f2 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -180,7 +180,7 @@
 }
 
 
-void BinaryOpStub::InitializeInterfaceDescriptor(
+void BinaryOpICStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
   static Register registers[] = { rdx, rax };
@@ -2788,7 +2788,7 @@
   // It is important that the store buffer overflow stubs are generated first.
   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
   CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
-  BinaryOpStub::GenerateAheadOfTime(isolate);
+  BinaryOpICStub::GenerateAheadOfTime(isolate);
 }
 
 
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 8a3f965..e479368 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -2268,7 +2268,7 @@
 
   __ bind(&stub_call);
   __ movq(rax, rcx);
-  BinaryOpStub stub(op, mode);
+  BinaryOpICStub stub(op, mode);
   CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
          expr->BinaryOperationFeedbackId());
   patch_site.EmitPatchInfo();
@@ -2317,7 +2317,7 @@
                                      Token::Value op,
                                      OverwriteMode mode) {
   __ pop(rdx);
-  BinaryOpStub stub(op, mode);
+  BinaryOpICStub stub(op, mode);
   JumpPatchSite patch_site(masm_);    // unbound, signals no inlined smi code.
   CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
          expr->BinaryOperationFeedbackId());
@@ -4405,7 +4405,7 @@
   __ bind(&stub_call);
   __ movq(rdx, rax);
   __ Move(rax, Smi::FromInt(1));
-  BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
+  BinaryOpICStub stub(expr->binary_op(), NO_OVERWRITE);
   CallIC(stub.GetCode(isolate()),
          RelocInfo::CODE_TARGET,
          expr->CountBinOpFeedbackId());
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index e3d477d..9448d37 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -1463,7 +1463,7 @@
 
 
 void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
-                                  StrictModeFlag strict_mode) {
+                                  ExtraICState extra_ic_state) {
   // ----------- S t a t e -------------
   //  -- rax    : value
   //  -- rcx    : name
@@ -1473,7 +1473,7 @@
 
   // Get the receiver from the stack and probe the stub cache.
   Code::Flags flags = Code::ComputeFlags(
-      Code::HANDLER, MONOMORPHIC, strict_mode,
+      Code::HANDLER, MONOMORPHIC, extra_ic_state,
       Code::NORMAL, Code::STORE_IC);
   masm->isolate()->stub_cache()->GenerateProbe(
       masm, flags, rdx, rcx, rbx, no_reg);
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 046edbd..9d0dc94 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -1951,7 +1951,7 @@
   ASSERT(ToRegister(instr->right()).is(rax));
   ASSERT(ToRegister(instr->result()).is(rax));
 
-  BinaryOpStub stub(instr->op(), NO_OVERWRITE);
+  BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
   CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
   __ nop();  // Signals no inlined code.
 }
@@ -3972,7 +3972,13 @@
 void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
   Register result = ToRegister(instr->result());
   Register base = ToRegister(instr->base_object());
-  __ lea(result, Operand(base, instr->offset()));
+  if (instr->offset()->IsConstantOperand()) {
+    LConstantOperand* offset = LConstantOperand::cast(instr->offset());
+    __ lea(result, Operand(base, ToInteger32(offset)));
+  } else {
+    Register offset = ToRegister(instr->offset());
+    __ lea(result, Operand(base, offset, times_1, 0));
+  }
 }
 
 
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index eb00593..0f7ebc4 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -275,7 +275,8 @@
 void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
   stream->Add(" = ");
   base_object()->PrintTo(stream);
-  stream->Add(" + %d", offset());
+  stream->Add(" + ");
+  offset()->PrintTo(stream);
 }
 
 
@@ -1116,11 +1117,11 @@
 
 
 LInstruction* LChunkBuilder::DoInnerAllocatedObject(
-    HInnerAllocatedObject* inner_object) {
-  LOperand* base_object = UseRegisterAtStart(inner_object->base_object());
-  LInnerAllocatedObject* result =
-    new(zone()) LInnerAllocatedObject(base_object);
-  return DefineAsRegister(result);
+    HInnerAllocatedObject* instr) {
+  LOperand* base_object = UseRegisterAtStart(instr->base_object());
+  LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
+  return DefineAsRegister(
+      new(zone()) LInnerAllocatedObject(base_object, offset));
 }
 
 
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index ca7831c..44bd992 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -1746,19 +1746,19 @@
 };
 
 
-class LInnerAllocatedObject V8_FINAL: public LTemplateInstruction<1, 1, 0> {
+class LInnerAllocatedObject V8_FINAL: public LTemplateInstruction<1, 2, 0> {
  public:
-  explicit LInnerAllocatedObject(LOperand* base_object) {
+  LInnerAllocatedObject(LOperand* base_object, LOperand* offset) {
     inputs_[0] = base_object;
+    inputs_[1] = offset;
   }
 
-  LOperand* base_object() { return inputs_[0]; }
-  int offset() { return hydrogen()->offset(); }
+  LOperand* base_object() const { return inputs_[0]; }
+  LOperand* offset() const { return inputs_[1]; }
 
   virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
 
-  DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "sub-allocated-object")
-  DECLARE_HYDROGEN_ACCESSOR(InnerAllocatedObject)
+  DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
 };
 
 
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index e7bbe27..9bf6e9f 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -1572,7 +1572,7 @@
   Handle<Code> code =
       isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
                                                kind_,
-                                               extra_state_);
+                                               extra_state());
   __ Jump(code, RelocInfo::CODE_TARGET);
 }
 
@@ -1957,7 +1957,7 @@
   Label index_out_of_range;
   Label* index_out_of_range_label = &index_out_of_range;
   if (kind_ == Code::CALL_IC &&
-      (CallICBase::StringStubState::decode(extra_state_) ==
+      (CallICBase::StringStubState::decode(extra_state()) ==
        DEFAULT_STRING_STUB)) {
     index_out_of_range_label = &miss;
   }
@@ -2024,7 +2024,7 @@
   Label index_out_of_range;
   Label* index_out_of_range_label = &index_out_of_range;
   if (kind_ == Code::CALL_IC &&
-      (CallICBase::StringStubState::decode(extra_state_) ==
+      (CallICBase::StringStubState::decode(extra_state()) ==
        DEFAULT_STRING_STUB)) {
     index_out_of_range_label = &miss;
   }
@@ -2497,7 +2497,7 @@
   StackArgumentsAccessor args(rsp, arguments());
   __ movq(rdx, args.GetReceiverOperand());
 
-  CallInterceptorCompiler compiler(this, arguments(), rcx, extra_state_);
+  CallInterceptorCompiler compiler(this, arguments(), rcx, extra_state());
   compiler.Compile(masm(), object, holder, name, &lookup, rdx, rbx, rdi, rax,
                    &miss);
 
diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h
index 4db0d83..aec3e0e 100644
--- a/test/cctest/cctest.h
+++ b/test/cctest/cctest.h
@@ -358,13 +358,13 @@
   HeapObjectsTracker() {
     heap_profiler_ = i::Isolate::Current()->heap_profiler();
     CHECK_NE(NULL, heap_profiler_);
-    heap_profiler_->StartHeapAllocationsRecording();
+    heap_profiler_->StartHeapObjectsTracking(true);
   }
 
   ~HeapObjectsTracker() {
     i::Isolate::Current()->heap()->CollectAllAvailableGarbage();
     CHECK_EQ(0, heap_profiler_->FindUntrackedObjects());
-    heap_profiler_->StopHeapAllocationsRecording();
+    heap_profiler_->StopHeapObjectsTracking();
   }
 
  private:
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index ff802e3..8c6f418 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -3943,8 +3943,6 @@
   v8::HandleScope scope(env->GetIsolate());
   env.ExposeDebug();
 
-  CcTest::i_isolate()->TraceException(false);
-
   // Create functions for testing break on exception.
   CompileFunction(&env, "function throws(){throw 1;}", "throws");
   v8::Local<v8::Function> caught =
@@ -4089,8 +4087,6 @@
   // For this test, we want to break on uncaught exceptions:
   ChangeBreakOnException(false, true);
 
-  CcTest::i_isolate()->TraceException(false);
-
   // Create a function for checking the function when hitting a break point.
   frame_count = CompileFunction(&env, frame_count_source, "frame_count");
 
@@ -7732,7 +7728,7 @@
   v8::internal::FLAG_allow_natives_syntax = true;
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
-  v8::Debug::SetLiveEditEnabled(false), env->GetIsolate();
+  v8::Debug::SetLiveEditEnabled(false, env->GetIsolate());
   CompileRun("%LiveEditCompareStrings('', '')");
 }
 
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index fed108d..88be693 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -2191,7 +2191,7 @@
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
-  heap_profiler->StartRecordingHeapAllocations();
+  heap_profiler->StartTrackingHeapObjects(true);
 
   CompileRun(
     "var a = [];\n"
@@ -2216,7 +2216,7 @@
   CHECK_NE(NULL, node);
   CHECK_GE(node->allocation_count(), 2);
   CHECK_GE(node->allocation_size(), 4 * 5);
-  heap_profiler->StopRecordingHeapAllocations();
+  heap_profiler->StopTrackingHeapObjects();
 }
 
 
@@ -2225,7 +2225,7 @@
   LocalContext env;
 
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
-  heap_profiler->StartRecordingHeapAllocations();
+  heap_profiler->StartTrackingHeapObjects(true);
 
   CompileRun(record_trace_tree_source);
 
@@ -2246,7 +2246,7 @@
   CHECK_NE(NULL, node);
   CHECK_GE(node->allocation_count(), 100);
   CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
-  heap_profiler->StopRecordingHeapAllocations();
+  heap_profiler->StopTrackingHeapObjects();
 }
 
 
@@ -2278,7 +2278,7 @@
   const char* names[] = { "(anonymous function)", "start", "f_0", "f_1" };
   // First check that normally all allocations are recorded.
   {
-    heap_profiler->StartRecordingHeapAllocations();
+    heap_profiler->StartTrackingHeapObjects(true);
 
     CompileRun(inline_heap_allocation_source);
 
@@ -2297,11 +2297,11 @@
     CHECK_NE(NULL, node);
     CHECK_GE(node->allocation_count(), 100);
     CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
-    heap_profiler->StopRecordingHeapAllocations();
+    heap_profiler->StopTrackingHeapObjects();
   }
 
   {
-    heap_profiler->StartRecordingHeapAllocations();
+    heap_profiler->StartTrackingHeapObjects(true);
 
     // Now check that not all allocations are tracked if we manually reenable
     // inline allocations.
@@ -2326,6 +2326,6 @@
     CHECK_LT(node->allocation_count(), 100);
 
     CcTest::heap()->DisableInlineAllocation();
-    heap_profiler->StopRecordingHeapAllocations();
+    heap_profiler->StopTrackingHeapObjects();
   }
 }
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index 77395b5..8a8df29 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -935,7 +935,7 @@
   Handle<JSObject> runaway;
 
   {
-      v8::HandleScope nested(CcTest::isolate());
+      v8::EscapableHandleScope nested(CcTest::isolate());
       Handle<JSObject> empty;
       runaway = empty.EscapeFrom(&nested);
   }
diff --git a/test/mjsunit/compiler/compare_map_elim.js b/test/mjsunit/compiler/compare_map_elim.js
new file mode 100644
index 0000000..288d481
--- /dev/null
+++ b/test/mjsunit/compiler/compare_map_elim.js
@@ -0,0 +1,51 @@
+// Copyright 2010 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.
+
+// Flags: --allow-natives-syntax --check-elimination
+
+a = {
+  f: function() { this.y = 3; }
+};
+b = {
+  f: function() { this.y = 4; }
+};
+
+function x(z) {
+  return z.f();
+}
+
+x(a);
+x(b);
+x(a);
+x(b);
+x(a);
+x(b);
+
+%OptimizeFunctionOnNextCall(x)
+
+x(a);
+x(b);
diff --git a/test/mjsunit/regress/regress-3029.js b/test/mjsunit/regress/regress-3029.js
new file mode 100644
index 0000000..ae412df
--- /dev/null
+++ b/test/mjsunit/regress/regress-3029.js
@@ -0,0 +1,45 @@
+// 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.
+
+// Flags: --allow-natives-syntax
+
+function c(x) {
+  undefined.boom();
+}
+
+function f() {
+  return new c();
+}
+
+function g() {
+  f();
+}
+
+assertThrows("g()", TypeError);
+assertThrows("g()", TypeError);
+%OptimizeFunctionOnNextCall(g);
+assertThrows("g()", TypeError);
diff --git a/test/mjsunit/regress/regress-3032.js b/test/mjsunit/regress/regress-3032.js
new file mode 100755
index 0000000..ae54543
--- /dev/null
+++ b/test/mjsunit/regress/regress-3032.js
@@ -0,0 +1,30 @@
+// 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.
+
+for (var i = 0; i < 1000000; i++) { }
+var xl = 4096;
+var z = i % xl;
diff --git a/test/mjsunit/sin-cos.js b/test/mjsunit/sin-cos.js
index b63c15e..02ae57b 100644
--- a/test/mjsunit/sin-cos.js
+++ b/test/mjsunit/sin-cos.js
@@ -29,6 +29,22 @@
 
 // Flags: --allow-natives-syntax
 
+assertEquals("-Infinity", String(1/Math.sin(-0)));
+assertEquals(1, Math.cos(-0));
+assertEquals("-Infinity", String(1/Math.tan(-0)));
+
+// Assert that minus zero does not cause deopt.
+function no_deopt_on_minus_zero(x) {
+  return Math.sin(x) + Math.cos(x) + Math.tan(x);
+}
+
+no_deopt_on_minus_zero(1);
+no_deopt_on_minus_zero(1);
+%OptimizeFunctionOnNextCall(no_deopt_on_minus_zero);
+no_deopt_on_minus_zero(-0);
+assertOptimized(no_deopt_on_minus_zero);
+
+
 function sinTest() {
   assertEquals(0, Math.sin(0));
   assertEquals(1, Math.sin(Math.PI / 2));
@@ -169,14 +185,3 @@
 assertFalse(isNaN(Math.cos(1.57079632679489700)));
 assertFalse(isNaN(Math.cos(-1e-100)));
 assertFalse(isNaN(Math.cos(-1e-323)));
-
-
-function no_deopt_on_minus_zero(x) {
-  return Math.sin(x) + Math.cos(x) + Math.tan(x);
-}
-
-no_deopt_on_minus_zero(1);
-no_deopt_on_minus_zero(1);
-%OptimizeFunctionOnNextCall(no_deopt_on_minus_zero);
-no_deopt_on_minus_zero(-0);
-assertOptimized(no_deopt_on_minus_zero);
diff --git a/tools/testrunner/local/progress.py b/tools/testrunner/local/progress.py
index a663be2..03116ee 100644
--- a/tools/testrunner/local/progress.py
+++ b/tools/testrunner/local/progress.py
@@ -89,6 +89,7 @@
         print failed.output.stdout.strip()
       print "Command: %s" % EscapeCommand(self.runner.GetCommand(failed))
       if failed.output.HasCrashed():
+        print "exit code: %d" % failed.output.exit_code
         print "--- CRASHED ---"
       if failed.output.HasTimedOut():
         print "--- TIMEOUT ---"