Refactor BinaryOpIC to be able to use different stubs.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Dec 2013 13:14:07 +0000 (13:14 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Dec 2013 13:14:07 +0000 (13:14 +0000)
Previously BinaryOpIC and BinaryOpStub were pretty much interdependent.
However, in order to use allocation sites for string adds on-demand,
we need to be able to use different stubs (with a different number of
register parameters, via trampolines) depending on the BinaryOpIC state.

R=hpayer@chromium.org, mvstanton@chromium.org

Review URL: https://codereview.chromium.org/97543002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18191 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

18 files changed:
src/arm/code-stubs-arm.cc
src/arm/full-codegen-arm.cc
src/arm/lithium-codegen-arm.cc
src/code-stubs-hydrogen.cc
src/code-stubs.cc
src/code-stubs.h
src/ia32/code-stubs-ia32.cc
src/ia32/full-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/ic.cc
src/ic.h
src/isolate.cc
src/log.cc
src/token.h
src/type-info.cc
src/x64/code-stubs-x64.cc
src/x64/full-codegen-x64.cc
src/x64/lithium-codegen-x64.cc

index d63bc65..cc2dbdc 100644 (file)
@@ -193,7 +193,7 @@ void CompareNilICStub::InitializeInterfaceDescriptor(
 }
 
 
-void BinaryOpStub::InitializeInterfaceDescriptor(
+void BinaryOpICStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
   static Register registers[] = { r1, r0 };
@@ -1666,7 +1666,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
   StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
   CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
-  BinaryOpStub::GenerateAheadOfTime(isolate);
+  BinaryOpICStub::GenerateAheadOfTime(isolate);
 }
 
 
index 88421af..5508803 100644 (file)
@@ -2298,7 +2298,7 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
   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 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
   __ 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 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
                                      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 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   // 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());
index b432bc8..c842df2 100644 (file)
@@ -2186,7 +2186,7 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
   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());
index acda324..e52ec65 100644 (file)
@@ -895,20 +895,21 @@ Handle<Code> CompareNilICStub::GenerateCode(Isolate* isolate) {
 
 
 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
@@ -919,16 +920,16 @@ HValue* CodeStubGraphBuilder<BinaryOpStub>::BuildCodeInitializedStub() {
       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();
@@ -938,32 +939,32 @@ HValue* CodeStubGraphBuilder<BinaryOpStub>::BuildCodeInitializedStub() {
       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;
@@ -981,8 +982,8 @@ HValue* CodeStubGraphBuilder<BinaryOpStub>::BuildCodeInitializedStub() {
 
   // 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();
@@ -998,7 +999,7 @@ HValue* CodeStubGraphBuilder<BinaryOpStub>::BuildCodeInitializedStub() {
 }
 
 
-Handle<Code> BinaryOpStub::GenerateCode(Isolate* isolate) {
+Handle<Code> BinaryOpICStub::GenerateCode(Isolate* isolate) {
   return DoGenerateCode(isolate, this);
 }
 
index 3f26e3f..3fb6153 100644 (file)
@@ -217,479 +217,32 @@ void CodeStub::PrintName(StringStream* stream) {
 }
 
 
-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);
     }
   }
-}
-
-
-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);
-}
-
-
-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;
+  // Generate special versions of the stub.
+  BinaryOpIC::State::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
 }
 
 
