Fix polymorphic inlined calls with migrating prototypes
LOG=Y R=verwaest@chromium.org Review URL: https://codereview.chromium.org/104793003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18307 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
3c601ff5b5
commit
48ff79a300
@ -137,7 +137,6 @@ Assignment::Assignment(Isolate* isolate,
|
||||
value_(value),
|
||||
binary_operation_(NULL),
|
||||
assignment_id_(GetNextId(isolate)),
|
||||
is_monomorphic_(false),
|
||||
is_uninitialized_(false),
|
||||
is_pre_monomorphic_(false),
|
||||
store_mode_(STANDARD_STORE) { }
|
||||
@ -742,8 +741,10 @@ void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
|
||||
|
||||
void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
|
||||
TypeFeedbackId id = key()->LiteralFeedbackId();
|
||||
receiver_type_ = oracle->ObjectLiteralStoreIsMonomorphic(id)
|
||||
? oracle->GetObjectLiteralStoreMap(id) : Handle<Map>::null();
|
||||
SmallMapList maps;
|
||||
oracle->CollectReceiverTypes(id, &maps);
|
||||
receiver_type_ = maps.length() == 1 ? maps.at(0)
|
||||
: Handle<Map>::null();
|
||||
}
|
||||
|
||||
|
||||
|
25
src/ast.h
25
src/ast.h
@ -279,9 +279,8 @@ class SmallMapList V8_FINAL {
|
||||
int length() const { return list_.length(); }
|
||||
|
||||
void AddMapIfMissing(Handle<Map> map, Zone* zone) {
|
||||
Map* updated = map->CurrentMapForDeprecated();
|
||||
if (updated == NULL) return;
|
||||
map = Handle<Map>(updated);
|
||||
map = Map::CurrentMapForDeprecated(map);
|
||||
if (map.is_null()) return;
|
||||
for (int i = 0; i < length(); ++i) {
|
||||
if (at(i).is_identical_to(map)) return;
|
||||
}
|
||||
@ -1691,7 +1690,9 @@ class Property V8_FINAL : public Expression {
|
||||
bool IsFunctionPrototype() const { return is_function_prototype_; }
|
||||
|
||||
// Type feedback information.
|
||||
virtual bool IsMonomorphic() V8_OVERRIDE { return is_monomorphic_; }
|
||||
virtual bool IsMonomorphic() V8_OVERRIDE {
|
||||
return receiver_types_.length() == 1;
|
||||
}
|
||||
virtual SmallMapList* GetReceiverTypes() V8_OVERRIDE {
|
||||
return &receiver_types_;
|
||||
}
|
||||
@ -1704,7 +1705,6 @@ class Property V8_FINAL : public Expression {
|
||||
return is_uninitialized_ || is_pre_monomorphic_;
|
||||
}
|
||||
void set_is_uninitialized(bool b) { is_uninitialized_ = b; }
|
||||
void set_is_monomorphic(bool b) { is_monomorphic_ = b; }
|
||||
void set_is_pre_monomorphic(bool b) { is_pre_monomorphic_ = b; }
|
||||
void set_is_string_access(bool b) { is_string_access_ = b; }
|
||||
void set_is_function_prototype(bool b) { is_function_prototype_ = b; }
|
||||
@ -1720,7 +1720,6 @@ class Property V8_FINAL : public Expression {
|
||||
obj_(obj),
|
||||
key_(key),
|
||||
load_id_(GetNextId(isolate)),
|
||||
is_monomorphic_(false),
|
||||
is_pre_monomorphic_(false),
|
||||
is_uninitialized_(false),
|
||||
is_string_access_(false),
|
||||
@ -1732,7 +1731,6 @@ class Property V8_FINAL : public Expression {
|
||||
const BailoutId load_id_;
|
||||
|
||||
SmallMapList receiver_types_;
|
||||
bool is_monomorphic_ : 1;
|
||||
bool is_pre_monomorphic_ : 1;
|
||||
bool is_uninitialized_ : 1;
|
||||
bool is_string_access_ : 1;
|
||||
@ -2001,7 +1999,9 @@ class CountOperation V8_FINAL : public Expression {
|
||||
|
||||
Expression* expression() const { return expression_; }
|
||||
|
||||
virtual bool IsMonomorphic() V8_OVERRIDE { return is_monomorphic_; }
|
||||
virtual bool IsMonomorphic() V8_OVERRIDE {
|
||||
return receiver_types_.length() == 1;
|
||||
}
|
||||
virtual SmallMapList* GetReceiverTypes() V8_OVERRIDE {
|
||||
return &receiver_types_;
|
||||
}
|
||||
@ -2009,7 +2009,6 @@ class CountOperation V8_FINAL : public Expression {
|
||||
return store_mode_;
|
||||
}
|
||||
Handle<Type> type() const { return type_; }
|
||||
void set_is_monomorphic(bool b) { is_monomorphic_ = b; }
|
||||
void set_store_mode(KeyedAccessStoreMode mode) { store_mode_ = mode; }
|
||||
void set_type(Handle<Type> type) { type_ = type; }
|
||||
|
||||
@ -2027,7 +2026,6 @@ class CountOperation V8_FINAL : public Expression {
|
||||
: Expression(isolate, pos),
|
||||
op_(op),
|
||||
is_prefix_(is_prefix),
|
||||
is_monomorphic_(false),
|
||||
store_mode_(STANDARD_STORE),
|
||||
expression_(expr),
|
||||
assignment_id_(GetNextId(isolate)),
|
||||
@ -2036,7 +2034,6 @@ class CountOperation V8_FINAL : public Expression {
|
||||
private:
|
||||
Token::Value op_;
|
||||
bool is_prefix_ : 1;
|
||||
bool is_monomorphic_ : 1;
|
||||
KeyedAccessStoreMode store_mode_ : 5; // Windows treats as signed,
|
||||
// must have extra bit.
|
||||
Handle<Type> type_;
|
||||
@ -2142,7 +2139,9 @@ class Assignment V8_FINAL : public Expression {
|
||||
|
||||
// Type feedback information.
|
||||
TypeFeedbackId AssignmentFeedbackId() { return reuse(id()); }
|
||||
virtual bool IsMonomorphic() V8_OVERRIDE { return is_monomorphic_; }
|
||||
virtual bool IsMonomorphic() V8_OVERRIDE {
|
||||
return receiver_types_.length() == 1;
|
||||
}
|
||||
bool IsUninitialized() { return is_uninitialized_; }
|
||||
bool IsPreMonomorphic() { return is_pre_monomorphic_; }
|
||||
bool HasNoTypeInformation() {
|
||||
@ -2155,7 +2154,6 @@ class Assignment V8_FINAL : public Expression {
|
||||
return store_mode_;
|
||||
}
|
||||
void set_is_uninitialized(bool b) { is_uninitialized_ = b; }
|
||||
void set_is_monomorphic(bool b) { is_monomorphic_ = b; }
|
||||
void set_is_pre_monomorphic(bool b) { is_pre_monomorphic_ = b; }
|
||||
void set_store_mode(KeyedAccessStoreMode mode) { store_mode_ = mode; }
|
||||
|
||||
@ -2182,7 +2180,6 @@ class Assignment V8_FINAL : public Expression {
|
||||
BinaryOperation* binary_operation_;
|
||||
const BailoutId assignment_id_;
|
||||
|
||||
bool is_monomorphic_ : 1;
|
||||
bool is_uninitialized_ : 1;
|
||||
bool is_pre_monomorphic_ : 1;
|
||||
KeyedAccessStoreMode store_mode_ : 5; // Windows treats as signed,
|
||||
|
@ -2803,31 +2803,44 @@ Handle<Map> Map::GeneralizeAllFieldRepresentations(
|
||||
}
|
||||
|
||||
|
||||
Map* Map::CurrentMapForDeprecated() {
|
||||
Handle<Map> Map::CurrentMapForDeprecated(Handle<Map> map) {
|
||||
Handle<Map> proto_map(map);
|
||||
while (proto_map->prototype()->IsJSObject()) {
|
||||
Handle<JSObject> holder(JSObject::cast(proto_map->prototype()));
|
||||
if (holder->map()->is_deprecated()) {
|
||||
JSObject::TryMigrateInstance(holder);
|
||||
}
|
||||
proto_map = Handle<Map>(holder->map());
|
||||
}
|
||||
return CurrentMapForDeprecatedInternal(map);
|
||||
}
|
||||
|
||||
|
||||
Handle<Map> Map::CurrentMapForDeprecatedInternal(Handle<Map> map) {
|
||||
if (!map->is_deprecated()) return map;
|
||||
|
||||
DisallowHeapAllocation no_allocation;
|
||||
if (!is_deprecated()) return this;
|
||||
DescriptorArray* old_descriptors = map->instance_descriptors();
|
||||
|
||||
DescriptorArray* old_descriptors = instance_descriptors();
|
||||
|
||||
int descriptors = NumberOfOwnDescriptors();
|
||||
Map* root_map = FindRootMap();
|
||||
int descriptors = map->NumberOfOwnDescriptors();
|
||||
Map* root_map = map->FindRootMap();
|
||||
|
||||
// Check the state of the root map.
|
||||
if (!EquivalentToForTransition(root_map)) return NULL;
|
||||
if (!map->EquivalentToForTransition(root_map)) return Handle<Map>();
|
||||
int verbatim = root_map->NumberOfOwnDescriptors();
|
||||
|
||||
Map* updated = root_map->FindUpdatedMap(
|
||||
verbatim, descriptors, old_descriptors);
|
||||
if (updated == NULL) return NULL;
|
||||
if (updated == NULL) return Handle<Map>();
|
||||
|
||||
DescriptorArray* updated_descriptors = updated->instance_descriptors();
|
||||
int valid = updated->NumberOfOwnDescriptors();
|
||||
if (!updated_descriptors->IsMoreGeneralThan(
|
||||
verbatim, valid, descriptors, old_descriptors)) {
|
||||
return NULL;
|
||||
return Handle<Map>();
|
||||
}
|
||||
|
||||
return updated;
|
||||
return handle(updated);
|
||||
}
|
||||
|
||||
|
||||
@ -3879,10 +3892,10 @@ void JSObject::MigrateInstance(Handle<JSObject> object) {
|
||||
|
||||
|
||||
Handle<Object> JSObject::TryMigrateInstance(Handle<JSObject> object) {
|
||||
Map* new_map = object->map()->CurrentMapForDeprecated();
|
||||
if (new_map == NULL) return Handle<Object>();
|
||||
Handle<Map> original_map(object->map());
|
||||
JSObject::MigrateToMap(object, handle(new_map));
|
||||
Handle<Map> new_map = Map::CurrentMapForDeprecatedInternal(original_map);
|
||||
if (new_map.is_null()) return Handle<Object>();
|
||||
JSObject::MigrateToMap(object, new_map);
|
||||
if (FLAG_trace_migration) {
|
||||
object->PrintInstanceMigration(stdout, *original_map, object->map());
|
||||
}
|
||||
|
@ -6039,7 +6039,10 @@ class Map: public HeapObject {
|
||||
// deprecated, it is directly returned. Otherwise, the non-deprecated version
|
||||
// is found by re-transitioning from the root of the transition tree using the
|
||||
// descriptor array of the map. Returns NULL if no updated map is found.
|
||||
Map* CurrentMapForDeprecated();
|
||||
// This method also applies any pending migrations along the prototype chain.
|
||||
static Handle<Map> CurrentMapForDeprecated(Handle<Map> map);
|
||||
// Same as above, but does not touch the prototype chain.
|
||||
static Handle<Map> CurrentMapForDeprecatedInternal(Handle<Map> map);
|
||||
|
||||
static Handle<Map> RawCopy(Handle<Map> map, int instance_size);
|
||||
MUST_USE_RESULT MaybeObject* RawCopy(int instance_size);
|
||||
|
288
src/type-info.cc
288
src/type-info.cc
@ -100,86 +100,37 @@ Handle<Cell> TypeFeedbackOracle::GetInfoCell(
|
||||
|
||||
|
||||
bool TypeFeedbackOracle::LoadIsUninitialized(TypeFeedbackId id) {
|
||||
Handle<Object> map_or_code = GetInfo(id);
|
||||
if (map_or_code->IsMap()) return false;
|
||||
if (map_or_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
Handle<Object> maybe_code = GetInfo(id);
|
||||
if (maybe_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(maybe_code);
|
||||
return code->is_inline_cache_stub() && code->ic_state() == UNINITIALIZED;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool TypeFeedbackOracle::LoadIsMonomorphicNormal(TypeFeedbackId id) {
|
||||
Handle<Object> map_or_code = GetInfo(id);
|
||||
if (map_or_code->IsMap()) return true;
|
||||
if (map_or_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
bool preliminary_checks = code->is_keyed_load_stub() &&
|
||||
code->ic_state() == MONOMORPHIC &&
|
||||
Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL;
|
||||
if (!preliminary_checks) return false;
|
||||
Map* map = code->FindFirstMap();
|
||||
if (map == NULL) return false;
|
||||
map = map->CurrentMapForDeprecated();
|
||||
return map != NULL && !CanRetainOtherContext(map, *native_context_);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool TypeFeedbackOracle::LoadIsPreMonomorphic(TypeFeedbackId id) {
|
||||
Handle<Object> map_or_code = GetInfo(id);
|
||||
if (map_or_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
Handle<Object> maybe_code = GetInfo(id);
|
||||
if (maybe_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(maybe_code);
|
||||
return code->is_inline_cache_stub() && code->ic_state() == PREMONOMORPHIC;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool TypeFeedbackOracle::LoadIsPolymorphic(TypeFeedbackId id) {
|
||||
Handle<Object> map_or_code = GetInfo(id);
|
||||
if (map_or_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
return code->is_keyed_load_stub() && code->ic_state() == POLYMORPHIC;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool TypeFeedbackOracle::StoreIsUninitialized(TypeFeedbackId ast_id) {
|
||||
Handle<Object> map_or_code = GetInfo(ast_id);
|
||||
if (map_or_code->IsMap()) return false;
|
||||
if (!map_or_code->IsCode()) return false;
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
Handle<Object> maybe_code = GetInfo(ast_id);
|
||||
if (!maybe_code->IsCode()) return false;
|
||||
Handle<Code> code = Handle<Code>::cast(maybe_code);
|
||||
return code->ic_state() == UNINITIALIZED;
|
||||
}
|
||||
|
||||
|
||||
bool TypeFeedbackOracle::StoreIsMonomorphicNormal(TypeFeedbackId ast_id) {
|
||||
Handle<Object> map_or_code = GetInfo(ast_id);
|
||||
if (map_or_code->IsMap()) return true;
|
||||
if (map_or_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
bool preliminary_checks =
|
||||
code->is_keyed_store_stub() &&
|
||||
code->ic_state() == MONOMORPHIC &&
|
||||
Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL;
|
||||
if (!preliminary_checks) return false;
|
||||
Map* map = code->FindFirstMap();
|
||||
if (map == NULL) return false;
|
||||
map = map->CurrentMapForDeprecated();
|
||||
return map != NULL && !CanRetainOtherContext(map, *native_context_);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool TypeFeedbackOracle::StoreIsPreMonomorphic(TypeFeedbackId ast_id) {
|
||||
Handle<Object> map_or_code = GetInfo(ast_id);
|
||||
if (map_or_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
Handle<Object> maybe_code = GetInfo(ast_id);
|
||||
if (maybe_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(maybe_code);
|
||||
return code->ic_state() == PREMONOMORPHIC;
|
||||
}
|
||||
return false;
|
||||
@ -187,9 +138,9 @@ bool TypeFeedbackOracle::StoreIsPreMonomorphic(TypeFeedbackId ast_id) {
|
||||
|
||||
|
||||
bool TypeFeedbackOracle::StoreIsKeyedPolymorphic(TypeFeedbackId ast_id) {
|
||||
Handle<Object> map_or_code = GetInfo(ast_id);
|
||||
if (map_or_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
Handle<Object> maybe_code = GetInfo(ast_id);
|
||||
if (maybe_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(maybe_code);
|
||||
return code->is_keyed_store_stub() &&
|
||||
code->ic_state() == POLYMORPHIC;
|
||||
}
|
||||
@ -199,8 +150,7 @@ bool TypeFeedbackOracle::StoreIsKeyedPolymorphic(TypeFeedbackId ast_id) {
|
||||
|
||||
bool TypeFeedbackOracle::CallIsMonomorphic(TypeFeedbackId id) {
|
||||
Handle<Object> value = GetInfo(id);
|
||||
return value->IsMap() || value->IsAllocationSite() || value->IsJSFunction() ||
|
||||
value->IsSmi() ||
|
||||
return value->IsAllocationSite() || value->IsJSFunction() || value->IsSmi() ||
|
||||
(value->IsCode() && Handle<Code>::cast(value)->ic_state() == MONOMORPHIC);
|
||||
}
|
||||
|
||||
@ -218,12 +168,6 @@ bool TypeFeedbackOracle::CallNewIsMonomorphic(TypeFeedbackId id) {
|
||||
}
|
||||
|
||||
|
||||
bool TypeFeedbackOracle::ObjectLiteralStoreIsMonomorphic(TypeFeedbackId id) {
|
||||
Handle<Object> map_or_code = GetInfo(id);
|
||||
return map_or_code->IsMap();
|
||||
}
|
||||
|
||||
|
||||
byte TypeFeedbackOracle::ForInType(TypeFeedbackId id) {
|
||||
Handle<Object> value = GetInfo(id);
|
||||
return value->IsSmi() &&
|
||||
@ -232,40 +176,11 @@ byte TypeFeedbackOracle::ForInType(TypeFeedbackId id) {
|
||||
}
|
||||
|
||||
|
||||
Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(TypeFeedbackId id) {
|
||||
ASSERT(LoadIsMonomorphicNormal(id));
|
||||
Handle<Object> map_or_code = GetInfo(id);
|
||||
if (map_or_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
Map* map = code->FindFirstMap()->CurrentMapForDeprecated();
|
||||
return map == NULL || CanRetainOtherContext(map, *native_context_)
|
||||
? Handle<Map>::null()
|
||||
: Handle<Map>(map);
|
||||
}
|
||||
return Handle<Map>::cast(map_or_code);
|
||||
}
|
||||
|
||||
|
||||
Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(
|
||||
TypeFeedbackId ast_id) {
|
||||
ASSERT(StoreIsMonomorphicNormal(ast_id));
|
||||
Handle<Object> map_or_code = GetInfo(ast_id);
|
||||
if (map_or_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
Map* map = code->FindFirstMap()->CurrentMapForDeprecated();
|
||||
return map == NULL || CanRetainOtherContext(map, *native_context_)
|
||||
? Handle<Map>::null()
|
||||
: Handle<Map>(map);
|
||||
}
|
||||
return Handle<Map>::cast(map_or_code);
|
||||
}
|
||||
|
||||
|
||||
KeyedAccessStoreMode TypeFeedbackOracle::GetStoreMode(
|
||||
TypeFeedbackId ast_id) {
|
||||
Handle<Object> map_or_code = GetInfo(ast_id);
|
||||
if (map_or_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
Handle<Object> maybe_code = GetInfo(ast_id);
|
||||
if (maybe_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(maybe_code);
|
||||
if (code->kind() == Code::KEYED_STORE_IC) {
|
||||
return KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state());
|
||||
}
|
||||
@ -274,26 +189,6 @@ KeyedAccessStoreMode TypeFeedbackOracle::GetStoreMode(
|
||||
}
|
||||
|
||||
|
||||
void TypeFeedbackOracle::LoadReceiverTypes(TypeFeedbackId id,
|
||||
Handle<String> name,
|
||||
SmallMapList* types) {
|
||||
Code::Flags flags = Code::ComputeFlags(
|
||||
Code::HANDLER, MONOMORPHIC, kNoExtraICState,
|
||||
Code::NORMAL, Code::LOAD_IC);
|
||||
CollectReceiverTypes(id, name, flags, types);
|
||||
}
|
||||
|
||||
|
||||
void TypeFeedbackOracle::StoreReceiverTypes(TypeFeedbackId id,
|
||||
Handle<String> name,
|
||||
SmallMapList* types) {
|
||||
Code::Flags flags = Code::ComputeFlags(
|
||||
Code::HANDLER, MONOMORPHIC, kNoExtraICState,
|
||||
Code::NORMAL, Code::STORE_IC);
|
||||
CollectReceiverTypes(id, name, flags, types);
|
||||
}
|
||||
|
||||
|
||||
void TypeFeedbackOracle::CallReceiverTypes(TypeFeedbackId id,
|
||||
Handle<String> name,
|
||||
int arity,
|
||||
@ -348,12 +243,6 @@ Handle<Cell> TypeFeedbackOracle::GetCallNewAllocationInfoCell(
|
||||
}
|
||||
|
||||
|
||||
Handle<Map> TypeFeedbackOracle::GetObjectLiteralStoreMap(TypeFeedbackId id) {
|
||||
ASSERT(ObjectLiteralStoreIsMonomorphic(id));
|
||||
return Handle<Map>::cast(GetInfo(id));
|
||||
}
|
||||
|
||||
|
||||
bool TypeFeedbackOracle::LoadIsBuiltin(
|
||||
TypeFeedbackId id, Builtins::Name builtin) {
|
||||
return *GetInfo(id) == isolate_->builtins()->builtin(builtin);
|
||||
@ -385,9 +274,9 @@ void TypeFeedbackOracle::CompareType(TypeFeedbackId id,
|
||||
Handle<Map> map;
|
||||
Map* raw_map = code->FindFirstMap();
|
||||
if (raw_map != NULL) {
|
||||
raw_map = raw_map->CurrentMapForDeprecated();
|
||||
if (raw_map != NULL && !CanRetainOtherContext(raw_map, *native_context_)) {
|
||||
map = handle(raw_map, isolate_);
|
||||
map = Map::CurrentMapForDeprecated(handle(raw_map));
|
||||
if (!map.is_null() && CanRetainOtherContext(*map, *native_context_)) {
|
||||
map = Handle<Map>::null();
|
||||
}
|
||||
}
|
||||
|
||||
@ -460,7 +349,10 @@ void TypeFeedbackOracle::PropertyReceiverTypes(
|
||||
FunctionPrototypeStub proto_stub(Code::LOAD_IC);
|
||||
*is_prototype = LoadIsStub(id, &proto_stub);
|
||||
if (!*is_prototype) {
|
||||
LoadReceiverTypes(id, name, receiver_types);
|
||||
Code::Flags flags = Code::ComputeFlags(
|
||||
Code::HANDLER, MONOMORPHIC, kNoExtraICState,
|
||||
Code::NORMAL, Code::LOAD_IC);
|
||||
CollectReceiverTypes(id, name, flags, receiver_types);
|
||||
}
|
||||
}
|
||||
|
||||
@ -471,11 +363,8 @@ void TypeFeedbackOracle::KeyedPropertyReceiverTypes(
|
||||
*is_string = false;
|
||||
if (LoadIsBuiltin(id, Builtins::kKeyedLoadIC_String)) {
|
||||
*is_string = true;
|
||||
} else if (LoadIsMonomorphicNormal(id)) {
|
||||
receiver_types->Add(LoadMonomorphicReceiverType(id), zone());
|
||||
} else if (LoadIsPolymorphic(id)) {
|
||||
receiver_types->Reserve(kMaxKeyedPolymorphism, zone());
|
||||
CollectKeyedReceiverTypes(id, receiver_types);
|
||||
} else {
|
||||
CollectReceiverTypes(id, receiver_types);
|
||||
}
|
||||
}
|
||||
|
||||
@ -483,7 +372,10 @@ void TypeFeedbackOracle::KeyedPropertyReceiverTypes(
|
||||
void TypeFeedbackOracle::AssignmentReceiverTypes(
|
||||
TypeFeedbackId id, Handle<String> name, SmallMapList* receiver_types) {
|
||||
receiver_types->Clear();
|
||||
StoreReceiverTypes(id, name, receiver_types);
|
||||
Code::Flags flags = Code::ComputeFlags(
|
||||
Code::HANDLER, MONOMORPHIC, kNoExtraICState,
|
||||
Code::NORMAL, Code::STORE_IC);
|
||||
CollectReceiverTypes(id, name, flags, receiver_types);
|
||||
}
|
||||
|
||||
|
||||
@ -491,43 +383,15 @@ void TypeFeedbackOracle::KeyedAssignmentReceiverTypes(
|
||||
TypeFeedbackId id, SmallMapList* receiver_types,
|
||||
KeyedAccessStoreMode* store_mode) {
|
||||
receiver_types->Clear();
|
||||
if (StoreIsMonomorphicNormal(id)) {
|
||||
// Record receiver type for monomorphic keyed stores.
|
||||
receiver_types->Add(StoreMonomorphicReceiverType(id), zone());
|
||||
} else if (StoreIsKeyedPolymorphic(id)) {
|
||||
receiver_types->Reserve(kMaxKeyedPolymorphism, zone());
|
||||
CollectKeyedReceiverTypes(id, receiver_types);
|
||||
}
|
||||
CollectReceiverTypes(id, receiver_types);
|
||||
*store_mode = GetStoreMode(id);
|
||||
}
|
||||
|
||||
|
||||
void TypeFeedbackOracle::CountReceiverTypes(
|
||||
TypeFeedbackId id, SmallMapList* receiver_types) {
|
||||
void TypeFeedbackOracle::CountReceiverTypes(TypeFeedbackId id,
|
||||
SmallMapList* receiver_types) {
|
||||
receiver_types->Clear();
|
||||
if (StoreIsMonomorphicNormal(id)) {
|
||||
// Record receiver type for monomorphic keyed stores.
|
||||
receiver_types->Add(StoreMonomorphicReceiverType(id), zone());
|
||||
} else if (StoreIsKeyedPolymorphic(id)) {
|
||||
receiver_types->Reserve(kMaxKeyedPolymorphism, zone());
|
||||
CollectKeyedReceiverTypes(id, receiver_types);
|
||||
} else {
|
||||
CollectPolymorphicStoreReceiverTypes(id, receiver_types);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TypeFeedbackOracle::CollectPolymorphicMaps(Handle<Code> code,
|
||||
SmallMapList* types) {
|
||||
MapHandleList maps;
|
||||
code->FindAllMaps(&maps);
|
||||
types->Reserve(maps.length(), zone());
|
||||
for (int i = 0; i < maps.length(); i++) {
|
||||
Handle<Map> map(maps.at(i));
|
||||
if (!CanRetainOtherContext(*map, *native_context_)) {
|
||||
types->AddMapIfMissing(map, zone());
|
||||
}
|
||||
}
|
||||
CollectReceiverTypes(id, receiver_types);
|
||||
}
|
||||
|
||||
|
||||
@ -538,20 +402,16 @@ void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id,
|
||||
Handle<Object> object = GetInfo(ast_id);
|
||||
if (object->IsUndefined() || object->IsSmi()) return;
|
||||
|
||||
if (object->IsMap()) {
|
||||
types->AddMapIfMissing(Handle<Map>::cast(object), zone());
|
||||
} else if (Handle<Code>::cast(object)->ic_state() == POLYMORPHIC ||
|
||||
Handle<Code>::cast(object)->ic_state() == MONOMORPHIC) {
|
||||
CollectPolymorphicMaps(Handle<Code>::cast(object), types);
|
||||
} else if (FLAG_collect_megamorphic_maps_from_stub_cache &&
|
||||
Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) {
|
||||
ASSERT(object->IsCode());
|
||||
Handle<Code> code(Handle<Code>::cast(object));
|
||||
|
||||
if (FLAG_collect_megamorphic_maps_from_stub_cache &&
|
||||
code->ic_state() == MEGAMORPHIC) {
|
||||
types->Reserve(4, zone());
|
||||
ASSERT(object->IsCode());
|
||||
isolate_->stub_cache()->CollectMatchingMaps(types,
|
||||
name,
|
||||
flags,
|
||||
native_context_,
|
||||
zone());
|
||||
isolate_->stub_cache()->CollectMatchingMaps(
|
||||
types, name, flags, native_context_, zone());
|
||||
} else {
|
||||
CollectReceiverTypes(ast_id, types);
|
||||
}
|
||||
}
|
||||
|
||||
@ -590,26 +450,26 @@ bool TypeFeedbackOracle::CanRetainOtherContext(JSFunction* function,
|
||||
}
|
||||
|
||||
|
||||
void TypeFeedbackOracle::CollectKeyedReceiverTypes(TypeFeedbackId ast_id,
|
||||
SmallMapList* types) {
|
||||
void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id,
|
||||
SmallMapList* types) {
|
||||
Handle<Object> object = GetInfo(ast_id);
|
||||
if (!object->IsCode()) return;
|
||||
Handle<Code> code = Handle<Code>::cast(object);
|
||||
if (code->kind() == Code::KEYED_LOAD_IC ||
|
||||
code->kind() == Code::KEYED_STORE_IC) {
|
||||
CollectPolymorphicMaps(code, types);
|
||||
MapHandleList maps;
|
||||
if (code->ic_state() == MONOMORPHIC) {
|
||||
Map* map = code->FindFirstMap();
|
||||
if (map != NULL) maps.Add(handle(map));
|
||||
} else if (code->ic_state() == POLYMORPHIC) {
|
||||
code->FindAllMaps(&maps);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TypeFeedbackOracle::CollectPolymorphicStoreReceiverTypes(
|
||||
TypeFeedbackId ast_id,
|
||||
SmallMapList* types) {
|
||||
Handle<Object> object = GetInfo(ast_id);
|
||||
if (!object->IsCode()) return;
|
||||
Handle<Code> code = Handle<Code>::cast(object);
|
||||
if (code->kind() == Code::STORE_IC && code->ic_state() == POLYMORPHIC) {
|
||||
CollectPolymorphicMaps(code, types);
|
||||
types->Reserve(maps.length(), zone());
|
||||
for (int i = 0; i < maps.length(); i++) {
|
||||
Handle<Map> map(maps.at(i));
|
||||
if (!CanRetainOtherContext(*map, *native_context_)) {
|
||||
types->AddMapIfMissing(map, zone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -679,28 +539,14 @@ void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) {
|
||||
TypeFeedbackId(static_cast<unsigned>((*infos)[i].data()));
|
||||
Code* target = Code::GetCodeFromTargetAddress(target_address);
|
||||
switch (target->kind()) {
|
||||
case Code::CALL_IC:
|
||||
if (target->ic_state() == MONOMORPHIC &&
|
||||
target->check_type() != RECEIVER_MAP_CHECK) {
|
||||
SetInfo(ast_id, Smi::FromInt(target->check_type()));
|
||||
break;
|
||||
}
|
||||
case Code::LOAD_IC:
|
||||
case Code::STORE_IC:
|
||||
case Code::CALL_IC:
|
||||
if (target->ic_state() == MONOMORPHIC) {
|
||||
if (target->kind() == Code::CALL_IC &&
|
||||
target->check_type() != RECEIVER_MAP_CHECK) {
|
||||
SetInfo(ast_id, Smi::FromInt(target->check_type()));
|
||||
} else {
|
||||
Object* map = target->FindFirstMap();
|
||||
if (map == NULL) {
|
||||
SetInfo(ast_id, static_cast<Object*>(target));
|
||||
} else if (!CanRetainOtherContext(Map::cast(map),
|
||||
*native_context_)) {
|
||||
Map* feedback = Map::cast(map)->CurrentMapForDeprecated();
|
||||
if (feedback != NULL) SetInfo(ast_id, feedback);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SetInfo(ast_id, target);
|
||||
}
|
||||
break;
|
||||
|
||||
case Code::KEYED_CALL_IC:
|
||||
case Code::KEYED_LOAD_IC:
|
||||
case Code::KEYED_STORE_IC:
|
||||
|
@ -230,18 +230,14 @@ class TypeFeedbackOracle: public ZoneObject {
|
||||
Isolate* isolate,
|
||||
Zone* zone);
|
||||
|
||||
bool LoadIsMonomorphicNormal(TypeFeedbackId id);
|
||||
bool LoadIsUninitialized(TypeFeedbackId id);
|
||||
bool LoadIsPreMonomorphic(TypeFeedbackId id);
|
||||
bool LoadIsPolymorphic(TypeFeedbackId id);
|
||||
bool StoreIsUninitialized(TypeFeedbackId id);
|
||||
bool StoreIsMonomorphicNormal(TypeFeedbackId id);
|
||||
bool StoreIsPreMonomorphic(TypeFeedbackId id);
|
||||
bool StoreIsKeyedPolymorphic(TypeFeedbackId id);
|
||||
bool CallIsMonomorphic(TypeFeedbackId aid);
|
||||
bool KeyedArrayCallIsHoley(TypeFeedbackId id);
|
||||
bool CallNewIsMonomorphic(TypeFeedbackId id);
|
||||
bool ObjectLiteralStoreIsMonomorphic(TypeFeedbackId id);
|
||||
|
||||
// TODO(1571) We can't use ForInStatement::ForInType as the return value due
|
||||
// to various cycles in our headers.
|
||||
@ -249,27 +245,13 @@ class TypeFeedbackOracle: public ZoneObject {
|
||||
// be possible.
|
||||
byte ForInType(TypeFeedbackId id);
|
||||
|
||||
Handle<Map> LoadMonomorphicReceiverType(TypeFeedbackId id);
|
||||
Handle<Map> StoreMonomorphicReceiverType(TypeFeedbackId id);
|
||||
|
||||
KeyedAccessStoreMode GetStoreMode(TypeFeedbackId id);
|
||||
|
||||
void LoadReceiverTypes(TypeFeedbackId id,
|
||||
Handle<String> name,
|
||||
SmallMapList* types);
|
||||
void StoreReceiverTypes(TypeFeedbackId id,
|
||||
Handle<String> name,
|
||||
SmallMapList* types);
|
||||
void CallReceiverTypes(TypeFeedbackId id,
|
||||
Handle<String> name,
|
||||
int arity,
|
||||
CallKind call_kind,
|
||||
SmallMapList* types);
|
||||
void CollectKeyedReceiverTypes(TypeFeedbackId id,
|
||||
SmallMapList* types);
|
||||
void CollectPolymorphicStoreReceiverTypes(TypeFeedbackId id,
|
||||
SmallMapList* types);
|
||||
|
||||
void PropertyReceiverTypes(TypeFeedbackId id,
|
||||
Handle<String> name,
|
||||
SmallMapList* receiver_types,
|
||||
@ -286,19 +268,18 @@ class TypeFeedbackOracle: public ZoneObject {
|
||||
void CountReceiverTypes(TypeFeedbackId id,
|
||||
SmallMapList* receiver_types);
|
||||
|
||||
void CollectReceiverTypes(TypeFeedbackId id,
|
||||
SmallMapList* types);
|
||||
|
||||
static bool CanRetainOtherContext(Map* map, Context* native_context);
|
||||
static bool CanRetainOtherContext(JSFunction* function,
|
||||
Context* native_context);
|
||||
|
||||
void CollectPolymorphicMaps(Handle<Code> code, SmallMapList* types);
|
||||
|
||||
CheckType GetCallCheckType(TypeFeedbackId id);
|
||||
Handle<JSFunction> GetCallTarget(TypeFeedbackId id);
|
||||
Handle<JSFunction> GetCallNewTarget(TypeFeedbackId id);
|
||||
Handle<Cell> GetCallNewAllocationInfoCell(TypeFeedbackId id);
|
||||
|
||||
Handle<Map> GetObjectLiteralStoreMap(TypeFeedbackId id);
|
||||
|
||||
bool LoadIsBuiltin(TypeFeedbackId id, Builtins::Name builtin_id);
|
||||
bool LoadIsStub(TypeFeedbackId id, ICStub* stub);
|
||||
|
||||
|
@ -394,8 +394,6 @@ void AstTyper::VisitAssignment(Assignment* expr) {
|
||||
expr->set_is_uninitialized(oracle()->StoreIsUninitialized(id));
|
||||
if (!expr->IsUninitialized()) {
|
||||
expr->set_is_pre_monomorphic(oracle()->StoreIsPreMonomorphic(id));
|
||||
expr->set_is_monomorphic(oracle()->StoreIsMonomorphicNormal(id));
|
||||
ASSERT(!expr->IsPreMonomorphic() || !expr->IsMonomorphic());
|
||||
if (prop->key()->IsPropertyName()) {
|
||||
Literal* lit_key = prop->key()->AsLiteral();
|
||||
ASSERT(lit_key != NULL && lit_key->value()->IsString());
|
||||
@ -407,6 +405,7 @@ void AstTyper::VisitAssignment(Assignment* expr) {
|
||||
id, expr->GetReceiverTypes(), &store_mode);
|
||||
expr->set_store_mode(store_mode);
|
||||
}
|
||||
ASSERT(!expr->IsPreMonomorphic() || !expr->IsMonomorphic());
|
||||
}
|
||||
}
|
||||
|
||||
@ -445,8 +444,6 @@ void AstTyper::VisitProperty(Property* expr) {
|
||||
expr->set_is_uninitialized(oracle()->LoadIsUninitialized(id));
|
||||
if (!expr->IsUninitialized()) {
|
||||
expr->set_is_pre_monomorphic(oracle()->LoadIsPreMonomorphic(id));
|
||||
expr->set_is_monomorphic(oracle()->LoadIsMonomorphicNormal(id));
|
||||
ASSERT(!expr->IsPreMonomorphic() || !expr->IsMonomorphic());
|
||||
if (expr->key()->IsPropertyName()) {
|
||||
Literal* lit_key = expr->key()->AsLiteral();
|
||||
ASSERT(lit_key != NULL && lit_key->value()->IsString());
|
||||
@ -461,6 +458,7 @@ void AstTyper::VisitProperty(Property* expr) {
|
||||
id, expr->GetReceiverTypes(), &is_string);
|
||||
expr->set_is_string_access(is_string);
|
||||
}
|
||||
ASSERT(!expr->IsPreMonomorphic() || !expr->IsMonomorphic());
|
||||
}
|
||||
|
||||
RECURSE(Visit(expr->obj()));
|
||||
@ -551,7 +549,6 @@ void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
void AstTyper::VisitCountOperation(CountOperation* expr) {
|
||||
// Collect type feedback.
|
||||
TypeFeedbackId store_id = expr->CountStoreFeedbackId();
|
||||
expr->set_is_monomorphic(oracle()->StoreIsMonomorphicNormal(store_id));
|
||||
expr->set_store_mode(oracle()->GetStoreMode(store_id));
|
||||
oracle()->CountReceiverTypes(store_id, expr->GetReceiverTypes());
|
||||
expr->set_type(oracle()->CountType(expr->CountBinOpFeedbackId()));
|
||||
|
@ -0,0 +1,49 @@
|
||||
// Copyright 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.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
function f() {
|
||||
return 1;
|
||||
}
|
||||
function C1(f) {
|
||||
this.f = f;
|
||||
}
|
||||
var o1 = new C1(f);
|
||||
var o2 = {__proto__: new C1(f) }
|
||||
function foo(o) {
|
||||
return o.f();
|
||||
}
|
||||
foo(o1);
|
||||
foo(o1);
|
||||
foo(o2);
|
||||
foo(o1);
|
||||
var o3 = new C1(function() { return 2; });
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
assertEquals(1, foo(o2));
|
||||
o2.__proto__.f = function() { return 3; };
|
||||
assertEquals(3, foo(o2));
|
Loading…
Reference in New Issue
Block a user