From: jkummerow@chromium.org Date: Thu, 12 Dec 2013 14:57:00 +0000 (+0000) Subject: Fix polymorphic inlined calls with migrating prototypes X-Git-Tag: upstream/4.7.83~11380 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=48ff79a300c5c77429857948e04aa0c0e675c69c;p=platform%2Fupstream%2Fv8.git 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 --- diff --git a/src/ast.cc b/src/ast.cc index aeb767ef0..681b3d46b 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -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::null(); + SmallMapList maps; + oracle->CollectReceiverTypes(id, &maps); + receiver_type_ = maps.length() == 1 ? maps.at(0) + : Handle::null(); } diff --git a/src/ast.h b/src/ast.h index 0bbb90452..4e413c542 100644 --- a/src/ast.h +++ b/src/ast.h @@ -279,9 +279,8 @@ class SmallMapList V8_FINAL { int length() const { return list_.length(); } void AddMapIfMissing(Handle map, Zone* zone) { - Map* updated = map->CurrentMapForDeprecated(); - if (updated == NULL) return; - map = Handle(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() 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; } @@ -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_; @@ -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, diff --git a/src/objects.cc b/src/objects.cc index 43a047e78..bfe1f5577 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -2803,31 +2803,44 @@ Handle Map::GeneralizeAllFieldRepresentations( } -Map* Map::CurrentMapForDeprecated() { - DisallowHeapAllocation no_allocation; - if (!is_deprecated()) return this; +Handle Map::CurrentMapForDeprecated(Handle map) { + Handle proto_map(map); + while (proto_map->prototype()->IsJSObject()) { + Handle holder(JSObject::cast(proto_map->prototype())); + if (holder->map()->is_deprecated()) { + JSObject::TryMigrateInstance(holder); + } + proto_map = Handle(holder->map()); + } + return CurrentMapForDeprecatedInternal(map); +} - DescriptorArray* old_descriptors = instance_descriptors(); - int descriptors = NumberOfOwnDescriptors(); - Map* root_map = FindRootMap(); +Handle Map::CurrentMapForDeprecatedInternal(Handle map) { + if (!map->is_deprecated()) return map; + + DisallowHeapAllocation no_allocation; + DescriptorArray* old_descriptors = map->instance_descriptors(); + + 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(); int verbatim = root_map->NumberOfOwnDescriptors(); Map* updated = root_map->FindUpdatedMap( verbatim, descriptors, old_descriptors); - if (updated == NULL) return NULL; + if (updated == NULL) return Handle(); DescriptorArray* updated_descriptors = updated->instance_descriptors(); int valid = updated->NumberOfOwnDescriptors(); if (!updated_descriptors->IsMoreGeneralThan( verbatim, valid, descriptors, old_descriptors)) { - return NULL; + return Handle(); } - return updated; + return handle(updated); } @@ -3879,10 +3892,10 @@ void JSObject::MigrateInstance(Handle object) { Handle JSObject::TryMigrateInstance(Handle object) { - Map* new_map = object->map()->CurrentMapForDeprecated(); - if (new_map == NULL) return Handle(); Handle original_map(object->map()); - JSObject::MigrateToMap(object, handle(new_map)); + Handle new_map = Map::CurrentMapForDeprecatedInternal(original_map); + if (new_map.is_null()) return Handle(); + JSObject::MigrateToMap(object, new_map); if (FLAG_trace_migration) { object->PrintInstanceMigration(stdout, *original_map, object->map()); } diff --git a/src/objects.h b/src/objects.h index 7b145744a..41c3f0341 100644 --- a/src/objects.h +++ b/src/objects.h @@ -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 CurrentMapForDeprecated(Handle map); + // Same as above, but does not touch the prototype chain. + static Handle CurrentMapForDeprecatedInternal(Handle map); static Handle RawCopy(Handle map, int instance_size); MUST_USE_RESULT MaybeObject* RawCopy(int instance_size); diff --git a/src/type-info.cc b/src/type-info.cc index 6e3a4f6b7..eed54ce2b 100644 --- a/src/type-info.cc +++ b/src/type-info.cc @@ -100,86 +100,37 @@ Handle TypeFeedbackOracle::GetInfoCell( bool TypeFeedbackOracle::LoadIsUninitialized(TypeFeedbackId id) { - Handle map_or_code = GetInfo(id); - if (map_or_code->IsMap()) return false; - if (map_or_code->IsCode()) { - Handle code = Handle::cast(map_or_code); + Handle maybe_code = GetInfo(id); + if (maybe_code->IsCode()) { + Handle code = Handle::cast(maybe_code); return code->is_inline_cache_stub() && code->ic_state() == UNINITIALIZED; } return false; } -bool TypeFeedbackOracle::LoadIsMonomorphicNormal(TypeFeedbackId id) { - Handle map_or_code = GetInfo(id); - if (map_or_code->IsMap()) return true; - if (map_or_code->IsCode()) { - Handle code = Handle::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 map_or_code = GetInfo(id); - if (map_or_code->IsCode()) { - Handle code = Handle::cast(map_or_code); + Handle maybe_code = GetInfo(id); + if (maybe_code->IsCode()) { + Handle code = Handle::cast(maybe_code); return code->is_inline_cache_stub() && code->ic_state() == PREMONOMORPHIC; } return false; } -bool TypeFeedbackOracle::LoadIsPolymorphic(TypeFeedbackId id) { - Handle map_or_code = GetInfo(id); - if (map_or_code->IsCode()) { - Handle code = Handle::cast(map_or_code); - return code->is_keyed_load_stub() && code->ic_state() == POLYMORPHIC; - } - return false; -} - - bool TypeFeedbackOracle::StoreIsUninitialized(TypeFeedbackId ast_id) { - Handle map_or_code = GetInfo(ast_id); - if (map_or_code->IsMap()) return false; - if (!map_or_code->IsCode()) return false; - Handle code = Handle::cast(map_or_code); + Handle maybe_code = GetInfo(ast_id); + if (!maybe_code->IsCode()) return false; + Handle code = Handle::cast(maybe_code); return code->ic_state() == UNINITIALIZED; } -bool TypeFeedbackOracle::StoreIsMonomorphicNormal(TypeFeedbackId ast_id) { - Handle map_or_code = GetInfo(ast_id); - if (map_or_code->IsMap()) return true; - if (map_or_code->IsCode()) { - Handle code = Handle::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 map_or_code = GetInfo(ast_id); - if (map_or_code->IsCode()) { - Handle code = Handle::cast(map_or_code); + Handle maybe_code = GetInfo(ast_id); + if (maybe_code->IsCode()) { + Handle code = Handle::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 map_or_code = GetInfo(ast_id); - if (map_or_code->IsCode()) { - Handle code = Handle::cast(map_or_code); + Handle maybe_code = GetInfo(ast_id); + if (maybe_code->IsCode()) { + Handle code = Handle::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 value = GetInfo(id); - return value->IsMap() || value->IsAllocationSite() || value->IsJSFunction() || - value->IsSmi() || + return value->IsAllocationSite() || value->IsJSFunction() || value->IsSmi() || (value->IsCode() && Handle::cast(value)->ic_state() == MONOMORPHIC); } @@ -218,12 +168,6 @@ bool TypeFeedbackOracle::CallNewIsMonomorphic(TypeFeedbackId id) { } -bool TypeFeedbackOracle::ObjectLiteralStoreIsMonomorphic(TypeFeedbackId id) { - Handle map_or_code = GetInfo(id); - return map_or_code->IsMap(); -} - - byte TypeFeedbackOracle::ForInType(TypeFeedbackId id) { Handle value = GetInfo(id); return value->IsSmi() && @@ -232,40 +176,11 @@ byte TypeFeedbackOracle::ForInType(TypeFeedbackId id) { } -Handle TypeFeedbackOracle::LoadMonomorphicReceiverType(TypeFeedbackId id) { - ASSERT(LoadIsMonomorphicNormal(id)); - Handle map_or_code = GetInfo(id); - if (map_or_code->IsCode()) { - Handle code = Handle::cast(map_or_code); - Map* map = code->FindFirstMap()->CurrentMapForDeprecated(); - return map == NULL || CanRetainOtherContext(map, *native_context_) - ? Handle::null() - : Handle(map); - } - return Handle::cast(map_or_code); -} - - -Handle TypeFeedbackOracle::StoreMonomorphicReceiverType( - TypeFeedbackId ast_id) { - ASSERT(StoreIsMonomorphicNormal(ast_id)); - Handle map_or_code = GetInfo(ast_id); - if (map_or_code->IsCode()) { - Handle code = Handle::cast(map_or_code); - Map* map = code->FindFirstMap()->CurrentMapForDeprecated(); - return map == NULL || CanRetainOtherContext(map, *native_context_) - ? Handle::null() - : Handle(map); - } - return Handle::cast(map_or_code); -} - - KeyedAccessStoreMode TypeFeedbackOracle::GetStoreMode( TypeFeedbackId ast_id) { - Handle map_or_code = GetInfo(ast_id); - if (map_or_code->IsCode()) { - Handle code = Handle::cast(map_or_code); + Handle maybe_code = GetInfo(ast_id); + if (maybe_code->IsCode()) { + Handle code = Handle::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 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 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 name, int arity, @@ -348,12 +243,6 @@ Handle TypeFeedbackOracle::GetCallNewAllocationInfoCell( } -Handle TypeFeedbackOracle::GetObjectLiteralStoreMap(TypeFeedbackId id) { - ASSERT(ObjectLiteralStoreIsMonomorphic(id)); - return Handle::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* 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::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 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, - SmallMapList* types) { - MapHandleList maps; - code->FindAllMaps(&maps); - types->Reserve(maps.length(), zone()); - for (int i = 0; i < maps.length(); i++) { - Handle 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 = GetInfo(ast_id); if (object->IsUndefined() || object->IsSmi()) return; - if (object->IsMap()) { - types->AddMapIfMissing(Handle::cast(object), zone()); - } else if (Handle::cast(object)->ic_state() == POLYMORPHIC || - Handle::cast(object)->ic_state() == MONOMORPHIC) { - CollectPolymorphicMaps(Handle::cast(object), types); - } else if (FLAG_collect_megamorphic_maps_from_stub_cache && - Handle::cast(object)->ic_state() == MEGAMORPHIC) { + ASSERT(object->IsCode()); + Handle code(Handle::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 = GetInfo(ast_id); if (!object->IsCode()) return; Handle code = Handle::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 = GetInfo(ast_id); - if (!object->IsCode()) return; - Handle code = Handle::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(maps.at(i)); + if (!CanRetainOtherContext(*map, *native_context_)) { + types->AddMapIfMissing(map, zone()); + } } } @@ -679,28 +539,14 @@ void TypeFeedbackOracle::ProcessRelocInfos(ZoneList* infos) { TypeFeedbackId(static_cast((*infos)[i].data())); Code* target = Code::GetCodeFromTargetAddress(target_address); switch (target->kind()) { - 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(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); + if (target->ic_state() == MONOMORPHIC && + target->check_type() != RECEIVER_MAP_CHECK) { + SetInfo(ast_id, Smi::FromInt(target->check_type())); + break; } - break; - + case Code::LOAD_IC: + case Code::STORE_IC: case Code::KEYED_CALL_IC: case Code::KEYED_LOAD_IC: case Code::KEYED_STORE_IC: diff --git a/src/type-info.h b/src/type-info.h index a0d321584..0ff99e994 100644 --- a/src/type-info.h +++ b/src/type-info.h @@ -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 LoadMonomorphicReceiverType(TypeFeedbackId id); - Handle StoreMonomorphicReceiverType(TypeFeedbackId id); - KeyedAccessStoreMode GetStoreMode(TypeFeedbackId id); - void LoadReceiverTypes(TypeFeedbackId id, - Handle name, - SmallMapList* types); - void StoreReceiverTypes(TypeFeedbackId id, - Handle name, - SmallMapList* types); void CallReceiverTypes(TypeFeedbackId id, Handle 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 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, SmallMapList* types); - CheckType GetCallCheckType(TypeFeedbackId id); Handle GetCallTarget(TypeFeedbackId id); Handle GetCallNewTarget(TypeFeedbackId id); Handle GetCallNewAllocationInfoCell(TypeFeedbackId id); - Handle GetObjectLiteralStoreMap(TypeFeedbackId id); - bool LoadIsBuiltin(TypeFeedbackId id, Builtins::Name builtin_id); bool LoadIsStub(TypeFeedbackId id, ICStub* stub); diff --git a/src/typing.cc b/src/typing.cc index 8487c05eb..9458d6dc2 100644 --- a/src/typing.cc +++ b/src/typing.cc @@ -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())); diff --git a/test/mjsunit/regress/regress-calls-with-migrating-prototypes.js b/test/mjsunit/regress/regress-calls-with-migrating-prototypes.js new file mode 100644 index 000000000..a306e5d9d --- /dev/null +++ b/test/mjsunit/regress/regress-calls-with-migrating-prototypes.js @@ -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));