Commit 6e27386d authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

Reland "[runtime] Add shortcuts for elements kinds transitions."

This is a reland of b90e83f5
Original change's description:
> [runtime] Add shortcuts for elements kinds transitions.
>
> The shortcuts ensure that field type generalization is properly
> propagated in the transition graph.
>
> Bug: chromium:738763
> Change-Id: Id701a6f95ed6ea093c707fbe0bac228f1f856e9f
> Reviewed-on: https://chromium-review.googlesource.com/567992
> Commit-Queue: Igor Sheludko <ishell@chromium.org>
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#46622}

Bug: chromium:738763, chromium:742346, chromium:742381, chromium:745844
Change-Id: I93974e3906b2c7710bd525f15037a2dd97f263ad
Reviewed-on: https://chromium-review.googlesource.com/575227
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46759}
parent e679dd45
...@@ -217,6 +217,7 @@ ...@@ -217,6 +217,7 @@
V(class_start_position_symbol) \ V(class_start_position_symbol) \
V(detailed_stack_trace_symbol) \ V(detailed_stack_trace_symbol) \
V(elements_transition_symbol) \ V(elements_transition_symbol) \
V(elements_transition_shortcut_symbol) \
V(error_end_pos_symbol) \ V(error_end_pos_symbol) \
V(error_script_symbol) \ V(error_script_symbol) \
V(error_start_pos_symbol) \ V(error_start_pos_symbol) \
......
...@@ -2974,6 +2974,22 @@ void MarkCompactCollector::ClearSimpleMapTransition(Map* map, ...@@ -2974,6 +2974,22 @@ void MarkCompactCollector::ClearSimpleMapTransition(Map* map,
} }
} }
namespace {
Map* GetTransitionArrayOwnerMap(Heap* heap, TransitionArray* transitions,
int num_transitions) {
// Search for any non-shortcut transition.
for (int i = 0; i < num_transitions; i++) {
Name* key = transitions->GetKey(i);
if (TransitionArray::IsShortcutTransition(key)) continue;
Map* target = transitions->GetTarget(i);
Map* parent = Map::cast(target->constructor_or_backpointer());
return parent;
}
return nullptr;
}
} // namespace
void MarkCompactCollector::ClearFullMapTransitions() { void MarkCompactCollector::ClearFullMapTransitions() {
HeapObject* undefined = heap()->undefined_value(); HeapObject* undefined = heap()->undefined_value();
...@@ -2983,10 +2999,13 @@ void MarkCompactCollector::ClearFullMapTransitions() { ...@@ -2983,10 +2999,13 @@ void MarkCompactCollector::ClearFullMapTransitions() {
int num_transitions = array->number_of_entries(); int num_transitions = array->number_of_entries();
DCHECK_EQ(TransitionArray::NumberOfTransitions(array), num_transitions); DCHECK_EQ(TransitionArray::NumberOfTransitions(array), num_transitions);
if (num_transitions > 0) { if (num_transitions > 0) {
Map* map = array->GetTarget(0); Map* parent = GetTransitionArrayOwnerMap(heap(), array, num_transitions);
Map* parent = Map::cast(map->constructor_or_backpointer()); if (!parent) {
bool parent_is_alive = // The transition array contains only shortcut transitions.
ObjectMarking::IsBlackOrGrey(parent, MarkingState::Internal(parent)); CompactTransitionArray(parent, array, nullptr);
} else {
bool parent_is_alive = ObjectMarking::IsBlackOrGrey(
parent, MarkingState::Internal(parent));
DescriptorArray* descriptors = DescriptorArray* descriptors =
parent_is_alive ? parent->instance_descriptors() : nullptr; parent_is_alive ? parent->instance_descriptors() : nullptr;
bool descriptors_owner_died = bool descriptors_owner_died =
...@@ -2995,12 +3014,48 @@ void MarkCompactCollector::ClearFullMapTransitions() { ...@@ -2995,12 +3014,48 @@ void MarkCompactCollector::ClearFullMapTransitions() {
TrimDescriptorArray(parent, descriptors); TrimDescriptorArray(parent, descriptors);
} }
} }
}
obj = array->next_link(); obj = array->next_link();
array->set_next_link(undefined, SKIP_WRITE_BARRIER); array->set_next_link(undefined, SKIP_WRITE_BARRIER);
} }
heap()->set_encountered_transition_arrays(Smi::kZero); heap()->set_encountered_transition_arrays(Smi::kZero);
} }
namespace {
// Returns true if the target is live and the transition entry should be kept
// in the transition array. In addition, if current transition entry is a dead
// shortcut transition this function tries to fixup the entry to make it point
// to the next live target in a shortcut chain.
bool FixupDeadTransition(bool is_shortcut_transition, Name* key, Map* target,
TransitionArray* transitions, int transition_index) {
if (!ObjectMarking::IsWhite(target, MarkingState::Internal(target))) {
return true;
}
if (!is_shortcut_transition) {
// Target map is dead.
return false;
}
Symbol* symbol = Symbol::cast(key);
// Follow the shortcut transition chain in order to find live target.
for (;;) {
target = TransitionArray::SearchSpecial(target, symbol);
if (target == nullptr ||
!ObjectMarking::IsWhite(target, MarkingState::Internal(target))) {
break;
}
}
if (target) {
// Found live target in shortcuts chain, now fixup the transitions array.
// Target slots do not need to be recorded since maps are not compacted.
transitions->SetTarget(transition_index, target);
return true;
}
return false;
}
} // namespace
bool MarkCompactCollector::CompactTransitionArray( bool MarkCompactCollector::CompactTransitionArray(
Map* map, TransitionArray* transitions, DescriptorArray* descriptors) { Map* map, TransitionArray* transitions, DescriptorArray* descriptors) {
...@@ -3009,16 +3064,24 @@ bool MarkCompactCollector::CompactTransitionArray( ...@@ -3009,16 +3064,24 @@ bool MarkCompactCollector::CompactTransitionArray(
int transition_index = 0; int transition_index = 0;
// Compact all live transitions to the left. // Compact all live transitions to the left.
for (int i = 0; i < num_transitions; ++i) { for (int i = 0; i < num_transitions; ++i) {
Map* target = transitions->GetTarget(i); Name* key;
DCHECK_EQ(target->constructor_or_backpointer(), map); Map* target;
if (ObjectMarking::IsWhite(target, MarkingState::Internal(target))) { std::tie(key, target) = TransitionArray::GetKeyAndTarget(transitions, i);
if (descriptors != nullptr && bool is_shortcut_transition =
TransitionArray::IsShortcutTransition(heap(), key);
DCHECK_IMPLIES(!is_shortcut_transition,
target->constructor_or_backpointer() == map);
bool is_live_transition = FixupDeadTransition(is_shortcut_transition, key,
target, transitions, i);
if (!is_live_transition) {
if (!is_shortcut_transition && descriptors != nullptr &&
target->instance_descriptors() == descriptors) { target->instance_descriptors() == descriptors) {
descriptors_owner_died = true; descriptors_owner_died = true;
} }
} else { } else {
if (i != transition_index) { if (i != transition_index) {
Name* key = transitions->GetKey(i);
transitions->SetKey(transition_index, key); transitions->SetKey(transition_index, key);
Object** key_slot = transitions->GetKeySlot(transition_index); Object** key_slot = transitions->GetKeySlot(transition_index);
RecordSlot(transitions, key_slot, key); RecordSlot(transitions, key_slot, key);
......
...@@ -1438,7 +1438,7 @@ void KeyedLoadIC::LoadElementPolymorphicHandlers( ...@@ -1438,7 +1438,7 @@ void KeyedLoadIC::LoadElementPolymorphicHandlers(
if (receiver_map->is_stable()) { if (receiver_map->is_stable()) {
Map* tmap = receiver_map->FindElementsKindTransitionedMap(*receiver_maps); Map* tmap = receiver_map->FindElementsKindTransitionedMap(*receiver_maps);
if (tmap != nullptr) { if (tmap != nullptr) {
receiver_map->NotifyLeafMapLayoutChange(); Map::RegisterElementsKindTransitionShortcut(receiver_map, handle(tmap));
} }
} }
handlers->Add(LoadElementHandler(receiver_map)); handlers->Add(LoadElementHandler(receiver_map));
...@@ -2129,10 +2129,9 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers( ...@@ -2129,10 +2129,9 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers(
Map* tmap = Map* tmap =
receiver_map->FindElementsKindTransitionedMap(*receiver_maps); receiver_map->FindElementsKindTransitionedMap(*receiver_maps);
if (tmap != nullptr) { if (tmap != nullptr) {
if (receiver_map->is_stable()) {
receiver_map->NotifyLeafMapLayoutChange();
}
transitioned_map = handle(tmap); transitioned_map = handle(tmap);
Map::RegisterElementsKindTransitionShortcut(receiver_map,
transitioned_map);
} }
} }
......
...@@ -617,7 +617,7 @@ MapUpdater::State MapUpdater::ConstructNewMap() { ...@@ -617,7 +617,7 @@ MapUpdater::State MapUpdater::ConstructNewMap() {
*split_map, split_details.kind(), GetKey(split_nof), *split_map, split_details.kind(), GetKey(split_nof),
split_details.attributes()); split_details.attributes());
if (maybe_transition != NULL) { if (maybe_transition != NULL) {
maybe_transition->DeprecateTransitionTree(); maybe_transition->DeprecateTransitionTree(isolate_);
} }
// If |maybe_transition| is not NULL then the transition array already // If |maybe_transition| is not NULL then the transition array already
......
...@@ -1625,7 +1625,12 @@ static bool CheckOneBackPointer(Map* current_map, Object* target) { ...@@ -1625,7 +1625,12 @@ static bool CheckOneBackPointer(Map* current_map, Object* target) {
// static // static
bool TransitionArray::IsConsistentWithBackPointers(Map* map) { bool TransitionArray::IsConsistentWithBackPointers(Map* map) {
Object* transitions = map->raw_transitions(); Object* transitions = map->raw_transitions();
Heap* heap = map->GetHeap();
for (int i = 0; i < TransitionArray::NumberOfTransitions(transitions); ++i) { for (int i = 0; i < TransitionArray::NumberOfTransitions(transitions); ++i) {
// Back pointers of shortcut transitions don't point to source maps.
Name* name = TransitionArray::GetKey(transitions, i);
if (IsShortcutTransition(heap, name)) continue;
Map* target = TransitionArray::GetTarget(transitions, i); Map* target = TransitionArray::GetTarget(transitions, i);
if (!CheckOneBackPointer(map, target)) return false; if (!CheckOneBackPointer(map, target)) return false;
} }
......
...@@ -3183,6 +3183,11 @@ Handle<Map> Map::AddMissingTransitionsForTesting( ...@@ -3183,6 +3183,11 @@ Handle<Map> Map::AddMissingTransitionsForTesting(
return AddMissingTransitions(split_map, descriptors, full_layout_descriptor); return AddMissingTransitions(split_map, descriptors, full_layout_descriptor);
} }
void Map::InsertElementsKindTransitionShortcutForTesting(
Isolate* isolate, Handle<Map> map, Handle<Map> transition) {
Map::InsertElementsKindTransitionShortcut(isolate, map, transition);
}
int HeapObject::SizeFromMap(Map* map) const { int HeapObject::SizeFromMap(Map* map) const {
int instance_size = map->instance_size(); int instance_size = map->instance_size();
if (instance_size != kVariableSizeSentinel) return instance_size; if (instance_size != kVariableSizeSentinel) return instance_size;
......
...@@ -1706,6 +1706,9 @@ void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions, ...@@ -1706,6 +1706,9 @@ void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions,
} else if (key == heap->elements_transition_symbol()) { } else if (key == heap->elements_transition_symbol()) {
os << "(transition to " << ElementsKindToString(target->elements_kind()) os << "(transition to " << ElementsKindToString(target->elements_kind())
<< ")"; << ")";
} else if (key == heap->elements_transition_shortcut_symbol()) {
os << "(shortcut to " << ElementsKindToString(target->elements_kind())
<< ")";
} else if (key == heap->strict_function_transition_symbol()) { } else if (key == heap->strict_function_transition_symbol()) {
os << " (transition to strict function)"; os << " (transition to strict function)";
} else { } else {
...@@ -1737,8 +1740,7 @@ void TransitionArray::PrintTransitionTree(std::ostream& os, Map* map, ...@@ -1737,8 +1740,7 @@ void TransitionArray::PrintTransitionTree(std::ostream& os, Map* map,
for (int i = 0; i < num_transitions; i++) { for (int i = 0; i < num_transitions; i++) {
Name* key = GetKey(transitions, i); Name* key = GetKey(transitions, i);
Map* target = GetTarget(transitions, i); Map* target = GetTarget(transitions, i);
os << std::endl os << "\n " << level << "/" << i << ":" << std::setw(level * 2 + 2) << " ";
<< " " << level << "/" << i << ":" << std::setw(level * 2 + 2) << " ";
std::stringstream ss; std::stringstream ss;
ss << Brief(target); ss << Brief(target);
os << std::left << std::setw(50) << ss.str() << ": "; os << std::left << std::setw(50) << ss.str() << ": ";
...@@ -1752,17 +1754,21 @@ void TransitionArray::PrintTransitionTree(std::ostream& os, Map* map, ...@@ -1752,17 +1754,21 @@ void TransitionArray::PrintTransitionTree(std::ostream& os, Map* map,
os << "to frozen"; os << "to frozen";
} else if (key == heap->elements_transition_symbol()) { } else if (key == heap->elements_transition_symbol()) {
os << "to " << ElementsKindToString(target->elements_kind()); os << "to " << ElementsKindToString(target->elements_kind());
} else if (key == heap->elements_transition_shortcut_symbol()) {
os << "shortcut to " << ElementsKindToString(target->elements_kind());
// Don't print transitions "through" the transition shortcut.
continue;
} else if (key == heap->strict_function_transition_symbol()) { } else if (key == heap->strict_function_transition_symbol()) {
os << "to strict function"; os << "to strict function";
} else { } else {
DCHECK(!IsSpecialTransition(key));
os << "to ";
#ifdef OBJECT_PRINT #ifdef OBJECT_PRINT
key->NamePrint(os); key->NamePrint(os);
#else #else
key->ShortPrint(os); key->ShortPrint(os);
#endif #endif
os << " "; os << " ";
DCHECK(!IsSpecialTransition(key));
os << "to ";
int descriptor = target->LastAdded(); int descriptor = target->LastAdded();
DescriptorArray* descriptors = target->instance_descriptors(); DescriptorArray* descriptors = target->instance_descriptors();
descriptors->PrintDescriptorDetails(os, descriptor, descriptors->PrintDescriptorDetails(os, descriptor,
......
This diff is collapsed.
...@@ -249,10 +249,11 @@ enum TransitionFlag { ...@@ -249,10 +249,11 @@ enum TransitionFlag {
enum SimpleTransitionFlag { enum SimpleTransitionFlag {
SIMPLE_PROPERTY_TRANSITION, SIMPLE_PROPERTY_TRANSITION,
PROPERTY_TRANSITION, PROPERTY_TRANSITION,
SPECIAL_TRANSITION // Below are the special transitions.
SPECIAL_TRANSITION,
SPECIAL_SHORTCUT_TRANSITION
}; };
// Indicates whether we are only interested in the descriptors of a particular // Indicates whether we are only interested in the descriptors of a particular
// map, or in all descriptors in the descriptor array. // map, or in all descriptors in the descriptor array.
enum DescriptorFlag { enum DescriptorFlag {
......
...@@ -345,11 +345,11 @@ class Map : public HeapObject { ...@@ -345,11 +345,11 @@ class Map : public HeapObject {
Representation new_representation, Representation new_representation,
Handle<FieldType> new_field_type); Handle<FieldType> new_field_type);
static Handle<Map> ReconfigureProperty(Handle<Map> map, int modify_index, static Handle<Map> ReconfigureProperty(
PropertyKind new_kind, Handle<Map> map, int modify_index, PropertyKind new_kind,
PropertyAttributes new_attributes, PropertyAttributes new_attributes, Representation new_representation,
Representation new_representation, Handle<FieldType> new_field_type,
Handle<FieldType> new_field_type); PropertyConstness new_constness = kConst);
static Handle<Map> ReconfigureElementsKind(Handle<Map> map, static Handle<Map> ReconfigureElementsKind(Handle<Map> map,
ElementsKind new_elements_kind); ElementsKind new_elements_kind);
...@@ -495,6 +495,9 @@ class Map : public HeapObject { ...@@ -495,6 +495,9 @@ class Map : public HeapObject {
static Handle<Map> TransitionElementsTo(Handle<Map> map, static Handle<Map> TransitionElementsTo(Handle<Map> map,
ElementsKind to_kind); ElementsKind to_kind);
static void RegisterElementsKindTransitionShortcut(Handle<Map> map,
Handle<Map> transition);
static Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind kind); static Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind kind);
static Handle<Map> CopyAsElementsKind(Handle<Map> map, ElementsKind kind, static Handle<Map> CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
...@@ -744,6 +747,9 @@ class Map : public HeapObject { ...@@ -744,6 +747,9 @@ class Map : public HeapObject {
Handle<Map> split_map, Handle<DescriptorArray> descriptors, Handle<Map> split_map, Handle<DescriptorArray> descriptors,
Handle<LayoutDescriptor> full_layout_descriptor); Handle<LayoutDescriptor> full_layout_descriptor);
static inline void InsertElementsKindTransitionShortcutForTesting(
Isolate* isolate, Handle<Map> map, Handle<Map> transition);
// Fires when the layout of an object with a leaf map changes. // Fires when the layout of an object with a leaf map changes.
// This includes adding transitions to the leaf map or changing // This includes adding transitions to the leaf map or changing
// the descriptor array. // the descriptor array.
...@@ -763,6 +769,12 @@ class Map : public HeapObject { ...@@ -763,6 +769,12 @@ class Map : public HeapObject {
// not found. // not found.
Map* TryReplayPropertyTransitions(Map* map); Map* TryReplayPropertyTransitions(Map* map);
static MaybeHandle<Map> GetTransitionShortcutRemoveDeprecated(
Isolate* isolate, Handle<Map> map, Handle<Symbol> name);
static void InsertElementsKindTransitionShortcut(Isolate* isolate,
Handle<Map> map,
Handle<Map> transition);
static void ConnectTransition(Handle<Map> parent, Handle<Map> child, static void ConnectTransition(Handle<Map> parent, Handle<Map> child,
Handle<Name> name, SimpleTransitionFlag flag); Handle<Name> name, SimpleTransitionFlag flag);
...@@ -802,7 +814,7 @@ class Map : public HeapObject { ...@@ -802,7 +814,7 @@ class Map : public HeapObject {
Handle<Map> map, ElementsKind elements_kind, int modify_index, Handle<Map> map, ElementsKind elements_kind, int modify_index,
PropertyKind kind, PropertyAttributes attributes, const char* reason); PropertyKind kind, PropertyAttributes attributes, const char* reason);
void DeprecateTransitionTree(); void DeprecateTransitionTree(Isolate* isolate);
void ReplaceDescriptors(DescriptorArray* new_descriptors, void ReplaceDescriptors(DescriptorArray* new_descriptors,
LayoutDescriptor* new_layout_descriptor); LayoutDescriptor* new_layout_descriptor);
...@@ -810,7 +822,8 @@ class Map : public HeapObject { ...@@ -810,7 +822,8 @@ class Map : public HeapObject {
// Update field type of the given descriptor to new representation and new // Update field type of the given descriptor to new representation and new
// type. The type must be prepared for storing in descriptor array: // type. The type must be prepared for storing in descriptor array:
// it must be either a simple type or a map wrapped in a weak cell. // it must be either a simple type or a map wrapped in a weak cell.
void UpdateFieldType(int descriptor_number, Handle<Name> name, // Returns true if the elements kind transition shortcut exists.
bool UpdateFieldType(int descriptor_number, Handle<Name> name,
PropertyConstness new_constness, PropertyConstness new_constness,
Representation new_representation, Representation new_representation,
Handle<Object> new_wrapped_type); Handle<Object> new_wrapped_type);
......
...@@ -98,6 +98,18 @@ void TransitionArray::SetTarget(int transition_number, Map* value) { ...@@ -98,6 +98,18 @@ void TransitionArray::SetTarget(int transition_number, Map* value) {
set(ToTargetIndex(transition_number), value); set(ToTargetIndex(transition_number), value);
} }
std::pair<Name*, Map*> TransitionArray::GetKeyAndTarget(Object* raw_transitions,
int transition_number) {
if (IsSimpleTransition(raw_transitions)) {
DCHECK(transition_number == 0);
Map* transition = GetSimpleTransition(raw_transitions);
return std::make_pair(GetSimpleTransitionKey(transition), transition);
}
DCHECK(IsFullTransitionArray(raw_transitions));
TransitionArray* transition_array = TransitionArray::cast(raw_transitions);
return std::make_pair(transition_array->GetKey(transition_number),
transition_array->GetTarget(transition_number));
}
int TransitionArray::SearchName(Name* name, int* out_insertion_index) { int TransitionArray::SearchName(Name* name, int* out_insertion_index) {
DCHECK(name->IsUniqueName()); DCHECK(name->IsUniqueName());
...@@ -112,9 +124,17 @@ bool TransitionArray::IsSpecialTransition(Name* name) { ...@@ -112,9 +124,17 @@ bool TransitionArray::IsSpecialTransition(Name* name) {
return name == heap->nonextensible_symbol() || return name == heap->nonextensible_symbol() ||
name == heap->sealed_symbol() || name == heap->frozen_symbol() || name == heap->sealed_symbol() || name == heap->frozen_symbol() ||
name == heap->elements_transition_symbol() || name == heap->elements_transition_symbol() ||
name == heap->elements_transition_shortcut_symbol() ||
name == heap->strict_function_transition_symbol(); name == heap->strict_function_transition_symbol();
} }
bool TransitionArray::IsShortcutTransition(Name* name) {
return IsShortcutTransition(name->GetHeap(), name);
}
bool TransitionArray::IsShortcutTransition(Heap* heap, Name* name) {
return name == heap->elements_transition_shortcut_symbol();
}
int TransitionArray::CompareKeys(Name* key1, uint32_t hash1, PropertyKind kind1, int TransitionArray::CompareKeys(Name* key1, uint32_t hash1, PropertyKind kind1,
PropertyAttributes attributes1, Name* key2, PropertyAttributes attributes1, Name* key2,
......
...@@ -16,7 +16,9 @@ namespace internal { ...@@ -16,7 +16,9 @@ namespace internal {
void TransitionArray::Insert(Handle<Map> map, Handle<Name> name, void TransitionArray::Insert(Handle<Map> map, Handle<Name> name,
Handle<Map> target, SimpleTransitionFlag flag) { Handle<Map> target, SimpleTransitionFlag flag) {
Isolate* isolate = map->GetIsolate(); Isolate* isolate = map->GetIsolate();
if (flag != SPECIAL_SHORTCUT_TRANSITION) {
target->SetBackPointer(*map); target->SetBackPointer(*map);
}
// If the map doesn't have any transitions at all yet, install the new one. // If the map doesn't have any transitions at all yet, install the new one.
if (CanStoreSimpleTransition(map->raw_transitions())) { if (CanStoreSimpleTransition(map->raw_transitions())) {
...@@ -30,7 +32,7 @@ void TransitionArray::Insert(Handle<Map> map, Handle<Name> name, ...@@ -30,7 +32,7 @@ void TransitionArray::Insert(Handle<Map> map, Handle<Name> name,
ReplaceTransitions(map, *result); ReplaceTransitions(map, *result);
} }
bool is_special_transition = flag == SPECIAL_TRANSITION; bool is_special_transition = flag >= SPECIAL_TRANSITION;
// If the map has a simple transition, check if it should be overwritten. // If the map has a simple transition, check if it should be overwritten.
if (IsSimpleTransition(map->raw_transitions())) { if (IsSimpleTransition(map->raw_transitions())) {
Map* old_target = GetSimpleTransition(map->raw_transitions()); Map* old_target = GetSimpleTransition(map->raw_transitions());
......
...@@ -153,6 +153,9 @@ class TransitionArray: public FixedArray { ...@@ -153,6 +153,9 @@ class TransitionArray: public FixedArray {
inline Map* GetTarget(int transition_number); inline Map* GetTarget(int transition_number);
inline void SetTarget(int transition_number, Map* target); inline void SetTarget(int transition_number, Map* target);
static inline std::pair<Name*, Map*> GetKeyAndTarget(Object* raw_transitions,
int transition_number);
static inline PropertyDetails GetTargetDetails(Name* name, Map* target); static inline PropertyDetails GetTargetDetails(Name* name, Map* target);
// Returns the number of transitions in the array. // Returns the number of transitions in the array.
...@@ -204,6 +207,10 @@ class TransitionArray: public FixedArray { ...@@ -204,6 +207,10 @@ class TransitionArray: public FixedArray {
// or frozen transitions. // or frozen transitions.
static inline bool IsSpecialTransition(Name* name); static inline bool IsSpecialTransition(Name* name);
// Returns true for shortcut transitions.
static inline bool IsShortcutTransition(Name* name);
static inline bool IsShortcutTransition(Heap* heap, Name* name);
// Constant for denoting key was not found. // Constant for denoting key was not found.
static const int kNotFound = -1; static const int kNotFound = -1;
......
This diff is collapsed.
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --verify-heap --allow-natives-syntax --expose-gc
let constant = { a: 1 };
function update_array(array) {
array.x = constant;
%HeapObjectVerify(array);
array[0] = undefined;
%HeapObjectVerify(array);
return array;
}
let ar1 = [1];
let ar2 = [2];
let ar3 = [3];
gc();
gc();
update_array(ar1);
constant = update_array(ar2);
update_array(ar3);
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-gc --throws
TypeError.prototype.__defineGetter__("name", function() {
this[1] = {};
gc();
new Uint16Array().reduceRight();
});
var v = WebAssembly.compile();
new TypeError().toString();
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
function f(v) {
v.x = 0;
v[1] = 0.1;
v.x = {};
}
f({});
f(new Array(1));
f(new Array(1));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment