Revision: 14928
Author:   [email protected]
Date:     Tue Jun  4 00:49:45 2013
Log:      Collect type feedback for power-of-2 right operands in BinaryOps.

Improved --trace-ic output for unary/binary ops a bit on the way. Moved int32_t/uint32_t conversion helpers around.

[email protected]

Review URL: https://codereview.chromium.org/15735005
http://code.google.com/p/v8/source/detail?r=14928

Modified:
 /branches/bleeding_edge/src/arm/code-stubs-arm.cc
 /branches/bleeding_edge/src/ast.cc
 /branches/bleeding_edge/src/ast.h
 /branches/bleeding_edge/src/code-stubs.h
 /branches/bleeding_edge/src/deoptimizer.cc
 /branches/bleeding_edge/src/hydrogen-instructions.cc
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/type-info.cc
 /branches/bleeding_edge/src/type-info.h
 /branches/bleeding_edge/src/x64/code-stubs-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Mon Jun 3 07:46:23 2013 +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Tue Jun 4 00:49:45 2013
@@ -2029,7 +2029,14 @@


 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
-  Label not_smis, call_runtime;
+  Label right_arg_changed, call_runtime;
+
+  if (op_ == Token::MOD && has_fixed_right_arg_) {
+    // It is guaranteed that the value will fit into a Smi, because if it
+    // didn't, we wouldn't be here, see BinaryOp_Patch.
+    __ cmp(r0, Operand(Smi::FromInt(fixed_right_arg_value())));
+    __ b(ne, &right_arg_changed);
+  }

   if (result_type_ == BinaryOpIC::UNINITIALIZED ||
       result_type_ == BinaryOpIC::SMI) {
@@ -2046,6 +2053,7 @@

// Code falls through if the result is not returned as either a smi or heap
   // number.
+  __ bind(&right_arg_changed);
   GenerateTypeTransition(masm);

   __ bind(&call_runtime);
@@ -2217,6 +2225,12 @@
         // to type transition.

       } else {
+        if (has_fixed_right_arg_) {
+          __ Vmov(d8, fixed_right_arg_value(), scratch1);
+          __ VFPCompareAndSetFlags(d1, d8);
+          __ b(ne, &transition);
+        }
+
         // We preserved r0 and r1 to be able to call runtime.
         // Save the left value on the stack.
         __ Push(r5, r4);
=======================================
--- /branches/bleeding_edge/src/ast.cc  Mon May 27 06:59:20 2013
+++ /branches/bleeding_edge/src/ast.cc  Tue Jun  4 00:49:45 2013
@@ -682,7 +682,8 @@


 void BinaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  oracle->BinaryType(this, &left_type_, &right_type_, &result_type_);
+  oracle->BinaryType(this, &left_type_, &right_type_, &result_type_,
+                     &has_fixed_right_arg_, &fixed_right_arg_value_);
 }


=======================================
--- /branches/bleeding_edge/src/ast.h   Mon May 27 06:59:20 2013
+++ /branches/bleeding_edge/src/ast.h   Tue Jun  4 00:49:45 2013
@@ -1799,6 +1799,8 @@
   TypeInfo left_type() const { return left_type_; }
   TypeInfo right_type() const { return right_type_; }
   TypeInfo result_type() const { return result_type_; }
