| Index: src/objects-inl.h
|
| diff --git a/src/objects-inl.h b/src/objects-inl.h
|
| index 41bf13e265cc22f3d39b99983bf85b405f5efa53..a5b2b352d79174ac87f08b4f6bc2d6e5f349f3a9 100644
|
| --- a/src/objects-inl.h
|
| +++ b/src/objects-inl.h
|
| @@ -1874,6 +1874,41 @@
|
| void JSObject::initialize_elements() {
|
| FixedArrayBase* elements = map()->GetInitialElements();
|
| WRITE_FIELD(this, kElementsOffset, elements);
|
| +}
|
| +
|
| +
|
| +Handle<String> Map::ExpectedTransitionKey(Handle<Map> map) {
|
| + DisallowHeapAllocation no_gc;
|
| + if (!map->HasTransitionArray()) return Handle<String>::null();
|
| + TransitionArray* transitions = map->transitions();
|
| + if (!transitions->IsSimpleTransition()) return Handle<String>::null();
|
| + int transition = TransitionArray::kSimpleTransitionIndex;
|
| + PropertyDetails details = transitions->GetTargetDetails(transition);
|
| + Name* name = transitions->GetKey(transition);
|
| + if (details.type() != DATA) return Handle<String>::null();
|
| + if (details.attributes() != NONE) return Handle<String>::null();
|
| + if (!name->IsString()) return Handle<String>::null();
|
| + return Handle<String>(String::cast(name));
|
| +}
|
| +
|
| +
|
| +Handle<Map> Map::ExpectedTransitionTarget(Handle<Map> map) {
|
| + DCHECK(!ExpectedTransitionKey(map).is_null());
|
| + return Handle<Map>(map->transitions()->GetTarget(
|
| + TransitionArray::kSimpleTransitionIndex));
|
| +}
|
| +
|
| +
|
| +Handle<Map> Map::FindTransitionToField(Handle<Map> map, Handle<Name> key) {
|
| + DisallowHeapAllocation no_allocation;
|
| + if (!map->HasTransitionArray()) return Handle<Map>::null();
|
| + TransitionArray* transitions = map->transitions();
|
| + int transition = transitions->Search(kData, *key, NONE);
|
| + if (transition == TransitionArray::kNotFound) return Handle<Map>::null();
|
| + PropertyDetails details = transitions->GetTargetDetails(transition);
|
| + if (details.type() != DATA) return Handle<Map>::null();
|
| + DCHECK_EQ(NONE, details.attributes());
|
| + return Handle<Map>(transitions->GetTarget(transition));
|
| }
|
|
|
|
|
| @@ -3002,7 +3037,7 @@
|
| return empty_array;
|
| } else if (has_fixed_typed_array_elements()) {
|
| FixedTypedArrayBase* empty_array =
|
| - GetHeap()->EmptyFixedTypedArrayForMap(this);
|
| + GetHeap()->EmptyFixedTypedArrayForMap(this);
|
| DCHECK(!GetHeap()->InNewSpace(empty_array));
|
| return empty_array;
|
| } else {
|
| @@ -5220,6 +5255,22 @@
|
| }
|
|
|
|
|
| +// If the descriptor is using the empty transition array, install a new empty
|
| +// transition array that will have place for an element transition.
|
| +static void EnsureHasTransitionArray(Handle<Map> map) {
|
| + Handle<TransitionArray> transitions;
|
| + if (!map->HasTransitionArray()) {
|
| + transitions = TransitionArray::Allocate(map->GetIsolate(), 0);
|
| + transitions->set_back_pointer_storage(map->GetBackPointer());
|
| + } else if (!map->transitions()->IsFullTransitionArray()) {
|
| + transitions = TransitionArray::ExtendToFullTransitionArray(map);
|
| + } else {
|
| + return;
|
| + }
|
| + map->set_transitions(*transitions);
|
| +}
|
| +
|
| +
|
| LayoutDescriptor* Map::layout_descriptor_gc_safe() {
|
| Object* layout_desc = READ_FIELD(this, kLayoutDecriptorOffset);
|
| return LayoutDescriptor::cast_gc_safe(layout_desc);
|
| @@ -5322,13 +5373,127 @@
|
| }
|
|
|
|
|
| -Map* Map::ElementsTransitionMap() {
|
| - return TransitionArray::SearchSpecial(
|
| - this, GetHeap()->elements_transition_symbol());
|
| -}
|
| -
|
| -
|
| -ACCESSORS(Map, raw_transitions, Object, kTransitionsOffset)
|
| +bool Map::HasElementsTransition() {
|
| + return HasTransitionArray() && transitions()->HasElementsTransition();
|
| +}
|
| +
|
| +
|
| +bool Map::HasTransitionArray() const {
|
| + Object* object = READ_FIELD(this, kTransitionsOffset);
|
| + return object->IsTransitionArray();
|
| +}
|
| +
|
| +
|
| +Map* Map::elements_transition_map() {
|
| + int index =
|
| + transitions()->SearchSpecial(GetHeap()->elements_transition_symbol());
|
| + return transitions()->GetTarget(index);
|
| +}
|
| +
|
| +
|
| +bool Map::CanHaveMoreTransitions() {
|
| + if (!HasTransitionArray()) return true;
|
| + return transitions()->number_of_transitions() <
|
| + TransitionArray::kMaxNumberOfTransitions;
|
| +}
|
| +
|
| +
|
| +Map* Map::GetTransition(int transition_index) {
|
| + return transitions()->GetTarget(transition_index);
|
| +}
|
| +
|
| +
|
| +int Map::SearchSpecialTransition(Symbol* name) {
|
| + if (HasTransitionArray()) {
|
| + return transitions()->SearchSpecial(name);
|
| + }
|
| + return TransitionArray::kNotFound;
|
| +}
|
| +
|
| +
|
| +int Map::SearchTransition(PropertyKind kind, Name* name,
|
| + PropertyAttributes attributes) {
|
| + if (HasTransitionArray()) {
|
| + return transitions()->Search(kind, name, attributes);
|
| + }
|
| + return TransitionArray::kNotFound;
|
| +}
|
| +
|
| +
|
| +FixedArray* Map::GetPrototypeTransitions() {
|
| + if (!HasTransitionArray()) return GetHeap()->empty_fixed_array();
|
| + if (!transitions()->HasPrototypeTransitions()) {
|
| + return GetHeap()->empty_fixed_array();
|
| + }
|
| + return transitions()->GetPrototypeTransitions();
|
| +}
|
| +
|
| +
|
| +void Map::SetPrototypeTransitions(
|
| + Handle<Map> map, Handle<FixedArray> proto_transitions) {
|
| + EnsureHasTransitionArray(map);
|
| + int old_number_of_transitions = map->NumberOfProtoTransitions();
|
| + if (Heap::ShouldZapGarbage() && map->HasPrototypeTransitions()) {
|
| + DCHECK(map->GetPrototypeTransitions() != *proto_transitions);
|
| + map->ZapPrototypeTransitions();
|
| + }
|
| + map->transitions()->SetPrototypeTransitions(*proto_transitions);
|
| + map->SetNumberOfProtoTransitions(old_number_of_transitions);
|
| +}
|
| +
|
| +
|
| +bool Map::HasPrototypeTransitions() {
|
| + return HasTransitionArray() && transitions()->HasPrototypeTransitions();
|
| +}
|
| +
|
| +
|
| +TransitionArray* Map::transitions() const {
|
| + DCHECK(HasTransitionArray());
|
| + Object* object = READ_FIELD(this, kTransitionsOffset);
|
| + return TransitionArray::cast(object);
|
| +}
|
| +
|
| +
|
| +void Map::set_transitions(TransitionArray* transition_array,
|
| + WriteBarrierMode mode) {
|
| + // Transition arrays are not shared. When one is replaced, it should not
|
| + // keep referenced objects alive, so we zap it.
|
| + // When there is another reference to the array somewhere (e.g. a handle),
|
| + // not zapping turns from a waste of memory into a source of crashes.
|
| + if (HasTransitionArray()) {
|
| +#ifdef DEBUG
|
| + for (int i = 0; i < transitions()->number_of_transitions(); i++) {
|
| + Map* target = transitions()->GetTarget(i);
|
| + if (target->instance_descriptors() == instance_descriptors()) {
|
| + Name* key = transitions()->GetKey(i);
|
| + int new_target_index;
|
| + if (TransitionArray::IsSpecialTransition(key)) {
|
| + new_target_index = transition_array->SearchSpecial(Symbol::cast(key));
|
| + } else {
|
| + PropertyDetails details =
|
| + TransitionArray::GetTargetDetails(key, target);
|
| + new_target_index = transition_array->Search(details.kind(), key,
|
| + details.attributes());
|
| + }
|
| + DCHECK_NE(TransitionArray::kNotFound, new_target_index);
|
| + DCHECK_EQ(target, transition_array->GetTarget(new_target_index));
|
| + }
|
| + }
|
| +#endif
|
| + DCHECK(transitions() != transition_array);
|
| + ZapTransitions();
|
| + }
|
| +
|
| + WRITE_FIELD(this, kTransitionsOffset, transition_array);
|
| + CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kTransitionsOffset,
|
| + transition_array, mode);
|
| +}
|
| +
|
| +
|
| +void Map::init_transitions(Object* undefined) {
|
| + DCHECK(undefined->IsUndefined());
|
| + WRITE_FIELD(this, kTransitionsOffset, undefined);
|
| +}
|
|
|
|
|
| void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
|
| @@ -5347,7 +5512,6 @@
|
| ACCESSORS(Map, constructor_or_backpointer, Object,
|
| kConstructorOrBackPointerOffset)
|
|
|
| -
|
| Object* Map::GetConstructor() const {
|
| Object* maybe_constructor = constructor_or_backpointer();
|
| // Follow any back pointers.
|
| @@ -5357,14 +5521,11 @@
|
| }
|
| return maybe_constructor;
|
| }
|
| -
|
| -
|
| void Map::SetConstructor(Object* constructor, WriteBarrierMode mode) {
|
| // Never overwrite a back pointer with a constructor.
|
| DCHECK(!constructor_or_backpointer()->IsMap());
|
| set_constructor_or_backpointer(constructor, mode);
|
| }
|
| -
|
|
|
| ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
|
| ACCESSORS(JSFunction, literals_or_bindings, FixedArray, kLiteralsOffset)
|
|
|