diff options
author | Michaël Zasso <targos@protonmail.com> | 2018-12-04 08:20:37 +0100 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2018-12-06 15:23:33 +0100 |
commit | 9b4bf7de6c9a7c25f116c7a502384c20b5cfaea3 (patch) | |
tree | 2b0c843168dafb939d8df8a15b2aa72b76dee51d /deps/v8/src/ic | |
parent | b8fbe69db1292307adb2c2b2e0d5ef48c4ab2faf (diff) | |
download | android-node-v8-9b4bf7de6c9a7c25f116c7a502384c20b5cfaea3.tar.gz android-node-v8-9b4bf7de6c9a7c25f116c7a502384c20b5cfaea3.tar.bz2 android-node-v8-9b4bf7de6c9a7c25f116c7a502384c20b5cfaea3.zip |
deps: update V8 to 7.1.302.28
PR-URL: https://github.com/nodejs/node/pull/23423
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Diffstat (limited to 'deps/v8/src/ic')
-rw-r--r-- | deps/v8/src/ic/accessor-assembler.cc | 383 | ||||
-rw-r--r-- | deps/v8/src/ic/accessor-assembler.h | 14 | ||||
-rw-r--r-- | deps/v8/src/ic/binary-op-assembler.cc | 5 | ||||
-rw-r--r-- | deps/v8/src/ic/call-optimization.h | 2 | ||||
-rw-r--r-- | deps/v8/src/ic/handler-configuration.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/ic/handler-configuration.h | 2 | ||||
-rw-r--r-- | deps/v8/src/ic/ic-inl.h | 7 | ||||
-rw-r--r-- | deps/v8/src/ic/ic-stats.cc | 2 | ||||
-rw-r--r-- | deps/v8/src/ic/ic.cc | 60 | ||||
-rw-r--r-- | deps/v8/src/ic/ic.h | 11 | ||||
-rw-r--r-- | deps/v8/src/ic/keyed-store-generic.cc | 306 | ||||
-rw-r--r-- | deps/v8/src/ic/keyed-store-generic.h | 5 |
12 files changed, 562 insertions, 239 deletions
diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc index 0b5e58b92e..f730c50555 100644 --- a/deps/v8/src/ic/accessor-assembler.cc +++ b/deps/v8/src/ic/accessor-assembler.cc @@ -4,11 +4,13 @@ #include "src/ic/accessor-assembler.h" +#include "src/ast/ast.h" #include "src/code-factory.h" #include "src/code-stubs.h" #include "src/counters.h" #include "src/ic/handler-configuration.h" #include "src/ic/ic.h" +#include "src/ic/keyed-store-generic.h" #include "src/ic/stub-cache.h" #include "src/objects-inl.h" #include "src/objects/module.h" @@ -127,7 +129,7 @@ void AccessorAssembler::HandlePolymorphicCase( Label next_entry(this); TNode<MaybeObject> maybe_cached_map = LoadWeakFixedArrayElement(feedback, map_index); - CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_cached_map)); + CSA_ASSERT(this, IsWeakOrCleared(maybe_cached_map)); GotoIf(IsNotWeakReferenceTo(maybe_cached_map, CAST(receiver_map)), &next_entry); @@ -151,7 +153,7 @@ void AccessorAssembler::HandlePolymorphicCase( Label next_entry(this); TNode<MaybeObject> maybe_cached_map = LoadWeakFixedArrayElement(feedback, index); - CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_cached_map)); + CSA_ASSERT(this, IsWeakOrCleared(maybe_cached_map)); GotoIf(IsNotWeakReferenceTo(maybe_cached_map, CAST(receiver_map)), &next_entry); @@ -241,9 +243,9 @@ void AccessorAssembler::HandleLoadAccessor( [=] { return LoadHandlerDataField(handler, 3); }, [=] { return LoadHandlerDataField(handler, 2); }); - CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_context)); - CSA_CHECK(this, IsNotClearedWeakHeapObject(maybe_context)); - TNode<Object> context = ToWeakHeapObject(maybe_context); + CSA_ASSERT(this, IsWeakOrCleared(maybe_context)); + CSA_CHECK(this, IsNotCleared(maybe_context)); + TNode<Object> context = GetHeapObjectAssumeWeak(maybe_context); GotoIf(IsRuntimeCallStatsEnabled(), &runtime); { @@ -700,8 +702,9 @@ Node* AccessorAssembler::HandleProtoHandler( BIND(&if_do_access_check); { TNode<MaybeObject> data2 = LoadHandlerDataField(handler, 2); - CSA_ASSERT(this, IsWeakOrClearedHeapObject(data2)); - TNode<Object> expected_native_context = ToWeakHeapObject(data2, miss); + CSA_ASSERT(this, IsWeakOrCleared(data2)); + TNode<Object> expected_native_context = + GetHeapObjectAssumeWeak(data2, miss); EmitAccessCheck(expected_native_context, p->context, p->receiver, &done, miss); } @@ -773,8 +776,8 @@ void AccessorAssembler::HandleLoadICProtoHandler( // For regular holders, having passed the receiver map check and the // validity cell check implies that |holder| is alive. However, for global // object receivers, |maybe_holder| may be cleared. - CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_holder)); - Node* holder = ToWeakHeapObject(maybe_holder, miss); + CSA_ASSERT(this, IsWeakOrCleared(maybe_holder)); + Node* holder = GetHeapObjectAssumeWeak(maybe_holder, miss); var_holder->Bind(holder); Goto(&done); @@ -807,9 +810,14 @@ void AccessorAssembler::EmitAccessCheck(Node* expected_native_context, void AccessorAssembler::JumpIfDataProperty(Node* details, Label* writable, Label* readonly) { - // Accessor properties never have the READ_ONLY attribute set. - GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask), - readonly); + if (readonly) { + // Accessor properties never have the READ_ONLY attribute set. + GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask), + readonly); + } else { + CSA_ASSERT(this, IsNotSetWord32(details, + PropertyDetails::kAttributesReadOnlyMask)); + } Node* kind = DecodeWord32<PropertyDetails::KindField>(details); GotoIf(Word32Equal(kind, Int32Constant(kData)), writable); // Fall through if it's an accessor property. @@ -907,7 +915,7 @@ void AccessorAssembler::HandleStoreICHandlerCase( BIND(&if_nonsmi_handler); { - GotoIf(IsWeakOrClearedHeapObject(handler), &store_transition_or_global); + GotoIf(IsWeakOrCleared(handler), &store_transition_or_global); TNode<HeapObject> strong_handler = CAST(handler); TNode<Map> handler_map = LoadMap(strong_handler); Branch(IsCodeMap(handler_map), &call_handler, &if_proto_handler); @@ -930,8 +938,9 @@ void AccessorAssembler::HandleStoreICHandlerCase( BIND(&store_transition_or_global); { // Load value or miss if the {handler} weak cell is cleared. - CSA_ASSERT(this, IsWeakOrClearedHeapObject(handler)); - TNode<HeapObject> map_or_property_cell = ToWeakHeapObject(handler, miss); + CSA_ASSERT(this, IsWeakOrCleared(handler)); + TNode<HeapObject> map_or_property_cell = + GetHeapObjectAssumeWeak(handler, miss); Label store_global(this), store_transition(this); Branch(IsMap(map_or_property_cell), &store_transition, &store_global); @@ -946,7 +955,8 @@ void AccessorAssembler::HandleStoreICHandlerCase( BIND(&store_transition); { TNode<Map> map = CAST(map_or_property_cell); - HandleStoreICTransitionMapHandlerCase(p, map, miss, false); + HandleStoreICTransitionMapHandlerCase(p, map, miss, + kCheckPrototypeValidity); Return(p->value); } } @@ -954,10 +964,13 @@ void AccessorAssembler::HandleStoreICHandlerCase( void AccessorAssembler::HandleStoreICTransitionMapHandlerCase( const StoreICParameters* p, TNode<Map> transition_map, Label* miss, - bool validate_transition_handler) { - Node* maybe_validity_cell = - LoadObjectField(transition_map, Map::kPrototypeValidityCellOffset); - CheckPrototypeValidityCell(maybe_validity_cell, miss); + StoreTransitionMapFlags flags) { + DCHECK_EQ(0, flags & ~kStoreTransitionMapFlagsMask); + if (flags & kCheckPrototypeValidity) { + Node* maybe_validity_cell = + LoadObjectField(transition_map, Map::kPrototypeValidityCellOffset); + CheckPrototypeValidityCell(maybe_validity_cell, miss); + } TNode<Uint32T> bitfield3 = LoadMapBitField3(transition_map); CSA_ASSERT(this, IsClearWord32<Map::IsDictionaryMapBit>(bitfield3)); @@ -971,7 +984,7 @@ void AccessorAssembler::HandleStoreICTransitionMapHandlerCase( Node* factor = IntPtrConstant(DescriptorArray::kEntrySize); TNode<IntPtrT> last_key_index = UncheckedCast<IntPtrT>(IntPtrAdd( IntPtrConstant(DescriptorArray::ToKeyIndex(-1)), IntPtrMul(nof, factor))); - if (validate_transition_handler) { + if (flags & kValidateTransitionHandler) { Node* key = LoadWeakFixedArrayElement(descriptors, last_key_index); GotoIf(WordNotEqual(key, p->name), miss); } else { @@ -981,16 +994,20 @@ void AccessorAssembler::HandleStoreICTransitionMapHandlerCase( p->name)); } Node* details = LoadDetailsByKeyIndex(descriptors, last_key_index); - if (validate_transition_handler) { + if (flags & kValidateTransitionHandler) { // Follow transitions only in the following cases: // 1) name is a non-private symbol and attributes equal to NONE, // 2) name is a private symbol and attributes equal to DONT_ENUM. Label attributes_ok(this); - const int kAttributesDontDeleteReadOnlyMask = + const int kKindAndAttributesDontDeleteReadOnlyMask = + PropertyDetails::KindField::kMask | PropertyDetails::kAttributesDontDeleteMask | PropertyDetails::kAttributesReadOnlyMask; - // Both DontDelete and ReadOnly attributes must not be set. - GotoIf(IsSetWord32(details, kAttributesDontDeleteReadOnlyMask), miss); + STATIC_ASSERT(kData == 0); + // Both DontDelete and ReadOnly attributes must not be set and it has to be + // a kData property. + GotoIf(IsSetWord32(details, kKindAndAttributesDontDeleteReadOnlyMask), + miss); // DontEnum attribute is allowed only for private symbols and vice versa. Branch(Word32Equal( @@ -1035,9 +1052,8 @@ void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors, Node* value_map = LoadMap(value); // While supporting mutable HeapNumbers would be straightforward, such // objects should not end up here anyway. - CSA_ASSERT(this, - WordNotEqual(value_map, - LoadRoot(Heap::kMutableHeapNumberMapRootIndex))); + CSA_ASSERT(this, WordNotEqual(value_map, + LoadRoot(RootIndex::kMutableHeapNumberMap))); Branch(IsHeapNumberMap(value_map), &all_fine, bailout); } @@ -1060,7 +1076,8 @@ void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors, &all_fine); // Cleared weak references count as FieldType::None, which can't hold any // value. - TNode<Map> field_type_map = CAST(ToWeakHeapObject(field_type, bailout)); + TNode<Map> field_type_map = + CAST(GetHeapObjectAssumeWeak(field_type, bailout)); // FieldType::Class(...) performs a map check. Branch(WordEqual(LoadMap(value), field_type_map), &all_fine, bailout); } @@ -1270,7 +1287,7 @@ void AccessorAssembler::HandleStoreICProtoHandler( TNode<MaybeObject> maybe_transition_map = LoadHandlerDataField(handler, 1); TNode<Map> transition_map = - CAST(ToWeakHeapObject(maybe_transition_map, miss)); + CAST(GetHeapObjectAssumeWeak(maybe_transition_map, miss)); GotoIf(IsDeprecatedMap(transition_map), miss); @@ -1312,8 +1329,8 @@ void AccessorAssembler::HandleStoreICProtoHandler( &if_add_normal); TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1); - CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_holder)); - TNode<Object> holder = ToWeakHeapObject(maybe_holder, miss); + CSA_ASSERT(this, IsWeakOrCleared(maybe_holder)); + TNode<Object> holder = GetHeapObjectAssumeWeak(maybe_holder, miss); GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kGlobalProxy)), &if_store_global_proxy); @@ -1374,11 +1391,10 @@ void AccessorAssembler::HandleStoreICProtoHandler( [=] { return LoadHandlerDataField(handler, 3); }, [=] { return LoadHandlerDataField(handler, 2); }); - CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_context)); - TNode<Object> context = - Select<Object>(IsClearedWeakHeapObject(maybe_context), - [=] { return SmiConstant(0); }, - [=] { return ToWeakHeapObject(maybe_context); }); + CSA_ASSERT(this, IsWeakOrCleared(maybe_context)); + TNode<Object> context = Select<Object>( + IsCleared(maybe_context), [=] { return SmiConstant(0); }, + [=] { return GetHeapObjectAssumeWeak(maybe_context); }); Node* foreign = LoadObjectField(call_handler_info, CallHandlerInfo::kJsCallbackOffset); @@ -1455,7 +1471,7 @@ void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p, TailCallRuntime(Runtime::kSetPropertyWithReceiver, p->context, proxy, p->name, p->value, p->receiver, language_mode); } else { - Node* name = ToName(p->context, p->name); + Node* name = CallBuiltin(Builtins::kToName, p->context, p->name); TailCallBuiltin(Builtins::kProxySetProperty, p->context, proxy, name, p->value, p->receiver, language_mode); } @@ -1575,7 +1591,7 @@ Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder, GotoIf(TaggedIsSmi(maybe_field_type), &done); // Check that value type matches the field type. { - Node* field_type = ToWeakHeapObject(maybe_field_type, bailout); + Node* field_type = GetHeapObjectAssumeWeak(maybe_field_type, bailout); Branch(WordEqual(LoadMap(value), field_type), &done, bailout); } BIND(&done); @@ -1855,7 +1871,7 @@ void AccessorAssembler::EmitElementLoad( GotoIf(IsDetachedBuffer(buffer), miss); // Bounds check. - Node* length = SmiUntag(LoadTypedArrayLength(CAST(object))); + Node* length = SmiUntag(LoadJSTypedArrayLength(CAST(object))); GotoIfNot(UintPtrLessThan(intptr_index, length), out_of_bounds); Node* backing_store = LoadFixedTypedArrayBackingStore(CAST(elements)); @@ -2082,7 +2098,7 @@ void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map, Comment("check if string"); GotoIfNot(IsStringInstanceType(instance_type), slow); Comment("load string character"); - Node* length = LoadAndUntagObjectField(receiver, String::kLengthOffset); + TNode<IntPtrT> length = LoadStringLengthAsWord(receiver); GotoIfNot(UintPtrLessThan(index, length), slow); IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1); TailCallBuiltin(Builtins::kStringCharAt, NoContextConstant(), receiver, @@ -2395,7 +2411,8 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LoadICParameters* p, BIND(&try_polymorphic); { - TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss); + TNode<HeapObject> strong_feedback = + GetHeapObjectIfStrong(feedback, &miss); GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &stub_call); HandlePolymorphicCase(recv_map, CAST(strong_feedback), &if_handler, &var_handler, &miss, 2); @@ -2443,7 +2460,7 @@ void AccessorAssembler::LoadIC(const LoadICParameters* p) { HandleLoadICHandlerCase(p, CAST(var_handler.value()), &miss, &direct_exit); BIND(&try_polymorphic); - TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss); + TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss); { // Check polymorphic case. Comment("LoadIC_try_polymorphic"); @@ -2480,7 +2497,7 @@ void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p, { // Check megamorphic case. - GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)), + GotoIfNot(WordEqual(feedback, LoadRoot(RootIndex::kmegamorphic_symbol)), &try_uninitialized); TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name, @@ -2490,9 +2507,8 @@ void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p, BIND(&try_uninitialized); { // Check uninitialized case. - GotoIfNot( - WordEqual(feedback, LoadRoot(Heap::kuninitialized_symbolRootIndex)), - miss); + GotoIfNot(WordEqual(feedback, LoadRoot(RootIndex::kuninitialized_symbol)), + miss); exit_point->ReturnCallStub( Builtins::CallableFor(isolate(), Builtins::kLoadIC_Uninitialized), p->context, p->receiver, p->name, p->slot, p->vector); @@ -2508,7 +2524,7 @@ void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) { // Optimistically write the state transition to the vector. StoreFeedbackVectorSlot(p->vector, p->slot, - LoadRoot(Heap::kpremonomorphic_symbolRootIndex), + LoadRoot(RootIndex::kpremonomorphic_symbol), SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS); StoreWeakReferenceInFeedbackVector(p->vector, p->slot, receiver_map, kPointerSize, SMI_PARAMETERS); @@ -2534,7 +2550,7 @@ void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) { { // Undo the optimistic state transition. StoreFeedbackVectorSlot(p->vector, p->slot, - LoadRoot(Heap::kuninitialized_symbolRootIndex), + LoadRoot(RootIndex::kuninitialized_symbol), SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS); TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name, @@ -2580,9 +2596,9 @@ void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase( BIND(&if_property_cell); { // Load value or try handler case if the weak reference is cleared. - CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_weak_ref)); + CSA_ASSERT(this, IsWeakOrCleared(maybe_weak_ref)); TNode<PropertyCell> property_cell = - CAST(ToWeakHeapObject(maybe_weak_ref, try_handler)); + CAST(GetHeapObjectAssumeWeak(maybe_weak_ref, try_handler)); TNode<Object> value = LoadObjectField(property_cell, PropertyCell::kValueOffset); GotoIf(WordEqual(value, TheHoleConstant()), miss); @@ -2616,8 +2632,7 @@ void AccessorAssembler::LoadGlobalIC_TryHandlerCase( TNode<MaybeObject> feedback_element = LoadFeedbackVectorSlot(vector, slot, kPointerSize, slot_mode); TNode<Object> handler = CAST(feedback_element); - GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)), - miss); + GotoIf(WordEqual(handler, LoadRoot(RootIndex::kuninitialized_symbol)), miss); OnNonExistent on_nonexistent = typeof_mode == NOT_INSIDE_TYPEOF ? OnNonExistent::kThrowReferenceError @@ -2660,7 +2675,7 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) { } BIND(&try_polymorphic); - TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss); + TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss); { // Check polymorphic case. Comment("KeyedLoadIC_try_polymorphic"); @@ -2673,9 +2688,9 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) { { // Check megamorphic case. Comment("KeyedLoadIC_try_megamorphic"); - GotoIfNot(WordEqual(strong_feedback, - LoadRoot(Heap::kmegamorphic_symbolRootIndex)), - &try_polymorphic_name); + GotoIfNot( + WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)), + &try_polymorphic_name); // TODO(jkummerow): Inline this? Or some of it? TailCallBuiltin(Builtins::kKeyedLoadIC_Megamorphic, p->context, p->receiver, p->name, p->slot, p->vector); @@ -2738,29 +2753,40 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) { void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) { VARIABLE(var_index, MachineType::PointerRepresentation()); - VARIABLE(var_unique, MachineRepresentation::kTagged); - var_unique.Bind(p->name); // Dummy initialization. - Label if_index(this), if_unique_name(this), if_notunique(this), slow(this); + VARIABLE(var_unique, MachineRepresentation::kTagged, p->name); + Label if_index(this), if_unique_name(this), if_notunique(this), + if_other(this, Label::kDeferred), if_runtime(this, Label::kDeferred); Node* receiver = p->receiver; - GotoIf(TaggedIsSmi(receiver), &slow); - Node* receiver_map = LoadMap(receiver); - Node* instance_type = LoadMapInstanceType(receiver_map); + GotoIf(TaggedIsSmi(receiver), &if_runtime); + + TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique, + &if_other, &if_notunique); - TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique, &slow, - &if_notunique); + BIND(&if_other); + { + Node* name = CallBuiltin(Builtins::kToName, p->context, p->name); + var_unique.Bind(name); + TryToName(name, &if_index, &var_index, &if_unique_name, &var_unique, + &if_runtime, &if_notunique); + } BIND(&if_index); { + Node* receiver_map = LoadMap(receiver); + Node* instance_type = LoadMapInstanceType(receiver_map); GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(), - &slow); + &if_runtime); } BIND(&if_unique_name); { LoadICParameters pp = *p; pp.name = var_unique.value(); - GenericPropertyLoad(receiver, receiver_map, instance_type, &pp, &slow); + Node* receiver_map = LoadMap(receiver); + Node* instance_type = LoadMapInstanceType(receiver_map); + GenericPropertyLoad(receiver, receiver_map, instance_type, &pp, + &if_runtime); } BIND(&if_notunique); @@ -2769,10 +2795,11 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) { // Ideally we could return undefined directly here if the name is not // found in the string table, i.e. it was never internalized, but that // invariant doesn't hold with named property interceptors (at this - // point), so we take the {slow} path instead. + // point), so we take the {if_runtime} path instead. Label if_in_string_table(this); - TryInternalizeString(p->name, &if_index, &var_index, &if_in_string_table, - &var_unique, &slow, &slow); + TryInternalizeString(var_unique.value(), &if_index, &var_index, + &if_in_string_table, &var_unique, &if_runtime, + &if_runtime); BIND(&if_in_string_table); { @@ -2783,21 +2810,23 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) { // cache. We may want to re-evaluate that in the future. LoadICParameters pp = *p; pp.name = var_unique.value(); - GenericPropertyLoad(receiver, receiver_map, instance_type, &pp, &slow, - kDontUseStubCache); + Node* receiver_map = LoadMap(receiver); + Node* instance_type = LoadMapInstanceType(receiver_map); + GenericPropertyLoad(receiver, receiver_map, instance_type, &pp, + &if_runtime, kDontUseStubCache); } } else { - Goto(&slow); + Goto(&if_runtime); } } - BIND(&slow); + BIND(&if_runtime); { Comment("KeyedLoadGeneric_slow"); IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1); // TODO(jkummerow): Should we use the GetProperty TF stub instead? - TailCallRuntime(Runtime::kKeyedGetProperty, p->context, p->receiver, - p->name); + TailCallRuntime(Runtime::kGetProperty, p->context, p->receiver, + var_unique.value()); } } @@ -2868,7 +2897,7 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) { } BIND(&try_polymorphic); - TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss); + TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss); { // Check polymorphic case. Comment("StoreIC_try_polymorphic"); @@ -2880,9 +2909,9 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) { BIND(&try_megamorphic); { // Check megamorphic case. - GotoIfNot(WordEqual(strong_feedback, - LoadRoot(Heap::kmegamorphic_symbolRootIndex)), - &try_uninitialized); + GotoIfNot( + WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)), + &try_uninitialized); TryProbeStubCache(isolate()->store_stub_cache(), p->receiver, p->name, &if_handler, &var_handler, &miss); @@ -2890,9 +2919,9 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) { BIND(&try_uninitialized); { // Check uninitialized case. - GotoIfNot(WordEqual(strong_feedback, - LoadRoot(Heap::kuninitialized_symbolRootIndex)), - &miss); + GotoIfNot( + WordEqual(strong_feedback, LoadRoot(RootIndex::kuninitialized_symbol)), + &miss); TailCallBuiltin(Builtins::kStoreIC_Uninitialized, p->context, p->receiver, p->name, p->value, p->slot, p->vector); } @@ -2912,9 +2941,9 @@ void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) { BIND(&if_property_cell); { Label try_handler(this), miss(this, Label::kDeferred); - CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_weak_ref)); + CSA_ASSERT(this, IsWeakOrCleared(maybe_weak_ref)); TNode<PropertyCell> property_cell = - CAST(ToWeakHeapObject(maybe_weak_ref, &try_handler)); + CAST(GetHeapObjectAssumeWeak(maybe_weak_ref, &try_handler)); ExitPoint direct_exit(this); StoreGlobalIC_PropertyCellCase(property_cell, pp->value, &direct_exit, @@ -2926,7 +2955,7 @@ void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) { TNode<MaybeObject> handler = LoadFeedbackVectorSlot( pp->vector, pp->slot, kPointerSize, SMI_PARAMETERS); - GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)), + GotoIf(WordEqual(handler, LoadRoot(RootIndex::kuninitialized_symbol)), &miss); StoreICParameters p = *pp; @@ -3049,7 +3078,7 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) { } BIND(&try_polymorphic); - TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss); + TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss); { // CheckPolymorphic case. Comment("KeyedStoreIC_try_polymorphic"); @@ -3063,9 +3092,9 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) { { // Check megamorphic case. Comment("KeyedStoreIC_try_megamorphic"); - GotoIfNot(WordEqual(strong_feedback, - LoadRoot(Heap::kmegamorphic_symbolRootIndex)), - &try_polymorphic_name); + GotoIfNot( + WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)), + &try_polymorphic_name); TailCallBuiltin(Builtins::kKeyedStoreIC_Megamorphic, p->context, p->receiver, p->name, p->value, p->slot, p->vector); } @@ -3123,7 +3152,7 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) { TNode<MaybeObject> maybe_transition_map = LoadHandlerDataField(CAST(handler), 1); TNode<Map> transition_map = - CAST(ToWeakHeapObject(maybe_transition_map, &miss)); + CAST(GetHeapObjectAssumeWeak(maybe_transition_map, &miss)); GotoIf(IsDeprecatedMap(transition_map), &miss); Node* code = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset); CSA_ASSERT(this, IsCode(code)); @@ -3133,7 +3162,7 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) { } BIND(&try_polymorphic); - TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss); + TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss); { Comment("StoreInArrayLiteralIC_try_polymorphic"); GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), @@ -3145,15 +3174,14 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) { BIND(&try_megamorphic); { Comment("StoreInArrayLiteralIC_try_megamorphic"); - CSA_ASSERT( - this, - Word32Or(WordEqual(strong_feedback, - LoadRoot(Heap::kuninitialized_symbolRootIndex)), - WordEqual(strong_feedback, - LoadRoot(Heap::kmegamorphic_symbolRootIndex)))); - GotoIfNot(WordEqual(strong_feedback, - LoadRoot(Heap::kmegamorphic_symbolRootIndex)), - &miss); + CSA_ASSERT(this, + Word32Or(WordEqual(strong_feedback, + LoadRoot(RootIndex::kuninitialized_symbol)), + WordEqual(strong_feedback, + LoadRoot(RootIndex::kmegamorphic_symbol)))); + GotoIfNot( + WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)), + &miss); TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, p->context, p->value, p->receiver, p->name); } @@ -3183,6 +3211,31 @@ void AccessorAssembler::GenerateLoadIC() { LoadIC(&p); } +void AccessorAssembler::GenerateLoadIC_Megamorphic() { + typedef LoadWithVectorDescriptor Descriptor; + + Node* receiver = Parameter(Descriptor::kReceiver); + Node* name = Parameter(Descriptor::kName); + Node* slot = Parameter(Descriptor::kSlot); + Node* vector = Parameter(Descriptor::kVector); + Node* context = Parameter(Descriptor::kContext); + + ExitPoint direct_exit(this); + TVARIABLE(MaybeObject, var_handler); + Label if_handler(this, &var_handler), miss(this, Label::kDeferred); + + TryProbeStubCache(isolate()->load_stub_cache(), receiver, name, &if_handler, + &var_handler, &miss); + + BIND(&if_handler); + LoadICParameters p(context, receiver, name, slot, vector); + HandleLoadICHandlerCase(&p, CAST(var_handler.value()), &miss, &direct_exit); + + BIND(&miss); + direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name, + slot, vector); +} + void AccessorAssembler::GenerateLoadIC_Noninlined() { typedef LoadWithVectorDescriptor Descriptor; @@ -3238,6 +3291,19 @@ void AccessorAssembler::GenerateLoadICTrampoline() { TailCallBuiltin(Builtins::kLoadIC, context, receiver, name, slot, vector); } +void AccessorAssembler::GenerateLoadICTrampoline_Megamorphic() { + typedef LoadDescriptor Descriptor; + + Node* receiver = Parameter(Descriptor::kReceiver); + Node* name = Parameter(Descriptor::kName); + Node* slot = Parameter(Descriptor::kSlot); + Node* context = Parameter(Descriptor::kContext); + Node* vector = LoadFeedbackVectorForStub(); + + TailCallBuiltin(Builtins::kLoadIC_Megamorphic, context, receiver, name, slot, + vector); +} + void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) { typedef LoadGlobalWithVectorDescriptor Descriptor; @@ -3280,6 +3346,19 @@ void AccessorAssembler::GenerateKeyedLoadIC() { KeyedLoadIC(&p); } +void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() { + typedef LoadWithVectorDescriptor Descriptor; + + Node* receiver = Parameter(Descriptor::kReceiver); + Node* name = Parameter(Descriptor::kName); + Node* slot = Parameter(Descriptor::kSlot); + Node* vector = Parameter(Descriptor::kVector); + Node* context = Parameter(Descriptor::kContext); + + LoadICParameters p(context, receiver, name, slot, vector); + KeyedLoadICGeneric(&p); +} + void AccessorAssembler::GenerateKeyedLoadICTrampoline() { typedef LoadDescriptor Descriptor; @@ -3293,17 +3372,17 @@ void AccessorAssembler::GenerateKeyedLoadICTrampoline() { vector); } -void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() { - typedef LoadWithVectorDescriptor Descriptor; +void AccessorAssembler::GenerateKeyedLoadICTrampoline_Megamorphic() { + typedef LoadDescriptor Descriptor; Node* receiver = Parameter(Descriptor::kReceiver); Node* name = Parameter(Descriptor::kName); Node* slot = Parameter(Descriptor::kSlot); - Node* vector = Parameter(Descriptor::kVector); Node* context = Parameter(Descriptor::kContext); + Node* vector = LoadFeedbackVectorForStub(); - LoadICParameters p(context, receiver, name, slot, vector); - KeyedLoadICGeneric(&p); + TailCallBuiltin(Builtins::kKeyedLoadIC_Megamorphic, context, receiver, name, + slot, vector); } void AccessorAssembler::GenerateKeyedLoadIC_PolymorphicName() { @@ -3414,6 +3493,76 @@ void AccessorAssembler::GenerateStoreInArrayLiteralIC() { StoreInArrayLiteralIC(&p); } +void AccessorAssembler::GenerateCloneObjectIC_Slow() { + typedef CloneObjectWithVectorDescriptor Descriptor; + TNode<HeapObject> source = CAST(Parameter(Descriptor::kSource)); + TNode<Smi> flags = CAST(Parameter(Descriptor::kFlags)); + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + + // The Slow case uses the same call interface as CloneObjectIC, so that it + // can be tail called from it. However, the feedback slot and vector are not + // used. + + TNode<Context> native_context = LoadNativeContext(context); + TNode<JSFunction> object_fn = + CAST(LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX)); + TNode<Map> initial_map = CAST( + LoadObjectField(object_fn, JSFunction::kPrototypeOrInitialMapOffset)); + CSA_ASSERT(this, IsMap(initial_map)); + + TNode<JSObject> result = CAST(AllocateJSObjectFromMap(initial_map)); + + { + Label did_set_proto_if_needed(this); + TNode<BoolT> is_null_proto = SmiNotEqual( + SmiAnd(flags, SmiConstant(ObjectLiteral::kHasNullPrototype)), + SmiConstant(Smi::kZero)); + GotoIfNot(is_null_proto, &did_set_proto_if_needed); + + CallRuntime(Runtime::kInternalSetPrototype, context, result, + NullConstant()); + + Goto(&did_set_proto_if_needed); + BIND(&did_set_proto_if_needed); + } + + ReturnIf(IsNullOrUndefined(source), result); + + CSA_ASSERT(this, IsJSReceiver(source)); + + Label call_runtime(this, Label::kDeferred); + Label done(this); + + TNode<Map> map = LoadMap(source); + TNode<Int32T> type = LoadMapInstanceType(map); + { + Label cont(this); + GotoIf(IsJSObjectInstanceType(type), &cont); + GotoIfNot(IsStringInstanceType(type), &done); + Branch(SmiEqual(LoadStringLengthAsSmi(CAST(source)), SmiConstant(0)), &done, + &call_runtime); + BIND(&cont); + } + + GotoIfNot(IsEmptyFixedArray(LoadElements(CAST(source))), &call_runtime); + + ForEachEnumerableOwnProperty( + context, map, CAST(source), + [=](TNode<Name> key, TNode<Object> value) { + KeyedStoreGenericGenerator::SetPropertyInLiteral(state(), context, + result, key, value); + }, + &call_runtime); + Goto(&done); + + BIND(&call_runtime); + CallRuntime(Runtime::kCopyDataProperties, context, result, source); + + Goto(&done); + BIND(&done); + Return(result); +} + void AccessorAssembler::GenerateCloneObjectIC() { typedef CloneObjectWithVectorDescriptor Descriptor; Node* source = Parameter(Descriptor::kSource); @@ -3502,7 +3651,7 @@ void AccessorAssembler::GenerateCloneObjectIC() { } BIND(&try_polymorphic); - TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss); + TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss); { Comment("CloneObjectIC_try_polymorphic"); GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic); @@ -3513,16 +3662,16 @@ void AccessorAssembler::GenerateCloneObjectIC() { BIND(&try_megamorphic); { Comment("CloneObjectIC_try_megamorphic"); - CSA_ASSERT( - this, - Word32Or(WordEqual(strong_feedback, - LoadRoot(Heap::kuninitialized_symbolRootIndex)), - WordEqual(strong_feedback, - LoadRoot(Heap::kmegamorphic_symbolRootIndex)))); - GotoIfNot(WordEqual(strong_feedback, - LoadRoot(Heap::kmegamorphic_symbolRootIndex)), - &miss); - TailCallRuntime(Runtime::kCloneObjectIC_Slow, context, source, flags); + CSA_ASSERT(this, + Word32Or(WordEqual(strong_feedback, + LoadRoot(RootIndex::kuninitialized_symbol)), + WordEqual(strong_feedback, + LoadRoot(RootIndex::kmegamorphic_symbol)))); + GotoIfNot( + WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)), + &miss); + TailCallBuiltin(Builtins::kCloneObjectIC_Slow, context, source, flags, slot, + vector); } BIND(&miss); diff --git a/deps/v8/src/ic/accessor-assembler.h b/deps/v8/src/ic/accessor-assembler.h index 0de48e021a..3d92ab26c3 100644 --- a/deps/v8/src/ic/accessor-assembler.h +++ b/deps/v8/src/ic/accessor-assembler.h @@ -28,18 +28,22 @@ class AccessorAssembler : public CodeStubAssembler { : CodeStubAssembler(state) {} void GenerateLoadIC(); + void GenerateLoadIC_Megamorphic(); void GenerateLoadIC_Noninlined(); void GenerateLoadIC_Uninitialized(); void GenerateLoadICTrampoline(); + void GenerateLoadICTrampoline_Megamorphic(); void GenerateKeyedLoadIC(); - void GenerateKeyedLoadICTrampoline(); void GenerateKeyedLoadIC_Megamorphic(); void GenerateKeyedLoadIC_PolymorphicName(); + void GenerateKeyedLoadICTrampoline(); + void GenerateKeyedLoadICTrampoline_Megamorphic(); void GenerateStoreIC(); void GenerateStoreICTrampoline(); void GenerateStoreGlobalIC(); void GenerateStoreGlobalICTrampoline(); void GenerateCloneObjectIC(); + void GenerateCloneObjectIC_Slow(); void GenerateLoadGlobalIC(TypeofMode typeof_mode); void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode); @@ -106,10 +110,16 @@ class AccessorAssembler : public CodeStubAssembler { void HandleStoreICHandlerCase( const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss, ICMode ic_mode, ElementSupport support_elements = kOnlyProperties); + enum StoreTransitionMapFlags { + kCheckPrototypeValidity = 1 << 0, + kValidateTransitionHandler = 1 << 1, + kStoreTransitionMapFlagsMask = + kCheckPrototypeValidity | kValidateTransitionHandler, + }; void HandleStoreICTransitionMapHandlerCase(const StoreICParameters* p, TNode<Map> transition_map, Label* miss, - bool validate_transition_handler); + StoreTransitionMapFlags flags); void JumpIfDataProperty(Node* details, Label* writable, Label* readonly); diff --git a/deps/v8/src/ic/binary-op-assembler.cc b/deps/v8/src/ic/binary-op-assembler.cc index 9016e9ba18..ebe64437c6 100644 --- a/deps/v8/src/ic/binary-op-assembler.cc +++ b/deps/v8/src/ic/binary-op-assembler.cc @@ -162,9 +162,8 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, &call_with_any_feedback); var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kString)); - Callable callable = - CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED); - var_result.Bind(CallStub(callable, context, lhs, rhs)); + var_result.Bind( + CallBuiltin(Builtins::kStringAdd_CheckNone, context, lhs, rhs)); Goto(&end); } diff --git a/deps/v8/src/ic/call-optimization.h b/deps/v8/src/ic/call-optimization.h index d87ec4fdb1..e3115bdbcd 100644 --- a/deps/v8/src/ic/call-optimization.h +++ b/deps/v8/src/ic/call-optimization.h @@ -12,7 +12,7 @@ namespace v8 { namespace internal { // Holds information about possible function call optimizations. -class CallOptimization BASE_EMBEDDED { +class CallOptimization { public: CallOptimization(Isolate* isolate, Handle<Object> function); diff --git a/deps/v8/src/ic/handler-configuration.cc b/deps/v8/src/ic/handler-configuration.cc index 86ea4f9d3b..73ab0de645 100644 --- a/deps/v8/src/ic/handler-configuration.cc +++ b/deps/v8/src/ic/handler-configuration.cc @@ -140,7 +140,7 @@ Handle<Object> LoadHandler::LoadFromPrototype(Isolate* isolate, // static Handle<Object> LoadHandler::LoadFullChain(Isolate* isolate, Handle<Map> receiver_map, - MaybeObjectHandle holder, + const MaybeObjectHandle& holder, Handle<Smi> smi_handler) { Handle<JSReceiver> end; // null handle, means full prototype chain lookup. MaybeObjectHandle data1 = holder; @@ -168,7 +168,7 @@ Handle<Object> LoadHandler::LoadFullChain(Isolate* isolate, KeyedAccessLoadMode LoadHandler::GetKeyedAccessLoadMode(MaybeObject* handler) { DisallowHeapAllocation no_gc; if (handler->IsSmi()) { - int const raw_handler = Smi::cast(handler->ToSmi())->value(); + int const raw_handler = handler->cast<Smi>()->value(); Kind const kind = KindBits::decode(raw_handler); if ((kind == kElement || kind == kIndexedString) && AllowOutOfBoundsBits::decode(raw_handler)) { diff --git a/deps/v8/src/ic/handler-configuration.h b/deps/v8/src/ic/handler-configuration.h index 305577a2df..72ab68140e 100644 --- a/deps/v8/src/ic/handler-configuration.h +++ b/deps/v8/src/ic/handler-configuration.h @@ -150,7 +150,7 @@ class LoadHandler final : public DataHandler { // needed (e.g., for "nonexistent"), null_value() may be passed in. static Handle<Object> LoadFullChain(Isolate* isolate, Handle<Map> receiver_map, - MaybeObjectHandle holder, + const MaybeObjectHandle& holder, Handle<Smi> smi_handler); // Creates a data handler that represents a prototype chain check followed diff --git a/deps/v8/src/ic/ic-inl.h b/deps/v8/src/ic/ic-inl.h index 640bf7250c..101703dc28 100644 --- a/deps/v8/src/ic/ic-inl.h +++ b/deps/v8/src/ic/ic-inl.h @@ -50,11 +50,10 @@ void IC::update_receiver_map(Handle<Object> receiver) { bool IC::IsHandler(MaybeObject* object) { HeapObject* heap_object; return (object->IsSmi() && (object != nullptr)) || - (object->ToWeakHeapObject(&heap_object) && + (object->GetHeapObjectIfWeak(&heap_object) && (heap_object->IsMap() || heap_object->IsPropertyCell())) || - (object->ToStrongHeapObject(&heap_object) && - (heap_object->IsDataHandler() || - heap_object->IsCode())); + (object->GetHeapObjectIfStrong(&heap_object) && + (heap_object->IsDataHandler() || heap_object->IsCode())); } bool IC::AddressIsDeoptimizedCode() const { diff --git a/deps/v8/src/ic/ic-stats.cc b/deps/v8/src/ic/ic-stats.cc index c305209d48..0c33863d3d 100644 --- a/deps/v8/src/ic/ic-stats.cc +++ b/deps/v8/src/ic/ic-stats.cc @@ -95,7 +95,7 @@ ICInfo::ICInfo() is_constructor(false), is_optimized(false), map(nullptr), - is_dictionary_map(0), + is_dictionary_map(false), number_of_own_descriptors(0) {} void ICInfo::Reset() { diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc index 9237441ac9..3ca62d0bb4 100644 --- a/deps/v8/src/ic/ic.cc +++ b/deps/v8/src/ic/ic.cc @@ -1260,9 +1260,8 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object, return result; } - bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, - JSReceiver::StoreFromKeyed store_mode) { + StoreOrigin store_origin) { // Disable ICs for non-JSObjects for now. Handle<Object> object = it->GetReceiver(); if (object->IsJSProxy()) return true; @@ -1319,7 +1318,7 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, if (it->ExtendingNonExtensible(receiver)) return false; it->PrepareTransitionToDataProperty(receiver, value, NONE, - store_mode); + store_origin); return it->IsCacheableTransition(); } } @@ -1328,7 +1327,7 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, receiver = it->GetStoreTarget<JSObject>(); if (it->ExtendingNonExtensible(receiver)) return false; - it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode); + it->PrepareTransitionToDataProperty(receiver, value, NONE, store_origin); return it->IsCacheableTransition(); } @@ -1381,7 +1380,7 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name, MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, Handle<Object> value, - JSReceiver::StoreFromKeyed store_mode) { + StoreOrigin store_origin) { // TODO(verwaest): Let SetProperty do the migration, since storing a property // might deprecate the current map again, if value does not fit. if (MigrateDeprecated(object)) { @@ -1424,15 +1423,15 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, use_ic = false; } } - if (use_ic) UpdateCaches(&it, value, store_mode); + if (use_ic) UpdateCaches(&it, value, store_origin); MAYBE_RETURN_NULL( - Object::SetProperty(&it, value, language_mode(), store_mode)); + Object::SetProperty(&it, value, language_mode(), store_origin)); return value; } void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, - JSReceiver::StoreFromKeyed store_mode) { + StoreOrigin store_origin) { if (state() == UNINITIALIZED && !IsStoreGlobalIC()) { // This is the first time we execute this inline cache. Transition // to premonomorphic state to delay setting the monomorphic state. @@ -1443,7 +1442,7 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, } MaybeObjectHandle handler; - if (LookupForWrite(lookup, value, store_mode)) { + if (LookupForWrite(lookup, value, store_origin)) { if (IsStoreGlobalIC()) { if (lookup->state() == LookupIterator::DATA && lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) { @@ -1988,8 +1987,9 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, if (MigrateDeprecated(object)) { Handle<Object> result; ASSIGN_RETURN_ON_EXCEPTION( - isolate(), result, Runtime::SetObjectProperty(isolate(), object, key, - value, language_mode()), + isolate(), result, + Runtime::SetObjectProperty(isolate(), object, key, value, + language_mode(), StoreOrigin::kMaybeKeyed), Object); return result; } @@ -2004,11 +2004,10 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, if ((key->IsInternalizedString() && !String::cast(*key)->AsArrayIndex(&index)) || key->IsSymbol()) { - ASSIGN_RETURN_ON_EXCEPTION( - isolate(), store_handle, - StoreIC::Store(object, Handle<Name>::cast(key), value, - JSReceiver::MAY_BE_STORE_FROM_KEYED), - Object); + ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle, + StoreIC::Store(object, Handle<Name>::cast(key), + value, StoreOrigin::kMaybeKeyed), + Object); if (vector_needs_update()) { if (ConfigureVectorState(MEGAMORPHIC, key)) { set_slow_stub_reason("unhandled internalized string key"); @@ -2062,10 +2061,11 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, bool receiver_was_cow = object->IsJSArray() && Handle<JSArray>::cast(object)->elements()->IsCowArray(); - ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle, - Runtime::SetObjectProperty(isolate(), object, key, - value, language_mode()), - Object); + ASSIGN_RETURN_ON_EXCEPTION( + isolate(), store_handle, + Runtime::SetObjectProperty(isolate(), object, key, value, language_mode(), + StoreOrigin::kMaybeKeyed), + Object); if (use_ic) { if (!old_receiver_map.is_null()) { @@ -2359,7 +2359,8 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) { LanguageMode language_mode = vector->GetLanguageMode(vector_slot); RETURN_RESULT_OR_FAILURE( isolate, - Runtime::SetObjectProperty(isolate, global, name, value, language_mode)); + Runtime::SetObjectProperty(isolate, global, name, value, language_mode, + StoreOrigin::kMaybeKeyed)); } RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) { @@ -2406,7 +2407,8 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) { LanguageMode language_mode = GetLanguageModeFromSlotKind(kind); RETURN_RESULT_OR_FAILURE( isolate, - Runtime::SetObjectProperty(isolate, object, key, value, language_mode)); + Runtime::SetObjectProperty(isolate, object, key, value, language_mode, + StoreOrigin::kMaybeKeyed)); } RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Slow) { @@ -2446,7 +2448,8 @@ RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) { LanguageMode language_mode = GetLanguageModeFromSlotKind(kind); RETURN_RESULT_OR_FAILURE( isolate, - Runtime::SetObjectProperty(isolate, object, key, value, language_mode)); + Runtime::SetObjectProperty(isolate, object, key, value, language_mode, + StoreOrigin::kMaybeKeyed)); } } @@ -2595,8 +2598,9 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) { if (V8_UNLIKELY(FLAG_runtime_stats)) { RETURN_RESULT_OR_FAILURE( - isolate, Runtime::SetObjectProperty(isolate, receiver, name, value, - language_mode)); + isolate, + Runtime::SetObjectProperty(isolate, receiver, name, value, + language_mode, StoreOrigin::kMaybeKeyed)); } DCHECK(info->IsCompatibleReceiver(*receiver)); @@ -2747,9 +2751,9 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) { DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); it.Next(); - MAYBE_RETURN(Object::SetProperty(&it, value, language_mode, - JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED), - ReadOnlyRoots(isolate).exception()); + MAYBE_RETURN( + Object::SetProperty(&it, value, language_mode, StoreOrigin::kNamed), + ReadOnlyRoots(isolate).exception()); return *value; } diff --git a/deps/v8/src/ic/ic.h b/deps/v8/src/ic/ic.h index 0a831b757f..05bde1ff61 100644 --- a/deps/v8/src/ic/ic.h +++ b/deps/v8/src/ic/ic.h @@ -36,7 +36,7 @@ class IC { // Construct the IC structure with the given number of extra // JavaScript frames on the stack. IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot); - virtual ~IC() {} + virtual ~IC() = default; State state() const { return state_; } inline Address address() const; @@ -88,7 +88,7 @@ class IC { bool vector_needs_update() { return (!vector_set_ && (state() != MEGAMORPHIC || - Smi::ToInt(nexus()->GetFeedbackExtra()->ToSmi()) != ELEMENT)); + Smi::ToInt(nexus()->GetFeedbackExtra()->cast<Smi>()) != ELEMENT)); } // Configure for most states. @@ -296,11 +296,10 @@ class StoreIC : public IC { V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store( Handle<Object> object, Handle<Name> name, Handle<Object> value, - JSReceiver::StoreFromKeyed store_mode = - JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED); + StoreOrigin store_origin = StoreOrigin::kNamed); bool LookupForWrite(LookupIterator* it, Handle<Object> value, - JSReceiver::StoreFromKeyed store_mode); + StoreOrigin store_origin); protected: // Stub accessors. @@ -312,7 +311,7 @@ class StoreIC : public IC { // Update the inline cache and the global stub cache based on the // lookup result. void UpdateCaches(LookupIterator* lookup, Handle<Object> value, - JSReceiver::StoreFromKeyed store_mode); + StoreOrigin store_origin); private: MaybeObjectHandle ComputeHandler(LookupIterator* lookup); 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 diff --git a/deps/v8/src/ic/keyed-store-generic.h b/deps/v8/src/ic/keyed-store-generic.h index 0934c96cc8..9442a54935 100644 --- a/deps/v8/src/ic/keyed-store-generic.h +++ b/deps/v8/src/ic/keyed-store-generic.h @@ -30,6 +30,11 @@ class KeyedStoreGenericGenerator { TNode<Context> context, TNode<Object> receiver, TNode<Object> key, TNode<Object> value, LanguageMode language_mode); + + static void SetPropertyInLiteral(compiler::CodeAssemblerState* state, + TNode<Context> context, + TNode<JSObject> receiver, TNode<Name> key, + TNode<Object> value); }; class StoreICUninitializedGenerator { |