diff options
Diffstat (limited to 'deps/v8/src/ic/keyed-store-generic.cc')
-rw-r--r-- | deps/v8/src/ic/keyed-store-generic.cc | 306 |
1 files changed, 232 insertions, 74 deletions
diff --git a/deps/v8/src/ic/keyed-store-generic.cc b/deps/v8/src/ic/keyed-store-generic.cc index 23c49c8d73..2b2f15bb82 100644 --- a/deps/v8/src/ic/keyed-store-generic.cc +++ b/deps/v8/src/ic/keyed-store-generic.cc @@ -43,6 +43,18 @@ class KeyedStoreGenericAssembler : public AccessorAssembler { TNode<Object> key, TNode<Object> value, LanguageMode language_mode); + // Set an own property + void SetPropertyInLiteral(TNode<Context> context, TNode<JSObject> receiver, + TNode<Map> map, TNode<Name> key, + TNode<Object> value) { + Label done(this); + ExitPoint exit_point(this, + [this, &done](Node* result) { this->Goto(&done); }); + EmitGenericPropertyStoreInLiteral(context, receiver, map, key, value, + &exit_point); + BIND(&done); + } + private: enum UpdateLength { kDontChangeLength, @@ -78,6 +90,12 @@ class KeyedStoreGenericAssembler : public AccessorAssembler { Nothing<LanguageMode>()); } + void EmitGenericPropertyStoreInLiteral(TNode<Context> context, + TNode<JSObject> receiver, + TNode<Map> map, TNode<Name> key, + TNode<Object> value, + ExitPoint* exit_point); + void BranchIfPrototypesHaveNonFastElements(Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements); @@ -111,6 +129,10 @@ class KeyedStoreGenericAssembler : public AccessorAssembler { Variable* var_accessor_pair, Variable* var_accessor_holder, Label* readonly, Label* bailout); + + TNode<Map> FindCandidateStoreICTransitionMapHandler(TNode<Map> map, + TNode<Name> name, + Label* slow); }; void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state) { @@ -141,6 +163,14 @@ void KeyedStoreGenericGenerator::SetProperty( assembler.SetProperty(context, receiver, key, value, language_mode); } +void KeyedStoreGenericGenerator::SetPropertyInLiteral( + compiler::CodeAssemblerState* state, TNode<Context> context, + TNode<JSObject> receiver, TNode<Name> key, TNode<Object> value) { + KeyedStoreGenericAssembler assembler(state); + TNode<Map> map = assembler.LoadMap(receiver); + assembler.SetPropertyInLiteral(context, receiver, map, key, value); +} + void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements( Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements) { VARIABLE(var_map, MachineRepresentation::kTagged); @@ -294,7 +324,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( Label check_double_elements(this), check_cow_elements(this); Node* elements_map = LoadMap(elements); - GotoIf(WordNotEqual(elements_map, LoadRoot(Heap::kFixedArrayMapRootIndex)), + GotoIf(WordNotEqual(elements_map, LoadRoot(RootIndex::kFixedArrayMap)), &check_double_elements); // FixedArray backing store -> Smi or object elements. @@ -355,7 +385,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( { Label transition_to_double(this), transition_to_object(this); Node* native_context = LoadNativeContext(context); - Branch(WordEqual(LoadMap(value), LoadRoot(Heap::kHeapNumberMapRootIndex)), + Branch(WordEqual(LoadMap(value), LoadRoot(RootIndex::kHeapNumberMap)), &transition_to_double, &transition_to_object); BIND(&transition_to_double); { @@ -398,7 +428,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( } BIND(&check_double_elements); - Node* fixed_double_array_map = LoadRoot(Heap::kFixedDoubleArrayMapRootIndex); + Node* fixed_double_array_map = LoadRoot(RootIndex::kFixedDoubleArrayMap); GotoIf(WordNotEqual(elements_map, fixed_double_array_map), &check_cow_elements); // FixedDoubleArray backing store -> double elements. @@ -656,6 +686,71 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( BIND(&ok_to_write); } +TNode<Map> KeyedStoreGenericAssembler::FindCandidateStoreICTransitionMapHandler( + TNode<Map> map, TNode<Name> name, Label* slow) { + TVARIABLE(Map, var_transition_map); + Label simple_transition(this), transition_array(this), + found_handler_candidate(this); + + TNode<MaybeObject> maybe_handler = + LoadMaybeWeakObjectField(map, Map::kTransitionsOrPrototypeInfoOffset); + + // Smi -> slow, + // Cleared weak reference -> slow + // weak reference -> simple_transition + // strong reference -> transition_array + TVARIABLE(Object, var_transition_map_or_array); + DispatchMaybeObject(maybe_handler, slow, slow, &simple_transition, + &transition_array, &var_transition_map_or_array); + + BIND(&simple_transition); + { + var_transition_map = CAST(var_transition_map_or_array.value()); + Goto(&found_handler_candidate); + } + + BIND(&transition_array); + { + TNode<Map> maybe_handler_map = + LoadMap(CAST(var_transition_map_or_array.value())); + GotoIfNot(IsTransitionArrayMap(maybe_handler_map), slow); + + TVARIABLE(IntPtrT, var_name_index); + Label if_found_candidate(this); + TNode<TransitionArray> transitions = + CAST(var_transition_map_or_array.value()); + TransitionLookup(name, transitions, &if_found_candidate, &var_name_index, + slow); + + BIND(&if_found_candidate); + { + // Given that + // 1) transitions with the same name are ordered in the transition + // array by PropertyKind and then by PropertyAttributes values, + // 2) kData < kAccessor, + // 3) NONE == 0, + // 4) properties with private symbol names are guaranteed to be + // non-enumerable (so DONT_ENUM bit in attributes is always set), + // the resulting map of transitioning store if it exists in the + // transition array is expected to be the first among the transitions + // with the same name. + // See TransitionArray::CompareDetails() for details. + STATIC_ASSERT(kData == 0); + STATIC_ASSERT(NONE == 0); + const int kKeyToTargetOffset = (TransitionArray::kEntryTargetIndex - + TransitionArray::kEntryKeyIndex) * + kPointerSize; + var_transition_map = CAST(GetHeapObjectAssumeWeak( + LoadArrayElement(transitions, WeakFixedArray::kHeaderSize, + var_name_index.value(), kKeyToTargetOffset))); + Goto(&found_handler_candidate); + } + } + + BIND(&found_handler_candidate); + return var_transition_map.value(); +} + void KeyedStoreGenericAssembler::EmitGenericPropertyStore( TNode<JSReceiver> receiver, TNode<Map> receiver_map, const StoreICParameters* p, ExitPoint* exit_point, Label* slow, @@ -705,71 +800,15 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( BIND(&lookup_transition); { Comment("lookup transition"); - TVARIABLE(Map, var_transition_map); - Label simple_transition(this), transition_array(this), - found_handler_candidate(this); - TNode<MaybeObject> maybe_handler = LoadMaybeWeakObjectField( - receiver_map, Map::kTransitionsOrPrototypeInfoOffset); - - // SMI -> slow - // cleared weak reference -> slow - // weak reference -> simple_transition - // strong reference -> transition_array - TVARIABLE(Object, var_transition_map_or_array); - DispatchMaybeObject(maybe_handler, slow, slow, &simple_transition, - &transition_array, &var_transition_map_or_array); - - BIND(&simple_transition); - { - var_transition_map = CAST(var_transition_map_or_array.value()); - Goto(&found_handler_candidate); - } - - BIND(&transition_array); - { - TNode<Map> maybe_handler_map = - LoadMap(CAST(var_transition_map_or_array.value())); - GotoIfNot(IsTransitionArrayMap(maybe_handler_map), slow); - - TVARIABLE(IntPtrT, var_name_index); - Label if_found_candidate(this); - TNode<TransitionArray> transitions = - CAST(var_transition_map_or_array.value()); - TransitionLookup(p->name, transitions, &if_found_candidate, - &var_name_index, slow); - - BIND(&if_found_candidate); - { - // Given that - // 1) transitions with the same name are ordered in the transition - // array by PropertyKind and then by PropertyAttributes values, - // 2) kData < kAccessor, - // 3) NONE == 0, - // 4) properties with private symbol names are guaranteed to be - // non-enumerable (so DONT_ENUM bit in attributes is always set), - // the resulting map of transitioning store if it exists in the - // transition array is expected to be the first among the transitions - // with the same name. - // See TransitionArray::CompareDetails() for details. - STATIC_ASSERT(kData == 0); - STATIC_ASSERT(NONE == 0); - const int kKeyToTargetOffset = (TransitionArray::kEntryTargetIndex - - TransitionArray::kEntryKeyIndex) * - kPointerSize; - var_transition_map = CAST(ToWeakHeapObject( - LoadArrayElement(transitions, WeakFixedArray::kHeaderSize, - var_name_index.value(), kKeyToTargetOffset))); - Goto(&found_handler_candidate); - } - } - - BIND(&found_handler_candidate); - { - // Validate the transition handler candidate and apply the transition. - HandleStoreICTransitionMapHandlerCase(p, var_transition_map.value(), - slow, true); - exit_point->Return(p->value); - } + TNode<Map> transition_map = FindCandidateStoreICTransitionMapHandler( + receiver_map, CAST(p->name), slow); + + // Validate the transition handler candidate and apply the transition. + HandleStoreICTransitionMapHandlerCase( + p, transition_map, slow, + StoreTransitionMapFlags(kCheckPrototypeValidity | + kValidateTransitionHandler)); + exit_point->Return(p->value); } } @@ -952,7 +991,7 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric( { Comment("KeyedStoreGeneric_slow"); if (language_mode.IsJust()) { - TailCallRuntime(Runtime::kSetProperty, context, receiver, key, value, + TailCallRuntime(Runtime::kSetKeyedProperty, context, receiver, key, value, SmiConstant(language_mode.FromJust())); } else { TVARIABLE(Smi, var_language_mode, SmiConstant(LanguageMode::kStrict)); @@ -961,7 +1000,7 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric( var_language_mode = SmiConstant(LanguageMode::kSloppy); Goto(&call_runtime); BIND(&call_runtime); - TailCallRuntime(Runtime::kSetProperty, context, receiver, key, value, + TailCallRuntime(Runtime::kSetKeyedProperty, context, receiver, key, value, var_language_mode.value()); } } @@ -1011,7 +1050,7 @@ void KeyedStoreGenericAssembler::StoreIC_Uninitialized() { // Optimistically write the state transition to the vector. StoreFeedbackVectorSlot(vector, slot, - LoadRoot(Heap::kpremonomorphic_symbolRootIndex), + LoadRoot(RootIndex::kpremonomorphic_symbol), SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS); StoreICParameters p(context, receiver, name, value, slot, vector); @@ -1021,7 +1060,7 @@ void KeyedStoreGenericAssembler::StoreIC_Uninitialized() { { // Undo the optimistic state transition. StoreFeedbackVectorSlot(vector, slot, - LoadRoot(Heap::kuninitialized_symbolRootIndex), + LoadRoot(RootIndex::kuninitialized_symbol), SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS); TailCallRuntime(Runtime::kStoreIC_Miss, context, value, slot, vector, receiver, name); @@ -1048,13 +1087,132 @@ void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context, BIND(&slow); { - CallRuntime(Runtime::kSetProperty, context, receiver, unique_name, value, - SmiConstant(language_mode)); + CallRuntime(Runtime::kSetKeyedProperty, context, receiver, unique_name, + value, SmiConstant(language_mode)); Goto(&done); } BIND(&done); } +// Sets data properties as in PropertyDefinitionEvaluation --- Does not invoke +// own setters or traverse the prototype chain. +void KeyedStoreGenericAssembler::EmitGenericPropertyStoreInLiteral( + TNode<Context> context, TNode<JSObject> receiver, TNode<Map> map, + TNode<Name> key, TNode<Object> value, ExitPoint* exit_point) { + CSA_ASSERT(this, IsSimpleObjectMap(map)); + + // This should only be used for storing data properties in object literals. + CSA_ASSERT(this, HasInstanceType(receiver, JS_OBJECT_TYPE)); + + Label stub_cache(this), fast_properties(this), dictionary_properties(this), + accessor(this), call_runtime(this, Label::kDeferred), done(this); + TNode<Uint32T> bit_field3 = LoadMapBitField3(map); + Branch(IsSetWord32<Map::IsDictionaryMapBit>(bit_field3), + &dictionary_properties, &fast_properties); + + BIND(&fast_properties); + { + Comment("fast property store"); + TNode<DescriptorArray> descriptors = LoadMapDescriptors(map); + Label descriptor_found(this), lookup_transition(this); + + TVARIABLE(IntPtrT, var_name_index); + DescriptorLookup(key, descriptors, bit_field3, &descriptor_found, + &var_name_index, &lookup_transition); + + BIND(&descriptor_found); + { + TNode<IntPtrT> name_index = var_name_index.value(); + TNode<Uint32T> details = LoadDetailsByKeyIndex(descriptors, name_index); + Label data_property(this); + JumpIfDataProperty(details, &data_property, nullptr); + + // Reconfigure the accessor to a data property via runtime call. + // TODO(caitp): reconfigure the property details inlinr here. + Goto(&call_runtime); + + BIND(&data_property); + { + // TODO(caitp): consider only checking for names associated with + // protectors that can apply to non-prototype JSObjects (currently, only + // [Symbol.isConcatSpreadable]), and request this behaviour with an + // enum parameter. + CheckForAssociatedProtector(key, &call_runtime); + OverwriteExistingFastDataProperty(receiver, map, descriptors, + name_index, details, value, + &call_runtime, false); + exit_point->Return(value); + } + } + + BIND(&lookup_transition); + { + Comment("lookup transition"); + TNode<Map> transition_map = + FindCandidateStoreICTransitionMapHandler(map, key, &call_runtime); + + // Validate the transition handler candidate and apply the transition. + StoreICParameters p(context, receiver, key, value, nullptr, nullptr); + HandleStoreICTransitionMapHandlerCase(&p, transition_map, &call_runtime, + kValidateTransitionHandler); + exit_point->Return(value); + } + } + + BIND(&dictionary_properties); + { + Comment("dictionary property store"); + TVARIABLE(IntPtrT, var_name_index); + Label dictionary_found(this, &var_name_index), not_found(this); + TNode<NameDictionary> properties = CAST(LoadSlowProperties(receiver)); + NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found, + &var_name_index, ¬_found); + BIND(&dictionary_found); + { + Label overwrite(this); + TNode<Uint32T> details = LoadDetailsByKeyIndex<NameDictionary>( + properties, var_name_index.value()); + JumpIfDataProperty(details, &overwrite, nullptr); + + // Reconfigure the accessor to a data property via runtime call. + Goto(&call_runtime); + + BIND(&overwrite); + { + // See above TODO regarding non-pertinent checks + CheckForAssociatedProtector(key, &call_runtime); + StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(), + value); + exit_point->Return(value); + } + } + + BIND(¬_found); + { + // See above TODO regarding non-pertinent checks + CheckForAssociatedProtector(key, &call_runtime); + + // This method should always be invoked on a new JSObject literal --- + // it should be impossible for the object to be made non-extensible, or to + // be a prototype map/ + CSA_ASSERT(this, IsExtensibleNonPrototypeMap(map)); + + Label add_dictionary_property_slow(this); + Add<NameDictionary>(properties, key, value, + &add_dictionary_property_slow); + exit_point->Return(value); + + BIND(&add_dictionary_property_slow); + exit_point->ReturnCallRuntime(Runtime::kAddDictionaryProperty, context, + receiver, key, value); + } + } + + BIND(&call_runtime); + exit_point->ReturnCallRuntime(Runtime::kStoreDataPropertyInLiteral, context, + receiver, key, value); +} + } // namespace internal } // namespace v8 |