Encapsulating Type information in the CompareICStub

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
This commit is contained in:
olivf@chromium.org 2013-05-16 10:59:17 +00:00
parent b3eff8cb37
commit c3dde4bd9d
14 changed files with 295 additions and 161 deletions

View 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(")");
}

View File

@ -1047,27 +1047,70 @@ 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;
}
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));
}
static Handle<Code> GetUninitialized(Isolate* isolate,
EqualityKind kind,
NilValue nil) {
return CompareNilICStub(kind, nil, CODE_STUB_IS_MISS).GetCode(isolate);
}
virtual void InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor);
static void InitializeForIsolate(Isolate* isolate) {
CompareNilICStub compare_stub(kStrictEquality, kNullValue,
CODE_STUB_IS_MISS);
compare_stub.InitializeInterfaceDescriptor(
isolate,
isolate->code_stub_interface_descriptor(CodeStub::CompareNilIC));
}
virtual InlineCacheState GetICState() {
Types types = GetTypes();
if (types == kFullCompare) {
if (types_ == Types::FullCompare()) {
return MEGAMORPHIC;
} else if ((types & kCompareAgainstMonomorphicMap) != 0) {
} else if (types_.Contains(MONOMORPHIC_MAP)) {
return MONOMORPHIC;
} else {
return PREMONOMORPHIC;
@ -1078,64 +1121,55 @@ class CompareNilICStub : public HydrogenCodeStub {
Handle<Code> GenerateCode();
static Handle<Code> GetUninitialized(Isolate* isolate,
EqualityKind kind,
NilValue nil) {
return CompareNilICStub(kind, nil).GetCode(isolate);
}
virtual void InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor);
static void InitializeForIsolate(Isolate* isolate) {
CompareNilICStub compare_stub(kStrictEquality, kNullValue);
compare_stub.InitializeInterfaceDescriptor(
isolate,
isolate->code_stub_interface_descriptor(CodeStub::CompareNilIC));
}
// extra ic state = nil_value | equality_kind | type_n-1 | ... | type_0
virtual Code::ExtraICState GetExtraICState() {
return bit_field_;
return NilValueField::encode(nil_value_) |
EqualityKindField::encode(equality_kind_) |
types_.ToIntegral();
}
EqualityKind GetKind() { return EqualityKindField::decode(bit_field_); }
NilValue GetNilValue() { return NilValueField::decode(bit_field_); }
Types GetTypes() { return TypesField::decode(bit_field_); }
static Types TypesFromExtraICState(
static byte ExtractTypesFromExtraICState(
Code::ExtraICState state) {
return TypesField::decode(state);
}
static EqualityKind EqualityKindFromExtraICState(
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)
: HydrogenCodeStub(CODE_STUB_IS_MISS), bit_field_(0) {
bit_field_ = EqualityKindField::encode(kind) |
NilValueField::encode(nil);
CompareNilICStub(EqualityKind kind, NilValue nil,
InitializationState init_state)
: HydrogenCodeStub(init_state), types_(0) {
equality_kind_ = kind;
nil_value_ = nil;
}
virtual CodeStub::Major MajorKey() { return CompareNilIC; }
virtual int NotMissMinorKey() { return bit_field_; }
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));
}
int bit_field_;
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 GetExtraICState(); }
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());

View 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,

View File

@ -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();
EqualityKind kind =
CompareNilICStub::EqualityKindFromExtraICState(extra_ic_state);
NilValue nil =
CompareNilICStub::NilValueFromExtraICState(extra_ic_state);
stub.Record(object);
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());
}

View File

@ -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);

View 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());
}

View 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.

View 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_

View 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()) {

View File

@ -281,8 +281,7 @@ class StubCache {
// ---
Handle<Code> ComputeCompareNil(Handle<Map> receiver_map,
NilValue nil,
CompareNilICStub::Types types);
CompareNilICStub& stub);
// ---

View 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();
}
}

View 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_);
}

View 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',

View File

@ -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());
}