}
-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(")");
}
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(")");
}
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(
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);
};
// 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(); }
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());
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
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,
}
-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);
}
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());
}
static Handle<Code> GetUninitialized();
- static Code* GetRawUninitialized(EqualityKind kind, NilValue nil);
-
static void Clear(Address address, Code* target);
void patch(Code* code);
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());
}
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.
};
+// 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_
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()) {
// ---
Handle<Code> ComputeCompareNil(Handle<Map> receiver_map,
- NilValue nil,
- CompareNilICStub::Types types);
+ CompareNilICStub& stub);
// ---
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();
}
}
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_);
}
'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',
--- /dev/null
+// 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());
+}