+  bool has_fixed_right_arg() const { return has_fixed_right_arg_; }
+  int fixed_right_arg_value() const { return fixed_right_arg_value_; }

  protected:
   BinaryOperation(Isolate* isolate,
@@ -1824,6 +1826,8 @@
   TypeInfo left_type_;
   TypeInfo right_type_;
   TypeInfo result_type_;
+  bool has_fixed_right_arg_;
+  int fixed_right_arg_value_;

   // The short-circuit logical operations need an AST ID for their
   // right-hand subexpression.
=======================================
--- /branches/bleeding_edge/src/code-stubs.h    Wed May 29 07:49:28 2013
+++ /branches/bleeding_edge/src/code-stubs.h    Tue Jun  4 00:49:45 2013
@@ -885,7 +885,9 @@
         platform_specific_bit_(false),
         left_type_(BinaryOpIC::UNINITIALIZED),
         right_type_(BinaryOpIC::UNINITIALIZED),
-        result_type_(BinaryOpIC::UNINITIALIZED) {
+        result_type_(BinaryOpIC::UNINITIALIZED),
+        has_fixed_right_arg_(false),
+        encoded_right_arg_(encode_arg_value(1)) {
     Initialize();
     ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
   }
@@ -894,13 +896,17 @@
       int key,
       BinaryOpIC::TypeInfo left_type,
       BinaryOpIC::TypeInfo right_type,
-      BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
+      BinaryOpIC::TypeInfo result_type,
+      bool has_fixed_right_arg,
+      int32_t fixed_right_arg_value)
       : op_(OpBits::decode(key)),
         mode_(ModeBits::decode(key)),
         platform_specific_bit_(PlatformSpecificBits::decode(key)),
         left_type_(left_type),
         right_type_(right_type),
-        result_type_(result_type) { }
+        result_type_(result_type),
+        has_fixed_right_arg_(has_fixed_right_arg),
+        encoded_right_arg_(encode_arg_value(fixed_right_arg_value)) { }

   static void decode_types_from_minor_key(int minor_key,
                                           BinaryOpIC::TypeInfo* left_type,
@@ -917,6 +923,24 @@
   static Token::Value decode_op_from_minor_key(int minor_key) {
     return static_cast<Token::Value>(OpBits::decode(minor_key));
   }
+
+  static bool decode_has_fixed_right_arg_from_minor_key(int minor_key) {
+    return HasFixedRightArgBits::decode(minor_key);
+  }
+
+  static int decode_fixed_right_arg_value_from_minor_key(int minor_key) {
+    return decode_arg_value(FixedRightArgValueBits::decode(minor_key));
+  }
+
+  int fixed_right_arg_value() const {
+    return decode_arg_value(encoded_right_arg_);
+  }
+
+  static bool can_encode_arg_value(int32_t value) {
+    return value > 0 &&
+        IsPowerOf2(value) &&
+        FixedRightArgValueBits::is_valid(WhichPowerOf2(value));
+  }

   enum SmiCodeGenerateHeapNumberResults {
     ALLOW_HEAPNUMBER_RESULTS,
@@ -932,16 +956,32 @@
   BinaryOpIC::TypeInfo left_type_;
   BinaryOpIC::TypeInfo right_type_;
   BinaryOpIC::TypeInfo result_type_;
+
+  bool has_fixed_right_arg_;
+  int encoded_right_arg_;
+
+  static int encode_arg_value(int32_t value) {
+    ASSERT(can_encode_arg_value(value));
+    return WhichPowerOf2(value);
+  }
+
+  static int32_t decode_arg_value(int value) {
+    return 1 << value;
+  }

   virtual void PrintName(StringStream* stream);

-  // Minor key encoding in 19 bits TTTRRRLLLSOOOOOOOMM.
+  // Minor key encoding in all 25 bits FFFFFHTTTRRRLLLPOOOOOOOMM.
+  // Note: We actually do not need 7 bits for the operation, just 4 bits to
+ // encode ADD, SUB, MUL, DIV, MOD, BIT_OR, BIT_AND, BIT_XOR, SAR, SHL, SHR.
   class ModeBits: public BitField<OverwriteMode, 0, 2> {};
   class OpBits: public BitField<Token::Value, 2, 7> {};
   class PlatformSpecificBits: public BitField<bool, 9, 1> {};
   class LeftTypeBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {};
   class RightTypeBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {};
   class ResultTypeBits: public BitField<BinaryOpIC::TypeInfo, 16, 3> {};
+  class HasFixedRightArgBits: public BitField<bool, 19, 1> {};
+  class FixedRightArgValueBits: public BitField<int, 20, 5> {};

   Major MajorKey() { return BinaryOp; }
   int MinorKey() {
@@ -950,7 +990,9 @@
            | PlatformSpecificBits::encode(platform_specific_bit_)
            | LeftTypeBits::encode(left_type_)
            | RightTypeBits::encode(right_type_)
-           | ResultTypeBits::encode(result_type_);
+           | ResultTypeBits::encode(result_type_)
+           | HasFixedRightArgBits::encode(has_fixed_right_arg_)
+           | FixedRightArgValueBits::encode(encoded_right_arg_);
   }


=======================================
--- /branches/bleeding_edge/src/deoptimizer.cc  Mon Jun  3 08:32:22 2013
+++ /branches/bleeding_edge/src/deoptimizer.cc  Tue Jun  4 00:49:45 2013
@@ -1984,56 +1984,6 @@
     }
   }
 }
