aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/ic/keyed-store-generic.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/ic/keyed-store-generic.cc')
-rw-r--r--deps/v8/src/ic/keyed-store-generic.cc306
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, &not_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(&not_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