Use AST's type field and merge types for unary, binary & compare ICs
authorrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 21 Jun 2013 11:10:06 +0000 (11:10 +0000)
committerrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 21 Jun 2013 11:10:06 +0000 (11:10 +0000)
R=jkummerow@chromium.org
BUG=

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

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

24 files changed:
src/arm/code-stubs-arm.cc
src/arm/lithium-arm.cc
src/arm/lithium-codegen-arm.cc
src/ast.cc
src/ast.h
src/code-stubs.h
src/globals.h
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/ia32/code-stubs-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ic.cc
src/objects.cc
src/objects.h
src/type-info.cc
src/type-info.h
src/types.cc
src/typing.cc
src/typing.h
src/x64/code-stubs-x64.cc
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc

index ca44ffef71ef3615a13ec474b2f1d1b02be48c13..fd387fe1652378d8e8fdb609e942a11dd35de031 100644 (file)
@@ -2075,7 +2075,7 @@ void BinaryOpStub_GenerateSmiCode(
 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
   Label right_arg_changed, call_runtime;
 
-  if (op_ == Token::MOD && has_fixed_right_arg_) {
+  if (op_ == Token::MOD && encoded_right_arg_.has_value) {
     // 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())));
@@ -2252,7 +2252,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
         // to type transition.
 
       } else {
-        if (has_fixed_right_arg_) {
+        if (encoded_right_arg_.has_value) {
           __ Vmov(d8, fixed_right_arg_value(), scratch1);
           __ VFPCompareAndSetFlags(d1, d8);
           __ b(ne, &transition);
index f222c2981f2e2bd3cca7eeddbf76dcbcf32592c1..a5b01d22d38e295e5235356edff2a95c11efb1ed 100644 (file)
@@ -1463,7 +1463,7 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
               instr->CheckFlag(HValue::kBailoutOnMinusZero))
           ? AssignEnvironment(result)
           : result;
-    } else if (instr->has_fixed_right_arg()) {
+    } else if (instr->fixed_right_arg().has_value) {
       LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
                                      UseRegisterAtStart(right));
       return AssignEnvironment(DefineAsRegister(mod));
index 2d9c3cd41803b394af0a000cb0dd66a0f495bb3c..b9a3a0bfec6eab310f0634f80ba1af81a9e56410 100644 (file)
@@ -1154,12 +1154,12 @@ void LCodeGen::DoModI(LModI* instr) {
     __ and_(result_reg, left_reg, Operand(divisor - 1));
     __ bind(&done);
 
-  } else if (hmod->has_fixed_right_arg()) {
+  } else if (hmod->fixed_right_arg().has_value) {
     Register left_reg = ToRegister(instr->left());
     Register right_reg = ToRegister(instr->right());
     Register result_reg = ToRegister(instr->result());
 
-    int32_t divisor = hmod->fixed_right_arg_value();
+    int32_t divisor = hmod->fixed_right_arg().value;
     ASSERT(IsPowerOf2(divisor));
 
     // Check if our assumption of a fixed right operand still holds.
index 5567fb338d59327de007803f0a486f2f1e42d529..f2ec67f69b7efb899e937089759f2f5d6a6c9cb5 100644 (file)
@@ -418,6 +418,10 @@ bool FunctionDeclaration::IsInlineable() const {
 // ----------------------------------------------------------------------------
 // Recording of type feedback
 
+// TODO(rossberg): all RecordTypeFeedback functions should disappear
+// once we use the common type field in the AST consistently.
+
+
 void ForInStatement::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
   for_in_type_ = static_cast<ForInType>(oracle->ForInType(this));
 }
@@ -665,26 +669,6 @@ void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
 }
 
 
-void UnaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  type_ = oracle->UnaryType(UnaryOperationFeedbackId());
-}
-
-
-void BinaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  oracle->BinaryType(BinaryOperationFeedbackId(),
-                     &left_type_, &right_type_, &result_type_,
-                     &has_fixed_right_arg_, &fixed_right_arg_value_);
-}
-
-
-// TODO(rossberg): this function (and all other RecordTypeFeedback functions)
-// should disappear once we use the common type field in the AST consistently.
-void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  oracle->CompareTypes(CompareOperationFeedbackId(),
-      &left_type_, &right_type_, &overall_type_, &compare_nil_type_);
-}
-
-
 // ----------------------------------------------------------------------------
 // Implementation of AstVisitor
 
