[runtime] Do not clear prototype map descriptors.
Mutating the descriptor array and the layout descriptor of a map races with the concurrent marking. This patch simply transfers ownership of the descriptor array without mutating the map. Since the old map is not going to be used anymore and there are not transitions from the old map, this should be safe for trimming the descriptor arrays during GC. This patch also adds checks in IC code avoid caching of dummy transitions from the abandoned prototype map. Bug: chromium:752461 Change-Id: I7b44ba7c369199bdb3ff48235226fe504c7eb4a5 Reviewed-on: https://chromium-review.googlesource.com/602210 Commit-Queue: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#47275}
This commit is contained in:
parent
80423e89b1
commit
d09f9c424f
@ -2890,6 +2890,8 @@ void MarkCompactCollector::ClearSimpleMapTransition(
|
||||
|
||||
void MarkCompactCollector::ClearSimpleMapTransition(Map* map,
|
||||
Map* dead_target) {
|
||||
DCHECK(!map->is_prototype_map());
|
||||
DCHECK(!dead_target->is_prototype_map());
|
||||
// Clear the useless weak cell pointer, and take ownership of the descriptor
|
||||
// array.
|
||||
map->set_raw_transitions(Smi::kZero);
|
||||
@ -2931,6 +2933,7 @@ void MarkCompactCollector::ClearFullMapTransitions() {
|
||||
|
||||
bool MarkCompactCollector::CompactTransitionArray(
|
||||
Map* map, TransitionArray* transitions, DescriptorArray* descriptors) {
|
||||
DCHECK(!map->is_prototype_map());
|
||||
int num_transitions = transitions->number_of_entries();
|
||||
bool descriptors_owner_died = false;
|
||||
int transition_index = 0;
|
||||
@ -2941,6 +2944,7 @@ bool MarkCompactCollector::CompactTransitionArray(
|
||||
if (ObjectMarking::IsWhite(target, MarkingState::Internal(target))) {
|
||||
if (descriptors != nullptr &&
|
||||
target->instance_descriptors() == descriptors) {
|
||||
DCHECK(!target->is_prototype_map());
|
||||
descriptors_owner_died = true;
|
||||
}
|
||||
} else {
|
||||
|
18
src/ic/ic.cc
18
src/ic/ic.cc
@ -713,8 +713,9 @@ void IC::CopyICToMegamorphicCache(Handle<Name> name) {
|
||||
|
||||
|
||||
bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
|
||||
if (source_map == NULL) return true;
|
||||
if (target_map == NULL) return false;
|
||||
if (source_map == nullptr) return true;
|
||||
if (target_map == nullptr) return false;
|
||||
if (source_map->is_abandoned_prototype_map()) return false;
|
||||
ElementsKind target_elements_kind = target_map->elements_kind();
|
||||
bool more_general_transition = IsMoreGeneralElementsKindTransition(
|
||||
source_map->elements_kind(), target_elements_kind);
|
||||
@ -2331,11 +2332,14 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
|
||||
if (is_arguments) {
|
||||
TRACE_GENERIC_IC("arguments receiver");
|
||||
} else if (key_is_valid_index) {
|
||||
// We should go generic if receiver isn't a dictionary, but our
|
||||
// prototype chain does have dictionary elements. This ensures that
|
||||
// other non-dictionary receivers in the polymorphic case benefit
|
||||
// from fast path keyed stores.
|
||||
if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly()) {
|
||||
if (old_receiver_map->is_abandoned_prototype_map()) {
|
||||
TRACE_GENERIC_IC("receiver with prototype map");
|
||||
} else if (!old_receiver_map
|
||||
->DictionaryElementsInPrototypeChainOnly()) {
|
||||
// We should go generic if receiver isn't a dictionary, but our
|
||||
// prototype chain does have dictionary elements. This ensures that
|
||||
// other non-dictionary receivers in the polymorphic case benefit
|
||||
// from fast path keyed stores.
|
||||
UpdateStoreElement(old_receiver_map, store_mode);
|
||||
} else {
|
||||
TRACE_GENERIC_IC("dictionary or proxy prototype");
|
||||
|
@ -3403,6 +3403,10 @@ bool Map::is_prototype_map() const {
|
||||
return IsPrototypeMapBits::decode(bit_field2());
|
||||
}
|
||||
|
||||
bool Map::is_abandoned_prototype_map() const {
|
||||
return is_prototype_map() && !owns_descriptors();
|
||||
}
|
||||
|
||||
bool Map::should_be_fast_prototype_map() const {
|
||||
if (!prototype_info()->IsPrototypeInfo()) return false;
|
||||
return PrototypeInfo::cast(prototype_info())->should_be_fast_map();
|
||||
|
@ -4177,14 +4177,17 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
|
||||
if (old_map->is_prototype_map()) {
|
||||
DCHECK(!old_map->is_stable());
|
||||
DCHECK(new_map->is_stable());
|
||||
// Clear out the old descriptor array to avoid problems to sharing
|
||||
// the descriptor array without using an explicit.
|
||||
old_map->InitializeDescriptors(
|
||||
old_map->GetHeap()->empty_descriptor_array(),
|
||||
LayoutDescriptor::FastPointerLayout());
|
||||
DCHECK(new_map->owns_descriptors());
|
||||
DCHECK(old_map->owns_descriptors());
|
||||
// Transfer ownership to the new map. Keep the descriptor pointer of the
|
||||
// old map intact because the concurrent marker might be iterating the
|
||||
// object with the old map.
|
||||
old_map->set_owns_descriptors(false);
|
||||
DCHECK(old_map->is_abandoned_prototype_map());
|
||||
// Ensure that no transition was inserted for prototype migrations.
|
||||
DCHECK_EQ(0, TransitionsAccessor(old_map).NumberOfTransitions());
|
||||
DCHECK(new_map->GetBackPointer()->IsUndefined(new_map->GetIsolate()));
|
||||
DCHECK(object->map() != *old_map);
|
||||
}
|
||||
} else {
|
||||
MigrateFastToSlow(object, new_map, expected_additional_properties);
|
||||
@ -5210,6 +5213,8 @@ Map* Map::FindElementsKindTransitionedMap(MapHandles const& candidates) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
DisallowDeoptimization no_deoptimization(GetIsolate());
|
||||
|
||||
if (is_prototype_map()) return nullptr;
|
||||
|
||||
ElementsKind kind = elements_kind();
|
||||
bool packed = IsFastPackedElementsKind(kind);
|
||||
|
||||
|
@ -258,6 +258,7 @@ class Map : public HeapObject {
|
||||
inline bool is_extensible() const;
|
||||
inline void set_is_prototype_map(bool value);
|
||||
inline bool is_prototype_map() const;
|
||||
inline bool is_abandoned_prototype_map() const;
|
||||
|
||||
inline void set_elements_kind(ElementsKind elements_kind);
|
||||
inline ElementsKind elements_kind() const;
|
||||
|
Loading…
Reference in New Issue
Block a user