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(
|
void CompareNilICStub::Record(Handle<Object> object) {
|
||||||
Code::ExtraICState extra_ic_state,
|
ASSERT(types_ != Types::FullCompare());
|
||||||
Handle<Object> object,
|
if (equality_kind_ == kStrictEquality) {
|
||||||
bool* already_monomorphic) {
|
// When testing for strict equality only one value will evaluate to true
|
||||||
Types types = TypesField::decode(extra_ic_state);
|
types_.RemoveAll();
|
||||||
NilValue nil = NilValueField::decode(extra_ic_state);
|
types_.Add((nil_value_ == kNullValue) ? NULL_TYPE:
|
||||||
EqualityKind kind = EqualityKindField::decode(extra_ic_state);
|
UNDEFINED);
|
||||||
ASSERT(types != CompareNilICStub::kFullCompare);
|
|
||||||
*already_monomorphic =
|
|
||||||
(types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0;
|
|
||||||
if (kind == kStrictEquality) {
|
|
||||||
if (nil == kNullValue) {
|
|
||||||
return CompareNilICStub::kCompareAgainstNull;
|
|
||||||
} else {
|
|
||||||
return CompareNilICStub::kCompareAgainstUndefined;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (object->IsNull()) {
|
if (object->IsNull()) {
|
||||||
types = static_cast<CompareNilICStub::Types>(
|
types_.Add(NULL_TYPE);
|
||||||
types | CompareNilICStub::kCompareAgainstNull);
|
|
||||||
} else if (object->IsUndefined()) {
|
} else if (object->IsUndefined()) {
|
||||||
types = static_cast<CompareNilICStub::Types>(
|
types_.Add(UNDEFINED);
|
||||||
types | CompareNilICStub::kCompareAgainstUndefined);
|
|
||||||
} else if (object->IsUndetectableObject() ||
|
} else if (object->IsUndetectableObject() ||
|
||||||
object->IsOddball() ||
|
object->IsOddball() ||
|
||||||
!object->IsHeapObject()) {
|
!object->IsHeapObject()) {
|
||||||
types = CompareNilICStub::kFullCompare;
|
types_ = Types::FullCompare();
|
||||||
} else if ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0) {
|
} else if (IsMonomorphic()) {
|
||||||
types = CompareNilICStub::kFullCompare;
|
types_ = Types::FullCompare();
|
||||||
} else {
|
} else {
|
||||||
types = static_cast<CompareNilICStub::Types>(
|
types_.Add(MONOMORPHIC_MAP);
|
||||||
types | CompareNilICStub::kCompareAgainstMonomorphicMap);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 {
|
void ToBooleanStub::Types::Print(StringStream* stream) const {
|
||||||
if (IsEmpty()) stream->Add("None");
|
stream->Add("(");
|
||||||
if (Contains(UNDEFINED)) stream->Add("Undefined");
|
SimpleListPrinter printer(stream);
|
||||||
if (Contains(BOOLEAN)) stream->Add("Bool");
|
if (IsEmpty()) printer.Add("None");
|
||||||
if (Contains(NULL_TYPE)) stream->Add("Null");
|
if (Contains(UNDEFINED)) printer.Add("Undefined");
|
||||||
if (Contains(SMI)) stream->Add("Smi");
|
if (Contains(BOOLEAN)) printer.Add("Bool");
|
||||||
if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
|
if (Contains(NULL_TYPE)) printer.Add("Null");
|
||||||
if (Contains(STRING)) stream->Add("String");
|
if (Contains(SMI)) printer.Add("Smi");
|
||||||
if (Contains(SYMBOL)) stream->Add("Symbol");
|
if (Contains(SPEC_OBJECT)) printer.Add("SpecObject");
|
||||||
if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
|
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 {
|
class CompareNilICStub : public HydrogenCodeStub {
|
||||||
public:
|
public:
|
||||||
enum Types {
|
enum Type {
|
||||||
kCompareAgainstNull = 1 << 0,
|
UNDEFINED,
|
||||||
kCompareAgainstUndefined = 1 << 1,
|
NULL_TYPE,
|
||||||
kCompareAgainstMonomorphicMap = 1 << 2,
|
MONOMORPHIC_MAP,
|
||||||
kCompareAgainstUndetectable = 1 << 3,
|
UNDETECTABLE,
|
||||||
kFullCompare = kCompareAgainstNull | kCompareAgainstUndefined |
|
NUMBER_OF_TYPES
|
||||||
kCompareAgainstUndetectable
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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)
|
CompareNilICStub(EqualityKind kind, NilValue nil, Types types)
|
||||||
: HydrogenCodeStub(CODE_STUB_IS_NOT_MISS), bit_field_(0) {
|
: HydrogenCodeStub(CODE_STUB_IS_NOT_MISS), types_(types) {
|
||||||
bit_field_ = EqualityKindField::encode(kind) |
|
equality_kind_ = kind;
|
||||||
NilValueField::encode(nil) |
|
nil_value_ = nil;
|
||||||
TypesField::encode(types);
|
}
|
||||||
|
|
||||||
|
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() {
|
virtual InlineCacheState GetICState() {
|
||||||
Types types = GetTypes();
|
if (types_ == Types::FullCompare()) {
|
||||||
if (types == kFullCompare) {
|
|
||||||
return MEGAMORPHIC;
|
return MEGAMORPHIC;
|
||||||
} else if ((types & kCompareAgainstMonomorphicMap) != 0) {
|
} else if (types_.Contains(MONOMORPHIC_MAP)) {
|
||||||
return MONOMORPHIC;
|
return MONOMORPHIC;
|
||||||
} else {
|
} else {
|
||||||
return PREMONOMORPHIC;
|
return PREMONOMORPHIC;
|
||||||
@ -1078,64 +1121,55 @@ class CompareNilICStub : public HydrogenCodeStub {
|
|||||||
|
|
||||||
Handle<Code> GenerateCode();
|
Handle<Code> GenerateCode();
|
||||||
|
|
||||||
static Handle<Code> GetUninitialized(Isolate* isolate,
|
// extra ic state = nil_value | equality_kind | type_n-1 | ... | type_0
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Code::ExtraICState GetExtraICState() {
|
virtual Code::ExtraICState GetExtraICState() {
|
||||||
return bit_field_;
|
return NilValueField::encode(nil_value_) |
|
||||||
|
EqualityKindField::encode(equality_kind_) |
|
||||||
|
types_.ToIntegral();
|
||||||
}
|
}
|
||||||
|
static byte ExtractTypesFromExtraICState(
|
||||||
EqualityKind GetKind() { return EqualityKindField::decode(bit_field_); }
|
|
||||||
NilValue GetNilValue() { return NilValueField::decode(bit_field_); }
|
|
||||||
Types GetTypes() { return TypesField::decode(bit_field_); }
|
|
||||||
|
|
||||||
static Types TypesFromExtraICState(
|
|
||||||
Code::ExtraICState state) {
|
Code::ExtraICState state) {
|
||||||
return TypesField::decode(state);
|
return state & ((1<<NUMBER_OF_TYPES)-1);
|
||||||
}
|
|
||||||
static EqualityKind EqualityKindFromExtraICState(
|
|
||||||
Code::ExtraICState state) {
|
|
||||||
return EqualityKindField::decode(state);
|
|
||||||
}
|
|
||||||
static NilValue NilValueFromExtraICState(Code::ExtraICState state) {
|
|
||||||
return NilValueField::decode(state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Types GetPatchedICFlags(Code::ExtraICState extra_ic_state,
|
void Record(Handle<Object> object);
|
||||||
Handle<Object> object,
|
|
||||||
bool* already_monomorphic);
|
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:
|
private:
|
||||||
friend class CompareNilIC;
|
friend class CompareNilIC;
|
||||||
|
|
||||||
class EqualityKindField : public BitField<EqualityKind, 0, 1> {};
|
CompareNilICStub(EqualityKind kind, NilValue nil,
|
||||||
class NilValueField : public BitField<NilValue, 1, 1> {};
|
InitializationState init_state)
|
||||||
class TypesField : public BitField<Types, 3, 4> {};
|
: HydrogenCodeStub(init_state), types_(0) {
|
||||||
|
equality_kind_ = kind;
|
||||||
CompareNilICStub(EqualityKind kind, NilValue nil)
|
nil_value_ = nil;
|
||||||
: HydrogenCodeStub(CODE_STUB_IS_MISS), bit_field_(0) {
|
|
||||||
bit_field_ = EqualityKindField::encode(kind) |
|
|
||||||
NilValueField::encode(nil);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual CodeStub::Major MajorKey() { return CompareNilIC; }
|
CompareNilICStub(Code::ExtraICState ic_state, InitializationState init_state)
|
||||||
virtual int NotMissMinorKey() { return bit_field_; }
|
: 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);
|
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
|
// only has room for a single byte to hold a set of these types. :-P
|
||||||
STATIC_ASSERT(NUMBER_OF_TYPES <= 8);
|
STATIC_ASSERT(NUMBER_OF_TYPES <= 8);
|
||||||
|
|
||||||
class Types {
|
class Types : public EnumSet<Type, byte> {
|
||||||
public:
|
public:
|
||||||
Types() {}
|
Types() {}
|
||||||
explicit Types(byte bits) : set_(bits) {}
|
explicit Types(byte bits) : EnumSet<Type, byte>(bits) {}
|
||||||
|
|
||||||
bool IsEmpty() const { return set_.IsEmpty(); }
|
byte ToByte() const { return ToIntegral(); }
|
||||||
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(); }
|
|
||||||
void Print(StringStream* stream) const;
|
void Print(StringStream* stream) const;
|
||||||
void TraceTransition(Types to) const;
|
void TraceTransition(Types to) const;
|
||||||
bool Record(Handle<Object> object);
|
bool Record(Handle<Object> object);
|
||||||
bool NeedsMap() const;
|
bool NeedsMap() const;
|
||||||
bool CanBeUndetectable() const;
|
bool CanBeUndetectable() const;
|
||||||
|
|
||||||
private:
|
|
||||||
EnumSet<Type, byte> set_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static Types no_types() { return Types(); }
|
static Types no_types() { return Types(); }
|
||||||
@ -1831,7 +1856,8 @@ class ToBooleanStub: public PlatformCodeStub {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Major MajorKey() { return ToBoolean; }
|
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) {
|
virtual void FinishCode(Handle<Code> code) {
|
||||||
code->set_to_boolean_state(types_.ToByte());
|
code->set_to_boolean_state(types_.ToByte());
|
||||||
|
@ -1812,27 +1812,27 @@ void HGraphBuilder::BuildCompareNil(
|
|||||||
HIfContinuation* continuation) {
|
HIfContinuation* continuation) {
|
||||||
IfBuilder if_nil(this, position);
|
IfBuilder if_nil(this, position);
|
||||||
bool needs_or = false;
|
bool needs_or = false;
|
||||||
if ((types & CompareNilICStub::kCompareAgainstNull) != 0) {
|
if (types.Contains(CompareNilICStub::NULL_TYPE)) {
|
||||||
if (needs_or) if_nil.Or();
|
if (needs_or) if_nil.Or();
|
||||||
if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull());
|
if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull());
|
||||||
needs_or = true;
|
needs_or = true;
|
||||||
}
|
}
|
||||||
if ((types & CompareNilICStub::kCompareAgainstUndefined) != 0) {
|
if (types.Contains(CompareNilICStub::UNDEFINED)) {
|
||||||
if (needs_or) if_nil.Or();
|
if (needs_or) if_nil.Or();
|
||||||
if_nil.If<HCompareObjectEqAndBranch>(value,
|
if_nil.If<HCompareObjectEqAndBranch>(value,
|
||||||
graph()->GetConstantUndefined());
|
graph()->GetConstantUndefined());
|
||||||
needs_or = true;
|
needs_or = true;
|
||||||
}
|
}
|
||||||
// Handle either undetectable or monomorphic, not both.
|
// Handle either undetectable or monomorphic, not both.
|
||||||
ASSERT(((types & CompareNilICStub::kCompareAgainstUndetectable) == 0) ||
|
ASSERT(!types.Contains(CompareNilICStub::UNDETECTABLE) ||
|
||||||
((types & CompareNilICStub::kCompareAgainstMonomorphicMap) == 0));
|
!types.Contains(CompareNilICStub::MONOMORPHIC_MAP));
|
||||||
if ((types & CompareNilICStub::kCompareAgainstUndetectable) != 0) {
|
if (types.Contains(CompareNilICStub::UNDETECTABLE)) {
|
||||||
if (needs_or) if_nil.Or();
|
if (needs_or) if_nil.Or();
|
||||||
if_nil.If<HIsUndetectableAndBranch>(value);
|
if_nil.If<HIsUndetectableAndBranch>(value);
|
||||||
} else {
|
} else {
|
||||||
if_nil.Then();
|
if_nil.Then();
|
||||||
if_nil.Else();
|
if_nil.Else();
|
||||||
if ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0) {
|
if (types.Contains(CompareNilICStub::MONOMORPHIC_MAP)) {
|
||||||
BuildCheckNonSmi(value);
|
BuildCheckNonSmi(value);
|
||||||
// For ICs, the map checked below is a sentinel map that gets replaced by
|
// 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
|
// 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();
|
TypeFeedbackId id = expr->CompareOperationFeedbackId();
|
||||||
CompareNilICStub::Types types;
|
CompareNilICStub::Types types;
|
||||||
if (kind == kStrictEquality) {
|
if (kind == kStrictEquality) {
|
||||||
if (nil == kNullValue) {
|
types.Add((nil == kNullValue) ? CompareNilICStub::NULL_TYPE :
|
||||||
types = CompareNilICStub::kCompareAgainstNull;
|
CompareNilICStub::UNDEFINED);
|
||||||
} else {
|
} 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));
|
Handle<Map> map_handle(oracle()->CompareNilMonomorphicReceiverType(id));
|
||||||
BuildCompareNil(value, kind, types, map_handle,
|
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) {
|
void CompareNilIC::Clear(Address address, Code* target) {
|
||||||
if (target->ic_state() == UNINITIALIZED) return;
|
if (target->ic_state() == UNINITIALIZED) return;
|
||||||
Code::ExtraICState state = target->extended_extra_ic_state();
|
Code::ExtraICState state = target->extended_extra_ic_state();
|
||||||
|
|
||||||
EqualityKind kind =
|
CompareNilICStub stub(state, CompareNilICStub::CODE_STUB_IS_MISS);
|
||||||
CompareNilICStub::EqualityKindFromExtraICState(state);
|
stub.ClearTypes();
|
||||||
NilValue nil =
|
|
||||||
CompareNilICStub::NilValueFromExtraICState(state);
|
|
||||||
|
|
||||||
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) {
|
MaybeObject* CompareNilIC::CompareNil(Handle<Object> object) {
|
||||||
Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
|
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
|
// Extract the current supported types from the patched IC and calculate what
|
||||||
// types must be supported as a result of the miss.
|
// types must be supported as a result of the miss.
|
||||||
bool already_monomorphic;
|
bool already_monomorphic = stub.IsMonomorphic();
|
||||||
CompareNilICStub::Types types =
|
|
||||||
CompareNilICStub::GetPatchedICFlags(extra_ic_state,
|
|
||||||
object, &already_monomorphic);
|
|
||||||
|
|
||||||
EqualityKind kind =
|
stub.Record(object);
|
||||||
CompareNilICStub::EqualityKindFromExtraICState(extra_ic_state);
|
|
||||||
NilValue nil =
|
EqualityKind kind = stub.GetKind();
|
||||||
CompareNilICStub::NilValueFromExtraICState(extra_ic_state);
|
NilValue nil = stub.GetNilValue();
|
||||||
|
|
||||||
// Find or create the specialized stub to support the new set of types.
|
// Find or create the specialized stub to support the new set of types.
|
||||||
CompareNilICStub stub(kind, nil, types);
|
|
||||||
Handle<Code> code;
|
Handle<Code> code;
|
||||||
if ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0) {
|
if (stub.IsMonomorphic()) {
|
||||||
Handle<Map> monomorphic_map(already_monomorphic
|
Handle<Map> monomorphic_map(already_monomorphic
|
||||||
? target()->FindFirstMap()
|
? target()->FindFirstMap()
|
||||||
: HeapObject::cast(*object)->map());
|
: HeapObject::cast(*object)->map());
|
||||||
code = isolate()->stub_cache()->ComputeCompareNil(monomorphic_map,
|
code = isolate()->stub_cache()->ComputeCompareNil(monomorphic_map, stub);
|
||||||
nil,
|
|
||||||
stub.GetTypes());
|
|
||||||
} else {
|
} else {
|
||||||
code = stub.GetCode(isolate());
|
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 Handle<Code> GetUninitialized();
|
||||||
|
|
||||||
static Code* GetRawUninitialized(EqualityKind kind, NilValue nil);
|
|
||||||
|
|
||||||
static void Clear(Address address, Code* target);
|
static void Clear(Address address, Code* target);
|
||||||
|
|
||||||
void patch(Code* code);
|
void patch(Code* code);
|
||||||
|
@ -9844,9 +9844,10 @@ void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
|
|||||||
VisitExternalReferences(p, p + 1);
|
VisitExternalReferences(p, p + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte Code::compare_nil_state() {
|
byte Code::compare_nil_types() {
|
||||||
ASSERT(is_compare_nil_ic_stub());
|
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);
|
inline void set_to_boolean_state(byte value);
|
||||||
|
|
||||||
// [compare_nil]: For kind COMPARE_NIL_IC tells what state the stub is in.
|
// [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
|
// [has_function_cache]: For kind STUB tells whether there is a function
|
||||||
// cache is passed to the stub.
|
// 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
|
} } // namespace v8::internal
|
||||||
|
|
||||||
#endif // V8_STRING_STREAM_H_
|
#endif // V8_STRING_STREAM_H_
|
||||||
|
@ -907,9 +907,8 @@ Handle<Code> StubCache::ComputeCallMiss(int argc,
|
|||||||
|
|
||||||
|
|
||||||
Handle<Code> StubCache::ComputeCompareNil(Handle<Map> receiver_map,
|
Handle<Code> StubCache::ComputeCompareNil(Handle<Map> receiver_map,
|
||||||
NilValue nil,
|
CompareNilICStub& stub) {
|
||||||
CompareNilICStub::Types types) {
|
stub.SetKind(kNonStrictEquality);
|
||||||
CompareNilICStub stub(kNonStrictEquality, nil, types);
|
|
||||||
|
|
||||||
Handle<String> name(isolate_->heap()->empty_string());
|
Handle<String> name(isolate_->heap()->empty_string());
|
||||||
if (!receiver_map->is_shared()) {
|
if (!receiver_map->is_shared()) {
|
||||||
|
@ -281,8 +281,7 @@ class StubCache {
|
|||||||
// ---
|
// ---
|
||||||
|
|
||||||
Handle<Code> ComputeCompareNil(Handle<Map> receiver_map,
|
Handle<Code> ComputeCompareNil(Handle<Map> receiver_map,
|
||||||
NilValue nil,
|
CompareNilICStub& stub);
|
||||||
CompareNilICStub::Types types);
|
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
|
@ -643,9 +643,9 @@ byte TypeFeedbackOracle::CompareNilTypes(TypeFeedbackId id) {
|
|||||||
Handle<Object> object = GetInfo(id);
|
Handle<Object> object = GetInfo(id);
|
||||||
if (object->IsCode() &&
|
if (object->IsCode() &&
|
||||||
Handle<Code>::cast(object)->is_compare_nil_ic_stub()) {
|
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 {
|
} else {
|
||||||
return CompareNilICStub::kFullCompare;
|
return CompareNilICStub::Types::FullCompare().ToIntegral();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1040,6 +1040,7 @@ class EnumSet {
|
|||||||
void Intersect(const EnumSet& set) { bits_ &= set.bits_; }
|
void Intersect(const EnumSet& set) { bits_ &= set.bits_; }
|
||||||
T ToIntegral() const { return bits_; }
|
T ToIntegral() const { return bits_; }
|
||||||
bool operator==(const EnumSet& set) { return bits_ == set.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 {
|
EnumSet<E, T> operator|(const EnumSet& set) const {
|
||||||
return EnumSet<E, T>(bits_ | set.bits_);
|
return EnumSet<E, T>(bits_ | set.bits_);
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
'test-bignum.cc',
|
'test-bignum.cc',
|
||||||
'test-bignum-dtoa.cc',
|
'test-bignum-dtoa.cc',
|
||||||
'test-circular-queue.cc',
|
'test-circular-queue.cc',
|
||||||
|
'test-compare-nil-ic-stub.cc',
|
||||||
'test-compiler.cc',
|
'test-compiler.cc',
|
||||||
'test-conversions.cc',
|
'test-conversions.cc',
|
||||||
'test-cpu-profiler.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