Encapsulating Type information in the CompareICStub
authorolivf@chromium.org <olivf@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 16 May 2013 10:59:17 +0000 (10:59 +0000)
committerolivf@chromium.org <olivf@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 16 May 2013 10:59:17 +0000 (10:59 +0000)
Encapsulate type information in a convenient wrapper instead of storing it in a naked bitfield. This especially facilitates transitioning to a new state and converting from/to the extraICState representation. Additionally cleaning up ToBooleanICStub::Types for consistency.

BUG=
R=svenpanne@chromium.org

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

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

14 files changed:
src/code-stubs.cc
src/code-stubs.h
src/hydrogen.cc
src/ic.cc
src/ic.h
src/objects.cc
src/objects.h
src/string-stream.h
src/stub-cache.cc
src/stub-cache.h
src/type-info.cc
src/utils.h
test/cctest/cctest.gyp
test/cctest/test-compare-nil-ic-stub.cc [new file with mode: 0644]

index 1847140..312febc 100644 (file)
@@ -408,41 +408,50 @@ void ICCompareStub::Generate(MacroAssembler* masm) {
 }
 
 
-CompareNilICStub::Types CompareNilICStub::GetPatchedICFlags(
-    Code::ExtraICState extra_ic_state,
-    Handle<Object> object,
-    bool* already_monomorphic) {
-  Types types = TypesField::decode(extra_ic_state);
-  NilValue nil = NilValueField::decode(extra_ic_state);
-  EqualityKind kind = EqualityKindField::decode(extra_ic_state);
-  ASSERT(types != CompareNilICStub::kFullCompare);
-  *already_monomorphic =
-      (types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0;
-  if (kind == kStrictEquality) {
-    if (nil == kNullValue) {
-      return CompareNilICStub::kCompareAgainstNull;
-    } else {
-      return CompareNilICStub::kCompareAgainstUndefined;
-    }
+void CompareNilICStub::Record(Handle<Object> object) {
+  ASSERT(types_ != Types::FullCompare());
+  if (equality_kind_ == kStrictEquality) {
+    // When testing for strict equality only one value will evaluate to true
+    types_.RemoveAll();
+    types_.Add((nil_value_ == kNullValue) ? NULL_TYPE:
+                                            UNDEFINED);
   } else {
     if (object->IsNull()) {
-      types = static_cast<CompareNilICStub::Types>(
-          types | CompareNilICStub::kCompareAgainstNull);
+      types_.Add(NULL_TYPE);
     } else if (object->IsUndefined()) {
-      types = static_cast<CompareNilICStub::Types>(
-          types | CompareNilICStub::kCompareAgainstUndefined);
+      types_.Add(UNDEFINED);
     } else if (object->IsUndetectableObject() ||
                object->IsOddball() ||
                !object->IsHeapObject()) {
-        types = CompareNilICStub::kFullCompare;
-    } else if ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0) {
-      types = CompareNilICStub::kFullCompare;
+      types_ = Types::FullCompare();
+    } else if (IsMonomorphic()) {
+      types_ = Types::FullCompare();
     } else {
-      types = static_cast<CompareNilICStub::Types>(
-          types | CompareNilICStub::kCompareAgainstMonomorphicMap);
+      types_.Add(MONOMORPHIC_MAP);
     }
   }
-  return types;
+}
+
+
+void CompareNilICStub::PrintName(StringStream* stream) {
+  stream->Add("CompareNilICStub_");
+  types_.Print(stream);
+  stream->Add((nil_value_ == kNullValue) ? "(NullValue|":
+                                           "(UndefinedValue|");
+  stream->Add((equality_kind_ == kStrictEquality) ? "StrictEquality)":
+                                                    "NonStrictEquality)");
+}
+
+
+void CompareNilICStub::Types::Print(StringStream* stream) const {
+  stream->Add("(");
+  SimpleListPrinter printer(stream);
+  if (IsEmpty()) printer.Add("None");
+  if (Contains(UNDEFINED)) printer.Add("Undefined");
+  if (Contains(NULL_TYPE)) printer.Add("Null");
+  if (Contains(MONOMORPHIC_MAP)) printer.Add("MonomorphicMap");
+  if (Contains(UNDETECTABLE)) printer.Add("Undetectable");
+  stream->Add(")");
 }
 
 
@@ -552,15 +561,18 @@ void ToBooleanStub::PrintName(StringStream* stream) {
 
 
 void ToBooleanStub::Types::Print(StringStream* stream) const {
-  if (IsEmpty()) stream->Add("None");
-  if (Contains(UNDEFINED)) stream->Add("Undefined");
-  if (Contains(BOOLEAN)) stream->Add("Bool");
-  if (Contains(NULL_TYPE)) stream->Add("Null");
-  if (Contains(SMI)) stream->Add("Smi");
-  if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
-  if (Contains(STRING)) stream->Add("String");
-  if (Contains(SYMBOL)) stream->Add("Symbol");
-  if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
+  stream->Add("(");
+  SimpleListPrinter printer(stream);
+  if (IsEmpty()) printer.Add("None");
+  if (Contains(UNDEFINED)) printer.Add("Undefined");
+  if (Contains(BOOLEAN)) printer.Add("Bool");
+  if (Contains(NULL_TYPE)) printer.Add("Null");
+  if (Contains(SMI)) printer.Add("Smi");
+  if (Contains(SPEC_OBJECT)) printer.Add("SpecObject");
+  if (Contains(STRING)) printer.Add("String");
+  if (Contains(SYMBOL)) printer.Add("Symbol");
+  if (Contains(HEAP_NUMBER)) printer.Add("HeapNumber");
+  stream->Add(")");
 }
 
 
index 646aee2..aa6a410 100644 (file)
@@ -1047,41 +1047,52 @@ class ICCompareStub: public PlatformCodeStub {
 
 class CompareNilICStub : public HydrogenCodeStub  {
  public:
-  enum Types {
-    kCompareAgainstNull = 1 << 0,
-    kCompareAgainstUndefined = 1 << 1,
-    kCompareAgainstMonomorphicMap = 1 << 2,
-    kCompareAgainstUndetectable = 1 << 3,
-    kFullCompare = kCompareAgainstNull | kCompareAgainstUndefined |
-        kCompareAgainstUndetectable
+  enum Type {
+    UNDEFINED,
+    NULL_TYPE,
+    MONOMORPHIC_MAP,
+    UNDETECTABLE,
+    NUMBER_OF_TYPES
+  };
+
+  class Types : public EnumSet<Type, byte> {
+   public:
+    Types() : EnumSet<Type, byte>(0) { }
+    explicit Types(byte bits) : EnumSet<Type, byte>(bits) { }
+
+    static Types FullCompare() {
+      Types set;
+      set.Add(UNDEFINED);
+      set.Add(NULL_TYPE);
+      set.Add(UNDETECTABLE);
+      return set;
+    }
+
+    void Print(StringStream* stream) const;
   };
 
+  // At most 6 different types can be distinguished, because the Code object
+  // only has room for a single byte to hold a set and there are two more
+  // boolean flags we need to store. :-P
+  STATIC_ASSERT(NUMBER_OF_TYPES <= 6);
+
   CompareNilICStub(EqualityKind kind, NilValue nil, Types types)
-      : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS), bit_field_(0) {
-    bit_field_ = EqualityKindField::encode(kind) |
-        NilValueField::encode(nil) |
-        TypesField::encode(types);
+      : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS), types_(types) {
+    equality_kind_ = kind;
+    nil_value_ = nil;
   }
 
-  virtual InlineCacheState GetICState() {
-    Types types = GetTypes();
-    if (types == kFullCompare) {
-      return MEGAMORPHIC;
-    } else if ((types & kCompareAgainstMonomorphicMap) != 0) {
-      return MONOMORPHIC;
-    } else {
-      return PREMONOMORPHIC;
-    }
+  explicit CompareNilICStub(Code::ExtraICState ic_state)
+      : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) {
+    equality_kind_ = EqualityKindField::decode(ic_state);
+    nil_value_ = NilValueField::decode(ic_state);
+    types_ = Types(ExtractTypesFromExtraICState(ic_state));
   }
 
-  virtual Code::Kind GetCodeKind() const { return Code::COMPARE_NIL_IC; }
-
-  Handle<Code> GenerateCode();
-
   static Handle<Code> GetUninitialized(Isolate* isolate,
                                        EqualityKind kind,
                                        NilValue nil) {
-    return CompareNilICStub(kind, nil).GetCode(isolate);
+    return CompareNilICStub(kind, nil, CODE_STUB_IS_MISS).GetCode(isolate);
   }
 
   virtual void InitializeInterfaceDescriptor(
@@ -1089,53 +1100,76 @@ class CompareNilICStub : public HydrogenCodeStub  {
       CodeStubInterfaceDescriptor* descriptor);
 
   static void InitializeForIsolate(Isolate* isolate) {
-    CompareNilICStub compare_stub(kStrictEquality, kNullValue);
+    CompareNilICStub compare_stub(kStrictEquality, kNullValue,
+                                  CODE_STUB_IS_MISS);
     compare_stub.InitializeInterfaceDescriptor(
         isolate,
         isolate->code_stub_interface_descriptor(CodeStub::CompareNilIC));
   }
 
-  virtual Code::ExtraICState GetExtraICState() {
-    return bit_field_;
+  virtual InlineCacheState GetICState() {
+    if (types_ == Types::FullCompare()) {
+      return MEGAMORPHIC;
+    } else if (types_.Contains(MONOMORPHIC_MAP)) {
+      return MONOMORPHIC;
+    } else {
+      return PREMONOMORPHIC;
+    }
   }
 
-  EqualityKind GetKind() { return EqualityKindField::decode(bit_field_); }
-  NilValue GetNilValue() { return NilValueField::decode(bit_field_); }
-  Types GetTypes() { return TypesField::decode(bit_field_); }
+  virtual Code::Kind GetCodeKind() const { return Code::COMPARE_NIL_IC; }
 
-  static Types TypesFromExtraICState(
-      Code::ExtraICState state) {
-    return TypesField::decode(state);
+  Handle<Code> GenerateCode();
+
+  // extra ic state = nil_value | equality_kind | type_n-1 | ... | type_0
+  virtual Code::ExtraICState GetExtraICState() {
+    return NilValueField::encode(nil_value_)         |
+           EqualityKindField::encode(equality_kind_) |
+           types_.ToIntegral();
   }
-  static EqualityKind EqualityKindFromExtraICState(
+  static byte ExtractTypesFromExtraICState(
       Code::ExtraICState state) {
-    return EqualityKindField::decode(state);
-  }
-  static NilValue NilValueFromExtraICState(Code::ExtraICState state) {
-    return NilValueField::decode(state);
+    return state & ((1<<NUMBER_OF_TYPES)-1);
   }
 
-  static Types GetPatchedICFlags(Code::ExtraICState extra_ic_state,
-                                 Handle<Object> object,
-                                 bool* already_monomorphic);
+  void Record(Handle<Object> object);
+
+  bool IsMonomorphic() const { return types_.Contains(MONOMORPHIC_MAP); }
+  EqualityKind GetKind() const { return equality_kind_; }
+  NilValue GetNilValue() const { return nil_value_; }
+  Types GetTypes() const { return types_; }
+  void ClearTypes() { types_.RemoveAll(); }
+  void SetKind(EqualityKind kind) { equality_kind_ = kind; }
+
+  virtual void PrintName(StringStream* stream);
 
  private:
   friend class CompareNilIC;
 
-  class EqualityKindField : public BitField<EqualityKind, 0, 1> {};
-  class NilValueField : public BitField<NilValue, 1, 1> {};
-  class TypesField : public BitField<Types, 3, 4> {};
+  CompareNilICStub(EqualityKind kind, NilValue nil,
+                   InitializationState init_state)
+      : HydrogenCodeStub(init_state), types_(0) {
+    equality_kind_ = kind;
+    nil_value_ = nil;
+  }
 
-  CompareNilICStub(EqualityKind kind, NilValue nil)
-      : HydrogenCodeStub(CODE_STUB_IS_MISS), bit_field_(0) {
-    bit_field_ = EqualityKindField::encode(kind) |
-        NilValueField::encode(nil);
+  CompareNilICStub(Code::ExtraICState ic_state, InitializationState init_state)
+      : HydrogenCodeStub(init_state) {
+    equality_kind_ = EqualityKindField::decode(ic_state);
+    nil_value_ = NilValueField::decode(ic_state);
+    types_ = Types(ExtractTypesFromExtraICState(ic_state));
   }
 
+  class EqualityKindField : public BitField<EqualityKind, NUMBER_OF_TYPES, 1> {
+  };
+  class NilValueField : public BitField<NilValue, NUMBER_OF_TYPES+1, 1> {};
+
   virtual CodeStub::Major MajorKey() { return CompareNilIC; }
-  virtual int NotMissMinorKey() { return bit_field_; }
+  virtual int NotMissMinorKey() { return GetExtraICState(); }
 
-  int bit_field_;
+  EqualityKind equality_kind_;
+  NilValue nil_value_;
+  Types types_;
 
   DISALLOW_COPY_AND_ASSIGN(CompareNilICStub);
 };
@@ -1795,26 +1829,17 @@ class ToBooleanStub: public PlatformCodeStub {
   // only has room for a single byte to hold a set of these types. :-P
   STATIC_ASSERT(NUMBER_OF_TYPES <= 8);
 
-  class Types {
+  class Types : public EnumSet<Type, byte> {
    public:
     Types() {}
-    explicit Types(byte bits) : set_(bits) {}
+    explicit Types(byte bits) : EnumSet<Type, byte>(bits) {}
 
-    bool IsEmpty() const { return set_.IsEmpty(); }
-    bool Contains(Type type) const { return set_.Contains(type); }
-    bool ContainsAnyOf(Types types) const {
-      return set_.ContainsAnyOf(types.set_);
-    }
-    void Add(Type type) { set_.Add(type); }
-    byte ToByte() const { return set_.ToIntegral(); }
+    byte ToByte() const { return ToIntegral(); }
     void Print(StringStream* stream) const;
     void TraceTransition(Types to) const;
     bool Record(Handle<Object> object);
     bool NeedsMap() const;
     bool CanBeUndetectable() const;
-
-   private:
-    EnumSet<Type, byte> set_;
   };
 
   static Types no_types() { return Types(); }
@@ -1831,7 +1856,8 @@ class ToBooleanStub: public PlatformCodeStub {
 
  private:
   Major MajorKey() { return ToBoolean; }
-  int MinorKey() { return (tos_.code() << NUMBER_OF_TYPES) | types_.ToByte(); }
+  int MinorKey() { return (tos_.code() << NUMBER_OF_TYPES) |
+                          types_.ToByte(); }
 
   virtual void FinishCode(Handle<Code> code) {
     code->set_to_boolean_state(types_.ToByte());
index de3254a..939a5fa 100644 (file)
@@ -1812,27 +1812,27 @@ void HGraphBuilder::BuildCompareNil(
     HIfContinuation* continuation) {
   IfBuilder if_nil(this, position);
   bool needs_or = false;
-  if ((types & CompareNilICStub::kCompareAgainstNull) != 0) {
+  if (types.Contains(CompareNilICStub::NULL_TYPE)) {
     if (needs_or) if_nil.Or();
     if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull());
     needs_or = true;
   }
-  if ((types & CompareNilICStub::kCompareAgainstUndefined) != 0) {
+  if (types.Contains(CompareNilICStub::UNDEFINED)) {
     if (needs_or) if_nil.Or();
     if_nil.If<HCompareObjectEqAndBranch>(value,
                                          graph()->GetConstantUndefined());
     needs_or = true;
   }
   // Handle either undetectable or monomorphic, not both.
-  ASSERT(((types & CompareNilICStub::kCompareAgainstUndetectable) == 0) ||
-         ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) == 0));
-  if ((types & CompareNilICStub::kCompareAgainstUndetectable) != 0) {
+  ASSERT(!types.Contains(CompareNilICStub::UNDETECTABLE) ||
+         !types.Contains(CompareNilICStub::MONOMORPHIC_MAP));
+  if (types.Contains(CompareNilICStub::UNDETECTABLE)) {
     if (needs_or) if_nil.Or();
     if_nil.If<HIsUndetectableAndBranch>(value);
   } else {
     if_nil.Then();
     if_nil.Else();
-    if ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0) {
+    if (types.Contains(CompareNilICStub::MONOMORPHIC_MAP)) {
       BuildCheckNonSmi(value);
       // For ICs, the map checked below is a sentinel map that gets replaced by
       // the monomorphic map when the code is used as a template to generate a
@@ -10823,15 +10823,13 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
   TypeFeedbackId id = expr->CompareOperationFeedbackId();
   CompareNilICStub::Types types;
   if (kind == kStrictEquality) {
-    if (nil == kNullValue) {
-      types = CompareNilICStub::kCompareAgainstNull;
-    } else {
-      types = CompareNilICStub::kCompareAgainstUndefined;
-    }
+    types.Add((nil == kNullValue) ? CompareNilICStub::NULL_TYPE :
+                                    CompareNilICStub::UNDEFINED);
   } else {
-    types = static_cast<CompareNilICStub::Types>(
-        oracle()->CompareNilTypes(id));
-    if (types == 0) types = CompareNilICStub::kFullCompare;
+    types = CompareNilICStub::Types(oracle()->CompareNilTypes(id));
+    if (types.IsEmpty()) {
+      types = CompareNilICStub::Types::FullCompare();
+    }
   }
   Handle<Map> map_handle(oracle()->CompareNilMonomorphicReceiverType(id));
   BuildCompareNil(value, kind, types, map_handle,
index 75c22c4..ea0c1fb 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -2888,25 +2888,17 @@ RUNTIME_FUNCTION(Code*, CompareIC_Miss) {
 }
 
 
-Code* CompareNilIC::GetRawUninitialized(EqualityKind kind,
-                                        NilValue nil) {
-  CompareNilICStub stub(kind, nil);
-  Code* code = NULL;
-  CHECK(stub.FindCodeInCache(&code, Isolate::Current()));
-  return code;
-}
-
-
 void CompareNilIC::Clear(Address address, Code* target) {
   if (target->ic_state() == UNINITIALIZED) return;
   Code::ExtraICState state = target->extended_extra_ic_state();
 
-  EqualityKind kind =
-      CompareNilICStub::EqualityKindFromExtraICState(state);
-  NilValue nil =
-      CompareNilICStub::NilValueFromExtraICState(state);
+  CompareNilICStub stub(state, CompareNilICStub::CODE_STUB_IS_MISS);
+  stub.ClearTypes();
 
-  SetTargetAtAddress(address, GetRawUninitialized(kind, nil));
+  Code* code = NULL;
+  CHECK(stub.FindCodeInCache(&code, target->GetIsolate()));
+
+  SetTargetAtAddress(address, code);
 }
 
 
@@ -2930,28 +2922,24 @@ MaybeObject* CompareNilIC::DoCompareNilSlow(EqualityKind kind,
 MaybeObject* CompareNilIC::CompareNil(Handle<Object> object) {
   Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
 
+  CompareNilICStub stub(extra_ic_state);
+
   // Extract the current supported types from the patched IC and calculate what
   // types must be supported as a result of the miss.
-  bool already_monomorphic;
-  CompareNilICStub::Types types =
-      CompareNilICStub::GetPatchedICFlags(extra_ic_state,
-                                          object, &already_monomorphic);
+  bool already_monomorphic = stub.IsMonomorphic();
+
+  stub.Record(object);
 
-  EqualityKind kind =
-      CompareNilICStub::EqualityKindFromExtraICState(extra_ic_state);
-  NilValue nil =
-      CompareNilICStub::NilValueFromExtraICState(extra_ic_state);
+  EqualityKind kind = stub.GetKind();
+  NilValue nil = stub.GetNilValue();
 
   // Find or create the specialized stub to support the new set of types.
-  CompareNilICStub stub(kind, nil, types);
   Handle<Code> code;
-  if ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0) {
+  if (stub.IsMonomorphic()) {
     Handle<Map> monomorphic_map(already_monomorphic
                                 ? target()->FindFirstMap()
                                 : HeapObject::cast(*object)->map());
-    code = isolate()->stub_cache()->ComputeCompareNil(monomorphic_map,
-                                                      nil,
-                                                      stub.GetTypes());
+    code = isolate()->stub_cache()->ComputeCompareNil(monomorphic_map, stub);
   } else {
     code = stub.GetCode(isolate());
   }
index 739f34c..a044f0c 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -787,8 +787,6 @@ class CompareNilIC: public IC {
 
   static Handle<Code> GetUninitialized();
 
-  static Code* GetRawUninitialized(EqualityKind kind, NilValue nil);
-
   static void Clear(Address address, Code* target);
 
   void patch(Code* code);
index 845fd45..ba7cdb1 100644 (file)
@@ -9844,9 +9844,10 @@ void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
   VisitExternalReferences(p, p + 1);
 }
 
-byte Code::compare_nil_state() {
+byte Code::compare_nil_types() {
   ASSERT(is_compare_nil_ic_stub());
-  return CompareNilICStub::TypesFromExtraICState(extended_extra_ic_state());
+  return CompareNilICStub::ExtractTypesFromExtraICState(
+      extended_extra_ic_state());
 }
 
 
index 6787da5..d466f65 100644 (file)
@@ -4620,7 +4620,7 @@ class Code: public HeapObject {
   inline void set_to_boolean_state(byte value);
 
   // [compare_nil]: For kind COMPARE_NIL_IC tells what state the stub is in.
-  byte compare_nil_state();
+  byte compare_nil_types();
 
   // [has_function_cache]: For kind STUB tells whether there is a function
   // cache is passed to the stub.
index 0ba8f52..88b4afe 100644 (file)
@@ -187,6 +187,31 @@ class StringStream {
 };
 
 
+// Utility class to print a list of items to a stream, divided by a separator.
+class SimpleListPrinter {
+ public:
+  explicit SimpleListPrinter(StringStream* stream, char separator = ',') {
+    separator_ = separator;
+    stream_ = stream;
+    first_ = true;
+  }
+
+  void Add(const char* str) {
+    if (first_) {
+      first_ = false;
+    } else {
+      stream_->Put(separator_);
+    }
+    stream_->Add(str);
+  }
+
+ private:
+  bool first_;
+  char separator_;
+  StringStream* stream_;
+};
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_STRING_STREAM_H_
index f43c9ac..89dee10 100644 (file)
@@ -907,9 +907,8 @@ Handle<Code> StubCache::ComputeCallMiss(int argc,
 
 
 Handle<Code> StubCache::ComputeCompareNil(Handle<Map> receiver_map,
-                                          NilValue nil,
-                                          CompareNilICStub::Types types) {
-  CompareNilICStub stub(kNonStrictEquality, nil, types);
+                                          CompareNilICStub& stub) {
+  stub.SetKind(kNonStrictEquality);
 
   Handle<String> name(isolate_->heap()->empty_string());
   if (!receiver_map->is_shared()) {
index cbaeace..9365d96 100644 (file)
@@ -281,8 +281,7 @@ class StubCache {
   // ---
 
   Handle<Code> ComputeCompareNil(Handle<Map> receiver_map,
-                                 NilValue nil,
-                                 CompareNilICStub::Types types);
+                                 CompareNilICStub& stub);
 
   // ---
 
index d52536e..21dcf74 100644 (file)
@@ -643,9 +643,9 @@ byte TypeFeedbackOracle::CompareNilTypes(TypeFeedbackId id) {
   Handle<Object> object = GetInfo(id);
   if (object->IsCode() &&
       Handle<Code>::cast(object)->is_compare_nil_ic_stub()) {
-    return Handle<Code>::cast(object)->compare_nil_state();
+    return Handle<Code>::cast(object)->compare_nil_types();
   } else {
-    return CompareNilICStub::kFullCompare;
+    return CompareNilICStub::Types::FullCompare().ToIntegral();
   }
 }
 
index 90d7f3c..93cded1 100644 (file)
@@ -1040,6 +1040,7 @@ class EnumSet {
   void Intersect(const EnumSet& set) { bits_ &= set.bits_; }
   T ToIntegral() const { return bits_; }
   bool operator==(const EnumSet& set) { return bits_ == set.bits_; }
+  bool operator!=(const EnumSet& set) { return bits_ != set.bits_; }
   EnumSet<E, T> operator|(const EnumSet& set) const {
     return EnumSet<E, T>(bits_ | set.bits_);
   }
index ecffeaa..0a91ed5 100644 (file)
@@ -53,6 +53,7 @@
         'test-bignum.cc',
         'test-bignum-dtoa.cc',
         'test-circular-queue.cc',
+        'test-compare-nil-ic-stub.cc',
         'test-compiler.cc',
         'test-conversions.cc',
         'test-cpu-profiler.cc',
diff --git a/test/cctest/test-compare-nil-ic-stub.cc b/test/cctest/test-compare-nil-ic-stub.cc
new file mode 100644 (file)
index 0000000..6177fde
--- /dev/null
@@ -0,0 +1,86 @@
+// Copyright 2006-2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+#include "cctest.h"
+#include "code-stubs.h"
+
+
+using namespace v8::internal;
+
+#define Types CompareNilICStub::Types
+
+TEST(TypeConstructors) {
+  Types types;
+  types.Add(CompareNilICStub::MONOMORPHIC_MAP);
+  Types types2(types);
+  CHECK_EQ(types.ToIntegral(), types2.ToIntegral());
+}
+
+TEST(ExternalICStateParsing) {
+  Types types;
+  types.Add(CompareNilICStub::UNDEFINED);
+  CompareNilICStub stub(kNonStrictEquality, kUndefinedValue, types);
+  CompareNilICStub stub2(stub.GetExtraICState());
+  CHECK_EQ(stub.GetKind(), stub2.GetKind());
+  CHECK_EQ(stub.GetNilValue(), stub2.GetNilValue());
+  CHECK_EQ(stub.GetTypes().ToIntegral(), stub2.GetTypes().ToIntegral());
+}
+
+TEST(SettingTypes) {
+  Types state;
+  CHECK(state.IsEmpty());
+  state.Add(CompareNilICStub::NULL_TYPE);
+  CHECK(!state.IsEmpty());
+  CHECK(state.Contains(CompareNilICStub::NULL_TYPE));
+  CHECK(!state.Contains(CompareNilICStub::UNDEFINED));
+  CHECK(!state.Contains(CompareNilICStub::UNDETECTABLE));
+  state.Add(CompareNilICStub::UNDEFINED);
+  CHECK(state.Contains(CompareNilICStub::UNDEFINED));
+  CHECK(state.Contains(CompareNilICStub::NULL_TYPE));
+  CHECK(!state.Contains(CompareNilICStub::UNDETECTABLE));
+}
+
+TEST(ClearTypes) {
+  Types state;
+  state.Add(CompareNilICStub::NULL_TYPE);
+  state.RemoveAll();
+  CHECK(state.IsEmpty());
+}
+
+TEST(FullCompare) {
+  Types state;
+  CHECK(Types::FullCompare() != state);
+  state.Add(CompareNilICStub::UNDEFINED);
+  CHECK(state != Types::FullCompare());
+  state.Add(CompareNilICStub::NULL_TYPE);
+  CHECK(state != Types::FullCompare());
+  state.Add(CompareNilICStub::UNDETECTABLE);
+  CHECK(state == Types::FullCompare());
+}