-
-
-static bool ObjectToInt32(Object* obj, int32_t* value) {
-  if (obj->IsSmi()) {
-    *value = Smi::cast(obj)->value();
-    return true;
-  }
-
-  if (obj->IsHeapNumber()) {
-    double num = HeapNumber::cast(obj)->value();
-    if (FastI2D(FastD2I(num)) != num) {
-      if (FLAG_trace_osr) {
-        PrintF("**** %g could not be converted to int32 ****\n",
-               HeapNumber::cast(obj)->value());
-      }
-      return false;
-    }
-
-    *value = FastD2I(num);
-    return true;
-  }
-
-  return false;
-}
-
-
-static bool ObjectToUint32(Object* obj, uint32_t* value) {
-  if (obj->IsSmi()) {
-    if (Smi::cast(obj)->value() < 0) return false;
-
-    *value = static_cast<uint32_t>(Smi::cast(obj)->value());
-    return true;
-  }
-
-  if (obj->IsHeapNumber()) {
-    double num = HeapNumber::cast(obj)->value();
-    if ((num < 0) || (FastUI2D(FastD2UI(num)) != num)) {
-      if (FLAG_trace_osr) {
-        PrintF("**** %g could not be converted to uint32 ****\n",
-               HeapNumber::cast(obj)->value());
-      }
-      return false;
-    }
-
-    *value = FastD2UI(num);
-    return true;
-  }
-
-  return false;
-}


 bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
