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:
parent
b3eff8cb37
commit
c3dde4bd9d
@ -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(")");
|
||||
}
|
||||
|
||||
|
||||
|
172
src/code-stubs.h
172
src/code-stubs.h
@ -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());
|
||||
|
@ -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;
|
||||
types.Add((nil == kNullValue) ? CompareNilICStub::NULL_TYPE :
|
||||
CompareNilICStub::UNDEFINED);
|
||||
} else {
|
||||
types = CompareNilICStub::kCompareAgainstUndefined;
|
||||
types = CompareNilICStub::Types(oracle()->CompareNilTypes(id));
|
||||
if (types.IsEmpty()) {
|
||||
types = CompareNilICStub::Types::FullCompare();
|
||||
}
|
||||
} else {
|
||||
types = static_cast<CompareNilICStub::Types>(
|
||||
oracle()->CompareNilTypes(id));
|
||||
if (types == 0) types = CompareNilICStub::kFullCompare;
|
||||
}
|
||||
Handle<Map> map_handle(oracle()->CompareNilMonomorphicReceiverType(id));
|
||||
BuildCompareNil(value, kind, types, map_handle,
|
||||
|
42
src/ic.cc
42
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();
|
||||
|
||||
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());
|
||||
}
|
||||
|
2
src/ic.h
2
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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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_
|
||||
|
@ -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()) {
|
||||
|
@ -281,8 +281,7 @@ class StubCache {
|
||||
// ---
|
||||
|
||||
Handle<Code> ComputeCompareNil(Handle<Map> receiver_map,
|
||||
NilValue nil,
|
||||
CompareNilICStub::Types types);
|
||||
CompareNilICStub& stub);
|
||||
|
||||
// ---
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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_);
|
||||
}
|
||||
|
@ -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',
|
||||
|
86
test/cctest/test-compare-nil-ic-stub.cc
Normal file
86
test/cctest/test-compare-nil-ic-stub.cc
Normal 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());
|
||||
}
|
Loading…
Reference in New Issue
Block a user