index 1c779b38f7932b23d6d95627c583f5430d86ddeb..555eee94228eb5a41781b09bfd12ec470b349366 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -356,9 +356,11 @@ class Expression: public AstNode {
   // True iff the expression is the undefined literal.
   bool IsUndefinedLiteral();
 
-  // Expression type
-  Handle<Type> type() { return type_; }
-  void set_type(Handle<Type> type) { type_ = type; }
+  // Expression type bounds
+  Handle<Type> upper_type() { return upper_type_; }
+  Handle<Type> lower_type() { return lower_type_; }
+  void set_upper_type(Handle<Type> type) { upper_type_ = type; }
+  void set_lower_type(Handle<Type> type) { lower_type_ = type; }
 
   // Type feedback information for assignments and properties.
   virtual bool IsMonomorphic() {
@@ -389,12 +391,14 @@ class Expression: public AstNode {
 
  protected:
   explicit Expression(Isolate* isolate)
-      : type_(Type::None(), isolate),
+      : upper_type_(Type::Any(), isolate),
+        lower_type_(Type::None(), isolate),
         id_(GetNextId(isolate)),
         test_id_(GetNextId(isolate)) {}
 
  private:
-  Handle<Type> type_;
+  Handle<Type> upper_type_;
+  Handle<Type> lower_type_;
   byte to_boolean_types_;
 
   const BailoutId id_;
@@ -1836,8 +1840,6 @@ class UnaryOperation: public Expression {
   BailoutId MaterializeFalseId() { return materialize_false_id_; }
 
   TypeFeedbackId UnaryOperationFeedbackId() const { return reuse(id()); }
-  void RecordTypeFeedback(TypeFeedbackOracle* oracle);
-  Handle<Type> type() const { return type_; }
 
  protected:
   UnaryOperation(Isolate* isolate,
@@ -1858,8 +1860,6 @@ class UnaryOperation: public Expression {
   Expression* expression_;
   int pos_;
 
-  Handle<Type> type_;
-
   // For unary not (Token::NOT), the AST ids where true and false will
   // actually be materialized, respectively.
   const BailoutId materialize_true_id_;
@@ -1881,12 +1881,11 @@ class BinaryOperation: public Expression {
   BailoutId RightId() const { return right_id_; }
 
   TypeFeedbackId BinaryOperationFeedbackId() const { return reuse(id()); }
-  void RecordTypeFeedback(TypeFeedbackOracle* oracle);
-  Handle<Type> left_type() const { return left_type_; }
-  Handle<Type> right_type() const { return right_type_; }
+  // TODO(rossberg): result_type should be subsumed by lower_type.
   Handle<Type> 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_; }
+  void set_result_type(Handle<Type> type) { result_type_ = type; }
+  Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
+  void set_fixed_right_arg(Maybe<int> arg) { fixed_right_arg_ = arg; }
 
  protected:
   BinaryOperation(Isolate* isolate,
@@ -1909,11 +1908,10 @@ class BinaryOperation: public Expression {
   Expression* right_;
   int pos_;
 
-  Handle<Type> left_type_;
-  Handle<Type> right_type_;
   Handle<Type> result_type_;
-  bool has_fixed_right_arg_;
-  int fixed_right_arg_value_;
+  // TODO(rossberg): the fixed arg should probably be represented as a Constant
+  // type for the RHS.
+  Maybe<int> fixed_right_arg_;
 
   // The short-circuit logical operations need an AST ID for their
   // right-hand subexpression.
@@ -1994,11 +1992,8 @@ class CompareOperation: public Expression {
 
   // Type feedback information.
   TypeFeedbackId CompareOperationFeedbackId() const { return reuse(id()); }
-  void RecordTypeFeedback(TypeFeedbackOracle* oracle);
-  Handle<Type> left_type() const { return left_type_; }
-  Handle<Type> right_type() const { return right_type_; }
-  Handle<Type> overall_type() const { return overall_type_; }
-  Handle<Type> compare_nil_type() const { return compare_nil_type_; }
+  Handle<Type> combined_type() const { return combined_type_; }
+  void set_combined_type(Handle<Type> type) { combined_type_ = type; }
 
   // Match special cases.
   bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check);
@@ -2025,10 +2020,7 @@ class CompareOperation: public Expression {
   Expression* right_;
   int pos_;
 
-  Handle<Type> left_type_;
-  Handle<Type> right_type_;
-  Handle<Type> overall_type_;
-  Handle<Type> compare_nil_type_;
+  Handle<Type> combined_type_;
 };
 
 
index c4f0c4d38a25658b34e9e73bb46472f6f46c3221..6b6ba79b44680eb3a2e5e1636053743845ff44a5 100644 (file)
@@ -904,8 +904,7 @@ class BinaryOpStub: public PlatformCodeStub {
         left_type_(BinaryOpIC::UNINITIALIZED),
         right_type_(BinaryOpIC::UNINITIALIZED),
         result_type_(BinaryOpIC::UNINITIALIZED),
-        has_fixed_right_arg_(false),
-        encoded_right_arg_(encode_arg_value(1)) {
+        encoded_right_arg_(false, encode_arg_value(1)) {
     Initialize();
     ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
   }
@@ -915,16 +914,15 @@ class BinaryOpStub: public PlatformCodeStub {
       BinaryOpIC::TypeInfo left_type,
       BinaryOpIC::TypeInfo right_type,
       BinaryOpIC::TypeInfo result_type,
-      bool has_fixed_right_arg,
-      int32_t fixed_right_arg_value)
+      Maybe<int32_t> fixed_right_arg)
       : 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),
-        has_fixed_right_arg_(has_fixed_right_arg),
-        encoded_right_arg_(encode_arg_value(fixed_right_arg_value)) { }
+        encoded_right_arg_(fixed_right_arg.has_value,
+                           encode_arg_value(fixed_right_arg.value)) { }
 
   static void decode_types_from_minor_key(int minor_key,
                                           BinaryOpIC::TypeInfo* left_type,
@@ -942,16 +940,14 @@ class BinaryOpStub: public PlatformCodeStub {
     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));
+  static Maybe<int> decode_fixed_right_arg_from_minor_key(int minor_key) {
+    return Maybe<int>(
+        HasFixedRightArgBits::decode(minor_key),
+        decode_arg_value(FixedRightArgValueBits::decode(minor_key)));
   }
 
   int fixed_right_arg_value() const {
-    return decode_arg_value(encoded_right_arg_);
+    return decode_arg_value(encoded_right_arg_.value);
   }
 
   static bool can_encode_arg_value(int32_t value) {
@@ -975,8 +971,7 @@ class BinaryOpStub: public PlatformCodeStub {
   BinaryOpIC::TypeInfo right_type_;
   BinaryOpIC::TypeInfo result_type_;
 
-  bool has_fixed_right_arg_;
-  int encoded_right_arg_;
+  Maybe<int> encoded_right_arg_;
 
   static int encode_arg_value(int32_t value) {
     ASSERT(can_encode_arg_value(value));
@@ -1009,8 +1004,8 @@ class BinaryOpStub: public PlatformCodeStub {
            | LeftTypeBits::encode(left_type_)
            | RightTypeBits::encode(right_type_)
            | ResultTypeBits::encode(result_type_)
-           | HasFixedRightArgBits::encode(has_fixed_right_arg_)
-           | FixedRightArgValueBits::encode(encoded_right_arg_);
+           | HasFixedRightArgBits::encode(encoded_right_arg_.has_value)
+           | FixedRightArgValueBits::encode(encoded_right_arg_.value);
   }
 
 
@@ -1207,6 +1202,9 @@ class CompareNilICStub : public HydrogenCodeStub  {
   static byte ExtractTypesFromExtraICState(Code::ExtraICState state) {
     return state & ((1 << NUMBER_OF_TYPES) - 1);
   }
+  static NilValue ExtractNilValueFromExtraICState(Code::ExtraICState state) {
+    return NilValueField::decode(state);
+  }
 
   void Record(Handle<Object> object);
 
index 59931bf5ddb3ba7a9908e97b43aaa7915e731791..9a03f3d53e13ad91f8998bd0d587932e17d057d6 100644 (file)
@@ -399,6 +399,18 @@ enum LanguageMode {
 };
 
 
+// A simple Maybe type, that can be passed by value.
+template<class T>
+struct Maybe {
+  Maybe() : has_value(false) {}
+  explicit Maybe(T t) : has_value(true), value(t) {}
+  Maybe(bool has, T t) : has_value(has), value(t) {}
+
+  bool has_value;
+  T value;
+};
+
+
 // The Strict Mode (ECMA-262 5th edition, 4.2.2).
 //
 // This flag is used in the backend to represent the language mode. So far
index a46fcb8c1897432eb2e183cc2793841dbed0c800..9185a745f2b628de2b5e83ed837a41da2e8f37f5 100644 (file)
@@ -3497,8 +3497,7 @@ HInstruction* HMod::New(Zone* zone,
                         HValue* context,
                         HValue* left,
                         HValue* right,
-                        bool has_fixed_right_arg,
-                        int fixed_right_arg_value) {
+                        Maybe<int> fixed_right_arg) {
   if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
     HConstant* c_left = HConstant::cast(left);
     HConstant* c_right = HConstant::cast(right);
@@ -3517,11 +3516,7 @@ HInstruction* HMod::New(Zone* zone,
       }
     }
   }
-  return new(zone) HMod(context,
-                        left,
-                        right,
-                        has_fixed_right_arg,
-                        fixed_right_arg_value);
+  return new(zone) HMod(context, left, right, fixed_right_arg);
 }
 
 
index 4ed0187eaee4853bd6267698997c76f305176b25..32eda119ca89cef688a0b80e9f24cd573cf109bb 100644 (file)
@@ -4468,11 +4468,9 @@ class HMod: public HArithmeticBinaryOperation {
                            HValue* context,
                            HValue* left,
                            HValue* right,
-                           bool has_fixed_right_arg,
-                           int fixed_right_arg_value);
+                           Maybe<int> fixed_right_arg);
 
-  bool has_fixed_right_arg() const { return has_fixed_right_arg_; }
-  int fixed_right_arg_value() const { return fixed_right_arg_value_; }
+  Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
 
   bool HasPowerOf2Divisor() {
     if (right()->IsConstant() &&
@@ -4499,17 +4497,14 @@ class HMod: public HArithmeticBinaryOperation {
   HMod(HValue* context,
        HValue* left,
        HValue* right,
-       bool has_fixed_right_arg,
-       int fixed_right_arg_value)
+       Maybe<int> fixed_right_arg)
       : HArithmeticBinaryOperation(context, left, right),
-        has_fixed_right_arg_(has_fixed_right_arg),
-        fixed_right_arg_value_(fixed_right_arg_value) {
+        fixed_right_arg_(fixed_right_arg) {
     SetFlag(kCanBeDivByZero);
     SetFlag(kCanOverflow);
   }
 
-  const bool has_fixed_right_arg_;
-  const int fixed_right_arg_value_;
+  const Maybe<int> fixed_right_arg_;
 };
 
 
index 1e261ef44e6366c872ad92432642d8fec95442fa..817c4178478a208995df5a81af106478fb2ce757 100644 (file)
@@ -9036,11 +9036,10 @@ void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) {
   HValue* context = environment()->LookupContext();
   HInstruction* instr =
       HMul::New(zone(), context, value, graph()->GetConstantMinus1());
-  Handle<Type> type = expr->type();
-  Representation rep = ToRepresentation(type);
-  if (type->Is(Type::None())) {
+  Handle<Type> operand_type = expr->expression()->lower_type();
+  Representation rep = ToRepresentation(operand_type);
+  if (operand_type->Is(Type::None())) {
     AddSoftDeoptimize();
-    type = handle(Type::Any(), isolate());
   }
   if (instr->IsBinaryOperation()) {
     HBinaryOperation::cast(instr)->set_observed_input_representation(1, rep);
@@ -9053,8 +9052,8 @@ void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) {
 void HOptimizedGraphBuilder::VisitBitNot(UnaryOperation* expr) {
   CHECK_ALIVE(VisitForValue(expr->expression()));
   HValue* value = Pop();
-  Handle<Type> info = expr->type();
-  if (info->Is(Type::None())) {
+  Handle<Type> operand_type = expr->expression()->lower_type();
+  if (operand_type->Is(Type::None())) {
     AddSoftDeoptimize();
   }
   HInstruction* instr = new(zone()) HBitNot(value);
@@ -9417,16 +9416,16 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation(
     HValue* left,
     HValue* right) {
   HValue* context = environment()->LookupContext();
-  Handle<Type> left_type = expr->left_type();
-  Handle<Type> right_type = expr->right_type();
+  Handle<Type> left_type = expr->left()->lower_type();
+  Handle<Type> right_type = expr->right()->lower_type();
   Handle<Type> result_type = expr->result_type();
-  bool has_fixed_right_arg = expr->has_fixed_right_arg();
-  int fixed_right_arg_value = expr->fixed_right_arg_value();
+  Maybe<int> fixed_right_arg = expr->fixed_right_arg();
   Representation left_rep = ToRepresentation(left_type);
   Representation right_rep = ToRepresentation(right_type);
   Representation result_rep = ToRepresentation(result_type);
   if (left_type->Is(Type::None())) {
     AddSoftDeoptimize();
+    // TODO(rossberg): we should be able to get rid of non-continuous defaults.
     left_type = handle(Type::Any(), isolate());
   }
   if (right_type->Is(Type::None())) {
@@ -9453,12 +9452,7 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation(
       instr = HMul::New(zone(), context, left, right);
       break;
     case Token::MOD:
-      instr = HMod::New(zone(),
-                        context,
-                        left,
-                        right,
-                        has_fixed_right_arg,
-                        fixed_right_arg_value);
+      instr = HMod::New(zone(), context, left, right, fixed_right_arg);
       break;
     case Token::DIV:
       instr = HDiv::New(zone(), context, left, right);
@@ -9765,17 +9759,17 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     return ast_context()->ReturnControl(instr, expr->id());
   }
 
-  Handle<Type> left_type = expr->left_type();
-  Handle<Type> right_type = expr->right_type();
-  Handle<Type> overall_type = expr->overall_type();
-  Representation combined_rep = ToRepresentation(overall_type);
+  Handle<Type> left_type = expr->left()->lower_type();
+  Handle<Type> right_type = expr->right()->lower_type();
+  Handle<Type> combined_type = expr->combined_type();
+  Representation combined_rep = ToRepresentation(combined_type);
   Representation left_rep = ToRepresentation(left_type);
   Representation right_rep = ToRepresentation(right_type);
   // Check if this expression was ever executed according to type feedback.
   // Note that for the special typeof/null/undefined cases we get unknown here.
-  if (overall_type->Is(Type::None())) {
+  if (combined_type->Is(Type::None())) {
     AddSoftDeoptimize();
-    overall_type = left_type = right_type = handle(Type::Any(), isolate());
+    combined_type = left_type = right_type = handle(Type::Any(), isolate());
   }
 
   CHECK_ALIVE(VisitForValue(expr->left()));
@@ -9847,13 +9841,13 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     HIn* result = new(zone()) HIn(context, left, right);
     result->set_position(expr->position());
     return ast_context()->ReturnInstruction(result, expr->id());
-  } else if (overall_type->Is(Type::Receiver())) {
+  } else if (combined_type->Is(Type::Receiver())) {
     switch (op) {
       case Token::EQ:
       case Token::EQ_STRICT: {
         // Can we get away with map check and not instance type check?
-        if (overall_type->IsClass()) {
-          Handle<Map> map = overall_type->AsClass();
+        if (combined_type->IsClass()) {
+          Handle<Map> map = combined_type->AsClass();
           AddCheckMapsWithTransitions(left, map);
           AddCheckMapsWithTransitions(right, map);
           HCompareObjectEqAndBranch* result =
@@ -9874,7 +9868,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
       default:
         return Bailout("Unsupported non-primitive compare");
     }
-  } else if (overall_type->Is(Type::InternalizedString()) &&
+  } else if (combined_type->Is(Type::InternalizedString()) &&
              Token::IsEqualityOp(op)) {
     BuildCheckNonSmi(left);
     AddInstruction(HCheckInstanceType::NewIsInternalizedString(left, zone()));
@@ -9925,8 +9919,8 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
     if_nil.CaptureContinuation(&continuation);
     return ast_context()->ReturnContinuation(&continuation, expr->id());
   }
-  Handle<Type> type = expr->compare_nil_type()->Is(Type::None())
-      ? handle(Type::Any(), isolate_) : expr->compare_nil_type();
+  Handle<Type> type = expr->combined_type()->Is(Type::None())
+      ? handle(Type::Any(), isolate_) : expr->combined_type();
   BuildCompareNil(value, type, expr->position(), &continuation);
   return ast_context()->ReturnContinuation(&continuation, expr->id());
 }
index 91dd9df93db65a87bdb6a739e1d8b3f1f0bf0516..4b6a6abc490f29a3b46d24cd676785a15cff1362 100644 (file)
@@ -1527,7 +1527,7 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
       UNREACHABLE();
   }
 
-  if (op_ == Token::MOD && has_fixed_right_arg_) {
+  if (op_ == Token::MOD && encoded_right_arg_.has_value) {
     // 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())));
@@ -1669,7 +1669,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
         FloatingPointHelper::CheckSSE2OperandIsInt32(
             masm, &not_int32, xmm1, edi, ecx, xmm2);
         if (op_ == Token::MOD) {
-          if (has_fixed_right_arg_) {
+          if (encoded_right_arg_.has_value) {
             __ cmp(edi, Immediate(fixed_right_arg_value()));
             __ j(not_equal, &right_arg_changed);
           }
index 29bdc1da996d8b1cdb32f8136b2dfa608f508fe6..b67441f93797f4ba4f9daea1d052650cfd96a8ab 100644 (file)
@@ -1223,12 +1223,12 @@ void LCodeGen::DoModI(LModI* instr) {
     __ and_(left_reg, divisor - 1);
     __ bind(&done);
 
-  } else if (hmod->has_fixed_right_arg()) {
+  } else if (hmod->fixed_right_arg().has_value) {
     Register left_reg = ToRegister(instr->left());
     ASSERT(left_reg.is(ToRegister(instr->result())));
     Register right_reg = ToRegister(instr->right());
 
-    int32_t divisor = hmod->fixed_right_arg_value();
+    int32_t divisor = hmod->fixed_right_arg().value;
     ASSERT(IsPowerOf2(divisor));
 
     // Check if our assumption of a fixed right operand still holds.
index 96fbc8a04f397bf3c663d1b92b909b74caca551a..5e40842eeb1386445c09873805d64389faf2bd09 100644 (file)
@@ -1551,7 +1551,7 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
               instr->CheckFlag(HValue::kBailoutOnMinusZero))
           ? AssignEnvironment(result)
           : result;
-    } else if (instr->has_fixed_right_arg()) {
+    } else if (instr->fixed_right_arg().has_value) {
       LModI* mod = new(zone()) LModI(UseRegister(left),
                                      UseRegisterAtStart(right),
                                      NULL);
index d6e35a7c47ccd16f2a8027ee7e762103db6d8a00..6abd52f2a16446967a00a182990dadba0f5cb283 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -2653,11 +2653,10 @@ static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type,
 #ifdef DEBUG
 static void TraceBinaryOp(BinaryOpIC::TypeInfo left,
                           BinaryOpIC::TypeInfo right,
-                          bool has_fixed_right_arg,
-                          int32_t fixed_right_arg_value,
+                          Maybe<int32_t> fixed_right_arg,
                           BinaryOpIC::TypeInfo result) {
   PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right));
-  if (has_fixed_right_arg) PrintF("{%d}", fixed_right_arg_value);
+  if (fixed_right_arg.has_value) PrintF("{%d}", fixed_right_arg.value);
   PrintF("->%s", BinaryOpIC::GetName(result));
 }
 #endif
@@ -2689,10 +2688,8 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
   BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right);
   BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right);
 
-  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);
+  Maybe<int> previous_fixed_right_arg =
+      BinaryOpStub::decode_fixed_right_arg_from_minor_key(key);
 
   int32_t value;
   bool new_has_fixed_right_arg =
@@ -2700,11 +2697,12 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
       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;
+       (previous_fixed_right_arg.has_value &&
+        previous_fixed_right_arg.value == value));
+  Maybe<int32_t> new_fixed_right_arg(
+      new_has_fixed_right_arg, new_has_fixed_right_arg ? value : 1);
 
-  if (previous_has_fixed_right_arg == new_has_fixed_right_arg) {
+  if (previous_fixed_right_arg.has_value == new_fixed_right_arg.has_value) {
     if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) {
       if (op == Token::DIV ||
           op == Token::MUL ||
@@ -2728,8 +2726,7 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
     }
   }
 
-  BinaryOpStub stub(key, new_left, new_right, result_type,
-                    new_has_fixed_right_arg, new_fixed_right_arg_value);
+  BinaryOpStub stub(key, new_left, new_right, result_type, new_fixed_right_arg);
   Handle<Code> code = stub.GetCode(isolate);
   if (!code.is_null()) {
 #ifdef DEBUG
@@ -2737,11 +2734,10 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
       PrintF("[BinaryOpIC in ");
       JavaScriptFrame::PrintTop(isolate, stdout, false, true);
       PrintF(" ");
-      TraceBinaryOp(previous_left, previous_right, previous_has_fixed_right_arg,
-                    previous_fixed_right_arg_value, previous_result);
+      TraceBinaryOp(previous_left, previous_right, previous_fixed_right_arg,
+                    previous_result);
       PrintF(" => ");
-      TraceBinaryOp(new_left, new_right, new_has_fixed_right_arg,
-                    new_fixed_right_arg_value, result_type);
+      TraceBinaryOp(new_left, new_right, new_fixed_right_arg, result_type);
       PrintF(" #%s @ %p]\n", Token::Name(op), static_cast<void*>(*code));
     }
 #endif
index 7f18ae01e23e1e858e74c2108d04ca0563282a51..715ab6249a46a011c03be576e1dc26f145b52a0b 100644 (file)
@@ -9980,6 +9980,12 @@ byte Code::compare_nil_state() {
       extended_extra_ic_state());
 }
 
+byte Code::compare_nil_value() {
+  ASSERT(is_compare_nil_ic_stub());
+  return CompareNilICStub::ExtractNilValueFromExtraICState(
+      extended_extra_ic_state());
+}
+
 
 void Code::InvalidateRelocation() {
   set_relocation_info(GetHeap()->empty_byte_array());
index c256a7cd9c6cb30c2f435cb93285103d96be3758..9edc4e9260cfa96edcdcf5b1dcb86b4133488501 100644 (file)
@@ -4663,6 +4663,7 @@ class Code: public HeapObject {
 
   // [compare_nil]: For kind COMPARE_NIL_IC tells what state the stub is in.
   byte compare_nil_state();
+  byte compare_nil_value();
 
   // [has_function_cache]: For kind STUB tells whether there is a function
   // cache is passed to the stub.
index d7af7ca696f150ef3f7b8e731af967c2d25b2d23..ae5bf9719dc62524ba6aee564265b281aa57b8a0 100644 (file)
@@ -352,13 +352,11 @@ bool TypeFeedbackOracle::LoadIsStub(Property* expr, ICStub* stub) {
 }
 
 
-void TypeFeedbackOracle::CompareTypes(TypeFeedbackId id,
-                                      Handle<Type>* left_type,
-                                      Handle<Type>* right_type,
-                                      Handle<Type>* overall_type,
-                                      Handle<Type>* compare_nil_type) {
-  *left_type = *right_type = *overall_type = *compare_nil_type =
-      handle(Type::Any(), isolate_);
+void TypeFeedbackOracle::CompareType(TypeFeedbackId id,
+                                     Handle<Type>* left_type,
+                                     Handle<Type>* right_type,
+                                     Handle<Type>* combined_type) {
+  *left_type = *right_type = *combined_type = handle(Type::Any(), isolate_);
   Handle<Object> info = GetInfo(id);
   if (!info->IsCode()) return;
   Handle<Code> code = Handle<Code>::cast(info);
@@ -375,10 +373,14 @@ void TypeFeedbackOracle::CompareTypes(TypeFeedbackId id,
   if (code->is_compare_ic_stub()) {
     int stub_minor_key = code->stub_info();
     CompareIC::StubInfoToType(
-        stub_minor_key, left_type, right_type, overall_type, map, isolate());
+        stub_minor_key, left_type, right_type, combined_type, map, isolate());
   } else if (code->is_compare_nil_ic_stub()) {
     CompareNilICStub::State state(code->compare_nil_state());
-    *compare_nil_type = CompareNilICStub::StateToType(isolate_, state, map);
+    *combined_type = CompareNilICStub::StateToType(isolate_, state, map);
+    Handle<Type> nil_type = handle(code->compare_nil_value() == kNullValue
+        ? Type::Null() : Type::Undefined(), isolate_);
+    *left_type = *right_type =
+        handle(Type::Union(*combined_type, nil_type), isolate_);
   }
 }
 
@@ -397,8 +399,7 @@ void TypeFeedbackOracle::BinaryType(TypeFeedbackId id,
                                     Handle<Type>* left,
                                     Handle<Type>* right,
                                     Handle<Type>* result,
-                                    bool* has_fixed_right_arg,
-                                    int* fixed_right_arg_value) {
+                                    Maybe<int>* fixed_right_arg) {
   Handle<Object> object = GetInfo(id);
   *left = *right = *result = handle(Type::Any(), isolate_);
   if (!object->IsCode()) return;
@@ -407,10 +408,8 @@ void TypeFeedbackOracle::BinaryType(TypeFeedbackId id,
 
   int minor_key = code->stub_info();
   BinaryOpIC::StubInfoToType(minor_key, left, right, result, isolate());
-  *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);
+  *fixed_right_arg =
+      BinaryOpStub::decode_fixed_right_arg_from_minor_key(minor_key);
 }
 
 
index c163b2bac04338161c99b6e87f5852e820ad5ecf..a1c1f54cc12d95959cea6485952d3fa7a7a31210 100644 (file)
@@ -300,14 +300,12 @@ class TypeFeedbackOracle: public ZoneObject {
                   Handle<Type>* left,
                   Handle<Type>* right,
                   Handle<Type>* result,
-                  bool* has_fixed_right_arg,
-                  int* fixed_right_arg_value);
-
-  void CompareTypes(TypeFeedbackId id,
-                    Handle<Type>* left_type,
-                    Handle<Type>* right_type,
-                    Handle<Type>* overall_type,
-                    Handle<Type>* compare_nil_type);
+                  Maybe<int>* fixed_right_arg);
+
+  void CompareType(TypeFeedbackId id,
+                   Handle<Type>* left_type,
+                   Handle<Type>* right_type,
+                   Handle<Type>* combined_type);
 
   Handle<Type> ClauseType(TypeFeedbackId id);
 
index 22a108b7206b0bd657ae57e90af4c20a11770190..a3489e24609e3fa651f670da9394b9260feb7395 100644 (file)
@@ -336,6 +336,12 @@ Type* Type::Union(Handle<Type> type1, Handle<Type> type2) {
     return from_bitset(type1->as_bitset() | type2->as_bitset());
   }
 
+  // Fast case: top or bottom types.
+  if (type1->SameValue(Type::Any())) return *type1;
+  if (type2->SameValue(Type::Any())) return *type2;
+  if (type1->SameValue(Type::None())) return *type2;
+  if (type2->SameValue(Type::None())) return *type1;
+
   // Semi-fast case: Unioned objects are neither involved nor produced.
   if (!(type1->is_union() || type2->is_union())) {
     if (type1->Is(type2)) return *type2;
@@ -406,6 +412,12 @@ Type* Type::Intersect(Handle<Type> type1, Handle<Type> type2) {
     return from_bitset(type1->as_bitset() & type2->as_bitset());
   }
 
+  // Fast case: top or bottom types.
+  if (type1->SameValue(Type::None())) return *type1;
+  if (type2->SameValue(Type::None())) return *type2;
+  if (type1->SameValue(Type::Any())) return *type2;
+  if (type2->SameValue(Type::Any())) return *type1;
+
   // Semi-fast case: Unioned objects are neither involved nor produced.
   if (!(type1->is_union() || type2->is_union())) {
     if (type1->Is(type2)) return *type1;
index e1fd8aab74d485887c0445ae88c482618772ee53..6157114c9bec4413b64fa9b3f2e18e4d08781843 100644 (file)
@@ -404,7 +404,9 @@ void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
   ASSERT(!HasStackOverflow());
   CHECK_ALIVE(Visit(expr->expression()));
 
-  expr->RecordTypeFeedback(oracle());
+  // Collect type feedback.
+  Handle<Type> op_type = oracle()->UnaryType(expr->UnaryOperationFeedbackId());
+  MergeLowerType(expr->expression(), op_type);
   if (expr->op() == Token::NOT) {
     // TODO(rossberg): only do in test or value context.
     expr->expression()->RecordToBooleanTypeFeedback(oracle());
@@ -429,7 +431,15 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
   CHECK_ALIVE(Visit(expr->left()));
   CHECK_ALIVE(Visit(expr->right()));
 
-  expr->RecordTypeFeedback(oracle());
+  // Collect type feedback.
+  Handle<Type> left_type, right_type, result_type;
+  Maybe<int> fixed_right_arg;
+  oracle()->BinaryType(expr->BinaryOperationFeedbackId(),
+      &left_type, &right_type, &result_type, &fixed_right_arg);
+  MergeLowerType(expr->left(), left_type);
+  MergeLowerType(expr->right(), right_type);
+  expr->set_result_type(result_type);
+  expr->set_fixed_right_arg(fixed_right_arg);
   if (expr->op() == Token::OR || expr->op() == Token::AND) {
     expr->left()->RecordToBooleanTypeFeedback(oracle());
   }
@@ -441,7 +451,13 @@ void AstTyper::VisitCompareOperation(CompareOperation* expr) {
   CHECK_ALIVE(Visit(expr->left()));
   CHECK_ALIVE(Visit(expr->right()));
 
-  expr->RecordTypeFeedback(oracle());
+  // Collect type feedback.
+  Handle<Type> left_type, right_type, combined_type;
+  oracle()->CompareType(expr->CompareOperationFeedbackId(),
+      &left_type, &right_type, &combined_type);
+  MergeLowerType(expr->left(), left_type);
+  MergeLowerType(expr->right(), right_type);
+  expr->set_combined_type(combined_type);
 }
 
 
index 1f172eaf59b6f59100e4f92f485b35bc4a02f5ee..2d3fac0650959cb9f6ac719b3973456510702b69 100644 (file)
@@ -62,6 +62,13 @@ class AstTyper: public AstVisitor {
   TypeFeedbackOracle* oracle() { return &oracle_; }
   Zone* zone() const { return info_->zone(); }
 
+  void MergeLowerType(Expression* e, Handle<Type> t) {
+    e->set_lower_type(handle(Type::Union(e->lower_type(), t), isolate_));
+  }
+  void MergeUpperType(Expression* e, Handle<Type> t) {
+    e->set_upper_type(handle(Type::Intersect(e->upper_type(), t), isolate_));
+  }
+
   void VisitDeclarations(ZoneList<Declaration*>* declarations);
   void VisitStatements(ZoneList<Statement*>* statements);
 
index 8868c7a88adc6c9136d66e29ddce79e837a05ac7..adfc8a1c14bef4b8c531b4878ad8e756de998064 100644 (file)
@@ -1232,7 +1232,7 @@ void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
   Label right_arg_changed, call_runtime;
 
-  if (op_ == Token::MOD && has_fixed_right_arg_) {
+  if (op_ == Token::MOD && encoded_right_arg_.has_value) {
     // 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()));
index 296458f3ef2d56d23a7edf452d9be6da40677881..0ce44868a01343af268eb48b44b1961774467226 100644 (file)
@@ -1034,12 +1034,12 @@ void LCodeGen::DoModI(LModI* instr) {
     __ andl(left_reg, Immediate(divisor - 1));
     __ bind(&done);
 
-  } else if (hmod->has_fixed_right_arg()) {
+  } else if (hmod->fixed_right_arg().has_value) {
     Register left_reg = ToRegister(instr->left());
     ASSERT(left_reg.is(ToRegister(instr->result())));
     Register right_reg = ToRegister(instr->right());
 
-    int32_t divisor = hmod->fixed_right_arg_value();
+    int32_t divisor = hmod->fixed_right_arg().value;
     ASSERT(IsPowerOf2(divisor));
 
     // Check if our assumption of a fixed right operand still holds.
index 5b15cec09f11f2898bcfb6e30ac237b14a4f11b4..1569d9aaded5dcb9a046bde63da0d3cae8c74d43 100644 (file)
@@ -1459,7 +1459,7 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
               instr->CheckFlag(HValue::kBailoutOnMinusZero))
           ? AssignEnvironment(result)
           : result;
-    } else if (instr->has_fixed_right_arg()) {
+    } else if (instr->fixed_right_arg().has_value) {
       LModI* mod = new(zone()) LModI(UseRegister(left),
                                      UseRegisterAtStart(right),
                                      NULL);