@@ -2079,7 +2029,7 @@

     case Translation::INT32_REGISTER: {
       int32_t int32_value = 0;
-      if (!ObjectToInt32(input_object, &int32_value)) return false;
+      if (!input_object->ToInt32(&int32_value)) return false;

       int output_reg = iterator->Next();
       if (FLAG_trace_osr) {
@@ -2094,7 +2044,7 @@

     case Translation::UINT32_REGISTER: {
       uint32_t uint32_value = 0;
-      if (!ObjectToUint32(input_object, &uint32_value)) return false;
+      if (!input_object->ToUint32(&uint32_value)) return false;

       int output_reg = iterator->Next();
       if (FLAG_trace_osr) {
@@ -2141,7 +2091,7 @@

     case Translation::INT32_STACK_SLOT: {
       int32_t int32_value = 0;
-      if (!ObjectToInt32(input_object, &int32_value)) return false;
+      if (!input_object->ToInt32(&int32_value)) return false;

       int output_index = iterator->Next();
       unsigned output_offset =
@@ -2158,7 +2108,7 @@

     case Translation::UINT32_STACK_SLOT: {
       uint32_t uint32_value = 0;
-      if (!ObjectToUint32(input_object, &uint32_value)) return false;
+      if (!input_object->ToUint32(&uint32_value)) return false;

       int output_index = iterator->Next();
       unsigned output_offset =
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Mon Jun 3 09:57:36 2013 +++ /branches/bleeding_edge/src/hydrogen-instructions.cc Tue Jun 4 00:49:45 2013
@@ -3369,8 +3369,12 @@
 }


-HInstruction* HMod::New(
-    Zone* zone, HValue* context, HValue* left, HValue* right) {
+HInstruction* HMod::New(Zone* zone,
+                        HValue* context,
+                        HValue* left,
+                        HValue* right,
+                        bool has_fixed_right_arg,
+                        int fixed_right_arg_value) {
   if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
     HConstant* c_left = HConstant::cast(left);
     HConstant* c_right = HConstant::cast(right);
@@ -3389,7 +3393,11 @@
       }
     }
   }
-  return new(zone) HMod(context, left, right);
+  return new(zone) HMod(context,
+                        left,
+                        right,
+                        has_fixed_right_arg,
+                        fixed_right_arg_value);
 }


=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Mon Jun 3 09:57:36 2013 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Tue Jun 4 00:49:45 2013
@@ -4340,7 +4340,12 @@
   static HInstruction* New(Zone* zone,
                            HValue* context,
                            HValue* left,
-                           HValue* right);
+                           HValue* right,
+                           bool has_fixed_right_arg,
+                           int fixed_right_arg_value);
+
+  bool has_fixed_right_arg() const { return has_fixed_right_arg_; }
+  int fixed_right_arg_value() const { return fixed_right_arg_value_; }

   bool HasPowerOf2Divisor() {
     if (right()->IsConstant() &&
@@ -4364,11 +4369,20 @@
   virtual Range* InferRange(Zone* zone);

  private:
-  HMod(HValue* context, HValue* left, HValue* right)
-      : HArithmeticBinaryOperation(context, left, right) {
+  HMod(HValue* context,
+       HValue* left,
+       HValue* right,
+       bool has_fixed_right_arg,
+       int fixed_right_arg_value)
+      : HArithmeticBinaryOperation(context, left, right),
+        has_fixed_right_arg_(has_fixed_right_arg),
+        fixed_right_arg_value_(fixed_right_arg_value) {
     SetFlag(kCanBeDivByZero);
     SetFlag(kCanOverflow);
   }
+
+  const bool has_fixed_right_arg_;
+  const int fixed_right_arg_value_;
 };


=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Mon Jun  3 09:57:36 2013
+++ /branches/bleeding_edge/src/hydrogen.cc     Tue Jun  4 00:49:45 2013
@@ -9334,7 +9334,8 @@
   TypeInfo left_info = expr->left_type();
   TypeInfo right_info = expr->right_type();
   TypeInfo result_info = expr->result_type();
-  TypeInfo combined_info;
+  bool has_fixed_right_arg = expr->has_fixed_right_arg();
+  int fixed_right_arg_value = expr->fixed_right_arg_value();
   Representation left_rep = ToRepresentation(left_info);
   Representation right_rep = ToRepresentation(right_info);
   Representation result_rep = ToRepresentation(result_info);
@@ -9364,7 +9365,12 @@
       instr = HMul::New(zone(), context, left, right);
       break;
     case Token::MOD:
-      instr = HMod::New(zone(), context, left, right);
+      instr = HMod::New(zone(),
+                        context,
+                        left,
+                        right,
+                        has_fixed_right_arg,
+                        fixed_right_arg_value);
       break;
     case Token::DIV:
       instr = HDiv::New(zone(), context, left, right);
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Mon Jun 3 07:46:23 2013 +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Tue Jun 4 00:49:45 2013
@@ -566,12 +566,6 @@
   // Expects operands in edx, eax.
   static void LoadSSE2Smis(MacroAssembler* masm, Register scratch);

-  // Checks that the two floating point numbers loaded into xmm0 and xmm1
-  // have int32 values.
-  static void CheckSSE2OperandsAreInt32(MacroAssembler* masm,
-                                        Label* non_int32,
-                                        Register scratch);
-
// Checks that |operand| has an int32 value. If |int32_result| is different
   // from |scratch|, it will contain that int32 value.
   static void CheckSSE2OperandIsInt32(MacroAssembler* masm,
@@ -1470,7 +1464,7 @@


 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
-  Label call_runtime;
+  Label right_arg_changed, call_runtime;

   switch (op_) {
     case Token::ADD:
@@ -1490,6 +1484,13 @@
     default:
       UNREACHABLE();
   }
+
+  if (op_ == Token::MOD && has_fixed_right_arg_) {
+    // It is guaranteed that the value will fit into a Smi, because if it
+    // didn't, we wouldn't be here, see BinaryOp_Patch.
+    __ cmp(eax, Immediate(Smi::FromInt(fixed_right_arg_value())));
+    __ j(not_equal, &right_arg_changed);
+  }

   if (result_type_ == BinaryOpIC::UNINITIALIZED ||
       result_type_ == BinaryOpIC::SMI) {
@@ -1502,6 +1503,7 @@

// Code falls through if the result is not returned as either a smi or heap
   // number.
+  __ bind(&right_arg_changed);
   switch (op_) {
     case Token::ADD:
     case Token::SUB:
@@ -1604,8 +1606,7 @@
     case Token::MUL:
     case Token::DIV:
     case Token::MOD: {
-      Label not_floats;
-      Label not_int32;
+      Label not_floats, not_int32, right_arg_changed;
       if (CpuFeatures::IsSupported(SSE2)) {
         CpuFeatureScope use_sse2(masm, SSE2);
         // It could be that only SMIs have been seen at either the left
@@ -1621,8 +1622,15 @@
           __ JumpIfNotSmi(eax, &not_int32);
         }
         FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
- FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
+        FloatingPointHelper::CheckSSE2OperandIsInt32(
+            masm, &not_int32, xmm0, ebx, ecx, xmm2);
+        FloatingPointHelper::CheckSSE2OperandIsInt32(
+            masm, &not_int32, xmm1, edi, ecx, xmm2);
         if (op_ == Token::MOD) {
+          if (has_fixed_right_arg_) {
+            __ cmp(edi, Immediate(fixed_right_arg_value()));
+            __ j(not_equal, &right_arg_changed);
+          }
           GenerateRegisterArgsPush(masm);
           __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
         } else {
@@ -1675,6 +1683,7 @@

       __ bind(&not_floats);
       __ bind(&not_int32);
+      __ bind(&right_arg_changed);
       GenerateTypeTransition(masm);
       break;
     }
@@ -2764,14 +2773,6 @@
   __ SmiUntag(scratch);
   __ cvtsi2sd(xmm1, scratch);
 }
-
-
-void FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm,
-                                                    Label* non_int32,
-                                                    Register scratch) {
-  CheckSSE2OperandIsInt32(masm, non_int32, xmm0, scratch, scratch, xmm2);
-  CheckSSE2OperandIsInt32(masm, non_int32, xmm1, scratch, scratch, xmm2);
-}


 void FloatingPointHelper::CheckSSE2OperandIsInt32(MacroAssembler* masm,
=======================================
--- /branches/bleeding_edge/src/ic.cc   Mon Jun  3 08:32:22 2013
+++ /branches/bleeding_edge/src/ic.cc   Tue Jun  4 00:49:45 2013
@@ -2498,7 +2498,7 @@
     if (FLAG_trace_ic) {
       PrintF("[UnaryOpIC in ");
       JavaScriptFrame::PrintTop(isolate, stdout, false, true);
-      PrintF(" (%s->%s)#%s @ %p]\n",
+      PrintF(" %s => %s #%s @ %p]\n",
              UnaryOpIC::GetName(previous_type),
              UnaryOpIC::GetName(type),
              Token::Name(op),
@@ -2570,6 +2570,19 @@
   }
   return Max(old_type, new_type);
 }
+
+
+#ifdef DEBUG
+static void TraceBinaryOp(BinaryOpIC::TypeInfo left,
+                          BinaryOpIC::TypeInfo right,
+                          bool has_fixed_right_arg,
+                          int32_t fixed_right_arg_value,
+                          BinaryOpIC::TypeInfo result) {
+  PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right));
+  if (has_fixed_right_arg) PrintF("{%d}", fixed_right_arg_value);
+  PrintF("->%s", BinaryOpIC::GetName(result));
+}
+#endif


 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
@@ -2580,9 +2593,10 @@
   Handle<Object> right = args.at<Object>(1);
   int key = args.smi_at(2);
   Token::Value op = BinaryOpStub::decode_op_from_minor_key(key);
- BinaryOpIC::TypeInfo previous_left, previous_right, unused_previous_result;
+
+  BinaryOpIC::TypeInfo previous_left, previous_right, previous_result;
   BinaryOpStub::decode_types_from_minor_key(
-      key, &previous_left, &previous_right, &unused_previous_result);
+      key, &previous_left, &previous_right, &previous_result);

   BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op);
   BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op);
@@ -2597,43 +2611,60 @@
   BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right);
BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right);

- if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) {
-    if (op == Token::DIV ||
-        op == Token::MUL ||
-        op == Token::SHR ||
-        kSmiValueSize == 32) {
-      // Arithmetic on two Smi inputs has yielded a heap number.
-      // That is the only way to get here from the Smi stub.
-      // With 32-bit Smis, all overflows give heap numbers, but with
-      // 31-bit Smis, most operations overflow to int32 results.
-      result_type = BinaryOpIC::NUMBER;
-    } else {
-      // Other operations on SMIs that overflow yield int32s.
-      result_type = BinaryOpIC::INT32;
+  bool previous_has_fixed_right_arg =
+      BinaryOpStub::decode_has_fixed_right_arg_from_minor_key(key);
+  int previous_fixed_right_arg_value =
+      BinaryOpStub::decode_fixed_right_arg_value_from_minor_key(key);
+
+  int32_t value;
+  bool new_has_fixed_right_arg =
+      op == Token::MOD &&
+      right->ToInt32(&value) &&
+      BinaryOpStub::can_encode_arg_value(value) &&
+      (previous_overall == BinaryOpIC::UNINITIALIZED ||
+       (previous_has_fixed_right_arg &&
+        previous_fixed_right_arg_value == value));
+  int32_t new_fixed_right_arg_value = new_has_fixed_right_arg ? value : 1;
+
+  if (previous_has_fixed_right_arg == new_has_fixed_right_arg) {
+ if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) {
+      if (op == Token::DIV ||
+          op == Token::MUL ||
+          op == Token::SHR ||
+          kSmiValueSize == 32) {
+        // Arithmetic on two Smi inputs has yielded a heap number.
+        // That is the only way to get here from the Smi stub.
+        // With 32-bit Smis, all overflows give heap numbers, but with
+        // 31-bit Smis, most operations overflow to int32 results.
+        result_type = BinaryOpIC::NUMBER;
+      } else {
+        // Other operations on SMIs that overflow yield int32s.
+        result_type = BinaryOpIC::INT32;
+      }
     }
-  }
-  if (new_overall == BinaryOpIC::INT32 &&
-      previous_overall == BinaryOpIC::INT32) {
-    if (new_left == previous_left && new_right == previous_right) {
-      result_type = BinaryOpIC::NUMBER;
+    if (new_overall == BinaryOpIC::INT32 &&
+        previous_overall == BinaryOpIC::INT32) {
+      if (new_left == previous_left && new_right == previous_right) {
+        result_type = BinaryOpIC::NUMBER;
+      }
     }
   }

-  BinaryOpStub stub(key, new_left, new_right, result_type);
+  BinaryOpStub stub(key, new_left, new_right, result_type,
+                    new_has_fixed_right_arg, new_fixed_right_arg_value);
   Handle<Code> code = stub.GetCode(isolate);
   if (!code.is_null()) {
 #ifdef DEBUG
     if (FLAG_trace_ic) {
       PrintF("[BinaryOpIC in ");
       JavaScriptFrame::PrintTop(isolate, stdout, false, true);
-      PrintF(" ((%s+%s)->((%s+%s)->%s))#%s @ %p]\n",
-             BinaryOpIC::GetName(previous_left),
-             BinaryOpIC::GetName(previous_right),
-             BinaryOpIC::GetName(new_left),
-             BinaryOpIC::GetName(new_right),
-             BinaryOpIC::GetName(result_type),
-             Token::Name(op),
-             static_cast<void*>(*code));
+      PrintF(" ");
+ TraceBinaryOp(previous_left, previous_right, previous_has_fixed_right_arg,
+                    previous_fixed_right_arg_value, previous_result);
+      PrintF(" => ");
+      TraceBinaryOp(new_left, new_right, new_has_fixed_right_arg,
+                    new_fixed_right_arg_value, result_type);
+      PrintF(" #%s @ %p]\n", Token::Name(op), static_cast<void*>(*code));
     }
 #endif
     BinaryOpIC ic(isolate);
=======================================
--- /branches/bleeding_edge/src/objects.cc      Mon Jun  3 08:32:22 2013
+++ /branches/bleeding_edge/src/objects.cc      Tue Jun  4 00:49:45 2013
@@ -153,6 +153,41 @@
   ASSERT(*attributes <= ABSENT);
   return value;
 }
+
+
+bool Object::ToInt32(int32_t* value) {
+  if (IsSmi()) {
+    *value = Smi::cast(this)->value();
+    return true;
+  }
+  if (IsHeapNumber()) {
+    double num = HeapNumber::cast(this)->value();
+    if (FastI2D(FastD2I(num)) == num) {
+      *value = FastD2I(num);
+      return true;
+    }
+  }
+  return false;
+}
+
+
+bool Object::ToUint32(uint32_t* value) {
+  if (IsSmi()) {
+    int num = Smi::cast(this)->value();
+    if (num >= 0) {
+      *value = static_cast<uint32_t>(num);
+      return true;
+    }
+  }
+  if (IsHeapNumber()) {
+    double num = HeapNumber::cast(this)->value();
+    if (num >= 0 && FastUI2D(FastD2UI(num)) == num) {
+      *value = FastD2UI(num);
+      return true;
+    }
+  }
+  return false;
+}


 template<typename To>
=======================================
--- /branches/bleeding_edge/src/objects.h       Mon Jun  3 08:32:22 2013
+++ /branches/bleeding_edge/src/objects.h       Tue Jun  4 00:49:45 2013
@@ -1057,6 +1057,8 @@
   // Extract the number.
   inline double Number();
   inline bool IsNaN();
+  bool ToInt32(int32_t* value);
+  bool ToUint32(uint32_t* value);

   inline Representation OptimalRepresentation() {
     if (FLAG_track_fields && IsSmi()) {
=======================================
--- /branches/bleeding_edge/src/type-info.cc    Mon Jun  3 08:32:22 2013
+++ /branches/bleeding_edge/src/type-info.cc    Tue Jun  4 00:49:45 2013
@@ -456,7 +456,9 @@
 void TypeFeedbackOracle::BinaryType(BinaryOperation* expr,
                                     TypeInfo* left,
                                     TypeInfo* right,
-                                    TypeInfo* result) {
+                                    TypeInfo* result,
+                                    bool* has_fixed_right_arg,
+                                    int* fixed_right_arg_value) {
   Handle<Object> object = GetInfo(expr->BinaryOperationFeedbackId());
   TypeInfo unknown = TypeInfo::Unknown();
   if (!object->IsCode()) {
@@ -465,12 +467,17 @@
   }
   Handle<Code> code = Handle<Code>::cast(object);
   if (code->is_binary_op_stub()) {
+    int minor_key = code->stub_info();
     BinaryOpIC::TypeInfo left_type, right_type, result_type;
- BinaryOpStub::decode_types_from_minor_key(code->stub_info(), &left_type,
-                                              &right_type, &result_type);
+    BinaryOpStub::decode_types_from_minor_key(
+        minor_key, &left_type, &right_type, &result_type);
     *left = TypeFromBinaryOpType(left_type);
     *right = TypeFromBinaryOpType(right_type);
     *result = TypeFromBinaryOpType(result_type);
+    *has_fixed_right_arg =
+        BinaryOpStub::decode_has_fixed_right_arg_from_minor_key(minor_key);
+    *fixed_right_arg_value =
+ BinaryOpStub::decode_fixed_right_arg_value_from_minor_key(minor_key);
     return;
   }
   // Not a binary op stub.
=======================================
--- /branches/bleeding_edge/src/type-info.h     Mon May 27 06:59:20 2013
+++ /branches/bleeding_edge/src/type-info.h     Tue Jun  4 00:49:45 2013
@@ -305,7 +305,9 @@
   void BinaryType(BinaryOperation* expr,
                   TypeInfo* left,
                   TypeInfo* right,
-                  TypeInfo* result);
+                  TypeInfo* result,
+                  bool* has_fixed_right_arg,
+                  int* fixed_right_arg_value);
   void CompareType(CompareOperation* expr,
                    TypeInfo* left_type,
                    TypeInfo* right_type,
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Mon Jun 3 07:46:23 2013 +++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Tue Jun 4 00:49:45 2013
@@ -1188,7 +1188,15 @@


 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
-  Label call_runtime;
+  Label right_arg_changed, call_runtime;
+
+  if (op_ == Token::MOD && has_fixed_right_arg_) {
+    // It is guaranteed that the value will fit into a Smi, because if it
+    // didn't, we wouldn't be here, see BinaryOp_Patch.
+    __ Cmp(rax, Smi::FromInt(fixed_right_arg_value()));
+    __ j(not_equal, &right_arg_changed);
+  }
+
   if (result_type_ == BinaryOpIC::UNINITIALIZED ||
       result_type_ == BinaryOpIC::SMI) {
     // Only allow smi results.
@@ -1202,6 +1210,7 @@

// Code falls through if the result is not returned as either a smi or heap
   // number.
+  __ bind(&right_arg_changed);
   GenerateTypeTransition(masm);

   if (call_runtime.is_linked()) {

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to