-Handle<Type> BinaryOpStub::GetLeftType(Isolate* isolate) const {
-  return StateToType(left_state_, isolate);
-}
-
-
-Handle<Type> BinaryOpStub::GetRightType(Isolate* isolate) const {
-  return StateToType(right_state_, isolate);
+void BinaryOpICStub::PrintState(StringStream* stream) {
+  state_.Print(stream);
 }
 
 
-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 @@ void FastNewClosureStub::InstallDescriptors(Isolate* isolate) {
 
 
 // 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);
index a852a5c..f2de616 100644 (file)
@@ -41,7 +41,7 @@ namespace internal {
 #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 @@ namespace internal {
   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 KeyedArrayCallStub: public HICStub {
 };
 
 
-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;
 
-  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;
-  }
+  static void InstallDescriptors(Isolate* isolate);
 
-  virtual void VerifyPlatformFeatures(Isolate* isolate) V8_OVERRIDE {
-    ASSERT(CpuFeatures::VerifyCrossCompiling(SSE2));
+  virtual Code::Kind GetCodeKind() const V8_OVERRIDE {
+    return Code::BINARY_OP_IC;
   }
 
-  virtual ExtraICState GetExtraICState() {
-    bool sse_field = Max(result_state_, Max(left_state_, right_state_)) > SMI &&
-                     CpuFeatures::IsSafeForSnapshot(SSE2);
-
-    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_);
+  virtual InlineCacheState GetICState() V8_OVERRIDE {
+    return state_.GetICState();
   }
 
-  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 ExtraICState GetExtraICState() V8_OVERRIDE {
+    return state_.GetExtraICState();
   }
 
-  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 void VerifyPlatformFeatures(Isolate* isolate) V8_OVERRIDE {
+    ASSERT(CpuFeatures::VerifyCrossCompiling(SSE2));
   }
 
-  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_; }
+  virtual Handle<Code> GenerateCode(Isolate* isolate) V8_OVERRIDE;
 
-  Handle<Type> GetLeftType(Isolate* isolate) const;
-  Handle<Type> GetRightType(Isolate* isolate) const;
-  Handle<Type> GetResultType(Isolate* isolate) const;
+  const BinaryOpIC::State& state() const { return state_; }
 
-  void UpdateStatus(Handle<Object> left,
-                    Handle<Object> right,
-                    Maybe<Handle<Object> > result);
+  virtual void PrintState(StringStream* stream) V8_OVERRIDE;
 
-  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();
-
-  enum State { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
-
-  // 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> {};
-
-  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);
+  static void GenerateAheadOfTime(Isolate* isolate,
+                                  const BinaryOpIC::State& state);
 
-  void UpdateStatus(Handle<Object> object,
-                    State* state);
+  virtual Major MajorKey() V8_OVERRIDE { return BinaryOpIC; }
+  virtual int NotMissMinorKey() V8_OVERRIDE { return GetExtraICState(); }
 
-  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_;
+  BinaryOpIC::State state_;
 
-  Maybe<int> fixed_right_arg_;
-  State left_state_;
-  State right_state_;
-  State result_state_;
+  DISALLOW_COPY_AND_ASSIGN(BinaryOpICStub);
 };
 
 
index f0dcf71..0481814 100644 (file)
@@ -330,7 +330,7 @@ void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
 }
 
 
-void BinaryOpStub::InitializeInterfaceDescriptor(
+void BinaryOpICStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
   static Register registers[] = { edx, eax };
@@ -2961,9 +2961,9 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
   CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
   if (Serializer::enabled()) {
     PlatformFeatureScope sse2(SSE2);
-    BinaryOpStub::GenerateAheadOfTime(isolate);
+    BinaryOpICStub::GenerateAheadOfTime(isolate);
   } else {
-    BinaryOpStub::GenerateAheadOfTime(isolate);
+    BinaryOpICStub::GenerateAheadOfTime(isolate);
   }
 }
 
index 649a58b..3c5d4aa 100644 (file)
@@ -2245,7 +2245,7 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
 
   __ 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 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
                                      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 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   __ 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());
index d3a5ff3..f26eeac 100644 (file)
@@ -2356,7 +2356,7 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
   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.
 }
index 33ce188..1ec9728 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -2317,76 +2317,464 @@ RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) {
 }
 
 
-const char* BinaryOpIC::GetName(TypeInfo type_info) {
-  switch (type_info) {
-    case UNINITIALIZED: return "Uninitialized";
+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;
+  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 ODDBALL: return "Oddball";
     case STRING: return "String";
     case GENERIC: return "Generic";
-    default: return "Invalid";
   }
+  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);
 }
index b1a47e2..e018d40 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -810,25 +810,114 @@ class KeyedStoreIC: public StoreIC {
 };
 
 
+// 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);
 };
index 6495d25..25bc546 100644 (file)
@@ -2104,7 +2104,7 @@ bool Isolate::Init(Deserializer* des) {
                                    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);
index e123231..a508e87 100644 (file)
@@ -1838,12 +1838,7 @@ void Logger::LogCodeObject(Object* object) {
     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
index 992adaa..39bcc24 100644 (file)
@@ -213,6 +213,10 @@ class Token {
     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;
   }
index e4eb7db..3cb5655 100644 (file)
@@ -410,28 +410,26 @@ void TypeFeedbackOracle::BinaryType(TypeFeedbackId id,
                                     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 +447,11 @@ Handle<Type> TypeFeedbackOracle::ClauseType(TypeFeedbackId id) {
 
 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());
 }
 
 
index 6f35a21..0c9a0f2 100644 (file)
@@ -180,7 +180,7 @@ void TransitionElementsKindStub::InitializeInterfaceDescriptor(
 }
 
 
-void BinaryOpStub::InitializeInterfaceDescriptor(
+void BinaryOpICStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
   static Register registers[] = { rdx, rax };
@@ -2788,7 +2788,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
   // It is important that the store buffer overflow stubs are generated first.
   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
   CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
-  BinaryOpStub::GenerateAheadOfTime(isolate);
+  BinaryOpICStub::GenerateAheadOfTime(isolate);
 }
 
 
index 8a3f965..e479368 100644 (file)
@@ -2268,7 +2268,7 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
 
   __ 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 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
                                      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 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   __ 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());
index b196254..9d0dc94 100644 (file)
@@ -1951,7 +1951,7 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
   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.
 }