diff options
Diffstat (limited to 'deps/v8/src/ic')
-rw-r--r-- | deps/v8/src/ic/accessor-assembler.cc | 1105 | ||||
-rw-r--r-- | deps/v8/src/ic/accessor-assembler.h | 186 | ||||
-rw-r--r-- | deps/v8/src/ic/binary-op-assembler.cc | 319 | ||||
-rw-r--r-- | deps/v8/src/ic/binary-op-assembler.h | 60 | ||||
-rw-r--r-- | deps/v8/src/ic/handler-configuration-inl.h | 36 | ||||
-rw-r--r-- | deps/v8/src/ic/handler-configuration.cc | 2 | ||||
-rw-r--r-- | deps/v8/src/ic/handler-configuration.h | 18 | ||||
-rw-r--r-- | deps/v8/src/ic/ic-stats.cc | 3 | ||||
-rw-r--r-- | deps/v8/src/ic/ic-stats.h | 1 | ||||
-rw-r--r-- | deps/v8/src/ic/ic.cc | 126 | ||||
-rw-r--r-- | deps/v8/src/ic/ic.h | 35 | ||||
-rw-r--r-- | deps/v8/src/ic/keyed-store-generic.cc | 261 | ||||
-rw-r--r-- | deps/v8/src/ic/keyed-store-generic.h | 3 | ||||
-rw-r--r-- | deps/v8/src/ic/stub-cache.cc | 5 | ||||
-rw-r--r-- | deps/v8/src/ic/stub-cache.h | 18 |
15 files changed, 1195 insertions, 983 deletions
diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc index f9efcba05f..99cbd3c3c8 100644 --- a/deps/v8/src/ic/accessor-assembler.cc +++ b/deps/v8/src/ic/accessor-assembler.cc @@ -5,6 +5,7 @@ #include "src/ic/accessor-assembler.h" #include "src/ast/ast.h" +#include "src/base/optional.h" #include "src/codegen/code-factory.h" #include "src/ic/handler-configuration.h" #include "src/ic/ic.h" @@ -16,6 +17,7 @@ #include "src/objects/heap-number.h" #include "src/objects/module.h" #include "src/objects/objects-inl.h" +#include "src/objects/property-details.h" #include "src/objects/smi.h" namespace v8 { @@ -23,10 +25,6 @@ namespace internal { using compiler::CodeAssemblerState; using compiler::Node; -template <typename T> -using TNode = compiler::TNode<T>; -template <typename T> -using SloppyTNode = compiler::SloppyTNode<T>; //////////////////// Private helpers. @@ -66,27 +64,25 @@ TNode<MaybeObject> AccessorAssembler::LoadHandlerDataField( } TNode<MaybeObject> AccessorAssembler::TryMonomorphicCase( - Node* slot, Node* vector, Node* receiver_map, Label* if_handler, - TVariable<MaybeObject>* var_handler, Label* if_miss) { + TNode<Smi> slot, TNode<FeedbackVector> vector, TNode<Map> receiver_map, + Label* if_handler, TVariable<MaybeObject>* var_handler, Label* if_miss) { Comment("TryMonomorphicCase"); DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep()); // TODO(ishell): add helper class that hides offset computations for a series // of loads. - CSA_ASSERT(this, IsFeedbackVector(vector), vector); int32_t header_size = FeedbackVector::kFeedbackSlotsOffset - kHeapObjectTag; // Adding |header_size| with a separate IntPtrAdd rather than passing it // into ElementOffsetFromIndex() allows it to be folded into a single // [base, index, offset] indirect memory access on x64. - TNode<IntPtrT> offset = - ElementOffsetFromIndex(slot, HOLEY_ELEMENTS, SMI_PARAMETERS); + TNode<IntPtrT> offset = ElementOffsetFromIndex(slot, HOLEY_ELEMENTS); TNode<MaybeObject> feedback = ReinterpretCast<MaybeObject>( Load(MachineType::AnyTagged(), vector, IntPtrAdd(offset, IntPtrConstant(header_size)))); // Try to quickly handle the monomorphic case without knowing for sure // if we have a weak reference in feedback. - GotoIf(IsNotWeakReferenceTo(feedback, CAST(receiver_map)), if_miss); + GotoIfNot(IsWeakReferenceTo(feedback, receiver_map), if_miss); TNode<MaybeObject> handler = UncheckedCast<MaybeObject>( Load(MachineType::AnyTagged(), vector, @@ -98,7 +94,7 @@ TNode<MaybeObject> AccessorAssembler::TryMonomorphicCase( } void AccessorAssembler::HandlePolymorphicCase( - Node* receiver_map, TNode<WeakFixedArray> feedback, Label* if_handler, + TNode<Map> receiver_map, TNode<WeakFixedArray> feedback, Label* if_handler, TVariable<MaybeObject>* var_handler, Label* if_miss) { Comment("HandlePolymorphicCase"); DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep()); @@ -121,8 +117,7 @@ void AccessorAssembler::HandlePolymorphicCase( TNode<MaybeObject> maybe_cached_map = LoadWeakFixedArrayElement(feedback, var_index.value()); CSA_ASSERT(this, IsWeakOrCleared(maybe_cached_map)); - GotoIf(IsNotWeakReferenceTo(maybe_cached_map, CAST(receiver_map)), - &loop_next); + GotoIfNot(IsWeakReferenceTo(maybe_cached_map, receiver_map), &loop_next); // Found, now call handler. TNode<MaybeObject> handler = @@ -157,7 +152,7 @@ void AccessorAssembler::HandleLoadICHandlerCase( BIND(&try_proto_handler); { GotoIf(IsCodeMap(LoadMap(CAST(handler))), &call_handler); - HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler, + HandleLoadICProtoHandler(p, CAST(handler), &var_holder, &var_smi_handler, &if_smi_handler, miss, exit_point, ic_mode, access_mode); } @@ -167,8 +162,8 @@ void AccessorAssembler::HandleLoadICHandlerCase( BIND(&if_smi_handler); { HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(), - handler, miss, exit_point, on_nonexistent, - support_elements, access_mode); + handler, miss, exit_point, ic_mode, + on_nonexistent, support_elements, access_mode); } BIND(&call_handler); @@ -237,9 +232,10 @@ void AccessorAssembler::HandleLoadAccessor( api_holder.value(), p->receiver())); } -void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word, +void AccessorAssembler::HandleLoadField(SloppyTNode<JSObject> holder, + TNode<WordT> handler_word, Variable* var_double_value, - Label* rebox_double, + Label* rebox_double, Label* miss, ExitPoint* exit_point) { Comment("field_load"); TNode<IntPtrT> index = @@ -261,8 +257,13 @@ void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word, var_double_value->Bind( LoadObjectField(holder, offset, MachineType::Float64())); } else { - TNode<HeapNumber> heap_number = CAST(LoadObjectField(holder, offset)); - var_double_value->Bind(LoadHeapNumberValue(heap_number)); + TNode<Object> heap_number = LoadObjectField(holder, offset); + // This is not an "old" Smi value from before a Smi->Double transition. + // Rather, it's possible that since the last update of this IC, the Double + // field transitioned to a Tagged field, and was then assigned a Smi. + GotoIf(TaggedIsSmi(heap_number), miss); + GotoIfNot(IsHeapNumber(CAST(heap_number)), miss); + var_double_value->Bind(LoadHeapNumberValue(CAST(heap_number))); } Goto(rebox_double); } @@ -276,6 +277,13 @@ void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word, exit_point->Return(value); BIND(&is_double); + if (!FLAG_unbox_double_fields) { + // This is not an "old" Smi value from before a Smi->Double transition. + // Rather, it's possible that since the last update of this IC, the Double + // field transitioned to a Tagged field, and was then assigned a Smi. + GotoIf(TaggedIsSmi(value), miss); + GotoIfNot(IsHeapNumber(CAST(value)), miss); + } var_double_value->Bind(LoadHeapNumberValue(CAST(value))); Goto(rebox_double); } @@ -293,10 +301,10 @@ TNode<MaybeObject> AccessorAssembler::LoadDescriptorValueOrFieldType( } void AccessorAssembler::HandleLoadICSmiHandlerCase( - const LazyLoadICParameters* p, Node* holder, SloppyTNode<Smi> smi_handler, - SloppyTNode<Object> handler, Label* miss, ExitPoint* exit_point, - OnNonExistent on_nonexistent, ElementSupport support_elements, - LoadAccessMode access_mode) { + const LazyLoadICParameters* p, SloppyTNode<HeapObject> holder, + SloppyTNode<Smi> smi_handler, SloppyTNode<Object> handler, Label* miss, + ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent, + ElementSupport support_elements, LoadAccessMode access_mode) { VARIABLE(var_double_value, MachineRepresentation::kFloat64); Label rebox_double(this, &var_double_value); @@ -388,10 +396,11 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase( Label if_oob(this, Label::kDeferred); Comment("indexed string"); + TNode<String> string_holder = CAST(holder); TNode<IntPtrT> intptr_index = TryToIntptr(p->name(), miss); - TNode<IntPtrT> length = LoadStringLengthAsWord(holder); + TNode<IntPtrT> length = LoadStringLengthAsWord(string_holder); GotoIf(UintPtrGreaterThanOrEqual(intptr_index, length), &if_oob); - TNode<Int32T> code = StringCharCodeAt(holder, intptr_index); + TNode<Int32T> code = StringCharCodeAt(string_holder, intptr_index); TNode<String> result = StringFromSingleCharCode(code); Return(result); @@ -410,23 +419,25 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase( if (access_mode == LoadAccessMode::kHas) { HandleLoadICSmiHandlerHasNamedCase(p, holder, handler_kind, miss, - exit_point); + exit_point, ic_mode); } else { HandleLoadICSmiHandlerLoadNamedCase( p, holder, handler_kind, handler_word, &rebox_double, &var_double_value, - handler, miss, exit_point, on_nonexistent, support_elements); + handler, miss, exit_point, ic_mode, on_nonexistent, support_elements); } } void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase( - const LazyLoadICParameters* p, Node* holder, TNode<IntPtrT> handler_kind, - TNode<WordT> handler_word, Label* rebox_double, Variable* var_double_value, - SloppyTNode<Object> handler, Label* miss, ExitPoint* exit_point, - OnNonExistent on_nonexistent, ElementSupport support_elements) { + const LazyLoadICParameters* p, TNode<HeapObject> holder, + TNode<IntPtrT> handler_kind, TNode<WordT> handler_word, Label* rebox_double, + Variable* var_double_value, SloppyTNode<Object> handler, Label* miss, + ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent, + ElementSupport support_elements) { Label constant(this), field(this), normal(this, Label::kDeferred), - interceptor(this, Label::kDeferred), nonexistent(this), - accessor(this, Label::kDeferred), global(this, Label::kDeferred), - module_export(this, Label::kDeferred), proxy(this, Label::kDeferred), + slow(this, Label::kDeferred), interceptor(this, Label::kDeferred), + nonexistent(this), accessor(this, Label::kDeferred), + global(this, Label::kDeferred), module_export(this, Label::kDeferred), + proxy(this, Label::kDeferred), native_data_property(this, Label::kDeferred), api_getter(this, Label::kDeferred); @@ -459,14 +470,16 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase( GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)), &global); + GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kSlow)), &slow); + GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kProxy)), &proxy); Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kModuleExport)), &module_export, &interceptor); BIND(&field); - HandleLoadField(holder, handler_word, var_double_value, rebox_double, - exit_point); + HandleLoadField(CAST(holder), handler_word, var_double_value, rebox_double, + miss, exit_point); BIND(&nonexistent); // This is a handler for a load of a non-existent value. @@ -487,7 +500,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase( BIND(&normal); { Comment("load_normal"); - TNode<NameDictionary> properties = CAST(LoadSlowProperties(holder)); + TNode<NameDictionary> properties = CAST(LoadSlowProperties(CAST(holder))); TVARIABLE(IntPtrT, var_name_index); Label found(this, &var_name_index); NameDictionaryLookup<NameDictionary>(properties, CAST(p->name()), &found, @@ -529,8 +542,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase( BIND(&proxy); { - VARIABLE(var_index, MachineType::PointerRepresentation()); - VARIABLE(var_unique, MachineRepresentation::kTagged); + TVARIABLE(IntPtrT, var_index); + TVARIABLE(Name, var_unique); Label if_index(this), if_unique_name(this), to_name_failed(this, Label::kDeferred); @@ -586,20 +599,31 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase( p->context(), p->name(), p->receiver(), holder, p->slot(), p->vector()); } + BIND(&slow); + { + Comment("load_slow"); + if (ic_mode == ICMode::kGlobalIC) { + exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Slow, p->context(), + p->name(), p->slot(), p->vector()); + + } else { + exit_point->ReturnCallRuntime(Runtime::kGetProperty, p->context(), + p->receiver(), p->name()); + } + } BIND(&module_export); { Comment("module export"); TNode<UintPtrT> index = DecodeWord<LoadHandler::ExportsIndexBits>(handler_word); - Node* module = - LoadObjectField(p->receiver(), JSModuleNamespace::kModuleOffset, - MachineType::TaggedPointer()); - TNode<ObjectHashTable> exports = CAST(LoadObjectField( - module, Module::kExportsOffset, MachineType::TaggedPointer())); + TNode<Module> module = + CAST(LoadObjectField(p->receiver(), JSModuleNamespace::kModuleOffset)); + TNode<ObjectHashTable> exports = + LoadObjectField<ObjectHashTable>(module, Module::kExportsOffset); TNode<Cell> cell = CAST(LoadFixedArrayElement(exports, index)); // The handler is only installed for exports that exist. - Node* value = LoadCellValue(cell); + TNode<Object> value = LoadCellValue(cell); Label is_the_hole(this, Label::kDeferred); GotoIf(IsTheHole(value), &is_the_hole); exit_point->Return(value); @@ -617,10 +641,11 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase( } void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase( - const LazyLoadICParameters* p, Node* holder, TNode<IntPtrT> handler_kind, - Label* miss, ExitPoint* exit_point) { + const LazyLoadICParameters* p, TNode<HeapObject> holder, + TNode<IntPtrT> handler_kind, Label* miss, ExitPoint* exit_point, + ICMode ic_mode) { Label return_true(this), return_false(this), return_lookup(this), - normal(this), global(this); + normal(this), global(this), slow(this); GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)), &return_true); @@ -649,6 +674,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase( IntPtrConstant(LoadHandler::kApiGetterHolderIsPrototype)), &return_true); + GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kSlow)), &slow); + Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)), &global, &return_lookup); @@ -676,7 +703,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase( BIND(&normal); { Comment("has_normal"); - TNode<NameDictionary> properties = CAST(LoadSlowProperties(holder)); + TNode<NameDictionary> properties = CAST(LoadSlowProperties(CAST(holder))); TVARIABLE(IntPtrT, var_name_index); Label found(this); NameDictionaryLookup<NameDictionary>(properties, CAST(p->name()), &found, @@ -695,6 +722,18 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase( exit_point->Return(TrueConstant()); } + + BIND(&slow); + { + Comment("load_slow"); + if (ic_mode == ICMode::kGlobalIC) { + exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Slow, p->context(), + p->name(), p->slot(), p->vector()); + } else { + exit_point->ReturnCallRuntime(Runtime::kHasProperty, p->context(), + p->receiver(), p->name()); + } + } } // Performs actions common to both load and store handlers: @@ -715,8 +754,9 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase( // TODO(ishell): Remove templatezation once we move common bits from // Load/StoreHandler to the base class. template <typename ICHandler, typename ICParameters> -Node* AccessorAssembler::HandleProtoHandler( - const ICParameters* p, Node* handler, const OnCodeHandler& on_code_handler, +TNode<Object> AccessorAssembler::HandleProtoHandler( + const ICParameters* p, TNode<DataHandler> handler, + const OnCodeHandler& on_code_handler, const OnFoundOnReceiver& on_found_on_receiver, Label* miss, ICMode ic_mode) { // @@ -738,8 +778,7 @@ Node* AccessorAssembler::HandleProtoHandler( Label if_smi_handler(this); GotoIf(TaggedIsSmi(smi_or_code_handler), &if_smi_handler); - CSA_ASSERT(this, IsCodeMap(LoadMap(CAST(smi_or_code_handler)))); - on_code_handler(smi_or_code_handler); + on_code_handler(CAST(smi_or_code_handler)); BIND(&if_smi_handler); } @@ -771,8 +810,8 @@ Node* AccessorAssembler::HandleProtoHandler( CSA_ASSERT(this, IsWeakOrCleared(data2)); TNode<Context> expected_native_context = CAST(GetHeapObjectAssumeWeak(data2, miss)); - EmitAccessCheck(expected_native_context, p->context(), p->receiver(), - &done, miss); + EmitAccessCheck(expected_native_context, p->context(), + CAST(p->receiver()), &done, miss); } // Dictionary lookup on receiver is not necessary for Load/StoreGlobalIC @@ -807,18 +846,19 @@ Node* AccessorAssembler::HandleProtoHandler( } void AccessorAssembler::HandleLoadICProtoHandler( - const LazyLoadICParameters* p, Node* handler, Variable* var_holder, - Variable* var_smi_handler, Label* if_smi_handler, Label* miss, - ExitPoint* exit_point, ICMode ic_mode, LoadAccessMode access_mode) { + const LazyLoadICParameters* p, TNode<DataHandler> handler, + Variable* var_holder, Variable* var_smi_handler, Label* if_smi_handler, + Label* miss, ExitPoint* exit_point, ICMode ic_mode, + LoadAccessMode access_mode) { DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep()); DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep()); - Node* smi_handler = HandleProtoHandler<LoadHandler>( + TNode<Smi> smi_handler = CAST(HandleProtoHandler<LoadHandler>( p, handler, // Code sub-handlers are not expected in LoadICs, so no |on_code_handler|. nullptr, // on_found_on_receiver - [=](Node* properties, Node* name_index) { + [=](TNode<NameDictionary> properties, TNode<IntPtrT> name_index) { if (access_mode == LoadAccessMode::kHas) { exit_point->Return(TrueConstant()); } else { @@ -832,7 +872,7 @@ void AccessorAssembler::HandleLoadICProtoHandler( exit_point->Return(value); } }, - miss, ic_mode); + miss, ic_mode)); TNode<MaybeObject> maybe_holder_or_constant = LoadHandlerDataField(handler, 1); @@ -840,7 +880,7 @@ void AccessorAssembler::HandleLoadICProtoHandler( Label load_from_cached_holder(this), is_smi(this), done(this); GotoIf(TaggedIsSmi(maybe_holder_or_constant), &is_smi); - Branch(IsStrongReferenceTo(maybe_holder_or_constant, NullConstant()), &done, + Branch(TaggedEqual(maybe_holder_or_constant, NullConstant()), &done, &load_from_cached_holder); BIND(&is_smi); @@ -878,14 +918,15 @@ void AccessorAssembler::HandleLoadICProtoHandler( } void AccessorAssembler::EmitAccessCheck(TNode<Context> expected_native_context, - TNode<Context> context, Node* receiver, + TNode<Context> context, + TNode<Object> receiver, Label* can_access, Label* miss) { CSA_ASSERT(this, IsNativeContext(expected_native_context)); - TNode<Context> native_context = LoadNativeContext(context); + TNode<NativeContext> native_context = LoadNativeContext(context); GotoIf(TaggedEqual(expected_native_context, native_context), can_access); // If the receiver is not a JSGlobalProxy then we miss. - GotoIfNot(IsJSGlobalProxy(receiver), miss); + GotoIfNot(IsJSGlobalProxy(CAST(receiver)), miss); // For JSGlobalProxy receiver try to compare security tokens of current // and expected native contexts. TNode<Object> expected_token = LoadContextElement( @@ -895,8 +936,8 @@ void AccessorAssembler::EmitAccessCheck(TNode<Context> expected_native_context, Branch(TaggedEqual(expected_token, current_token), can_access, miss); } -void AccessorAssembler::JumpIfDataProperty(Node* details, Label* writable, - Label* readonly) { +void AccessorAssembler::JumpIfDataProperty(TNode<Uint32T> details, + Label* writable, Label* readonly) { if (readonly) { // Accessor properties never have the READ_ONLY attribute set. GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask), @@ -911,10 +952,11 @@ void AccessorAssembler::JumpIfDataProperty(Node* details, Label* writable, } void AccessorAssembler::HandleStoreICNativeDataProperty( - const StoreICParameters* p, Node* holder, Node* handler_word) { + const StoreICParameters* p, SloppyTNode<HeapObject> holder, + TNode<Word32T> handler_word) { Comment("native_data_property_store"); TNode<IntPtrT> descriptor = - Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word)); + Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word)); TNode<AccessorInfo> accessor_info = CAST(LoadDescriptorValue(LoadMap(holder), descriptor)); @@ -936,23 +978,30 @@ void AccessorAssembler::HandleStoreICHandlerCase( BIND(&if_smi_handler); { Node* holder = p->receiver(); - TNode<IntPtrT> handler_word = SmiUntag(CAST(handler)); + TNode<Int32T> handler_word = SmiToInt32(CAST(handler)); - Label if_fast_smi(this), if_proxy(this); + Label if_fast_smi(this), if_proxy(this), if_interceptor(this), + if_slow(this); STATIC_ASSERT(StoreHandler::kGlobalProxy + 1 == StoreHandler::kNormal); - STATIC_ASSERT(StoreHandler::kNormal + 1 == StoreHandler::kProxy); + STATIC_ASSERT(StoreHandler::kNormal + 1 == StoreHandler::kInterceptor); + STATIC_ASSERT(StoreHandler::kInterceptor + 1 == StoreHandler::kSlow); + STATIC_ASSERT(StoreHandler::kSlow + 1 == StoreHandler::kProxy); STATIC_ASSERT(StoreHandler::kProxy + 1 == StoreHandler::kKindsNumber); - TNode<UintPtrT> handler_kind = - DecodeWord<StoreHandler::KindBits>(handler_word); - GotoIf(IntPtrLessThan(handler_kind, - IntPtrConstant(StoreHandler::kGlobalProxy)), - &if_fast_smi); - GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kProxy)), + TNode<Uint32T> handler_kind = + DecodeWord32<StoreHandler::KindBits>(handler_word); + GotoIf( + Int32LessThan(handler_kind, Int32Constant(StoreHandler::kGlobalProxy)), + &if_fast_smi); + GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kProxy)), &if_proxy); + GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kInterceptor)), + &if_interceptor); + GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kSlow)), + &if_slow); CSA_ASSERT(this, - WordEqual(handler_kind, IntPtrConstant(StoreHandler::kNormal))); + Word32Equal(handler_kind, Int32Constant(StoreHandler::kNormal))); TNode<NameDictionary> properties = CAST(LoadSlowProperties(holder)); TVARIABLE(IntPtrT, var_name_index); @@ -976,14 +1025,14 @@ void AccessorAssembler::HandleStoreICHandlerCase( BIND(&if_fast_smi); { - TNode<UintPtrT> handler_kind = - DecodeWord<StoreHandler::KindBits>(handler_word); + TNode<Uint32T> handler_kind = + DecodeWord32<StoreHandler::KindBits>(handler_word); Label data(this), accessor(this), native_data_property(this); - GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kAccessor)), + GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kAccessor)), &accessor); - Branch(WordEqual(handler_kind, - IntPtrConstant(StoreHandler::kNativeDataProperty)), + Branch(Word32Equal(handler_kind, + Int32Constant(StoreHandler::kNativeDataProperty)), &native_data_property, &data); BIND(&accessor); @@ -999,6 +1048,29 @@ void AccessorAssembler::HandleStoreICHandlerCase( BIND(&if_proxy); HandleStoreToProxy(p, holder, miss, support_elements); + + BIND(&if_interceptor); + { + Comment("store_interceptor"); + TailCallRuntime(Runtime::kStorePropertyWithInterceptor, p->context(), + p->value(), p->slot(), p->vector(), p->receiver(), + p->name()); + } + + BIND(&if_slow); + { + Comment("store_slow"); + // The slow case calls into the runtime to complete the store without + // causing an IC miss that would otherwise cause a transition to the + // generic stub. + if (ic_mode == ICMode::kGlobalIC) { + TailCallRuntime(Runtime::kStoreGlobalIC_Slow, p->context(), p->value(), + p->slot(), p->vector(), p->receiver(), p->name()); + } else { + TailCallRuntime(Runtime::kKeyedStoreIC_Slow, p->context(), p->value(), + p->receiver(), p->name()); + } + } } BIND(&if_nonsmi_handler); @@ -1111,7 +1183,7 @@ void AccessorAssembler::HandleStoreICTransitionMapHandlerCase( } void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors, - Node* name_index, + TNode<IntPtrT> name_index, TNode<Word32T> representation, Node* value, Label* bailout) { Label r_smi(this), r_double(this), r_heapobject(this), all_fine(this); @@ -1143,20 +1215,20 @@ void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors, BIND(&r_heapobject); { GotoIf(TaggedIsSmi(value), bailout); - TNode<MaybeObject> field_type = LoadFieldTypeByKeyIndex( - descriptors, UncheckedCast<IntPtrT>(name_index)); + TNode<MaybeObject> field_type = + LoadFieldTypeByKeyIndex(descriptors, name_index); const Address kNoneType = FieldType::None().ptr(); const Address kAnyType = FieldType::Any().ptr(); DCHECK_NE(static_cast<uint32_t>(kNoneType), kClearedWeakHeapObjectLower32); DCHECK_NE(static_cast<uint32_t>(kAnyType), kClearedWeakHeapObjectLower32); // FieldType::None can't hold any value. - GotoIf(WordEqual(BitcastMaybeObjectToWord(field_type), - IntPtrConstant(kNoneType)), - bailout); + GotoIf( + TaggedEqual(field_type, BitcastWordToTagged(IntPtrConstant(kNoneType))), + bailout); // FieldType::Any can hold any value. - GotoIf(WordEqual(BitcastMaybeObjectToWord(field_type), - IntPtrConstant(kAnyType)), - &all_fine); + GotoIf( + TaggedEqual(field_type, BitcastWordToTagged(IntPtrConstant(kAnyType))), + &all_fine); // Cleared weak references count as FieldType::None, which can't hold any // value. TNode<Map> field_type_map = @@ -1168,15 +1240,16 @@ void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors, BIND(&all_fine); } -TNode<BoolT> AccessorAssembler::IsPropertyDetailsConst(Node* details) { +TNode<BoolT> AccessorAssembler::IsPropertyDetailsConst(TNode<Uint32T> details) { return Word32Equal(DecodeWord32<PropertyDetails::ConstnessField>(details), Int32Constant(static_cast<int32_t>(VariableMode::kConst))); } void AccessorAssembler::OverwriteExistingFastDataProperty( - Node* object, Node* object_map, Node* descriptors, - Node* descriptor_name_index, Node* details, TNode<Object> value, - Label* slow, bool do_transitioning_store) { + SloppyTNode<HeapObject> object, TNode<Map> object_map, + TNode<DescriptorArray> descriptors, TNode<IntPtrT> descriptor_name_index, + TNode<Uint32T> details, TNode<Object> value, Label* slow, + bool do_transitioning_store) { Label done(this), if_field(this), if_descriptor(this); CSA_ASSERT(this, @@ -1192,8 +1265,8 @@ void AccessorAssembler::OverwriteExistingFastDataProperty( TNode<Uint32T> representation = DecodeWord32<PropertyDetails::RepresentationField>(details); - CheckFieldType(CAST(descriptors), descriptor_name_index, representation, - value, slow); + CheckFieldType(descriptors, descriptor_name_index, representation, value, + slow); TNode<UintPtrT> field_index = DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details); @@ -1224,7 +1297,7 @@ void AccessorAssembler::OverwriteExistingFastDataProperty( Label if_mutable(this); GotoIfNot(IsPropertyDetailsConst(details), &if_mutable); TNode<Float64T> current_value = - LoadObjectField<Float64T>(CAST(object), field_offset); + LoadObjectField<Float64T>(object, field_offset); BranchIfSameNumberValue(current_value, double_value, &done, slow); BIND(&if_mutable); } @@ -1257,8 +1330,7 @@ void AccessorAssembler::OverwriteExistingFastDataProperty( } else { Label if_mutable(this); GotoIfNot(IsPropertyDetailsConst(details), &if_mutable); - TNode<Object> current_value = - LoadObjectField(CAST(object), field_offset); + TNode<Object> current_value = LoadObjectField(object, field_offset); BranchIfSameValue(current_value, value, &done, slow, SameValueMode::kNumbersOnly); BIND(&if_mutable); @@ -1302,7 +1374,8 @@ void AccessorAssembler::OverwriteExistingFastDataProperty( } else { Label tagged_rep(this), double_rep(this); - TNode<PropertyArray> properties = CAST(LoadFastProperties(object)); + TNode<PropertyArray> properties = + CAST(LoadFastProperties(CAST(object))); Branch( Word32Equal(representation, Int32Constant(Representation::kDouble)), &double_rep, &tagged_rep); @@ -1342,7 +1415,7 @@ void AccessorAssembler::OverwriteExistingFastDataProperty( { // Check that constant matches value. TNode<Object> constant = LoadValueByKeyIndex( - CAST(descriptors), UncheckedCast<IntPtrT>(descriptor_name_index)); + descriptors, UncheckedCast<IntPtrT>(descriptor_name_index)); GotoIf(TaggedNotEqual(value, constant), slow); if (do_transitioning_store) { @@ -1370,10 +1443,11 @@ void AccessorAssembler::CheckPrototypeValidityCell( } void AccessorAssembler::HandleStoreAccessor(const StoreICParameters* p, - Node* holder, Node* handler_word) { + SloppyTNode<HeapObject> holder, + TNode<Word32T> handler_word) { Comment("accessor_store"); TNode<IntPtrT> descriptor = - Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word)); + Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word)); TNode<HeapObject> accessor_pair = CAST(LoadDescriptorValue(LoadMap(holder), descriptor)); CSA_ASSERT(this, IsAccessorPair(accessor_pair)); @@ -1393,7 +1467,7 @@ void AccessorAssembler::HandleStoreICProtoHandler( OnCodeHandler on_code_handler; if (support_elements == kSupportElements) { // Code sub-handlers are expected only in KeyedStoreICs. - on_code_handler = [=](Node* code_handler) { + on_code_handler = [=](TNode<Code> code_handler) { // This is either element store or transitioning element store. Label if_element_store(this), if_transitioning_element_store(this); Branch(IsStoreHandler0Map(LoadMap(handler)), &if_element_store, @@ -1421,10 +1495,10 @@ void AccessorAssembler::HandleStoreICProtoHandler( }; } - Node* smi_handler = HandleProtoHandler<StoreHandler>( + TNode<Object> smi_handler = HandleProtoHandler<StoreHandler>( p, handler, on_code_handler, // on_found_on_receiver - [=](Node* properties, Node* name_index) { + [=](TNode<NameDictionary> properties, TNode<IntPtrT> name_index) { TNode<Uint32T> details = LoadDetailsByKeyIndex<NameDictionary>(properties, name_index); // Check that the property is a writable data property (no accessor). @@ -1434,49 +1508,80 @@ void AccessorAssembler::HandleStoreICProtoHandler( STATIC_ASSERT(kData == 0); GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss); - StoreValueByKeyIndex<NameDictionary>( - CAST(properties), UncheckedCast<IntPtrT>(name_index), p->value()); + StoreValueByKeyIndex<NameDictionary>(properties, name_index, + p->value()); Return(p->value()); }, miss, ic_mode); { Label if_add_normal(this), if_store_global_proxy(this), if_api_setter(this), - if_accessor(this), if_native_data_property(this); + if_accessor(this), if_native_data_property(this), if_slow(this), + if_interceptor(this); CSA_ASSERT(this, TaggedIsSmi(smi_handler)); - TNode<IntPtrT> handler_word = SmiUntag(smi_handler); + TNode<Int32T> handler_word = SmiToInt32(CAST(smi_handler)); - TNode<UintPtrT> handler_kind = - DecodeWord<StoreHandler::KindBits>(handler_word); - GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kNormal)), + TNode<Uint32T> handler_kind = + DecodeWord32<StoreHandler::KindBits>(handler_word); + GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kNormal)), &if_add_normal); TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1); CSA_ASSERT(this, IsWeakOrCleared(maybe_holder)); TNode<HeapObject> holder = GetHeapObjectAssumeWeak(maybe_holder, miss); - GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kGlobalProxy)), + GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kGlobalProxy)), &if_store_global_proxy); - GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kAccessor)), + GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kAccessor)), &if_accessor); - GotoIf(WordEqual(handler_kind, - IntPtrConstant(StoreHandler::kNativeDataProperty)), + GotoIf(Word32Equal(handler_kind, + Int32Constant(StoreHandler::kNativeDataProperty)), &if_native_data_property); - GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kApiSetter)), + GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kApiSetter)), &if_api_setter); - GotoIf(WordEqual(handler_kind, - IntPtrConstant(StoreHandler::kApiSetterHolderIsPrototype)), - &if_api_setter); + GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kSlow)), + &if_slow); + + GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kInterceptor)), + &if_interceptor); + + GotoIf( + Word32Equal(handler_kind, + Int32Constant(StoreHandler::kApiSetterHolderIsPrototype)), + &if_api_setter); CSA_ASSERT(this, - WordEqual(handler_kind, IntPtrConstant(StoreHandler::kProxy))); + Word32Equal(handler_kind, Int32Constant(StoreHandler::kProxy))); HandleStoreToProxy(p, holder, miss, support_elements); + BIND(&if_slow); + { + Comment("store_slow"); + // The slow case calls into the runtime to complete the store without + // causing an IC miss that would otherwise cause a transition to the + // generic stub. + if (ic_mode == ICMode::kGlobalIC) { + TailCallRuntime(Runtime::kStoreGlobalIC_Slow, p->context(), p->value(), + p->slot(), p->vector(), p->receiver(), p->name()); + } else { + TailCallRuntime(Runtime::kKeyedStoreIC_Slow, p->context(), p->value(), + p->receiver(), p->name()); + } + } + + BIND(&if_interceptor); + { + Comment("store_interceptor"); + TailCallRuntime(Runtime::kStorePropertyWithInterceptor, p->context(), + p->value(), p->slot(), p->vector(), p->receiver(), + p->name()); + } + BIND(&if_add_normal); { // This is a case of "transitioning store" to a dictionary mode object @@ -1512,7 +1617,7 @@ void AccessorAssembler::HandleStoreICProtoHandler( // Context is stored either in data2 or data3 field depending on whether // the access check is enabled for this handler or not. TNode<MaybeObject> maybe_context = Select<MaybeObject>( - IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word), + IsSetWord32<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word), [=] { return LoadHandlerDataField(handler, 3); }, [=] { return LoadHandlerDataField(handler, 2); }); @@ -1530,13 +1635,13 @@ void AccessorAssembler::HandleStoreICProtoHandler( VARIABLE(api_holder, MachineRepresentation::kTagged, p->receiver()); Label store(this); - GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kApiSetter)), + GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kApiSetter)), &store); - CSA_ASSERT( - this, - WordEqual(handler_kind, - IntPtrConstant(StoreHandler::kApiSetterHolderIsPrototype))); + CSA_ASSERT(this, + Word32Equal( + handler_kind, + Int32Constant(StoreHandler::kApiSetterHolderIsPrototype))); api_holder.Bind(LoadMapPrototype(LoadMap(p->receiver()))); Goto(&store); @@ -1559,8 +1664,8 @@ void AccessorAssembler::HandleStoreICProtoHandler( void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p, Node* proxy, Label* miss, ElementSupport support_elements) { - VARIABLE(var_index, MachineType::PointerRepresentation()); - VARIABLE(var_unique, MachineRepresentation::kTagged); + TVARIABLE(IntPtrT, var_index); + TVARIABLE(Name, var_unique); Label if_index(this), if_unique_name(this), to_name_failed(this, Label::kDeferred); @@ -1591,128 +1696,200 @@ void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p, } } -void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word, - Node* holder, Node* value, - Label* miss) { +void AccessorAssembler::HandleStoreICSmiHandlerCase( + SloppyTNode<Word32T> handler_word, SloppyTNode<JSObject> holder, + SloppyTNode<Object> value, Label* miss) { Comment("field store"); #ifdef DEBUG - TNode<UintPtrT> handler_kind = - DecodeWord<StoreHandler::KindBits>(handler_word); + TNode<Uint32T> handler_kind = + DecodeWord32<StoreHandler::KindBits>(handler_word); CSA_ASSERT( this, Word32Or( - WordEqual(handler_kind, IntPtrConstant(StoreHandler::kField)), - WordEqual(handler_kind, IntPtrConstant(StoreHandler::kConstField)))); + Word32Equal(handler_kind, Int32Constant(StoreHandler::kField)), + Word32Equal(handler_kind, Int32Constant(StoreHandler::kConstField)))); #endif - TNode<UintPtrT> field_representation = - DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word); + TNode<Uint32T> field_representation = + DecodeWord32<StoreHandler::RepresentationBits>(handler_word); Label if_smi_field(this), if_double_field(this), if_heap_object_field(this), if_tagged_field(this); - GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kTagged)), - &if_tagged_field); - GotoIf(WordEqual(field_representation, - IntPtrConstant(StoreHandler::kHeapObject)), - &if_heap_object_field); - GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kDouble)), - &if_double_field); - CSA_ASSERT(this, WordEqual(field_representation, - IntPtrConstant(StoreHandler::kSmi))); - Goto(&if_smi_field); + int32_t case_values[] = {Representation::kTagged, Representation::kHeapObject, + Representation::kSmi}; + Label* case_labels[] = {&if_tagged_field, &if_heap_object_field, + &if_smi_field}; + + Switch(field_representation, &if_double_field, case_values, case_labels, 3); BIND(&if_tagged_field); { Comment("store tagged field"); - HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(), - value, miss); - } - - BIND(&if_double_field); - { - Comment("store double field"); - HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(), - value, miss); + HandleStoreFieldAndReturn(handler_word, holder, value, base::nullopt, + Representation::Tagged(), miss); } BIND(&if_heap_object_field); { + Comment("heap object field checks"); + CheckHeapObjectTypeMatchesDescriptor(handler_word, holder, value, miss); + Comment("store heap object field"); - HandleStoreFieldAndReturn(handler_word, holder, - Representation::HeapObject(), value, miss); + HandleStoreFieldAndReturn(handler_word, holder, value, base::nullopt, + Representation::HeapObject(), miss); } BIND(&if_smi_field); { + Comment("smi field checks"); + GotoIfNot(TaggedIsSmi(value), miss); + Comment("store smi field"); - HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(), - value, miss); + HandleStoreFieldAndReturn(handler_word, holder, value, base::nullopt, + Representation::Smi(), miss); + } + + BIND(&if_double_field); + { + CSA_ASSERT(this, Word32Equal(field_representation, + Int32Constant(Representation::kDouble))); + Comment("double field checks"); + TNode<Float64T> double_value = TryTaggedToFloat64(value, miss); + CheckDescriptorConsidersNumbersMutable(handler_word, holder, miss); + + Comment("store double field"); + HandleStoreFieldAndReturn(handler_word, holder, value, double_value, + Representation::Double(), miss); } } -void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word, - Node* holder, - Representation representation, - Node* value, Label* miss) { - Node* prepared_value = - PrepareValueForStore(handler_word, holder, representation, value, miss); +void AccessorAssembler::CheckHeapObjectTypeMatchesDescriptor( + TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value, + Label* bailout) { + GotoIf(TaggedIsSmi(value), bailout); - Label if_inobject(this), if_out_of_object(this); - Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject, - &if_out_of_object); + Label done(this); + // Skip field type check in favor of constant value check when storing + // to constant field. + GotoIf(Word32Equal(DecodeWord32<StoreHandler::KindBits>(handler_word), + Int32Constant(StoreHandler::kConstField)), + &done); + TNode<IntPtrT> descriptor = + Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word)); + TNode<MaybeObject> maybe_field_type = + LoadDescriptorValueOrFieldType(LoadMap(holder), descriptor); - BIND(&if_inobject); + GotoIf(TaggedIsSmi(maybe_field_type), &done); + // Check that value type matches the field type. { - StoreNamedField(handler_word, holder, true, representation, prepared_value, - miss); - Return(value); + TNode<HeapObject> field_type = + GetHeapObjectAssumeWeak(maybe_field_type, bailout); + Branch(TaggedEqual(LoadMap(CAST(value)), field_type), &done, bailout); } + BIND(&done); +} - BIND(&if_out_of_object); - { - StoreNamedField(handler_word, holder, false, representation, prepared_value, - miss); - Return(value); - } +void AccessorAssembler::CheckDescriptorConsidersNumbersMutable( + TNode<Word32T> handler_word, TNode<JSObject> holder, Label* bailout) { + // We have to check that the representation is Double. Checking the value + // (either in the field or being assigned) is not enough, as we could have + // transitioned to Tagged but still be holding a HeapNumber, which would no + // longer be allowed to be mutable. + + // TODO(leszeks): We could skip the representation check in favor of a + // constant value check in HandleStoreFieldAndReturn here, but then + // HandleStoreFieldAndReturn would need an IsHeapNumber check in case both the + // representation changed and the value is no longer a HeapNumber. + TNode<IntPtrT> descriptor_entry = + Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word)); + TNode<DescriptorArray> descriptors = LoadMapDescriptors(LoadMap(holder)); + TNode<Uint32T> details = + LoadDetailsByDescriptorEntry(descriptors, descriptor_entry); + + GotoIfNot(IsEqualInWord32<PropertyDetails::RepresentationField>( + details, Representation::kDouble), + bailout); } -Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder, - Representation representation, - Node* value, Label* bailout) { - if (representation.IsDouble()) { - value = TryTaggedToFloat64(value, bailout); +void AccessorAssembler::HandleStoreFieldAndReturn( + TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value, + base::Optional<TNode<Float64T>> double_value, Representation representation, + Label* miss) { + Label done(this); - } else if (representation.IsHeapObject()) { - GotoIf(TaggedIsSmi(value), bailout); + bool store_value_as_double = representation.IsDouble(); - Label done(this); - // Skip field type check in favor of constant value check when storing - // to constant field. - GotoIf(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word), - IntPtrConstant(StoreHandler::kConstField)), - &done); - TNode<IntPtrT> descriptor = - Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word)); - TNode<MaybeObject> maybe_field_type = - LoadDescriptorValueOrFieldType(LoadMap(holder), descriptor); + TNode<BoolT> is_inobject = + IsSetWord32<StoreHandler::IsInobjectBits>(handler_word); + TNode<HeapObject> property_storage = Select<HeapObject>( + is_inobject, [&]() { return holder; }, + [&]() { return LoadFastProperties(holder); }); - GotoIf(TaggedIsSmi(maybe_field_type), &done); - // Check that value type matches the field type. - { - TNode<HeapObject> field_type = - GetHeapObjectAssumeWeak(maybe_field_type, bailout); - Branch(TaggedEqual(LoadMap(CAST(value)), field_type), &done, bailout); + TNode<UintPtrT> index = + DecodeWordFromWord32<StoreHandler::FieldIndexBits>(handler_word); + TNode<IntPtrT> offset = Signed(TimesTaggedSize(index)); + + // For Double fields, we want to mutate the current double-value + // field rather than changing it to point at a new HeapNumber. + if (store_value_as_double) { + TVARIABLE(HeapObject, actual_property_storage, property_storage); + TVARIABLE(IntPtrT, actual_offset, offset); + + Label property_and_offset_ready(this); + + // If we are unboxing double fields, and this is an in-object field, the + // property_storage and offset are already pointing to the double-valued + // field. + if (FLAG_unbox_double_fields) { + GotoIf(is_inobject, &property_and_offset_ready); } - BIND(&done); - } else if (representation.IsSmi()) { - GotoIfNot(TaggedIsSmi(value), bailout); + // Store the double value directly into the mutable HeapNumber. + TNode<Object> field = LoadObjectField(property_storage, offset); + CSA_ASSERT(this, IsHeapNumber(CAST(field))); + actual_property_storage = CAST(field); + actual_offset = IntPtrConstant(HeapNumber::kValueOffset); + Goto(&property_and_offset_ready); + + BIND(&property_and_offset_ready); + property_storage = actual_property_storage.value(); + offset = actual_offset.value(); + } + + // Do constant value check if necessary. + Label do_store(this); + GotoIfNot(Word32Equal(DecodeWord32<StoreHandler::KindBits>(handler_word), + Int32Constant(StoreHandler::kConstField)), + &do_store); + { + if (store_value_as_double) { + Label done(this); + TNode<Float64T> current_value = + LoadObjectField<Float64T>(property_storage, offset); + BranchIfSameNumberValue(current_value, *double_value, &done, miss); + BIND(&done); + Return(value); + } else { + TNode<Object> current_value = LoadObjectField(property_storage, offset); + GotoIfNot(TaggedEqual(current_value, value), miss); + Return(value); + } + } + BIND(&do_store); + // Do the store. + if (store_value_as_double) { + StoreObjectFieldNoWriteBarrier(property_storage, offset, *double_value, + MachineRepresentation::kFloat64); + } else if (representation.IsSmi()) { + TNode<Smi> value_smi = CAST(value); + StoreObjectFieldNoWriteBarrier(property_storage, offset, value_smi); } else { - DCHECK(representation.IsTagged()); + StoreObjectField(property_storage, offset, value); } - return value; + + Return(value); } Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object, @@ -1737,7 +1914,7 @@ Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object, BIND(&if_smi_hash); { TNode<Int32T> hash = SmiToInt32(CAST(properties)); - TNode<Word32T> encoded_hash = + TNode<Int32T> encoded_hash = Word32Shl(hash, Int32Constant(PropertyArray::HashField::kShift)); var_encoded_hash.Bind(encoded_hash); var_length.Bind(IntPtrOrSmiConstant(0, mode)); @@ -1813,59 +1990,6 @@ Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object, } } -void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object, - bool is_inobject, - Representation representation, - Node* value, Label* bailout) { - bool store_value_as_double = representation.IsDouble(); - Node* property_storage = object; - if (!is_inobject) { - property_storage = LoadFastProperties(object); - } - - TNode<UintPtrT> index = - DecodeWord<StoreHandler::FieldIndexBits>(handler_word); - TNode<IntPtrT> offset = Signed(TimesTaggedSize(index)); - if (representation.IsDouble()) { - if (!FLAG_unbox_double_fields || !is_inobject) { - // Load the mutable heap number. - property_storage = LoadObjectField(property_storage, offset); - // Store the double value into it. - offset = IntPtrConstant(HeapNumber::kValueOffset); - } - } - - // Do constant value check if necessary. - Label const_checked(this); - GotoIfNot(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word), - IntPtrConstant(StoreHandler::kConstField)), - &const_checked); - { - if (store_value_as_double) { - TNode<Float64T> current_value = - LoadObjectField<Float64T>(CAST(property_storage), offset); - BranchIfSameNumberValue(current_value, UncheckedCast<Float64T>(value), - &const_checked, bailout); - } else { - TNode<Object> current_value = LoadObjectField(property_storage, offset); - Branch(TaggedEqual(current_value, UncheckedCast<Object>(value)), - &const_checked, bailout); - } - } - - BIND(&const_checked); - // Do the store. - if (store_value_as_double) { - StoreObjectFieldNoWriteBarrier(property_storage, offset, value, - MachineRepresentation::kFloat64); - } else if (representation.IsSmi()) { - TNode<Smi> value_smi = CAST(value); - StoreObjectFieldNoWriteBarrier(property_storage, offset, value_smi); - } else { - StoreObjectField(property_storage, offset, value); - } -} - void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object, Node* elements, Node* intptr_index, @@ -2012,8 +2136,7 @@ void AccessorAssembler::EmitElementLoad( if (access_mode == LoadAccessMode::kHas) { exit_point->Return(TrueConstant()); } else { - TNode<RawPtrT> backing_store = - LoadJSTypedArrayBackingStore(CAST(object)); + TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(CAST(object)); Label uint8_elements(this), int8_elements(this), uint16_elements(this), int16_elements(this), uint32_elements(this), int32_elements(this), @@ -2039,50 +2162,48 @@ void AccessorAssembler::EmitElementLoad( BIND(&uint8_elements); { Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too. - Node* element = - Load(MachineType::Uint8(), backing_store, intptr_index); + Node* element = Load(MachineType::Uint8(), data_ptr, intptr_index); exit_point->Return(SmiFromInt32(element)); } BIND(&int8_elements); { Comment("INT8_ELEMENTS"); - Node* element = - Load(MachineType::Int8(), backing_store, intptr_index); + Node* element = Load(MachineType::Int8(), data_ptr, intptr_index); exit_point->Return(SmiFromInt32(element)); } BIND(&uint16_elements); { Comment("UINT16_ELEMENTS"); TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(1)); - Node* element = Load(MachineType::Uint16(), backing_store, index); + Node* element = Load(MachineType::Uint16(), data_ptr, index); exit_point->Return(SmiFromInt32(element)); } BIND(&int16_elements); { Comment("INT16_ELEMENTS"); TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(1)); - Node* element = Load(MachineType::Int16(), backing_store, index); + Node* element = Load(MachineType::Int16(), data_ptr, index); exit_point->Return(SmiFromInt32(element)); } BIND(&uint32_elements); { Comment("UINT32_ELEMENTS"); TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2)); - Node* element = Load(MachineType::Uint32(), backing_store, index); + Node* element = Load(MachineType::Uint32(), data_ptr, index); exit_point->Return(ChangeUint32ToTagged(element)); } BIND(&int32_elements); { Comment("INT32_ELEMENTS"); TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2)); - Node* element = Load(MachineType::Int32(), backing_store, index); + Node* element = Load(MachineType::Int32(), data_ptr, index); exit_point->Return(ChangeInt32ToTagged(element)); } BIND(&float32_elements); { Comment("FLOAT32_ELEMENTS"); TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2)); - Node* element = Load(MachineType::Float32(), backing_store, index); + Node* element = Load(MachineType::Float32(), data_ptr, index); var_double_value->Bind(ChangeFloat32ToFloat64(element)); Goto(rebox_double); } @@ -2090,7 +2211,7 @@ void AccessorAssembler::EmitElementLoad( { Comment("FLOAT64_ELEMENTS"); TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(3)); - Node* element = Load(MachineType::Float64(), backing_store, index); + Node* element = Load(MachineType::Float64(), data_ptr, index); var_double_value->Bind(element); Goto(rebox_double); } @@ -2098,15 +2219,13 @@ void AccessorAssembler::EmitElementLoad( { Comment("BIGINT64_ELEMENTS"); exit_point->Return(LoadFixedTypedArrayElementAsTagged( - backing_store, intptr_index, BIGINT64_ELEMENTS, - INTPTR_PARAMETERS)); + data_ptr, intptr_index, BIGINT64_ELEMENTS, INTPTR_PARAMETERS)); } BIND(&biguint64_elements); { Comment("BIGUINT64_ELEMENTS"); exit_point->Return(LoadFixedTypedArrayElementAsTagged( - backing_store, intptr_index, BIGUINT64_ELEMENTS, - INTPTR_PARAMETERS)); + data_ptr, intptr_index, BIGUINT64_ELEMENTS, INTPTR_PARAMETERS)); } } } @@ -2152,7 +2271,8 @@ void AccessorAssembler::InvalidateValidityCellIfPrototype(Node* map, BIND(&cont); } -void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map, +void AccessorAssembler::GenericElementLoad(Node* receiver, + TNode<Map> receiver_map, SloppyTNode<Int32T> instance_type, Node* index, Label* slow) { Comment("integer index"); @@ -2213,11 +2333,9 @@ void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map, } } -void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, - SloppyTNode<Int32T> instance_type, - const LoadICParameters* p, - Label* slow, - UseStubCache use_stub_cache) { +void AccessorAssembler::GenericPropertyLoad( + Node* receiver, TNode<Map> receiver_map, SloppyTNode<Int32T> instance_type, + const LoadICParameters* p, Label* slow, UseStubCache use_stub_cache) { ExitPoint direct_exit(this); Comment("key is unique name"); @@ -2317,13 +2435,13 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, BIND(&lookup_prototype_chain); { - VARIABLE(var_holder_map, MachineRepresentation::kTagged); + TVARIABLE(Map, var_holder_map); VARIABLE(var_holder_instance_type, MachineRepresentation::kWord32); Label return_undefined(this), is_private_symbol(this); Variable* merged_variables[] = {&var_holder_map, &var_holder_instance_type}; Label loop(this, arraysize(merged_variables), merged_variables); - var_holder_map.Bind(receiver_map); + var_holder_map = receiver_map; var_holder_instance_type.Bind(instance_type); GotoIf(IsPrivateSymbol(name), &is_private_symbol); @@ -2338,7 +2456,7 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, GotoIf(TaggedEqual(proto, NullConstant()), &return_undefined); TNode<Map> proto_map = LoadMap(proto); TNode<Uint16T> proto_instance_type = LoadMapInstanceType(proto_map); - var_holder_map.Bind(proto_map); + var_holder_map = proto_map; var_holder_instance_type.Bind(proto_instance_type); Label next_proto(this), return_value(this, &var_value), goto_slow(this); TryGetOwnProperty(p->context(), receiver, proto, proto_map, @@ -2394,8 +2512,6 @@ enum AccessorAssembler::StubCacheTable : int { }; Node* AccessorAssembler::StubCachePrimaryOffset(Node* name, Node* map) { - // See v8::internal::StubCache::PrimaryOffset(). - STATIC_ASSERT(StubCache::kCacheIndexShift == Name::kHashShift); // Compute the hash of the name (use entire hash field). TNode<Uint32T> hash_field = LoadNameHashField(name); CSA_ASSERT(this, @@ -2422,7 +2538,7 @@ Node* AccessorAssembler::StubCacheSecondaryOffset(Node* name, Node* seed) { // Use the seed from the primary cache in the secondary cache. TNode<Int32T> name32 = TruncateIntPtrToInt32(BitcastTaggedToWord(name)); - TNode<Word32T> hash = Int32Sub(TruncateIntPtrToInt32(seed), name32); + TNode<Int32T> hash = Int32Sub(TruncateIntPtrToInt32(seed), name32); hash = Int32Add(hash, Int32Constant(StubCache::kSecondaryMagic)); int32_t mask = (StubCache::kSecondaryTableSize - 1) << StubCache::kCacheIndexShift; @@ -2436,7 +2552,8 @@ void AccessorAssembler::TryProbeStubCacheTable( StubCache::Table table = static_cast<StubCache::Table>(table_id); // The {table_offset} holds the entry offset times four (due to masking // and shifting optimizations). - const int kMultiplier = sizeof(StubCache::Entry) >> Name::kHashShift; + const int kMultiplier = + sizeof(StubCache::Entry) >> StubCache::kCacheIndexShift; entry_offset = IntPtrMul(entry_offset, IntPtrConstant(kMultiplier)); TNode<ExternalReference> key_base = ExternalConstant( @@ -2527,7 +2644,7 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LazyLoadICParameters* p, Label try_polymorphic(this), if_handler(this, &var_handler); TNode<MaybeObject> feedback = - TryMonomorphicCase(p->slot(), p->vector(), recv_map, &if_handler, + TryMonomorphicCase(p->slot(), CAST(p->vector()), recv_map, &if_handler, &var_handler, &try_polymorphic); BIND(&if_handler); @@ -2589,8 +2706,8 @@ void AccessorAssembler::LoadIC(const LoadICParameters* p) { // Check monomorphic case. TNode<MaybeObject> feedback = - TryMonomorphicCase(p->slot(), p->vector(), receiver_map, &if_handler, - &var_handler, &try_polymorphic); + TryMonomorphicCase(p->slot(), CAST(p->vector()), receiver_map, + &if_handler, &var_handler, &try_polymorphic); BIND(&if_handler); { LazyLoadICParameters lazy_p(p); @@ -2673,21 +2790,25 @@ void AccessorAssembler::LoadIC_NoFeedback(const LoadICParameters* p) { } } -void AccessorAssembler::LoadGlobalIC(Node* vector, Node* slot, +void AccessorAssembler::LoadGlobalIC(TNode<HeapObject> maybe_feedback_vector, + const LazyNode<Smi>& lazy_smi_slot, + const LazyNode<UintPtrT>& lazy_slot, const LazyNode<Context>& lazy_context, const LazyNode<Name>& lazy_name, TypeofMode typeof_mode, - ExitPoint* exit_point, - ParameterMode slot_mode) { + ExitPoint* exit_point) { Label try_handler(this, Label::kDeferred), miss(this, Label::kDeferred); - GotoIf(IsUndefined(vector), &miss); - - LoadGlobalIC_TryPropertyCellCase(CAST(vector), slot, lazy_context, exit_point, - &try_handler, &miss, slot_mode); + GotoIf(IsUndefined(maybe_feedback_vector), &miss); + { + TNode<FeedbackVector> vector = CAST(maybe_feedback_vector); + TNode<UintPtrT> slot = lazy_slot(); + LoadGlobalIC_TryPropertyCellCase(vector, slot, lazy_context, exit_point, + &try_handler, &miss); - BIND(&try_handler); - LoadGlobalIC_TryHandlerCase(CAST(vector), slot, lazy_context, lazy_name, - typeof_mode, exit_point, &miss, slot_mode); + BIND(&try_handler); + LoadGlobalIC_TryHandlerCase(vector, slot, lazy_smi_slot, lazy_context, + lazy_name, typeof_mode, exit_point, &miss); + } BIND(&miss); { @@ -2695,20 +2816,19 @@ void AccessorAssembler::LoadGlobalIC(Node* vector, Node* slot, TNode<Context> context = lazy_context(); TNode<Name> name = lazy_name(); exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Miss, context, name, - ParameterToTagged(slot, slot_mode), vector, + lazy_smi_slot(), maybe_feedback_vector, SmiConstant(typeof_mode)); } } void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase( - TNode<FeedbackVector> vector, Node* slot, + TNode<FeedbackVector> vector, TNode<UintPtrT> slot, const LazyNode<Context>& lazy_context, ExitPoint* exit_point, - Label* try_handler, Label* miss, ParameterMode slot_mode) { + Label* try_handler, Label* miss) { Comment("LoadGlobalIC_TryPropertyCellCase"); Label if_lexical_var(this), if_property_cell(this); - TNode<MaybeObject> maybe_weak_ref = - LoadFeedbackVectorSlot(vector, slot, 0, slot_mode); + TNode<MaybeObject> maybe_weak_ref = LoadFeedbackVectorSlot(vector, slot); Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_property_cell); BIND(&if_property_cell); @@ -2739,16 +2859,16 @@ void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase( } void AccessorAssembler::LoadGlobalIC_TryHandlerCase( - TNode<FeedbackVector> vector, Node* slot, - const LazyNode<Context>& lazy_context, const LazyNode<Name>& lazy_name, - TypeofMode typeof_mode, ExitPoint* exit_point, Label* miss, - ParameterMode slot_mode) { + TNode<FeedbackVector> vector, TNode<UintPtrT> slot, + const LazyNode<Smi>& lazy_smi_slot, const LazyNode<Context>& lazy_context, + const LazyNode<Name>& lazy_name, TypeofMode typeof_mode, + ExitPoint* exit_point, Label* miss) { Comment("LoadGlobalIC_TryHandlerCase"); Label call_handler(this), non_smi(this); TNode<MaybeObject> feedback_element = - LoadFeedbackVectorSlot(vector, slot, kTaggedSize, slot_mode); + LoadFeedbackVectorSlot(vector, slot, kTaggedSize); TNode<Object> handler = CAST(feedback_element); GotoIf(TaggedEqual(handler, UninitializedSymbolConstant()), miss); @@ -2757,14 +2877,14 @@ void AccessorAssembler::LoadGlobalIC_TryHandlerCase( : OnNonExistent::kReturnUndefined; TNode<Context> context = lazy_context(); - TNode<Context> native_context = LoadNativeContext(context); + TNode<NativeContext> native_context = LoadNativeContext(context); TNode<JSGlobalProxy> receiver = CAST(LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX)); TNode<Object> holder = LoadContextElement(native_context, Context::EXTENSION_INDEX); LazyLoadICParameters p([=] { return context; }, receiver, lazy_name, - ParameterToTagged(slot, slot_mode), vector, holder); + lazy_smi_slot, vector, holder); HandleLoadICHandlerCase(&p, handler, miss, exit_point, ICMode::kGlobalIC, on_nonexistent); @@ -2788,8 +2908,8 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p, // Check monomorphic case. TNode<MaybeObject> feedback = - TryMonomorphicCase(p->slot(), p->vector(), receiver_map, &if_handler, - &var_handler, &try_polymorphic); + TryMonomorphicCase(p->slot(), CAST(p->vector()), receiver_map, + &if_handler, &var_handler, &try_polymorphic); BIND(&if_handler); { LazyLoadICParameters lazy_p(p); @@ -2840,13 +2960,13 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p, // We might have a name in feedback, and a weak fixed array in the next // slot. Comment("KeyedLoadIC_try_polymorphic_name"); - TVARIABLE(Object, var_name, p->name()); + TVARIABLE(Name, var_name); TVARIABLE(IntPtrT, var_index); - Label if_polymorphic_name(this, &var_name), if_internalized(this), - if_notinternalized(this, Label::kDeferred); + Label if_polymorphic_name(this), feedback_matches(this), + if_internalized(this), if_notinternalized(this, Label::kDeferred); // Fast-case: The recorded {feedback} matches the {name}. - GotoIf(TaggedEqual(strong_feedback, p->name()), &if_polymorphic_name); + GotoIf(TaggedEqual(strong_feedback, p->name()), &feedback_matches); // Try to internalize the {name} if it isn't already. TryToName(p->name(), &miss, &var_index, &if_internalized, &var_name, &miss, @@ -2861,16 +2981,15 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p, BIND(&if_notinternalized); { - // Try to internalize the {name}. - TNode<ExternalReference> function = ExternalConstant( - ExternalReference::try_internalize_string_function()); - TNode<ExternalReference> const isolate_ptr = - ExternalConstant(ExternalReference::isolate_address(isolate())); - var_name = CAST( - CallCFunction(function, MachineType::AnyTagged(), - std::make_pair(MachineType::Pointer(), isolate_ptr), - std::make_pair(MachineType::AnyTagged(), p->name()))); - Goto(&if_internalized); + TVARIABLE(IntPtrT, var_index); + TryInternalizeString(CAST(p->name()), &miss, &var_index, &if_internalized, + &var_name, &miss, &miss); + } + + BIND(&feedback_matches); + { + var_name = CAST(p->name()); + Goto(&if_polymorphic_name); } BIND(&if_polymorphic_name); @@ -2896,71 +3015,74 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p, } void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) { - TVARIABLE(IntPtrT, var_index); - TVARIABLE(Object, var_unique, p->name()); - Label if_index(this), if_unique_name(this), if_notunique(this), - if_other(this, Label::kDeferred), if_runtime(this, Label::kDeferred); + TVARIABLE(Object, var_name, p->name()); + Label if_runtime(this, Label::kDeferred); Node* receiver = p->receiver(); GotoIf(TaggedIsSmi(receiver), &if_runtime); GotoIf(IsNullOrUndefined(receiver), &if_runtime); - TryToName(p->name(), &if_index, &var_index, &if_unique_name, &var_unique, - &if_other, &if_notunique); - - BIND(&if_other); { - TNode<Name> name = - CAST(CallBuiltin(Builtins::kToName, p->context(), p->name())); - var_unique = name; - TryToName(name, &if_index, &var_index, &if_unique_name, &var_unique, - &if_runtime, &if_notunique); - } + TVARIABLE(IntPtrT, var_index); + TVARIABLE(Name, var_unique); + Label if_index(this), if_unique_name(this, &var_name), if_notunique(this), + if_other(this, Label::kDeferred); - BIND(&if_index); - { - TNode<Map> receiver_map = LoadMap(receiver); - TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map); - GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(), - &if_runtime); - } + TryToName(var_name.value(), &if_index, &var_index, &if_unique_name, + &var_unique, &if_other, &if_notunique); - BIND(&if_unique_name); - { - LoadICParameters pp(p, var_unique.value()); - TNode<Map> receiver_map = LoadMap(receiver); - TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map); - GenericPropertyLoad(receiver, receiver_map, instance_type, &pp, - &if_runtime); - } + BIND(&if_unique_name); + { + LoadICParameters pp(p, var_unique.value()); + TNode<Map> receiver_map = LoadMap(receiver); + TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map); + GenericPropertyLoad(receiver, receiver_map, instance_type, &pp, + &if_runtime); + } - BIND(&if_notunique); - { - if (FLAG_internalize_on_the_fly) { - // 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 {if_runtime} path instead. - Label if_in_string_table(this); - TryInternalizeString(var_unique.value(), &if_index, &var_index, - &if_in_string_table, &var_unique, &if_runtime, - &if_runtime); + BIND(&if_other); + { + var_name = CallBuiltin(Builtins::kToName, p->context(), var_name.value()); + TryToName(var_name.value(), &if_index, &var_index, &if_unique_name, + &var_unique, &if_runtime, &if_notunique); + } - BIND(&if_in_string_table); - { - // TODO(bmeurer): We currently use a version of GenericPropertyLoad - // here, where we don't try to probe the megamorphic stub cache after - // successfully internalizing the incoming string. Past experiments - // with this have shown that it causes too much traffic on the stub - // cache. We may want to re-evaluate that in the future. - LoadICParameters pp(p, var_unique.value()); - TNode<Map> receiver_map = LoadMap(receiver); - TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map); - GenericPropertyLoad(receiver, receiver_map, instance_type, &pp, - &if_runtime, kDontUseStubCache); + BIND(&if_notunique); + { + if (FLAG_internalize_on_the_fly) { + // 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 {if_runtime} path instead. + Label if_in_string_table(this); + TryInternalizeString(CAST(var_name.value()), &if_index, &var_index, + &if_in_string_table, &var_unique, &if_runtime, + &if_runtime); + + BIND(&if_in_string_table); + { + // TODO(bmeurer): We currently use a version of GenericPropertyLoad + // here, where we don't try to probe the megamorphic stub cache + // after successfully internalizing the incoming string. Past + // experiments with this have shown that it causes too much traffic + // on the stub cache. We may want to re-evaluate that in the future. + LoadICParameters pp(p, var_unique.value()); + TNode<Map> receiver_map = LoadMap(receiver); + TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map); + GenericPropertyLoad(receiver, receiver_map, instance_type, &pp, + &if_runtime, kDontUseStubCache); + } + } else { + Goto(&if_runtime); } - } else { - Goto(&if_runtime); + } + + BIND(&if_index); + { + TNode<Map> receiver_map = LoadMap(receiver); + TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map); + GenericElementLoad(receiver, receiver_map, instance_type, + var_index.value(), &if_runtime); } } @@ -2970,7 +3092,7 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) { IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1); // TODO(jkummerow): Should we use the GetProperty TF stub instead? TailCallRuntime(Runtime::kGetProperty, p->context(), p->receiver(), - var_unique.value()); + var_name.value()); } } @@ -2982,22 +3104,20 @@ void AccessorAssembler::KeyedLoadICPolymorphicName(const LoadICParameters* p, Node* receiver = p->receiver(); TNode<Map> receiver_map = LoadReceiverMap(receiver); TNode<Name> name = CAST(p->name()); - Node* vector = p->vector(); - Node* slot = p->slot(); + TNode<FeedbackVector> vector = CAST(p->vector()); + TNode<Smi> slot = p->slot(); TNode<Context> context = p->context(); // When we get here, we know that the {name} matches the recorded // feedback name in the {vector} and can safely be used for the // LoadIC handler logic below. CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(receiver_map))); - CSA_ASSERT(this, - TaggedEqual( - name, LoadFeedbackVectorSlot(vector, slot, 0, SMI_PARAMETERS)), + CSA_ASSERT(this, TaggedEqual(name, LoadFeedbackVectorSlot(vector, slot)), name, vector); // Check if we have a matching handler for the {receiver_map}. TNode<MaybeObject> feedback_element = - LoadFeedbackVectorSlot(vector, slot, kTaggedSize, SMI_PARAMETERS); + LoadFeedbackVectorSlot(vector, slot, kTaggedSize); TNode<WeakFixedArray> array = CAST(feedback_element); HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss); @@ -3038,8 +3158,8 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) { // Check monomorphic case. TNode<MaybeObject> feedback = - TryMonomorphicCase(p->slot(), p->vector(), receiver_map, &if_handler, - &var_handler, &try_polymorphic); + TryMonomorphicCase(p->slot(), CAST(p->vector()), receiver_map, + &if_handler, &var_handler, &try_polymorphic); BIND(&if_handler); { Comment("StoreIC_if_handler"); @@ -3082,17 +3202,12 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) { void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) { Label if_lexical_var(this), if_heapobject(this); TNode<MaybeObject> maybe_weak_ref = - LoadFeedbackVectorSlot(pp->vector(), pp->slot(), 0, SMI_PARAMETERS); + LoadFeedbackVectorSlot(CAST(pp->vector()), pp->slot()); Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_heapobject); BIND(&if_heapobject); { Label try_handler(this), miss(this, Label::kDeferred); - // We use pre-monomorphic state for global stores that run into - // interceptors because the property doesn't exist yet. Using - // pre-monomorphic state gives it a chance to find more information the - // second time. - GotoIf(TaggedEqual(maybe_weak_ref, PremonomorphicSymbolConstant()), &miss); CSA_ASSERT(this, IsWeakOrCleared(maybe_weak_ref)); TNode<PropertyCell> property_cell = @@ -3105,13 +3220,13 @@ void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) { BIND(&try_handler); { Comment("StoreGlobalIC_try_handler"); - TNode<MaybeObject> handler = LoadFeedbackVectorSlot( - pp->vector(), pp->slot(), kTaggedSize, SMI_PARAMETERS); + TNode<MaybeObject> handler = + LoadFeedbackVectorSlot(CAST(pp->vector()), pp->slot(), kTaggedSize); GotoIf(TaggedEqual(handler, UninitializedSymbolConstant()), &miss); DCHECK_NULL(pp->receiver()); - TNode<Context> native_context = LoadNativeContext(pp->context()); + TNode<NativeContext> native_context = LoadNativeContext(pp->context()); StoreICParameters p( pp->context(), LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX), @@ -3225,8 +3340,8 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) { // Check monomorphic case. TNode<MaybeObject> feedback = - TryMonomorphicCase(p->slot(), p->vector(), receiver_map, &if_handler, - &var_handler, &try_polymorphic); + TryMonomorphicCase(p->slot(), CAST(p->vector()), receiver_map, + &if_handler, &var_handler, &try_polymorphic); BIND(&if_handler); { Comment("KeyedStoreIC_if_handler"); @@ -3266,8 +3381,8 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) { GotoIfNot(TaggedEqual(strong_feedback, p->name()), &miss); // If the name comparison succeeded, we know we have a feedback vector // with at least one map/handler pair. - TNode<MaybeObject> feedback_element = LoadFeedbackVectorSlot( - p->vector(), p->slot(), kTaggedSize, SMI_PARAMETERS); + TNode<MaybeObject> feedback_element = + LoadFeedbackVectorSlot(CAST(p->vector()), p->slot(), kTaggedSize); TNode<WeakFixedArray> array = CAST(feedback_element); HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss); @@ -3296,16 +3411,20 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) { GotoIf(IsUndefined(p->vector()), &miss); TNode<MaybeObject> feedback = - TryMonomorphicCase(p->slot(), p->vector(), array_map, &if_handler, + TryMonomorphicCase(p->slot(), CAST(p->vector()), array_map, &if_handler, &var_handler, &try_polymorphic); BIND(&if_handler); { Comment("StoreInArrayLiteralIC_if_handler"); // This is a stripped-down version of HandleStoreICHandlerCase. + Label if_transitioning_element_store(this), if_smi_handler(this); + + // Check used to identify the Slow case. + // Currently only the Slow case uses a Smi handler. + GotoIf(TaggedIsSmi(var_handler.value()), &if_smi_handler); TNode<HeapObject> handler = CAST(var_handler.value()); - Label if_transitioning_element_store(this); GotoIfNot(IsCode(handler), &if_transitioning_element_store); TailCallStub(StoreWithVectorDescriptor{}, CAST(handler), p->context(), p->receiver(), p->name(), p->value(), p->slot(), @@ -3324,6 +3443,22 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) { p->receiver(), p->name(), transition_map, p->value(), p->slot(), p->vector()); } + + BIND(&if_smi_handler); + { +#ifdef DEBUG + // A check to ensure that no other Smi handler uses this path. + TNode<Int32T> handler_word = SmiToInt32(CAST(var_handler.value())); + TNode<Uint32T> handler_kind = + DecodeWord32<StoreHandler::KindBits>(handler_word); + CSA_ASSERT(this, Word32Equal(handler_kind, + Int32Constant(StoreHandler::kSlow))); +#endif + + Comment("StoreInArrayLiteralIC_Slow"); + TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, p->context(), + p->value(), p->receiver(), p->name()); + } } BIND(&try_polymorphic); @@ -3366,7 +3501,7 @@ void AccessorAssembler::GenerateLoadIC() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); Node* vector = Parameter(Descriptor::kVector); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); @@ -3379,7 +3514,7 @@ void AccessorAssembler::GenerateLoadIC_Megamorphic() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); Node* vector = Parameter(Descriptor::kVector); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); @@ -3392,7 +3527,7 @@ void AccessorAssembler::GenerateLoadIC_Megamorphic() { BIND(&if_handler); LazyLoadICParameters p([=] { return context; }, receiver, - [=] { return name; }, slot, vector); + [=] { return name; }, [=] { return slot; }, vector); HandleLoadICHandlerCase(&p, CAST(var_handler.value()), &miss, &direct_exit); BIND(&miss); @@ -3405,8 +3540,8 @@ void AccessorAssembler::GenerateLoadIC_Noninlined() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); - Node* slot = Parameter(Descriptor::kSlot); - Node* vector = Parameter(Descriptor::kVector); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); + TNode<FeedbackVector> vector = CAST(Parameter(Descriptor::kVector)); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); ExitPoint direct_exit(this); @@ -3414,8 +3549,7 @@ void AccessorAssembler::GenerateLoadIC_Noninlined() { Label if_handler(this, &var_handler), miss(this, Label::kDeferred); TNode<Map> receiver_map = LoadReceiverMap(receiver); - TNode<MaybeObject> feedback_element = - LoadFeedbackVectorSlot(vector, slot, 0, SMI_PARAMETERS); + TNode<MaybeObject> feedback_element = LoadFeedbackVectorSlot(vector, slot); TNode<HeapObject> feedback = CAST(feedback_element); LoadICParameters p(context, receiver, name, slot, vector); @@ -3439,7 +3573,7 @@ void AccessorAssembler::GenerateLoadIC_NoFeedback() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); LoadICParameters p(context, receiver, name, slot, UndefinedConstant()); @@ -3475,13 +3609,17 @@ void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) { using Descriptor = LoadGlobalWithVectorDescriptor; TNode<Name> name = CAST(Parameter(Descriptor::kName)); - Node* slot = Parameter(Descriptor::kSlot); - Node* vector = Parameter(Descriptor::kVector); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); + TNode<HeapObject> vector = CAST(Parameter(Descriptor::kVector)); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); ExitPoint direct_exit(this); LoadGlobalIC( - vector, slot, + vector, + // lazy_smi_slot + [=] { return slot; }, + // lazy_slot + [=] { return Unsigned(SmiUntag(slot)); }, // lazy_context [=] { return context; }, // lazy_name @@ -3506,7 +3644,7 @@ void AccessorAssembler::GenerateKeyedLoadIC() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); Node* vector = Parameter(Descriptor::kVector); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); @@ -3519,7 +3657,7 @@ void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); Node* vector = Parameter(Descriptor::kVector); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); @@ -3532,7 +3670,7 @@ void AccessorAssembler::GenerateKeyedLoadICTrampoline() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); TNode<FeedbackVector> vector = LoadFeedbackVectorForStub(); @@ -3545,7 +3683,7 @@ void AccessorAssembler::GenerateKeyedLoadICTrampoline_Megamorphic() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); TNode<FeedbackVector> vector = LoadFeedbackVectorForStub(); @@ -3558,7 +3696,7 @@ void AccessorAssembler::GenerateKeyedLoadIC_PolymorphicName() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); Node* vector = Parameter(Descriptor::kVector); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); @@ -3571,7 +3709,7 @@ void AccessorAssembler::GenerateStoreGlobalIC() { TNode<Object> name = CAST(Parameter(Descriptor::kName)); Node* value = Parameter(Descriptor::kValue); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); Node* vector = Parameter(Descriptor::kVector); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); @@ -3584,7 +3722,7 @@ void AccessorAssembler::GenerateStoreGlobalICTrampoline() { TNode<Object> name = CAST(Parameter(Descriptor::kName)); Node* value = Parameter(Descriptor::kValue); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); TNode<FeedbackVector> vector = LoadFeedbackVectorForStub(); @@ -3597,7 +3735,7 @@ void AccessorAssembler::GenerateStoreIC() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); Node* value = Parameter(Descriptor::kValue); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); Node* vector = Parameter(Descriptor::kVector); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); @@ -3611,7 +3749,7 @@ void AccessorAssembler::GenerateStoreICTrampoline() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); Node* value = Parameter(Descriptor::kValue); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); TNode<FeedbackVector> vector = LoadFeedbackVectorForStub(); @@ -3625,7 +3763,7 @@ void AccessorAssembler::GenerateKeyedStoreIC() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); Node* value = Parameter(Descriptor::kValue); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); Node* vector = Parameter(Descriptor::kVector); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); @@ -3639,7 +3777,7 @@ void AccessorAssembler::GenerateKeyedStoreICTrampoline() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); Node* value = Parameter(Descriptor::kValue); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); TNode<FeedbackVector> vector = LoadFeedbackVectorForStub(); @@ -3653,7 +3791,7 @@ void AccessorAssembler::GenerateStoreInArrayLiteralIC() { Node* array = Parameter(Descriptor::kReceiver); TNode<Object> index = CAST(Parameter(Descriptor::kName)); Node* value = Parameter(Descriptor::kValue); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); Node* vector = Parameter(Descriptor::kVector); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); @@ -3671,7 +3809,7 @@ void AccessorAssembler::GenerateCloneObjectIC_Slow() { // can be tail called from it. However, the feedback slot and vector are not // used. - TNode<Context> native_context = LoadNativeContext(context); + TNode<NativeContext> native_context = LoadNativeContext(context); TNode<JSFunction> object_fn = CAST(LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX)); TNode<Map> initial_map = CAST( @@ -3724,7 +3862,7 @@ void AccessorAssembler::GenerateCloneObjectIC() { TNode<Object> source = CAST(Parameter(Descriptor::kSource)); TNode<Smi> flags = CAST(Parameter(Descriptor::kFlags)); TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); - TNode<HeapObject> vector = CAST(Parameter(Descriptor::kVector)); + TNode<HeapObject> maybe_vector = CAST(Parameter(Descriptor::kVector)); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); TVARIABLE(MaybeObject, var_handler); Label if_handler(this, &var_handler), miss(this, Label::kDeferred), @@ -3734,10 +3872,11 @@ void AccessorAssembler::GenerateCloneObjectIC() { TNode<Map> source_map = LoadReceiverMap(source); GotoIf(IsDeprecatedMap(source_map), &miss); - GotoIf(IsUndefined(vector), &slow); + GotoIf(IsUndefined(maybe_vector), &slow); - TNode<MaybeObject> feedback = TryMonomorphicCase( - slot, vector, source_map, &if_handler, &var_handler, &try_polymorphic); + TNode<MaybeObject> feedback = + TryMonomorphicCase(slot, CAST(maybe_vector), source_map, &if_handler, + &var_handler, &try_polymorphic); BIND(&if_handler); { @@ -3801,30 +3940,28 @@ void AccessorAssembler::GenerateCloneObjectIC() { // Just copy the fields as raw data (pretending that there are no mutable // HeapNumbers). This doesn't need write barriers. - BuildFastLoop( + BuildFastLoop<IntPtrT>( source_start, source_size, - [=](Node* field_index) { - TNode<IntPtrT> field_offset = - TimesTaggedSize(UncheckedCast<IntPtrT>(field_index)); + [=](TNode<IntPtrT> field_index) { + TNode<IntPtrT> field_offset = TimesTaggedSize(field_index); TNode<TaggedT> field = LoadObjectField<TaggedT>(CAST(source), field_offset); TNode<IntPtrT> result_offset = IntPtrAdd(field_offset, field_offset_difference); StoreObjectFieldNoWriteBarrier(object, result_offset, field); }, - 1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost); + 1, IndexAdvanceMode::kPost); // If mutable HeapNumbers can occur, we need to go through the {object} // again here and properly clone them. We use a second loop here to // ensure that the GC (and heap verifier) always sees properly initialized // objects, i.e. never hits undefined values in double fields. if (!FLAG_unbox_double_fields) { - BuildFastLoop( + BuildFastLoop<IntPtrT>( source_start, source_size, - [=](Node* field_index) { - TNode<IntPtrT> result_offset = - IntPtrAdd(TimesTaggedSize(UncheckedCast<IntPtrT>(field_index)), - field_offset_difference); + [=](TNode<IntPtrT> field_index) { + TNode<IntPtrT> result_offset = IntPtrAdd( + TimesTaggedSize(field_index), field_offset_difference); TNode<Object> field = LoadObjectField(object, result_offset); Label if_done(this), if_mutableheapnumber(this, Label::kDeferred); GotoIf(TaggedIsSmi(field), &if_done); @@ -3838,7 +3975,7 @@ void AccessorAssembler::GenerateCloneObjectIC() { } BIND(&if_done); }, - 1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost); + 1, IndexAdvanceMode::kPost); } Return(object); @@ -3867,14 +4004,15 @@ void AccessorAssembler::GenerateCloneObjectIC() { BIND(&slow); { TailCallBuiltin(Builtins::kCloneObjectIC_Slow, context, source, flags, slot, - vector); + maybe_vector); } BIND(&miss); { Comment("CloneObjectIC_miss"); - TNode<HeapObject> map_or_result = CAST(CallRuntime( - Runtime::kCloneObjectIC_Miss, context, source, flags, slot, vector)); + TNode<HeapObject> map_or_result = + CAST(CallRuntime(Runtime::kCloneObjectIC_Miss, context, source, flags, + slot, maybe_vector)); var_handler = UncheckedCast<MaybeObject>(map_or_result); GotoIf(IsMap(map_or_result), &if_handler); CSA_ASSERT(this, IsJSObject(map_or_result)); @@ -3887,7 +4025,7 @@ void AccessorAssembler::GenerateKeyedHasIC() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); Node* vector = Parameter(Descriptor::kVector); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); @@ -3911,7 +4049,7 @@ void AccessorAssembler::GenerateKeyedHasIC_PolymorphicName() { Node* receiver = Parameter(Descriptor::kReceiver); TNode<Object> name = CAST(Parameter(Descriptor::kName)); - Node* slot = Parameter(Descriptor::kSlot); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); Node* vector = Parameter(Descriptor::kVector); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); @@ -3919,5 +4057,54 @@ void AccessorAssembler::GenerateKeyedHasIC_PolymorphicName() { KeyedLoadICPolymorphicName(&p, LoadAccessMode::kHas); } +void AccessorAssembler::BranchIfPrototypesHaveNoElements( + TNode<Map> receiver_map, Label* definitely_no_elements, + Label* possibly_elements) { + TVARIABLE(Map, var_map, receiver_map); + Label loop_body(this, &var_map); + TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant(); + TNode<NumberDictionary> empty_slow_element_dictionary = + EmptySlowElementDictionaryConstant(); + Goto(&loop_body); + + BIND(&loop_body); + { + TNode<Map> map = var_map.value(); + TNode<HeapObject> prototype = LoadMapPrototype(map); + GotoIf(IsNull(prototype), definitely_no_elements); + TNode<Map> prototype_map = LoadMap(prototype); + TNode<Uint16T> prototype_instance_type = LoadMapInstanceType(prototype_map); + + // Pessimistically assume elements if a Proxy, Special API Object, + // or JSPrimitiveWrapper wrapper is found on the prototype chain. After this + // instance type check, it's not necessary to check for interceptors or + // access checks. + Label if_custom(this, Label::kDeferred), if_notcustom(this); + Branch(IsCustomElementsReceiverInstanceType(prototype_instance_type), + &if_custom, &if_notcustom); + + BIND(&if_custom); + { + // For string JSPrimitiveWrapper wrappers we still support the checks as + // long as they wrap the empty string. + GotoIfNot( + InstanceTypeEqual(prototype_instance_type, JS_PRIMITIVE_WRAPPER_TYPE), + possibly_elements); + TNode<Object> prototype_value = + LoadJSPrimitiveWrapperValue(CAST(prototype)); + Branch(IsEmptyString(prototype_value), &if_notcustom, possibly_elements); + } + + BIND(&if_notcustom); + { + TNode<FixedArrayBase> prototype_elements = LoadElements(CAST(prototype)); + var_map = prototype_map; + GotoIf(TaggedEqual(prototype_elements, empty_fixed_array), &loop_body); + Branch(TaggedEqual(prototype_elements, empty_slow_element_dictionary), + &loop_body, possibly_elements); + } + } +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/accessor-assembler.h b/deps/v8/src/ic/accessor-assembler.h index 0de2292fd6..ccc2de9323 100644 --- a/deps/v8/src/ic/accessor-assembler.h +++ b/deps/v8/src/ic/accessor-assembler.h @@ -5,6 +5,7 @@ #ifndef V8_IC_ACCESSOR_ASSEMBLER_H_ #define V8_IC_ACCESSOR_ASSEMBLER_H_ +#include "src/base/optional.h" #include "src/codegen/code-stub-assembler.h" namespace v8 { @@ -19,10 +20,6 @@ class ExitPoint; class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { public: using Node = compiler::Node; - template <class T> - using TNode = compiler::TNode<T>; - template <class T> - using SloppyTNode = compiler::SloppyTNode<T>; explicit AccessorAssembler(compiler::CodeAssemblerState* state) : CodeStubAssembler(state) {} @@ -69,7 +66,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { struct LoadICParameters { LoadICParameters(TNode<Context> context, Node* receiver, TNode<Object> name, - Node* slot, Node* vector, Node* holder = nullptr) + TNode<Smi> slot, Node* vector, Node* holder = nullptr) : context_(context), receiver_(receiver), name_(name), @@ -88,7 +85,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { TNode<Context> context() const { return context_; } Node* receiver() const { return receiver_; } TNode<Object> name() const { return name_; } - Node* slot() const { return slot_; } + TNode<Smi> slot() const { return slot_; } Node* vector() const { return vector_; } Node* holder() const { return holder_; } @@ -96,15 +93,15 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { TNode<Context> context_; Node* receiver_; TNode<Object> name_; - Node* slot_; + TNode<Smi> slot_; Node* vector_; Node* holder_; }; struct LazyLoadICParameters { LazyLoadICParameters(LazyNode<Context> context, Node* receiver, - LazyNode<Object> name, Node* slot, Node* vector, - Node* holder = nullptr) + LazyNode<Object> name, LazyNode<Smi> slot, + Node* vector, Node* holder = nullptr) : context_(context), receiver_(receiver), name_(name), @@ -114,19 +111,17 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { explicit LazyLoadICParameters(const LoadICParameters* p) : receiver_(p->receiver()), - slot_(p->slot()), vector_(p->vector()), holder_(p->holder()) { - TNode<Context> p_context = p->context(); - context_ = [=] { return p_context; }; - TNode<Object> p_name = p->name(); - name_ = [=] { return p_name; }; + slot_ = [=] { return p->slot(); }; + context_ = [=] { return p->context(); }; + name_ = [=] { return p->name(); }; } TNode<Context> context() const { return context_(); } Node* receiver() const { return receiver_; } TNode<Object> name() const { return name_(); } - Node* slot() const { return slot_; } + TNode<Smi> slot() const { return slot_(); } Node* vector() const { return vector_; } Node* holder() const { return holder_; } @@ -134,16 +129,17 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { LazyNode<Context> context_; Node* receiver_; LazyNode<Object> name_; - Node* slot_; + LazyNode<Smi> slot_; Node* vector_; Node* holder_; }; - void LoadGlobalIC(Node* vector, Node* slot, + void LoadGlobalIC(TNode<HeapObject> maybe_feedback_vector, + const LazyNode<Smi>& lazy_smi_slot, + const LazyNode<UintPtrT>& lazy_slot, const LazyNode<Context>& lazy_context, const LazyNode<Name>& lazy_name, TypeofMode typeof_mode, - ExitPoint* exit_point, - ParameterMode slot_mode = SMI_PARAMETERS); + ExitPoint* exit_point); // Specialized LoadIC for inlined bytecode handler, hand-tuned to omit frame // construction on common paths. @@ -157,8 +153,8 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { protected: struct StoreICParameters : public LoadICParameters { StoreICParameters(TNode<Context> context, Node* receiver, - TNode<Object> name, SloppyTNode<Object> value, Node* slot, - Node* vector) + TNode<Object> name, SloppyTNode<Object> value, + TNode<Smi> slot, Node* vector) : LoadICParameters(context, receiver, name, slot, vector), value_(value) {} @@ -185,20 +181,22 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { Label* miss, StoreTransitionMapFlags flags); - void JumpIfDataProperty(Node* details, Label* writable, Label* readonly); + void JumpIfDataProperty(TNode<Uint32T> details, Label* writable, + Label* readonly); void InvalidateValidityCellIfPrototype(Node* map, Node* bitfield3 = nullptr); - void OverwriteExistingFastDataProperty(Node* object, Node* object_map, - Node* descriptors, - Node* descriptor_name_index, - Node* details, TNode<Object> value, - Label* slow, + void OverwriteExistingFastDataProperty(SloppyTNode<HeapObject> object, + TNode<Map> object_map, + TNode<DescriptorArray> descriptors, + TNode<IntPtrT> descriptor_name_index, + TNode<Uint32T> details, + TNode<Object> value, Label* slow, bool do_transitioning_store); - void CheckFieldType(TNode<DescriptorArray> descriptors, Node* name_index, - TNode<Word32T> representation, Node* value, - Label* bailout); + void CheckFieldType(TNode<DescriptorArray> descriptors, + TNode<IntPtrT> name_index, TNode<Word32T> representation, + Node* value, Label* bailout); private: // Stub generation entry points. @@ -232,12 +230,11 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { // IC dispatcher behavior. // Checks monomorphic case. Returns {feedback} entry of the vector. - TNode<MaybeObject> TryMonomorphicCase(Node* slot, Node* vector, - Node* receiver_map, Label* if_handler, - TVariable<MaybeObject>* var_handler, - Label* if_miss); - void HandlePolymorphicCase(Node* receiver_map, TNode<WeakFixedArray> feedback, - Label* if_handler, + TNode<MaybeObject> TryMonomorphicCase( + TNode<Smi> slot, TNode<FeedbackVector> vector, TNode<Map> receiver_map, + Label* if_handler, TVariable<MaybeObject>* var_handler, Label* if_miss); + void HandlePolymorphicCase(TNode<Map> receiver_map, + TNode<WeakFixedArray> feedback, Label* if_handler, TVariable<MaybeObject>* var_handler, Label* if_miss); @@ -249,15 +246,14 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { ElementSupport support_elements = kOnlyProperties, LoadAccessMode access_mode = LoadAccessMode::kLoad); - void HandleLoadICSmiHandlerCase(const LazyLoadICParameters* p, Node* holder, - SloppyTNode<Smi> smi_handler, - SloppyTNode<Object> handler, Label* miss, - ExitPoint* exit_point, - OnNonExistent on_nonexistent, - ElementSupport support_elements, - LoadAccessMode access_mode); + void HandleLoadICSmiHandlerCase( + const LazyLoadICParameters* p, SloppyTNode<HeapObject> holder, + SloppyTNode<Smi> smi_handler, SloppyTNode<Object> handler, Label* miss, + ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent, + ElementSupport support_elements, LoadAccessMode access_mode); - void HandleLoadICProtoHandler(const LazyLoadICParameters* p, Node* handler, + void HandleLoadICProtoHandler(const LazyLoadICParameters* p, + TNode<DataHandler> handler, Variable* var_holder, Variable* var_smi_handler, Label* if_smi_handler, Label* miss, ExitPoint* exit_point, ICMode ic_mode, @@ -273,40 +269,43 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { TNode<WordT> handler_word, TNode<DataHandler> handler, TNode<IntPtrT> handler_kind, ExitPoint* exit_point); - void HandleLoadField(Node* holder, Node* handler_word, + void HandleLoadField(SloppyTNode<JSObject> holder, TNode<WordT> handler_word, Variable* var_double_value, Label* rebox_double, - ExitPoint* exit_point); + Label* miss, ExitPoint* exit_point); void EmitAccessCheck(TNode<Context> expected_native_context, - TNode<Context> context, Node* receiver, + TNode<Context> context, TNode<Object> receiver, Label* can_access, Label* miss); void HandleLoadICSmiHandlerLoadNamedCase( - const LazyLoadICParameters* p, Node* holder, TNode<IntPtrT> handler_kind, - TNode<WordT> handler_word, Label* rebox_double, - Variable* var_double_value, SloppyTNode<Object> handler, Label* miss, - ExitPoint* exit_point, OnNonExistent on_nonexistent, + const LazyLoadICParameters* p, TNode<HeapObject> holder, + TNode<IntPtrT> handler_kind, TNode<WordT> handler_word, + Label* rebox_double, Variable* var_double_value, + SloppyTNode<Object> handler, Label* miss, ExitPoint* exit_point, + ICMode ic_mode, OnNonExistent on_nonexistent, ElementSupport support_elements); void HandleLoadICSmiHandlerHasNamedCase(const LazyLoadICParameters* p, - Node* holder, + TNode<HeapObject> holder, TNode<IntPtrT> handler_kind, - Label* miss, ExitPoint* exit_point); + Label* miss, ExitPoint* exit_point, + ICMode ic_mode); // LoadGlobalIC implementation. - void LoadGlobalIC_TryPropertyCellCase( - TNode<FeedbackVector> vector, Node* slot, - const LazyNode<Context>& lazy_context, ExitPoint* exit_point, - Label* try_handler, Label* miss, - ParameterMode slot_mode = SMI_PARAMETERS); + void LoadGlobalIC_TryPropertyCellCase(TNode<FeedbackVector> vector, + TNode<UintPtrT> slot, + const LazyNode<Context>& lazy_context, + ExitPoint* exit_point, + Label* try_handler, Label* miss); - void LoadGlobalIC_TryHandlerCase(TNode<FeedbackVector> vector, Node* slot, + void LoadGlobalIC_TryHandlerCase(TNode<FeedbackVector> vector, + TNode<UintPtrT> slot, + const LazyNode<Smi>& lazy_smi_slot, const LazyNode<Context>& lazy_context, const LazyNode<Name>& lazy_name, TypeofMode typeof_mode, - ExitPoint* exit_point, Label* miss, - ParameterMode slot_mode); + ExitPoint* exit_point, Label* miss); // StoreIC implementation. @@ -314,59 +313,66 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { TNode<StoreHandler> handler, Label* miss, ICMode ic_mode, ElementSupport support_elements); - void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder, - Node* value, Label* miss); - void HandleStoreFieldAndReturn(Node* handler_word, Node* holder, - Representation representation, Node* value, - Label* miss); + void HandleStoreICSmiHandlerCase(SloppyTNode<Word32T> handler_word, + SloppyTNode<JSObject> holder, + SloppyTNode<Object> value, Label* miss); + void HandleStoreFieldAndReturn(TNode<Word32T> handler_word, + TNode<JSObject> holder, TNode<Object> value, + base::Optional<TNode<Float64T>> double_value, + Representation representation, Label* miss); void CheckPrototypeValidityCell(TNode<Object> maybe_validity_cell, Label* miss); - void HandleStoreICNativeDataProperty(const StoreICParameters* p, Node* holder, - Node* handler_word); + void HandleStoreICNativeDataProperty(const StoreICParameters* p, + SloppyTNode<HeapObject> holder, + TNode<Word32T> handler_word); void HandleStoreToProxy(const StoreICParameters* p, Node* proxy, Label* miss, ElementSupport support_elements); - void HandleStoreAccessor(const StoreICParameters* p, Node* holder, - Node* handler_word); + void HandleStoreAccessor(const StoreICParameters* p, + SloppyTNode<HeapObject> holder, + TNode<Word32T> handler_word); // KeyedLoadIC_Generic implementation. - void GenericElementLoad(Node* receiver, Node* receiver_map, + void GenericElementLoad(Node* receiver, TNode<Map> receiver_map, SloppyTNode<Int32T> instance_type, Node* index, Label* slow); enum UseStubCache { kUseStubCache, kDontUseStubCache }; - void GenericPropertyLoad(Node* receiver, Node* receiver_map, + void GenericPropertyLoad(Node* receiver, TNode<Map> receiver_map, SloppyTNode<Int32T> instance_type, const LoadICParameters* p, Label* slow, UseStubCache use_stub_cache = kUseStubCache); // Low-level helpers. - using OnCodeHandler = std::function<void(Node* code_handler)>; - using OnFoundOnReceiver = - std::function<void(Node* properties, Node* name_index)>; + using OnCodeHandler = std::function<void(TNode<Code> code_handler)>; + using OnFoundOnReceiver = std::function<void(TNode<NameDictionary> properties, + TNode<IntPtrT> name_index)>; template <typename ICHandler, typename ICParameters> - Node* HandleProtoHandler(const ICParameters* p, Node* handler, - const OnCodeHandler& on_code_handler, - const OnFoundOnReceiver& on_found_on_receiver, - Label* miss, ICMode ic_mode); - - Node* PrepareValueForStore(Node* handler_word, Node* holder, - Representation representation, Node* value, - Label* bailout); + TNode<Object> HandleProtoHandler( + const ICParameters* p, TNode<DataHandler> handler, + const OnCodeHandler& on_code_handler, + const OnFoundOnReceiver& on_found_on_receiver, Label* miss, + ICMode ic_mode); + + void CheckHeapObjectTypeMatchesDescriptor(TNode<Word32T> handler_word, + TNode<JSObject> holder, + TNode<Object> value, + Label* bailout); + // Double fields store double values in a mutable box, where stores are + // writes into this box rather than HeapNumber assignment. + void CheckDescriptorConsidersNumbersMutable(TNode<Word32T> handler_word, + TNode<JSObject> holder, + Label* bailout); // Extends properties backing store by JSObject::kFieldsAdded elements, // returns updated properties backing store. Node* ExtendPropertiesBackingStore(Node* object, Node* index); - void StoreNamedField(Node* handler_word, Node* object, bool is_inobject, - Representation representation, Node* value, - Label* bailout); - void EmitFastElementsBoundsCheck(Node* object, Node* elements, Node* intptr_index, Node* is_jsarray_condition, Label* miss); @@ -379,7 +385,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { LoadAccessMode access_mode = LoadAccessMode::kLoad); void NameDictionaryNegativeLookup(Node* object, SloppyTNode<Name> name, Label* miss); - TNode<BoolT> IsPropertyDetailsConst(Node* details); + TNode<BoolT> IsPropertyDetailsConst(TNode<Uint32T> details); // Stub cache access helpers. @@ -395,6 +401,10 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { TNode<Map> map, Label* if_handler, TVariable<MaybeObject>* var_handler, Label* if_miss); + + void BranchIfPrototypesHaveNoElements(TNode<Map> receiver_map, + Label* definitely_no_elements, + Label* possibly_elements); }; // Abstraction over direct and indirect exit points. Direct exits correspond to diff --git a/deps/v8/src/ic/binary-op-assembler.cc b/deps/v8/src/ic/binary-op-assembler.cc index f6bec6eab9..ee488100e9 100644 --- a/deps/v8/src/ic/binary-op-assembler.cc +++ b/deps/v8/src/ic/binary-op-assembler.cc @@ -9,21 +9,19 @@ namespace v8 { namespace internal { -using compiler::Node; - -Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, - Node* rhs, Node* slot_id, - Node* feedback_vector, - bool rhs_is_smi) { +TNode<Object> BinaryOpAssembler::Generate_AddWithFeedback( + TNode<Context> context, TNode<Object> lhs, TNode<Object> rhs, + TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector, + bool rhs_known_smi) { // Shared entry for floating point addition. Label do_fadd(this), if_lhsisnotnumber(this, Label::kDeferred), check_rhsisoddball(this, Label::kDeferred), call_with_oddball_feedback(this), call_with_any_feedback(this), call_add_stub(this), end(this), bigint(this, Label::kDeferred); - VARIABLE(var_fadd_lhs, MachineRepresentation::kFloat64); - VARIABLE(var_fadd_rhs, MachineRepresentation::kFloat64); - VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned); - VARIABLE(var_result, MachineRepresentation::kTagged); + TVARIABLE(Float64T, var_fadd_lhs); + TVARIABLE(Float64T, var_fadd_rhs); + TVARIABLE(Smi, var_type_feedback); + TVARIABLE(Object, var_result); // Check if the {lhs} is a Smi or a HeapObject. Label if_lhsissmi(this); @@ -32,13 +30,14 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, // both Smi and Number operations, so this path should not be marked as // Deferred. Label if_lhsisnotsmi(this, - rhs_is_smi ? Label::kDeferred : Label::kNonDeferred); + rhs_known_smi ? Label::kDeferred : Label::kNonDeferred); Branch(TaggedIsNotSmi(lhs), &if_lhsisnotsmi, &if_lhsissmi); BIND(&if_lhsissmi); { Comment("lhs is Smi"); - if (!rhs_is_smi) { + TNode<Smi> lhs_smi = CAST(lhs); + if (!rhs_known_smi) { // Check if the {rhs} is also a Smi. Label if_rhsissmi(this), if_rhsisnotsmi(this); Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); @@ -46,10 +45,11 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, BIND(&if_rhsisnotsmi); { // Check if the {rhs} is a HeapNumber. - GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball); + TNode<HeapObject> rhs_heap_object = CAST(rhs); + GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball); - var_fadd_lhs.Bind(SmiToFloat64(lhs)); - var_fadd_rhs.Bind(LoadHeapNumberValue(rhs)); + var_fadd_lhs = SmiToFloat64(lhs_smi); + var_fadd_rhs = LoadHeapNumberValue(rhs_heap_object); Goto(&do_fadd); } @@ -62,21 +62,21 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, // is for AddSmi operation. For the normal Add operation, we want to fast // path both Smi and Number operations, so this path should not be marked // as Deferred. + TNode<Smi> rhs_smi = CAST(rhs); Label if_overflow(this, - rhs_is_smi ? Label::kDeferred : Label::kNonDeferred); - TNode<Smi> smi_result = TrySmiAdd(CAST(lhs), CAST(rhs), &if_overflow); + rhs_known_smi ? Label::kDeferred : Label::kNonDeferred); + TNode<Smi> smi_result = TrySmiAdd(lhs_smi, rhs_smi, &if_overflow); // Not overflowed. { - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kSignedSmall)); - var_result.Bind(smi_result); + var_type_feedback = SmiConstant(BinaryOperationFeedback::kSignedSmall); + var_result = smi_result; Goto(&end); } BIND(&if_overflow); { - var_fadd_lhs.Bind(SmiToFloat64(lhs)); - var_fadd_rhs.Bind(SmiToFloat64(rhs)); + var_fadd_lhs = SmiToFloat64(lhs_smi); + var_fadd_rhs = SmiToFloat64(rhs_smi); Goto(&do_fadd); } } @@ -85,9 +85,10 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, BIND(&if_lhsisnotsmi); { // Check if {lhs} is a HeapNumber. - GotoIfNot(IsHeapNumber(lhs), &if_lhsisnotnumber); + TNode<HeapObject> lhs_heap_object = CAST(lhs); + GotoIfNot(IsHeapNumber(lhs_heap_object), &if_lhsisnotnumber); - if (!rhs_is_smi) { + if (!rhs_known_smi) { // Check if the {rhs} is Smi. Label if_rhsissmi(this), if_rhsisnotsmi(this); Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); @@ -95,29 +96,30 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, BIND(&if_rhsisnotsmi); { // Check if the {rhs} is a HeapNumber. - GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball); + TNode<HeapObject> rhs_heap_object = CAST(rhs); + GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball); - var_fadd_lhs.Bind(LoadHeapNumberValue(lhs)); - var_fadd_rhs.Bind(LoadHeapNumberValue(rhs)); + var_fadd_lhs = LoadHeapNumberValue(lhs_heap_object); + var_fadd_rhs = LoadHeapNumberValue(rhs_heap_object); Goto(&do_fadd); } BIND(&if_rhsissmi); } { - var_fadd_lhs.Bind(LoadHeapNumberValue(lhs)); - var_fadd_rhs.Bind(SmiToFloat64(rhs)); + var_fadd_lhs = LoadHeapNumberValue(lhs_heap_object); + var_fadd_rhs = SmiToFloat64(CAST(rhs)); Goto(&do_fadd); } } BIND(&do_fadd); { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); + var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumber); TNode<Float64T> value = Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value()); TNode<HeapNumber> result = AllocateHeapNumberWithValue(value); - var_result.Bind(result); + var_result = result; Goto(&end); } @@ -125,7 +127,7 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, { // No checks on rhs are done yet. We just know lhs is not a number or Smi. Label if_lhsisoddball(this), if_lhsisnotoddball(this); - TNode<Uint16T> lhs_instance_type = LoadInstanceType(lhs); + TNode<Uint16T> lhs_instance_type = LoadInstanceType(CAST(lhs)); TNode<BoolT> lhs_is_oddball = InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE); Branch(lhs_is_oddball, &if_lhsisoddball, &if_lhsisnotoddball); @@ -135,39 +137,40 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback); // Check if {rhs} is a HeapNumber. - Branch(IsHeapNumber(rhs), &call_with_oddball_feedback, + Branch(IsHeapNumber(CAST(rhs)), &call_with_oddball_feedback, &check_rhsisoddball); } BIND(&if_lhsisnotoddball); { + // Check if the {rhs} is a smi, and exit the string and bigint check early + // if it is. + GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback); + TNode<HeapObject> rhs_heap_object = CAST(rhs); + Label lhs_is_string(this), lhs_is_bigint(this); GotoIf(IsStringInstanceType(lhs_instance_type), &lhs_is_string); GotoIf(IsBigIntInstanceType(lhs_instance_type), &lhs_is_bigint); Goto(&call_with_any_feedback); BIND(&lhs_is_bigint); - { - GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback); - Branch(IsBigInt(rhs), &bigint, &call_with_any_feedback); - } + Branch(IsBigInt(rhs_heap_object), &bigint, &call_with_any_feedback); BIND(&lhs_is_string); - // Check if the {rhs} is a smi, and exit the string check early if it is. - GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback); - - TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs); + { + TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs_heap_object); - // Exit unless {rhs} is a string. Since {lhs} is a string we no longer - // need an Oddball check. - GotoIfNot(IsStringInstanceType(rhs_instance_type), - &call_with_any_feedback); + // Exit unless {rhs} is a string. Since {lhs} is a string we no longer + // need an Oddball check. + GotoIfNot(IsStringInstanceType(rhs_instance_type), + &call_with_any_feedback); - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kString)); - var_result.Bind( - CallBuiltin(Builtins::kStringAdd_CheckNone, context, lhs, rhs)); + var_type_feedback = SmiConstant(BinaryOperationFeedback::kString); + var_result = + CallBuiltin(Builtins::kStringAdd_CheckNone, context, lhs, rhs); - Goto(&end); + Goto(&end); + } } } @@ -175,7 +178,7 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, { // Check if rhs is an oddball. At this point we know lhs is either a // Smi or number or oddball and rhs is not a number or Smi. - TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs); + TNode<Uint16T> rhs_instance_type = LoadInstanceType(CAST(rhs)); TNode<BoolT> rhs_is_oddball = InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE); GotoIf(rhs_is_oddball, &call_with_oddball_feedback); @@ -186,59 +189,58 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, { // Both {lhs} and {rhs} are of BigInt type. Label bigint_too_big(this); - var_result.Bind( - CallBuiltin(Builtins::kBigIntAddNoThrow, context, lhs, rhs)); + var_result = CallBuiltin(Builtins::kBigIntAddNoThrow, context, lhs, rhs); // Check for sentinel that signals BigIntTooBig exception. GotoIf(TaggedIsSmi(var_result.value()), &bigint_too_big); - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt)); + var_type_feedback = SmiConstant(BinaryOperationFeedback::kBigInt); Goto(&end); BIND(&bigint_too_big); { // Update feedback to prevent deopt loop. UpdateFeedback(SmiConstant(BinaryOperationFeedback::kAny), - feedback_vector, slot_id); + maybe_feedback_vector, slot_id); ThrowRangeError(context, MessageTemplate::kBigIntTooBig); } } BIND(&call_with_oddball_feedback); { - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumberOrOddball); Goto(&call_add_stub); } BIND(&call_with_any_feedback); { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); + var_type_feedback = SmiConstant(BinaryOperationFeedback::kAny); Goto(&call_add_stub); } BIND(&call_add_stub); { - var_result.Bind(CallBuiltin(Builtins::kAdd, context, lhs, rhs)); + var_result = CallBuiltin(Builtins::kAdd, context, lhs, rhs); Goto(&end); } BIND(&end); - UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); + UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector, slot_id); return var_result.value(); } -Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( - Node* context, Node* lhs, Node* rhs, Node* slot_id, Node* feedback_vector, +TNode<Object> BinaryOpAssembler::Generate_BinaryOperationWithFeedback( + TNode<Context> context, TNode<Object> lhs, TNode<Object> rhs, + TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector, const SmiOperation& smiOperation, const FloatOperation& floatOperation, - Operation op, bool rhs_is_smi) { + Operation op, bool rhs_known_smi) { Label do_float_operation(this), end(this), call_stub(this), check_rhsisoddball(this, Label::kDeferred), call_with_any_feedback(this), if_lhsisnotnumber(this, Label::kDeferred), if_bigint(this, Label::kDeferred); - VARIABLE(var_float_lhs, MachineRepresentation::kFloat64); - VARIABLE(var_float_rhs, MachineRepresentation::kFloat64); - VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned); - VARIABLE(var_result, MachineRepresentation::kTagged); + TVARIABLE(Float64T, var_float_lhs); + TVARIABLE(Float64T, var_float_rhs); + TVARIABLE(Smi, var_type_feedback); + TVARIABLE(Object, var_result); Label if_lhsissmi(this); // If rhs is known to be an Smi (in the SubSmi, MulSmi, DivSmi, ModSmi @@ -246,25 +248,28 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( // operation, we want to fast path both Smi and Number operations, so this // path should not be marked as Deferred. Label if_lhsisnotsmi(this, - rhs_is_smi ? Label::kDeferred : Label::kNonDeferred); + rhs_known_smi ? Label::kDeferred : Label::kNonDeferred); Branch(TaggedIsNotSmi(lhs), &if_lhsisnotsmi, &if_lhsissmi); // Check if the {lhs} is a Smi or a HeapObject. BIND(&if_lhsissmi); { Comment("lhs is Smi"); - if (!rhs_is_smi) { + TNode<Smi> lhs_smi = CAST(lhs); + if (!rhs_known_smi) { // Check if the {rhs} is also a Smi. Label if_rhsissmi(this), if_rhsisnotsmi(this); Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + BIND(&if_rhsisnotsmi); { // Check if {rhs} is a HeapNumber. - GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball); + TNode<HeapObject> rhs_heap_object = CAST(rhs); + GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball); // Perform a floating point operation. - var_float_lhs.Bind(SmiToFloat64(lhs)); - var_float_rhs.Bind(LoadHeapNumberValue(rhs)); + var_float_lhs = SmiToFloat64(lhs_smi); + var_float_rhs = LoadHeapNumberValue(rhs_heap_object); Goto(&do_float_operation); } @@ -273,7 +278,7 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( { Comment("perform smi operation"); - var_result.Bind(smiOperation(lhs, rhs, &var_type_feedback)); + var_result = smiOperation(lhs_smi, CAST(rhs), &var_type_feedback); Goto(&end); } } @@ -282,9 +287,10 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( { Comment("lhs is not Smi"); // Check if the {lhs} is a HeapNumber. - GotoIfNot(IsHeapNumber(lhs), &if_lhsisnotnumber); + TNode<HeapObject> lhs_heap_object = CAST(lhs); + GotoIfNot(IsHeapNumber(lhs_heap_object), &if_lhsisnotnumber); - if (!rhs_is_smi) { + if (!rhs_known_smi) { // Check if the {rhs} is a Smi. Label if_rhsissmi(this), if_rhsisnotsmi(this); Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); @@ -292,11 +298,12 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( BIND(&if_rhsisnotsmi); { // Check if the {rhs} is a HeapNumber. - GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball); + TNode<HeapObject> rhs_heap_object = CAST(rhs); + GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball); // Perform a floating point operation. - var_float_lhs.Bind(LoadHeapNumberValue(lhs)); - var_float_rhs.Bind(LoadHeapNumberValue(rhs)); + var_float_lhs = LoadHeapNumberValue(lhs_heap_object); + var_float_rhs = LoadHeapNumberValue(rhs_heap_object); Goto(&do_float_operation); } @@ -305,19 +312,19 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( { // Perform floating point operation. - var_float_lhs.Bind(LoadHeapNumberValue(lhs)); - var_float_rhs.Bind(SmiToFloat64(rhs)); + var_float_lhs = LoadHeapNumberValue(lhs_heap_object); + var_float_rhs = SmiToFloat64(CAST(rhs)); Goto(&do_float_operation); } } BIND(&do_float_operation); { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); - Node* lhs_value = var_float_lhs.value(); - Node* rhs_value = var_float_rhs.value(); - Node* value = floatOperation(lhs_value, rhs_value); - var_result.Bind(AllocateHeapNumberWithValue(value)); + var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumber); + TNode<Float64T> lhs_value = var_float_lhs.value(); + TNode<Float64T> rhs_value = var_float_rhs.value(); + TNode<Float64T> value = floatOperation(lhs_value, rhs_value); + var_result = AllocateHeapNumberWithValue(value); Goto(&end); } @@ -325,7 +332,7 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( { // No checks on rhs are done yet. We just know lhs is not a number or Smi. Label if_left_bigint(this), if_left_oddball(this); - TNode<Uint16T> lhs_instance_type = LoadInstanceType(lhs); + TNode<Uint16T> lhs_instance_type = LoadInstanceType(CAST(lhs)); GotoIf(IsBigIntInstanceType(lhs_instance_type), &if_left_bigint); TNode<BoolT> lhs_is_oddball = InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE); @@ -338,18 +345,18 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( BIND(&if_rhsissmi); { - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + var_type_feedback = + SmiConstant(BinaryOperationFeedback::kNumberOrOddball); Goto(&call_stub); } BIND(&if_rhsisnotsmi); { // Check if {rhs} is a HeapNumber. - GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball); + GotoIfNot(IsHeapNumber(CAST(rhs)), &check_rhsisoddball); - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + var_type_feedback = + SmiConstant(BinaryOperationFeedback::kNumberOrOddball); Goto(&call_stub); } } @@ -357,7 +364,7 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( BIND(&if_left_bigint); { GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback); - Branch(IsBigInt(rhs), &if_bigint, &call_with_any_feedback); + Branch(IsBigInt(CAST(rhs)), &if_bigint, &call_with_any_feedback); } } @@ -365,39 +372,38 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( { // Check if rhs is an oddball. At this point we know lhs is either a // Smi or number or oddball and rhs is not a number or Smi. - TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs); + TNode<Uint16T> rhs_instance_type = LoadInstanceType(CAST(rhs)); GotoIf(IsBigIntInstanceType(rhs_instance_type), &if_bigint); TNode<BoolT> rhs_is_oddball = InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE); GotoIfNot(rhs_is_oddball, &call_with_any_feedback); - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumberOrOddball); Goto(&call_stub); } // This handles the case where at least one input is a BigInt. BIND(&if_bigint); { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt)); + var_type_feedback = SmiConstant(BinaryOperationFeedback::kBigInt); if (op == Operation::kAdd) { - var_result.Bind(CallBuiltin(Builtins::kBigIntAdd, context, lhs, rhs)); + var_result = CallBuiltin(Builtins::kBigIntAdd, context, lhs, rhs); } else { - var_result.Bind(CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs, - SmiConstant(op))); + var_result = CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs, + SmiConstant(op)); } Goto(&end); } BIND(&call_with_any_feedback); { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); + var_type_feedback = SmiConstant(BinaryOperationFeedback::kAny); Goto(&call_stub); } BIND(&call_stub); { - Node* result; + TNode<Object> result; switch (op) { case Operation::kSubtract: result = CallBuiltin(Builtins::kSubtract, context, lhs, rhs); @@ -414,34 +420,35 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( default: UNREACHABLE(); } - var_result.Bind(result); + var_result = result; Goto(&end); } BIND(&end); - UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); + UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector, slot_id); return var_result.value(); } -Node* BinaryOpAssembler::Generate_SubtractWithFeedback(Node* context, Node* lhs, - Node* rhs, Node* slot_id, - Node* feedback_vector, - bool rhs_is_smi) { - auto smiFunction = [=](Node* lhs, Node* rhs, Variable* var_type_feedback) { +TNode<Object> BinaryOpAssembler::Generate_SubtractWithFeedback( + TNode<Context> context, TNode<Object> lhs, TNode<Object> rhs, + TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector, + bool rhs_known_smi) { + auto smiFunction = [=](TNode<Smi> lhs, TNode<Smi> rhs, + TVariable<Smi>* var_type_feedback) { Label end(this); TVARIABLE(Number, var_result); // If rhs is known to be an Smi (for SubSmi) we want to fast path Smi // operation. For the normal Sub operation, we want to fast path both // Smi and Number operations, so this path should not be marked as Deferred. Label if_overflow(this, - rhs_is_smi ? Label::kDeferred : Label::kNonDeferred); - var_result = TrySmiSub(CAST(lhs), CAST(rhs), &if_overflow); - var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kSignedSmall)); + rhs_known_smi ? Label::kDeferred : Label::kNonDeferred); + var_result = TrySmiSub(lhs, rhs, &if_overflow); + *var_type_feedback = SmiConstant(BinaryOperationFeedback::kSignedSmall); Goto(&end); BIND(&if_overflow); { - var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kNumber)); + *var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumber); TNode<Float64T> value = Float64Sub(SmiToFloat64(lhs), SmiToFloat64(rhs)); var_result = AllocateHeapNumberWithValue(value); Goto(&end); @@ -450,91 +457,97 @@ Node* BinaryOpAssembler::Generate_SubtractWithFeedback(Node* context, Node* lhs, BIND(&end); return var_result.value(); }; - auto floatFunction = [=](Node* lhs, Node* rhs) { + auto floatFunction = [=](TNode<Float64T> lhs, TNode<Float64T> rhs) { return Float64Sub(lhs, rhs); }; return Generate_BinaryOperationWithFeedback( - context, lhs, rhs, slot_id, feedback_vector, smiFunction, floatFunction, - Operation::kSubtract, rhs_is_smi); + context, lhs, rhs, slot_id, maybe_feedback_vector, smiFunction, + floatFunction, Operation::kSubtract, rhs_known_smi); } -Node* BinaryOpAssembler::Generate_MultiplyWithFeedback(Node* context, Node* lhs, - Node* rhs, Node* slot_id, - Node* feedback_vector, - bool rhs_is_smi) { - auto smiFunction = [=](Node* lhs, Node* rhs, Variable* var_type_feedback) { - TNode<Number> result = SmiMul(CAST(lhs), CAST(rhs)); - var_type_feedback->Bind(SelectSmiConstant( +TNode<Object> BinaryOpAssembler::Generate_MultiplyWithFeedback( + TNode<Context> context, TNode<Object> lhs, TNode<Object> rhs, + TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector, + bool rhs_known_smi) { + auto smiFunction = [=](TNode<Smi> lhs, TNode<Smi> rhs, + TVariable<Smi>* var_type_feedback) { + TNode<Number> result = SmiMul(lhs, rhs); + *var_type_feedback = SelectSmiConstant( TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall, - BinaryOperationFeedback::kNumber)); + BinaryOperationFeedback::kNumber); return result; }; - auto floatFunction = [=](Node* lhs, Node* rhs) { + auto floatFunction = [=](TNode<Float64T> lhs, TNode<Float64T> rhs) { return Float64Mul(lhs, rhs); }; return Generate_BinaryOperationWithFeedback( - context, lhs, rhs, slot_id, feedback_vector, smiFunction, floatFunction, - Operation::kMultiply, rhs_is_smi); + context, lhs, rhs, slot_id, maybe_feedback_vector, smiFunction, + floatFunction, Operation::kMultiply, rhs_known_smi); } -Node* BinaryOpAssembler::Generate_DivideWithFeedback( - Node* context, Node* dividend, Node* divisor, Node* slot_id, - Node* feedback_vector, bool rhs_is_smi) { - auto smiFunction = [=](Node* lhs, Node* rhs, Variable* var_type_feedback) { - VARIABLE(var_result, MachineRepresentation::kTagged); +TNode<Object> BinaryOpAssembler::Generate_DivideWithFeedback( + TNode<Context> context, TNode<Object> dividend, TNode<Object> divisor, + TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector, + bool rhs_known_smi) { + auto smiFunction = [=](TNode<Smi> lhs, TNode<Smi> rhs, + TVariable<Smi>* var_type_feedback) { + TVARIABLE(Object, var_result); // If rhs is known to be an Smi (for DivSmi) we want to fast path Smi // operation. For the normal Div operation, we want to fast path both // Smi and Number operations, so this path should not be marked as Deferred. - Label bailout(this, rhs_is_smi ? Label::kDeferred : Label::kNonDeferred), + Label bailout(this, rhs_known_smi ? Label::kDeferred : Label::kNonDeferred), end(this); - var_result.Bind(TrySmiDiv(CAST(lhs), CAST(rhs), &bailout)); - var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kSignedSmall)); + var_result = TrySmiDiv(lhs, rhs, &bailout); + *var_type_feedback = SmiConstant(BinaryOperationFeedback::kSignedSmall); Goto(&end); BIND(&bailout); { - var_type_feedback->Bind( - SmiConstant(BinaryOperationFeedback::kSignedSmallInputs)); + *var_type_feedback = + SmiConstant(BinaryOperationFeedback::kSignedSmallInputs); TNode<Float64T> value = Float64Div(SmiToFloat64(lhs), SmiToFloat64(rhs)); - var_result.Bind(AllocateHeapNumberWithValue(value)); + var_result = AllocateHeapNumberWithValue(value); Goto(&end); } BIND(&end); return var_result.value(); }; - auto floatFunction = [=](Node* lhs, Node* rhs) { + auto floatFunction = [=](TNode<Float64T> lhs, TNode<Float64T> rhs) { return Float64Div(lhs, rhs); }; return Generate_BinaryOperationWithFeedback( - context, dividend, divisor, slot_id, feedback_vector, smiFunction, - floatFunction, Operation::kDivide, rhs_is_smi); + context, dividend, divisor, slot_id, maybe_feedback_vector, smiFunction, + floatFunction, Operation::kDivide, rhs_known_smi); } -Node* BinaryOpAssembler::Generate_ModulusWithFeedback( - Node* context, Node* dividend, Node* divisor, Node* slot_id, - Node* feedback_vector, bool rhs_is_smi) { - auto smiFunction = [=](Node* lhs, Node* rhs, Variable* var_type_feedback) { - TNode<Number> result = SmiMod(CAST(lhs), CAST(rhs)); - var_type_feedback->Bind(SelectSmiConstant( +TNode<Object> BinaryOpAssembler::Generate_ModulusWithFeedback( + TNode<Context> context, TNode<Object> dividend, TNode<Object> divisor, + TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector, + bool rhs_known_smi) { + auto smiFunction = [=](TNode<Smi> lhs, TNode<Smi> rhs, + TVariable<Smi>* var_type_feedback) { + TNode<Number> result = SmiMod(lhs, rhs); + *var_type_feedback = SelectSmiConstant( TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall, - BinaryOperationFeedback::kNumber)); + BinaryOperationFeedback::kNumber); return result; }; - auto floatFunction = [=](Node* lhs, Node* rhs) { + auto floatFunction = [=](TNode<Float64T> lhs, TNode<Float64T> rhs) { return Float64Mod(lhs, rhs); }; return Generate_BinaryOperationWithFeedback( - context, dividend, divisor, slot_id, feedback_vector, smiFunction, - floatFunction, Operation::kModulus, rhs_is_smi); + context, dividend, divisor, slot_id, maybe_feedback_vector, smiFunction, + floatFunction, Operation::kModulus, rhs_known_smi); } -Node* BinaryOpAssembler::Generate_ExponentiateWithFeedback( - Node* context, Node* base, Node* exponent, Node* slot_id, - Node* feedback_vector, bool rhs_is_smi) { +TNode<Object> BinaryOpAssembler::Generate_ExponentiateWithFeedback( + TNode<Context> context, TNode<Object> base, TNode<Object> exponent, + TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector, + bool rhs_known_smi) { // We currently don't optimize exponentiation based on feedback. TNode<Smi> dummy_feedback = SmiConstant(BinaryOperationFeedback::kAny); - UpdateFeedback(dummy_feedback, feedback_vector, slot_id); + UpdateFeedback(dummy_feedback, maybe_feedback_vector, slot_id); return CallBuiltin(Builtins::kExponentiate, context, base, exponent); } diff --git a/deps/v8/src/ic/binary-op-assembler.h b/deps/v8/src/ic/binary-op-assembler.h index 26324660c8..37484909d4 100644 --- a/deps/v8/src/ic/binary-op-assembler.h +++ b/deps/v8/src/ic/binary-op-assembler.h @@ -17,44 +17,50 @@ class CodeAssemblerState; class BinaryOpAssembler : public CodeStubAssembler { public: - using Node = compiler::Node; - explicit BinaryOpAssembler(compiler::CodeAssemblerState* state) : CodeStubAssembler(state) {} - Node* Generate_AddWithFeedback(Node* context, Node* lhs, Node* rhs, - Node* slot_id, Node* feedback_vector, - bool rhs_is_smi); + TNode<Object> Generate_AddWithFeedback( + TNode<Context> context, TNode<Object> left, TNode<Object> right, + TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector, + bool rhs_known_smi); - Node* Generate_SubtractWithFeedback(Node* context, Node* lhs, Node* rhs, - Node* slot_id, Node* feedback_vector, - bool rhs_is_smi); + TNode<Object> Generate_SubtractWithFeedback( + TNode<Context> context, TNode<Object> left, TNode<Object> right, + TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector, + bool rhs_known_smi); - Node* Generate_MultiplyWithFeedback(Node* context, Node* lhs, Node* rhs, - Node* slot_id, Node* feedback_vector, - bool rhs_is_smi); + TNode<Object> Generate_MultiplyWithFeedback( + TNode<Context> context, TNode<Object> left, TNode<Object> right, + TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector, + bool rhs_known_smi); - Node* Generate_DivideWithFeedback(Node* context, Node* dividend, - Node* divisor, Node* slot_id, - Node* feedback_vector, bool rhs_is_smi); + TNode<Object> Generate_DivideWithFeedback( + TNode<Context> context, TNode<Object> dividend, TNode<Object> divisor, + TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector, + bool rhs_known_smi); - Node* Generate_ModulusWithFeedback(Node* context, Node* dividend, - Node* divisor, Node* slot_id, - Node* feedback_vector, bool rhs_is_smi); + TNode<Object> Generate_ModulusWithFeedback( + TNode<Context> context, TNode<Object> dividend, TNode<Object> divisor, + TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector, + bool rhs_known_smi); - Node* Generate_ExponentiateWithFeedback(Node* context, Node* dividend, - Node* divisor, Node* slot_id, - Node* feedback_vector, - bool rhs_is_smi); + TNode<Object> Generate_ExponentiateWithFeedback( + TNode<Context> context, TNode<Object> base, TNode<Object> exponent, + TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector, + bool rhs_known_smi); private: - using SmiOperation = std::function<Node*(Node*, Node*, Variable*)>; - using FloatOperation = std::function<Node*(Node*, Node*)>; - - Node* Generate_BinaryOperationWithFeedback( - Node* context, Node* lhs, Node* rhs, Node* slot_id, Node* feedback_vector, + using SmiOperation = + std::function<TNode<Object>(TNode<Smi>, TNode<Smi>, TVariable<Smi>*)>; + using FloatOperation = + std::function<TNode<Float64T>(TNode<Float64T>, TNode<Float64T>)>; + + TNode<Object> Generate_BinaryOperationWithFeedback( + TNode<Context> context, TNode<Object> left, TNode<Object> right, + TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector, const SmiOperation& smiOperation, const FloatOperation& floatOperation, - Operation op, bool rhs_is_smi); + Operation op, bool rhs_known_smi); }; } // namespace internal diff --git a/deps/v8/src/ic/handler-configuration-inl.h b/deps/v8/src/ic/handler-configuration-inl.h index c0ff8a4c9b..95ef353277 100644 --- a/deps/v8/src/ic/handler-configuration-inl.h +++ b/deps/v8/src/ic/handler-configuration-inl.h @@ -43,6 +43,11 @@ Handle<Smi> LoadHandler::LoadInterceptor(Isolate* isolate) { return handle(Smi::FromInt(config), isolate); } +Handle<Smi> LoadHandler::LoadSlow(Isolate* isolate) { + int config = KindBits::encode(kSlow); + return handle(Smi::FromInt(config), isolate); +} + Handle<Smi> LoadHandler::LoadField(Isolate* isolate, FieldIndex field_index) { int config = KindBits::encode(kField) | IsInobjectBits::encode(field_index.is_inobject()) | @@ -127,6 +132,16 @@ Handle<Smi> StoreHandler::StoreNormal(Isolate* isolate) { return handle(Smi::FromInt(config), isolate); } +Handle<Smi> StoreHandler::StoreInterceptor(Isolate* isolate) { + int config = KindBits::encode(kInterceptor); + return handle(Smi::FromInt(config), isolate); +} + +Handle<Smi> StoreHandler::StoreSlow(Isolate* isolate) { + int config = KindBits::encode(kSlow); + return handle(Smi::FromInt(config), isolate); +} + Handle<Smi> StoreHandler::StoreProxy(Isolate* isolate) { int config = KindBits::encode(kProxy); return handle(Smi::FromInt(config), isolate); @@ -135,29 +150,12 @@ Handle<Smi> StoreHandler::StoreProxy(Isolate* isolate) { Handle<Smi> StoreHandler::StoreField(Isolate* isolate, Kind kind, int descriptor, FieldIndex field_index, Representation representation) { - FieldRepresentation field_rep; - switch (representation.kind()) { - case Representation::kSmi: - field_rep = kSmi; - break; - case Representation::kDouble: - field_rep = kDouble; - break; - case Representation::kHeapObject: - field_rep = kHeapObject; - break; - case Representation::kTagged: - field_rep = kTagged; - break; - default: - UNREACHABLE(); - } - + DCHECK(!representation.IsNone()); DCHECK(kind == kField || kind == kConstField); int config = KindBits::encode(kind) | IsInobjectBits::encode(field_index.is_inobject()) | - FieldRepresentationBits::encode(field_rep) | + RepresentationBits::encode(representation.kind()) | DescriptorBits::encode(descriptor) | FieldIndexBits::encode(field_index.index()); return handle(Smi::FromInt(config), isolate); diff --git a/deps/v8/src/ic/handler-configuration.cc b/deps/v8/src/ic/handler-configuration.cc index 814935c6eb..3af5fe4953 100644 --- a/deps/v8/src/ic/handler-configuration.cc +++ b/deps/v8/src/ic/handler-configuration.cc @@ -196,7 +196,7 @@ MaybeObjectHandle StoreHandler::StoreTransition(Isolate* isolate, bool is_dictionary_map = transition_map->is_dictionary_map(); #ifdef DEBUG if (!is_dictionary_map) { - int descriptor = transition_map->LastAdded(); + InternalIndex descriptor = transition_map->LastAdded(); Handle<DescriptorArray> descriptors(transition_map->instance_descriptors(), isolate); PropertyDetails details = descriptors->GetDetails(descriptor); diff --git a/deps/v8/src/ic/handler-configuration.h b/deps/v8/src/ic/handler-configuration.h index 80d19d73ec..fd0cee2920 100644 --- a/deps/v8/src/ic/handler-configuration.h +++ b/deps/v8/src/ic/handler-configuration.h @@ -43,6 +43,7 @@ class LoadHandler final : public DataHandler { kApiGetter, kApiGetterHolderIsPrototype, kInterceptor, + kSlow, kProxy, kNonExistent, kModuleExport @@ -113,6 +114,9 @@ class LoadHandler final : public DataHandler { // interceptor. static inline Handle<Smi> LoadInterceptor(Isolate* isolate); + // Creates a Smi-handler for loading a property from a object. + static inline Handle<Smi> LoadSlow(Isolate* isolate); + // Creates a Smi-handler for loading a field from fast object. static inline Handle<Smi> LoadField(Isolate* isolate, FieldIndex field_index); @@ -197,13 +201,13 @@ class StoreHandler final : public DataHandler { kApiSetterHolderIsPrototype, kGlobalProxy, kNormal, + kInterceptor, + kSlow, kProxy, kKindsNumber // Keep last }; using KindBits = BitField<Kind, 0, 4>; - enum FieldRepresentation { kSmi, kDouble, kHeapObject, kTagged }; - // Applicable to kGlobalProxy, kProxy kinds. // Defines whether access rights check should be done on receiver object. @@ -231,10 +235,10 @@ class StoreHandler final : public DataHandler { // Encoding when KindBits contains kField or kTransitionToField. // using IsInobjectBits = DescriptorBits::Next<bool, 1>; - using FieldRepresentationBits = IsInobjectBits::Next<FieldRepresentation, 2>; + using RepresentationBits = IsInobjectBits::Next<Representation::Kind, 3>; // +1 here is to cover all possible JSObject header sizes. using FieldIndexBits = - FieldRepresentationBits::Next<unsigned, kDescriptorIndexBitCount + 1>; + RepresentationBits::Next<unsigned, kDescriptorIndexBitCount + 1>; // Make sure we don't overflow the smi. STATIC_ASSERT(FieldIndexBits::kLastUsedBit < kSmiValueSize); @@ -283,6 +287,12 @@ class StoreHandler final : public DataHandler { // Creates a Smi-handler for storing a property to a slow object. static inline Handle<Smi> StoreNormal(Isolate* isolate); + // Creates a Smi-handler for storing a property to an interceptor. + static inline Handle<Smi> StoreInterceptor(Isolate* isolate); + + // Creates a Smi-handler for storing a property. + static inline Handle<Smi> StoreSlow(Isolate* isolate); + // Creates a Smi-handler for storing a property on a proxy. static inline Handle<Smi> StoreProxy(Isolate* isolate); diff --git a/deps/v8/src/ic/ic-stats.cc b/deps/v8/src/ic/ic-stats.cc index f387239aee..54d4856631 100644 --- a/deps/v8/src/ic/ic-stats.cc +++ b/deps/v8/src/ic/ic-stats.cc @@ -94,6 +94,7 @@ ICInfo::ICInfo() script_offset(0), script_name(nullptr), line_num(-1), + column_num(-1), is_constructor(false), is_optimized(false), map(nullptr), @@ -106,6 +107,7 @@ void ICInfo::Reset() { script_offset = 0; script_name = nullptr; line_num = -1; + column_num = -1; is_constructor = false; is_optimized = false; state.clear(); @@ -127,6 +129,7 @@ void ICInfo::AppendToTracedValue(v8::tracing::TracedValue* value) const { if (script_offset) value->SetInteger("offset", script_offset); if (script_name) value->SetString("scriptName", script_name); if (line_num != -1) value->SetInteger("lineNum", line_num); + if (column_num != -1) value->SetInteger("columnNum", column_num); if (is_constructor) value->SetInteger("constructor", is_constructor); if (!state.empty()) value->SetString("state", state); if (map) { diff --git a/deps/v8/src/ic/ic-stats.h b/deps/v8/src/ic/ic-stats.h index 76c65c3862..44b968c6c0 100644 --- a/deps/v8/src/ic/ic-stats.h +++ b/deps/v8/src/ic/ic-stats.h @@ -34,6 +34,7 @@ struct ICInfo { int script_offset; const char* script_name; int line_num; + int column_num; bool is_constructor; bool is_optimized; std::string state; diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc index 54f4be7a22..4ac5fd7abe 100644 --- a/deps/v8/src/ic/ic.cc +++ b/deps/v8/src/ic/ic.cc @@ -15,6 +15,7 @@ #include "src/execution/execution.h" #include "src/execution/frames-inl.h" #include "src/execution/isolate-inl.h" +#include "src/execution/protectors-inl.h" #include "src/execution/runtime-profiler.h" #include "src/handles/handles-inl.h" #include "src/ic/call-optimization.h" @@ -47,8 +48,6 @@ char IC::TransitionMarkFromState(IC::State state) { return 'X'; case UNINITIALIZED: return '0'; - case PREMONOMORPHIC: - return '.'; case MONOMORPHIC: return '1'; case RECOMPUTE_HANDLER: @@ -343,11 +342,6 @@ bool IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) { return changed; } -void IC::ConfigureVectorState(Handle<Map> map) { - nexus()->ConfigurePremonomorphic(map); - OnFeedbackChanged("Premonomorphic"); -} - void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map, Handle<Object> handler) { ConfigureVectorState(name, map, MaybeObjectHandle(handler)); @@ -383,11 +377,11 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { // of its properties; throw a TypeError in that case. if (IsAnyHas() ? !object->IsJSReceiver() : object->IsNullOrUndefined(isolate())) { - if (use_ic && state() != PREMONOMORPHIC) { + if (use_ic) { // Ensure the IC state progresses. TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver); update_receiver_map(object); - PatchCache(name, slow_stub()); + SetCache(name, LoadHandler::LoadSlow(isolate())); TraceIC("LoadIC", name); } @@ -490,7 +484,7 @@ MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) { } else { // Given combination of indices can't be encoded, so use slow stub. TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_SlowStub); - PatchCache(name, slow_stub()); + SetCache(name, LoadHandler::LoadSlow(isolate())); } TraceIC("LoadGlobalIC", name); } @@ -613,11 +607,11 @@ bool IC::IsTransitionOfMonomorphicTarget(Map source_map, Map target_map) { return transitioned_map == target_map; } -void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { - PatchCache(name, MaybeObjectHandle(handler)); +void IC::SetCache(Handle<Name> name, Handle<Object> handler) { + SetCache(name, MaybeObjectHandle(handler)); } -void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) { +void IC::SetCache(Handle<Name> name, const MaybeObjectHandle& handler) { DCHECK(IsHandler(*handler)); // Currently only load and store ICs support non-code handlers. DCHECK(IsAnyLoad() || IsAnyStore() || IsAnyHas()); @@ -625,7 +619,6 @@ void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) { case NO_FEEDBACK: UNREACHABLE(); case UNINITIALIZED: - case PREMONOMORPHIC: UpdateMonomorphicIC(handler, name); break; case RECOMPUTE_HANDLER: @@ -659,7 +652,7 @@ __attribute__((__aligned__(32))) void LoadIC::UpdateCaches(LookupIterator* lookup) { Handle<Object> code; if (lookup->state() == LookupIterator::ACCESS_CHECK) { - code = slow_stub(); + code = LoadHandler::LoadSlow(isolate()); } else if (!lookup->IsFound()) { TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH); Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate()); @@ -683,7 +676,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { code = ComputeHandler(lookup); } - PatchCache(lookup->name(), code); + SetCache(lookup->name(), code); TraceIC("LoadIC", lookup->name()); } @@ -798,7 +791,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { isolate()); if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) { TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); - return slow_stub(); + return LoadHandler::LoadSlow(isolate()); } if ((getter->IsFunctionTemplateInfo() && @@ -807,7 +800,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { JSFunction::cast(*getter).shared().BreakAtEntry())) { // Do not install an IC if the api function has a breakpoint. TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); - return slow_stub(); + return LoadHandler::LoadSlow(isolate()); } Handle<Smi> smi_handler; @@ -817,7 +810,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { if (!call_optimization.IsCompatibleReceiverMap(map, holder) || !holder->HasFastProperties()) { TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); - return slow_stub(); + return LoadHandler::LoadSlow(isolate()); } CallOptimization::HolderLookup holder_lookup; @@ -868,7 +861,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { !holder->HasFastProperties() || (info->is_sloppy() && !receiver->IsJSReceiver())) { TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); - return slow_stub(); + return LoadHandler::LoadSlow(isolate()); } Handle<Smi> smi_handler = LoadHandler::LoadNativeDataProperty( @@ -1076,7 +1069,7 @@ bool AllowConvertHoleElementToUndefined(Isolate* isolate, } // For other {receiver}s we need to check the "no elements" protector. - if (isolate->IsNoElementsProtectorIntact()) { + if (Protectors::IsNoElementsIntact(isolate)) { if (receiver_map->IsStringMap()) { return true; } @@ -1315,12 +1308,11 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, case LookupIterator::INTERCEPTOR: { Handle<JSObject> holder = it->GetHolder<JSObject>(); InterceptorInfo info = holder->GetNamedInterceptor(); - if (it->HolderIsReceiverOrHiddenPrototype()) { - return !info.non_masking() && receiver.is_identical_to(holder) && - !info.setter().IsUndefined(isolate()); - } else if (!info.getter().IsUndefined(isolate()) || - !info.query().IsUndefined(isolate())) { - return false; + if ((it->HolderIsReceiverOrHiddenPrototype() && + !info.non_masking()) || + !info.getter().IsUndefined(isolate()) || + !info.query().IsUndefined(isolate())) { + return true; } break; } @@ -1403,7 +1395,7 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name, } else { // Given combination of indices can't be encoded, so use slow stub. TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_SlowStub); - PatchCache(name, slow_stub()); + SetCache(name, StoreHandler::StoreSlow(isolate())); } TraceIC("StoreGlobalIC", name); } @@ -1432,11 +1424,11 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, // If the object is undefined or null it's illegal to try to set any // properties on it; throw a TypeError in that case. if (object->IsNullOrUndefined(isolate())) { - if (use_ic && state() != PREMONOMORPHIC) { + if (use_ic) { // Ensure the IC state progresses. TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver); update_receiver_map(object); - PatchCache(name, slow_stub()); + SetCache(name, StoreHandler::StoreSlow(isolate())); TraceIC("StoreIC", name); } return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name); @@ -1481,30 +1473,11 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, } handler = ComputeHandler(lookup); } else { - if (state() == UNINITIALIZED && IsStoreGlobalIC() && - lookup->state() == LookupIterator::INTERCEPTOR) { - InterceptorInfo info = - lookup->GetHolder<JSObject>()->GetNamedInterceptor(); - if (!lookup->HolderIsReceiverOrHiddenPrototype() && - !info.getter().IsUndefined(isolate())) { - // Utilize premonomorphic state for global store ics that run into - // an interceptor because the property doesn't exist yet. - // After we actually set the property, we'll have more information. - // Premonomorphism gives us a chance to find more information the - // second time. - TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_Premonomorphic); - ConfigureVectorState(receiver_map()); - TraceIC("StoreGlobalIC", lookup->name()); - return; - } - } - set_slow_stub_reason("LookupForWrite said 'false'"); - // TODO(marja): change slow_stub to return MaybeObjectHandle. - handler = MaybeObjectHandle(slow_stub()); + handler = MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); } - PatchCache(lookup->name(), handler); + SetCache(lookup->name(), handler); TraceIC("StoreIC", lookup->name()); } @@ -1542,12 +1515,27 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { case LookupIterator::INTERCEPTOR: { Handle<JSObject> holder = lookup->GetHolder<JSObject>(); - USE(holder); + InterceptorInfo info = holder->GetNamedInterceptor(); + + // If the interceptor is on the receiver + if (lookup->HolderIsReceiverOrHiddenPrototype() && !info.non_masking()) { + // return a store interceptor smi handler if there is one, + if (!info.setter().IsUndefined(isolate())) { + return MaybeObjectHandle(StoreHandler::StoreInterceptor(isolate())); + } + // otherwise return a slow-case smi handler. + return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); + } - DCHECK(!holder->GetNamedInterceptor().setter().IsUndefined(isolate())); - // TODO(jgruber): Update counter name. - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreInterceptorStub); - return MaybeObjectHandle(BUILTIN_CODE(isolate(), StoreInterceptorIC)); + // If the interceptor is a getter/query interceptor on the prototype + // chain, return an invalidatable slow handler so it can turn fast if the + // interceptor is masked by a regular property later. + DCHECK(!info.getter().IsUndefined(isolate()) || + !info.query().IsUndefined(isolate())); + Handle<Object> handler = StoreHandler::StoreThroughPrototype( + isolate(), receiver_map(), holder, + StoreHandler::StoreSlow(isolate())); + return MaybeObjectHandle(handler); } case LookupIterator::ACCESSOR: { @@ -1559,7 +1547,9 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { if (!holder->HasFastProperties()) { set_slow_stub_reason("accessor on slow map"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); - return MaybeObjectHandle(slow_stub()); + MaybeObjectHandle handler = + MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); + return handler; } Handle<Object> accessors = lookup->GetAccessors(); if (accessors->IsAccessorInfo()) { @@ -1567,18 +1557,18 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { if (v8::ToCData<Address>(info->setter()) == kNullAddress) { set_slow_stub_reason("setter == kNullAddress"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); - return MaybeObjectHandle(slow_stub()); + return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); } if (AccessorInfo::cast(*accessors).is_special_data_property() && !lookup->HolderIsReceiverOrHiddenPrototype()) { set_slow_stub_reason("special data property in prototype chain"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); - return MaybeObjectHandle(slow_stub()); + return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); } if (!AccessorInfo::IsCompatibleReceiverMap(info, receiver_map())) { set_slow_stub_reason("incompatible receiver type"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); - return MaybeObjectHandle(slow_stub()); + return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); } Handle<Smi> smi_handler = StoreHandler::StoreNativeDataProperty( @@ -1598,7 +1588,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) { set_slow_stub_reason("setter not a function"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); - return MaybeObjectHandle(slow_stub()); + return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); } if ((setter->IsFunctionTemplateInfo() && @@ -1607,7 +1597,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { JSFunction::cast(*setter).shared().BreakAtEntry())) { // Do not install an IC if the api function has a breakpoint. TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); - return MaybeObjectHandle(slow_stub()); + return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); } CallOptimization call_optimization(isolate(), setter); @@ -1631,11 +1621,11 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { } set_slow_stub_reason("incompatible receiver"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); - return MaybeObjectHandle(slow_stub()); + return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); } else if (setter->IsFunctionTemplateInfo()) { set_slow_stub_reason("setter non-simple template"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); - return MaybeObjectHandle(slow_stub()); + return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); } Handle<Smi> smi_handler = @@ -1651,7 +1641,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { isolate(), receiver_map(), holder, smi_handler)); } TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); - return MaybeObjectHandle(slow_stub()); + return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); } case LookupIterator::DATA: { @@ -1694,7 +1684,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { DCHECK_EQ(kDescriptor, lookup->property_details().location()); set_slow_stub_reason("constant property"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); - return MaybeObjectHandle(slow_stub()); + return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); } case LookupIterator::JSPROXY: { Handle<JSReceiver> receiver = @@ -1905,7 +1895,7 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers( // TODO(mvstanton): Consider embedding store_mode in the state of the slow // keyed store ic for uniformity. TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub); - handler = slow_stub(); + handler = StoreHandler::StoreSlow(isolate()); } else { { @@ -2532,7 +2522,7 @@ static bool CanFastCloneObject(Handle<Map> map) { } DescriptorArray descriptors = map->instance_descriptors(); - for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { + for (InternalIndex i : map->IterateOwnDescriptors()) { PropertyDetails details = descriptors.GetDetails(i); Name key = descriptors.GetKey(i); if (details.kind() != kData || !details.IsEnumerable() || diff --git a/deps/v8/src/ic/ic.h b/deps/v8/src/ic/ic.h index 29f3b4a60a..a3c68f4fbf 100644 --- a/deps/v8/src/ic/ic.h +++ b/deps/v8/src/ic/ic.h @@ -74,8 +74,6 @@ class IC { // Configure for most states. bool ConfigureVectorState(IC::State new_state, Handle<Object> key); - // Configure the vector for PREMONOMORPHIC. - void ConfigureVectorState(Handle<Map> map); // Configure the vector for MONOMORPHIC. void ConfigureVectorState(Handle<Name> name, Handle<Map> map, Handle<Object> handler); @@ -103,8 +101,8 @@ class IC { void CopyICToMegamorphicCache(Handle<Name> name); bool IsTransitionOfMonomorphicTarget(Map source_map, Map target_map); - void PatchCache(Handle<Name> name, Handle<Object> handler); - void PatchCache(Handle<Name> name, const MaybeObjectHandle& handler); + void SetCache(Handle<Name> name, Handle<Object> handler); + void SetCache(Handle<Name> name, const MaybeObjectHandle& handler); FeedbackSlotKind kind() const { return kind_; } bool IsGlobalIC() const { return IsLoadGlobalIC() || IsStoreGlobalIC(); } bool IsLoadIC() const { return IsLoadICKind(kind_); } @@ -188,11 +186,6 @@ class LoadIC : public IC { Handle<Name> name); protected: - virtual Handle<Code> slow_stub() const { - return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIC_Slow) - : BUILTIN_CODE(isolate(), LoadIC_Slow); - } - // Update the inline cache and the global stub cache based on the // lookup result. void UpdateCaches(LookupIterator* lookup); @@ -211,11 +204,6 @@ class LoadGlobalIC : public LoadIC { : LoadIC(isolate, vector, slot, kind) {} V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Name> name); - - protected: - Handle<Code> slow_stub() const override { - return BUILTIN_CODE(isolate(), LoadGlobalIC_Slow); - } }; class KeyedLoadIC : public LoadIC { @@ -268,11 +256,6 @@ class StoreIC : public IC { protected: // Stub accessors. - virtual Handle<Code> slow_stub() const { - // All StoreICs share the same slow stub. - return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow); - } - // Update the inline cache and the global stub cache based on the // lookup result. void UpdateCaches(LookupIterator* lookup, Handle<Object> value, @@ -292,11 +275,6 @@ class StoreGlobalIC : public StoreIC { V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Name> name, Handle<Object> value); - - protected: - Handle<Code> slow_stub() const override { - return BUILTIN_CODE(isolate(), StoreGlobalIC_Slow); - } }; enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap }; @@ -328,10 +306,6 @@ class KeyedStoreIC : public StoreIC { KeyedAccessStoreMode store_mode, Handle<Map> new_receiver_map); - Handle<Code> slow_stub() const override { - return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow); - } - private: Handle<Map> ComputeTransitionedMap(Handle<Map> map, TransitionMode transition_mode); @@ -356,11 +330,6 @@ class StoreInArrayLiteralIC : public KeyedStoreIC { } void Store(Handle<JSArray> array, Handle<Object> index, Handle<Object> value); - - private: - Handle<Code> slow_stub() const override { - return BUILTIN_CODE(isolate(), StoreInArrayLiteralIC_Slow); - } }; } // namespace internal diff --git a/deps/v8/src/ic/keyed-store-generic.cc b/deps/v8/src/ic/keyed-store-generic.cc index bb4e6cb427..ff830a022e 100644 --- a/deps/v8/src/ic/keyed-store-generic.cc +++ b/deps/v8/src/ic/keyed-store-generic.cc @@ -16,10 +16,6 @@ namespace v8 { namespace internal { -using Node = compiler::Node; -template <class T> -using TNode = compiler::TNode<T>; - enum class StoreMode { kOrdinary, kInLiteral }; class KeyedStoreGenericAssembler : public AccessorAssembler { @@ -62,9 +58,11 @@ class KeyedStoreGenericAssembler : public AccessorAssembler { TNode<Object> key, TNode<Object> value, Maybe<LanguageMode> language_mode); - void EmitGenericElementStore(Node* receiver, TNode<Map> receiver_map, - Node* instance_type, TNode<IntPtrT> index, - Node* value, Node* context, Label* slow); + void EmitGenericElementStore(TNode<JSObject> receiver, + TNode<Map> receiver_map, + TNode<Uint16T> instance_type, + TNode<IntPtrT> index, TNode<Object> value, + TNode<Context> context, Label* slow); // If language mode is not provided it is deduced from the feedback slot's // kind. @@ -86,38 +84,46 @@ class KeyedStoreGenericAssembler : public AccessorAssembler { Label* non_fast_elements, Label* only_fast_elements); - void TryRewriteElements(Node* receiver, TNode<Map> receiver_map, - Node* elements, Node* native_context, + void TryRewriteElements(TNode<JSObject> receiver, TNode<Map> receiver_map, + TNode<FixedArrayBase> elements, + TNode<NativeContext> native_context, ElementsKind from_kind, ElementsKind to_kind, Label* bailout); - void StoreElementWithCapacity(Node* receiver, TNode<Map> receiver_map, + void StoreElementWithCapacity(TNode<JSObject> receiver, + TNode<Map> receiver_map, SloppyTNode<FixedArrayBase> elements, TNode<Word32T> elements_kind, - TNode<IntPtrT> index, Node* value, - Node* context, Label* slow, + TNode<IntPtrT> index, SloppyTNode<Object> value, + TNode<Context> context, Label* slow, UpdateLength update_length); - void MaybeUpdateLengthAndReturn(Node* receiver, Node* index, Node* value, + void MaybeUpdateLengthAndReturn(TNode<JSObject> receiver, + TNode<IntPtrT> index, TNode<Object> value, UpdateLength update_length); - void TryChangeToHoleyMapHelper(Node* receiver, TNode<Map> receiver_map, - Node* native_context, ElementsKind packed_kind, + void TryChangeToHoleyMapHelper(TNode<JSObject> receiver, + TNode<Map> receiver_map, + TNode<NativeContext> native_context, + ElementsKind packed_kind, ElementsKind holey_kind, Label* done, Label* map_mismatch, Label* bailout); - void TryChangeToHoleyMap(Node* receiver, TNode<Map> receiver_map, - TNode<Word32T> current_elements_kind, Node* context, - ElementsKind packed_kind, Label* bailout); - void TryChangeToHoleyMapMulti(Node* receiver, TNode<Map> receiver_map, + void TryChangeToHoleyMap(TNode<JSObject> receiver, TNode<Map> receiver_map, + TNode<Word32T> current_elements_kind, + TNode<Context> context, ElementsKind packed_kind, + Label* bailout); + void TryChangeToHoleyMapMulti(TNode<JSObject> receiver, + TNode<Map> receiver_map, TNode<Word32T> current_elements_kind, - Node* context, ElementsKind packed_kind, + TNode<Context> context, + ElementsKind packed_kind, ElementsKind packed_kind_2, Label* bailout); - void LookupPropertyOnPrototypeChain(TNode<Map> receiver_map, Node* name, - Label* accessor, - Variable* var_accessor_pair, - Variable* var_accessor_holder, - Label* readonly, Label* bailout); + void LookupPropertyOnPrototypeChain( + TNode<Map> receiver_map, TNode<Name> name, Label* accessor, + TVariable<Object>* var_accessor_pair, + TVariable<HeapObject>* var_accessor_holder, Label* readonly, + Label* bailout); TNode<Map> FindCandidateStoreICTransitionMapHandler(TNode<Map> map, TNode<Name> name, @@ -173,18 +179,18 @@ void KeyedStoreGenericGenerator::SetPropertyInLiteral( void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements( TNode<Map> receiver_map, Label* non_fast_elements, Label* only_fast_elements) { - VARIABLE(var_map, MachineRepresentation::kTagged); - var_map.Bind(receiver_map); + TVARIABLE(Map, var_map); + var_map = receiver_map; Label loop_body(this, &var_map); Goto(&loop_body); BIND(&loop_body); { - Node* map = var_map.value(); + TNode<Map> map = var_map.value(); TNode<HeapObject> prototype = LoadMapPrototype(map); GotoIf(IsNull(prototype), only_fast_elements); TNode<Map> prototype_map = LoadMap(prototype); - var_map.Bind(prototype_map); + var_map = prototype_map; TNode<Uint16T> instance_type = LoadMapInstanceType(prototype_map); GotoIf(IsCustomElementsReceiverInstanceType(instance_type), non_fast_elements); @@ -196,9 +202,9 @@ void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements( } void KeyedStoreGenericAssembler::TryRewriteElements( - Node* receiver, TNode<Map> receiver_map, Node* elements, - Node* native_context, ElementsKind from_kind, ElementsKind to_kind, - Label* bailout) { + TNode<JSObject> receiver, TNode<Map> receiver_map, + TNode<FixedArrayBase> elements, TNode<NativeContext> native_context, + ElementsKind from_kind, ElementsKind to_kind, Label* bailout) { DCHECK(IsFastPackedElementsKind(from_kind)); ElementsKind holey_from_kind = GetHoleyElementsKind(from_kind); ElementsKind holey_to_kind = GetHoleyElementsKind(to_kind); @@ -206,12 +212,12 @@ void KeyedStoreGenericAssembler::TryRewriteElements( TrapAllocationMemento(receiver, bailout); } Label perform_transition(this), check_holey_map(this); - VARIABLE(var_target_map, MachineRepresentation::kTagged); + TVARIABLE(Map, var_target_map); // Check if the receiver has the default |from_kind| map. { TNode<Map> packed_map = LoadJSArrayElementsMap(from_kind, native_context); GotoIf(TaggedNotEqual(receiver_map, packed_map), &check_holey_map); - var_target_map.Bind( + var_target_map = CAST( LoadContextElement(native_context, Context::ArrayMapIndex(to_kind))); Goto(&perform_transition); } @@ -222,7 +228,7 @@ void KeyedStoreGenericAssembler::TryRewriteElements( TNode<Object> holey_map = LoadContextElement( native_context, Context::ArrayMapIndex(holey_from_kind)); GotoIf(TaggedNotEqual(receiver_map, holey_map), bailout); - var_target_map.Bind(LoadContextElement( + var_target_map = CAST(LoadContextElement( native_context, Context::ArrayMapIndex(holey_to_kind))); Goto(&perform_transition); } @@ -240,9 +246,9 @@ void KeyedStoreGenericAssembler::TryRewriteElements( } void KeyedStoreGenericAssembler::TryChangeToHoleyMapHelper( - Node* receiver, TNode<Map> receiver_map, Node* native_context, - ElementsKind packed_kind, ElementsKind holey_kind, Label* done, - Label* map_mismatch, Label* bailout) { + TNode<JSObject> receiver, TNode<Map> receiver_map, + TNode<NativeContext> native_context, ElementsKind packed_kind, + ElementsKind holey_kind, Label* done, Label* map_mismatch, Label* bailout) { TNode<Map> packed_map = LoadJSArrayElementsMap(packed_kind, native_context); GotoIf(TaggedNotEqual(receiver_map, packed_map), map_mismatch); if (AllocationSite::ShouldTrack(packed_kind, holey_kind)) { @@ -255,23 +261,23 @@ void KeyedStoreGenericAssembler::TryChangeToHoleyMapHelper( } void KeyedStoreGenericAssembler::TryChangeToHoleyMap( - Node* receiver, TNode<Map> receiver_map, - TNode<Word32T> current_elements_kind, Node* context, + TNode<JSObject> receiver, TNode<Map> receiver_map, + TNode<Word32T> current_elements_kind, TNode<Context> context, ElementsKind packed_kind, Label* bailout) { ElementsKind holey_kind = GetHoleyElementsKind(packed_kind); Label already_holey(this); GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind)), &already_holey); - TNode<Context> native_context = LoadNativeContext(context); + TNode<NativeContext> native_context = LoadNativeContext(context); TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind, holey_kind, &already_holey, bailout, bailout); BIND(&already_holey); } void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti( - Node* receiver, TNode<Map> receiver_map, - TNode<Word32T> current_elements_kind, Node* context, + TNode<JSObject> receiver, TNode<Map> receiver_map, + TNode<Word32T> current_elements_kind, TNode<Context> context, ElementsKind packed_kind, ElementsKind packed_kind_2, Label* bailout) { ElementsKind holey_kind = GetHoleyElementsKind(packed_kind); ElementsKind holey_kind_2 = GetHoleyElementsKind(packed_kind_2); @@ -282,7 +288,7 @@ void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti( GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind_2)), &already_holey); - TNode<Context> native_context = LoadNativeContext(context); + TNode<NativeContext> native_context = LoadNativeContext(context); TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind, holey_kind, &already_holey, &check_other_kind, bailout); @@ -294,7 +300,8 @@ void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti( } void KeyedStoreGenericAssembler::MaybeUpdateLengthAndReturn( - Node* receiver, Node* index, Node* value, UpdateLength update_length) { + TNode<JSObject> receiver, TNode<IntPtrT> index, TNode<Object> value, + UpdateLength update_length) { if (update_length != kDontChangeLength) { TNode<Smi> new_length = SmiTag(Signed(IntPtrAdd(index, IntPtrConstant(1)))); StoreObjectFieldNoWriteBarrier(receiver, JSArray::kLengthOffset, new_length, @@ -304,10 +311,10 @@ void KeyedStoreGenericAssembler::MaybeUpdateLengthAndReturn( } void KeyedStoreGenericAssembler::StoreElementWithCapacity( - Node* receiver, TNode<Map> receiver_map, + TNode<JSObject> receiver, TNode<Map> receiver_map, SloppyTNode<FixedArrayBase> elements, TNode<Word32T> elements_kind, - TNode<IntPtrT> index, Node* value, Node* context, Label* slow, - UpdateLength update_length) { + TNode<IntPtrT> index, SloppyTNode<Object> value, TNode<Context> context, + Label* slow, UpdateLength update_length) { if (update_length != kDontChangeLength) { CSA_ASSERT(this, InstanceTypeEqual(LoadMapInstanceType(receiver_map), JS_ARRAY_TYPE)); @@ -331,8 +338,8 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( // FixedArray backing store -> Smi or object elements. { - TNode<IntPtrT> offset = ElementOffsetFromIndex( - index, PACKED_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize); + TNode<IntPtrT> offset = + ElementOffsetFromIndex(index, PACKED_ELEMENTS, kHeaderSize); // Check if we're about to overwrite the hole. We can safely do that // only if there can be no setters on the prototype chain. // If we know that we're storing beyond the previous array length, we @@ -387,8 +394,8 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( // Transition to the required ElementsKind. { Label transition_to_double(this), transition_to_object(this); - TNode<Context> native_context = LoadNativeContext(context); - Branch(TaggedEqual(LoadMap(value), HeapNumberMapConstant()), + TNode<NativeContext> native_context = LoadNativeContext(context); + Branch(TaggedEqual(LoadMap(CAST(value)), HeapNumberMapConstant()), &transition_to_double, &transition_to_object); BIND(&transition_to_double); { @@ -401,11 +408,11 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( PACKED_SMI_ELEMENTS, target_kind, slow); // Reload migrated elements. TNode<FixedArrayBase> double_elements = LoadElements(receiver); - TNode<IntPtrT> double_offset = ElementOffsetFromIndex( - index, PACKED_DOUBLE_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize); + TNode<IntPtrT> double_offset = + ElementOffsetFromIndex(index, PACKED_DOUBLE_ELEMENTS, kHeaderSize); // Make sure we do not store signalling NaNs into double arrays. TNode<Float64T> double_value = - Float64SilenceNaN(LoadHeapNumberValue(value)); + Float64SilenceNaN(LoadHeapNumberValue(CAST(value))); StoreNoWriteBarrier(MachineRepresentation::kFloat64, double_elements, double_offset, double_value); MaybeUpdateLengthAndReturn(receiver, index, value, update_length); @@ -434,8 +441,8 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( &check_cow_elements); // FixedDoubleArray backing store -> double elements. { - TNode<IntPtrT> offset = ElementOffsetFromIndex( - index, PACKED_DOUBLE_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize); + TNode<IntPtrT> offset = + ElementOffsetFromIndex(index, PACKED_DOUBLE_ELEMENTS, kHeaderSize); // Check if we're about to overwrite the hole. We can safely do that // only if there can be no setters on the prototype chain. { @@ -457,7 +464,8 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( // Try to store the value as a double. { Label non_number_value(this); - Node* double_value = TryTaggedToFloat64(value, &non_number_value); + TNode<Float64T> double_value = + TryTaggedToFloat64(value, &non_number_value); // Make sure we do not store signalling NaNs into double arrays. double_value = Float64SilenceNaN(double_value); @@ -475,7 +483,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( // Transition to object elements. { - TNode<Context> native_context = LoadNativeContext(context); + TNode<NativeContext> native_context = LoadNativeContext(context); ElementsKind target_kind = update_length == kBumpLengthWithGap ? HOLEY_ELEMENTS : PACKED_ELEMENTS; @@ -483,8 +491,8 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( PACKED_DOUBLE_ELEMENTS, target_kind, slow); // Reload migrated elements. TNode<FixedArrayBase> fast_elements = LoadElements(receiver); - TNode<IntPtrT> fast_offset = ElementOffsetFromIndex( - index, PACKED_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize); + TNode<IntPtrT> fast_offset = + ElementOffsetFromIndex(index, PACKED_ELEMENTS, kHeaderSize); Store(fast_elements, fast_offset, value); MaybeUpdateLengthAndReturn(receiver, index, value, update_length); } @@ -498,8 +506,9 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( } void KeyedStoreGenericAssembler::EmitGenericElementStore( - Node* receiver, TNode<Map> receiver_map, Node* instance_type, - TNode<IntPtrT> index, Node* value, Node* context, Label* slow) { + TNode<JSObject> receiver, TNode<Map> receiver_map, + TNode<Uint16T> instance_type, TNode<IntPtrT> index, TNode<Object> value, + TNode<Context> context, Label* slow) { Label if_fast(this), if_in_bounds(this), if_out_of_bounds(this), if_increment_length_by_one(this), if_bump_length_with_gap(this), if_grow(this), if_nonfast(this), if_typed_array(this), @@ -517,7 +526,7 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore( } BIND(&if_array); { - TNode<IntPtrT> length = SmiUntag(LoadFastJSArrayLength(receiver)); + TNode<IntPtrT> length = SmiUntag(LoadFastJSArrayLength(CAST(receiver))); GotoIf(UintPtrLessThan(index, length), &if_in_bounds); TNode<IntPtrT> capacity = SmiUntag(LoadFixedArrayBaseLength(elements)); GotoIf(UintPtrGreaterThanOrEqual(index, capacity), &if_grow); @@ -595,32 +604,32 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore( } void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( - TNode<Map> receiver_map, Node* name, Label* accessor, - Variable* var_accessor_pair, Variable* var_accessor_holder, Label* readonly, + TNode<Map> receiver_map, TNode<Name> name, Label* accessor, + TVariable<Object>* var_accessor_pair, + TVariable<HeapObject>* var_accessor_holder, Label* readonly, Label* bailout) { Label ok_to_write(this); - VARIABLE(var_holder, MachineRepresentation::kTagged); - var_holder.Bind(LoadMapPrototype(receiver_map)); - VARIABLE(var_holder_map, MachineRepresentation::kTagged); - var_holder_map.Bind(LoadMap(var_holder.value())); + TVARIABLE(HeapObject, var_holder); + TVARIABLE(Map, var_holder_map); + var_holder = LoadMapPrototype(receiver_map); + var_holder_map = LoadMap(var_holder.value()); - Variable* merged_variables[] = {&var_holder, &var_holder_map}; - Label loop(this, arraysize(merged_variables), merged_variables); + Label loop(this, {&var_holder, &var_holder_map}); Goto(&loop); BIND(&loop); { - Node* holder = var_holder.value(); + TNode<HeapObject> holder = var_holder.value(); GotoIf(IsNull(holder), &ok_to_write); - Node* holder_map = var_holder_map.value(); + TNode<Map> holder_map = var_holder_map.value(); TNode<Uint16T> instance_type = LoadMapInstanceType(holder_map); Label next_proto(this); { Label found(this), found_fast(this), found_dict(this), found_global(this); TVARIABLE(HeapObject, var_meta_storage); TVARIABLE(IntPtrT, var_entry); - TryLookupProperty(holder, holder_map, instance_type, name, &found_fast, - &found_dict, &found_global, &var_meta_storage, - &var_entry, &next_proto, bailout); + TryLookupProperty(CAST(holder), holder_map, instance_type, name, + &found_fast, &found_dict, &found_global, + &var_meta_storage, &var_entry, &next_proto, bailout); BIND(&found_fast); { TNode<DescriptorArray> descriptors = CAST(var_meta_storage.value()); @@ -631,10 +640,10 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( // Accessor case. // TODO(jkummerow): Implement a trimmed-down // LoadAccessorFromFastObject. - VARIABLE(var_details, MachineRepresentation::kWord32); + TVARIABLE(Uint32T, var_details); LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index, &var_details, var_accessor_pair); - var_accessor_holder->Bind(holder); + *var_accessor_holder = holder; Goto(accessor); } @@ -648,9 +657,9 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( if (accessor != nullptr) { // Accessor case. - var_accessor_pair->Bind( - LoadValueByKeyIndex<NameDictionary>(dictionary, entry)); - var_accessor_holder->Bind(holder); + *var_accessor_pair = + LoadValueByKeyIndex<NameDictionary>(dictionary, entry); + *var_accessor_holder = holder; Goto(accessor); } else { Goto(&ok_to_write); @@ -666,14 +675,14 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( TNode<Object> value = LoadObjectField(property_cell, PropertyCell::kValueOffset); GotoIf(TaggedEqual(value, TheHoleConstant()), &next_proto); - TNode<Int32T> details = LoadAndUntagToWord32ObjectField( - property_cell, PropertyCell::kPropertyDetailsRawOffset); + TNode<Uint32T> details = Unsigned(LoadAndUntagToWord32ObjectField( + property_cell, PropertyCell::kPropertyDetailsRawOffset)); JumpIfDataProperty(details, &ok_to_write, readonly); if (accessor != nullptr) { // Accessor case. - var_accessor_pair->Bind(value); - var_accessor_holder->Bind(holder); + *var_accessor_pair = value; + *var_accessor_holder = holder; Goto(accessor); } else { Goto(&ok_to_write); @@ -686,8 +695,8 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( GotoIf(InstanceTypeEqual(instance_type, JS_TYPED_ARRAY_TYPE), bailout); TNode<HeapObject> proto = LoadMapPrototype(holder_map); GotoIf(IsNull(proto), &ok_to_write); - var_holder.Bind(proto); - var_holder_map.Bind(LoadMap(proto)); + var_holder = proto; + var_holder_map = LoadMap(proto); Goto(&loop); } BIND(&ok_to_write); @@ -763,8 +772,10 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( const StoreICParameters* p, ExitPoint* exit_point, Label* slow, Maybe<LanguageMode> maybe_language_mode) { CSA_ASSERT(this, IsSimpleObjectMap(receiver_map)); - VARIABLE(var_accessor_pair, MachineRepresentation::kTagged); - VARIABLE(var_accessor_holder, MachineRepresentation::kTagged); + // TODO(rmcilroy) Type as Struct once we use a trimmed down + // LoadAccessorFromFastObject instead of LoadPropertyFromFastObject. + TVARIABLE(Object, var_accessor_pair); + TVARIABLE(HeapObject, var_accessor_holder); Label fast_properties(this), dictionary_properties(this), accessor(this), readonly(this); TNode<Uint32T> bitfield3 = LoadMapBitField3(receiver_map); @@ -792,11 +803,11 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( if (ShouldCallSetter()) { // Accessor case. // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject. - VARIABLE(var_details, MachineRepresentation::kWord32); + TVARIABLE(Uint32T, var_details); LoadPropertyFromFastObject(receiver, receiver_map, descriptors, name_index, &var_details, &var_accessor_pair); - var_accessor_holder.Bind(receiver); + var_accessor_holder = receiver; Goto(&accessor); } else { // Handle accessor to data property reconfiguration in runtime. @@ -836,7 +847,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( TVARIABLE(IntPtrT, var_name_index); Label dictionary_found(this, &var_name_index), not_found(this); - TNode<NameDictionary> properties = CAST(LoadSlowProperties(CAST(receiver))); + TNode<NameDictionary> properties = CAST(LoadSlowProperties(receiver)); NameDictionaryLookup<NameDictionary>(properties, name, &dictionary_found, &var_name_index, ¬_found); BIND(&dictionary_found); @@ -849,9 +860,9 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( if (ShouldCallSetter()) { // Accessor case. - var_accessor_pair.Bind(LoadValueByKeyIndex<NameDictionary>( - properties, var_name_index.value())); - var_accessor_holder.Bind(receiver); + var_accessor_pair = LoadValueByKeyIndex<NameDictionary>( + properties, var_name_index.value()); + var_accessor_holder = receiver; Goto(&accessor); } else { // We must reconfigure an accessor property to a data property @@ -870,6 +881,11 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( BIND(¬_found); { + // TODO(jkummerow): Also add support to correctly handle integer exotic + // cases for typed arrays and remove this check here. + GotoIf(InstanceTypeEqual(LoadMapInstanceType(receiver_map), + JS_TYPED_ARRAY_TYPE), + slow); CheckForAssociatedProtector(name, slow); Label extensible(this), is_private_symbol(this); TNode<Uint32T> bitfield3 = LoadMapBitField3(receiver_map); @@ -909,7 +925,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( BIND(&accessor); { Label not_callable(this); - Node* accessor_pair = var_accessor_pair.value(); + TNode<Struct> accessor_pair = CAST(var_accessor_pair.value()); GotoIf(IsAccessorInfoMap(LoadMap(accessor_pair)), slow); CSA_ASSERT(this, HasInstanceType(accessor_pair, ACCESSOR_PAIR_TYPE)); TNode<HeapObject> setter = @@ -951,7 +967,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( LanguageMode language_mode; if (maybe_language_mode.To(&language_mode)) { if (language_mode == LanguageMode::kStrict) { - Node* type = Typeof(p->receiver()); + TNode<String> type = Typeof(p->receiver()); ThrowTypeError(p->context(), MessageTemplate::kStrictReadOnlyProperty, name, type, p->receiver()); } else { @@ -969,15 +985,16 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( // Helper that is used by the public KeyedStoreGeneric and by SetProperty. void KeyedStoreGenericAssembler::KeyedStoreGeneric( - TNode<Context> context, TNode<Object> receiver, TNode<Object> key, + TNode<Context> context, TNode<Object> receiver_maybe_smi, TNode<Object> key, TNode<Object> value, Maybe<LanguageMode> language_mode) { TVARIABLE(IntPtrT, var_index); - TVARIABLE(Object, var_unique, key); + TVARIABLE(Name, var_unique); Label if_index(this), if_unique_name(this), not_internalized(this), slow(this); - GotoIf(TaggedIsSmi(receiver), &slow); - TNode<Map> receiver_map = LoadMap(CAST(receiver)); + GotoIf(TaggedIsSmi(receiver_maybe_smi), &slow); + TNode<HeapObject> receiver = CAST(receiver_maybe_smi); + TNode<Map> receiver_map = LoadMap(receiver); TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map); // Receivers requiring non-standard element accesses (interceptors, access // checks, strings and string wrappers, proxies) are handled in the runtime. @@ -989,14 +1006,14 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric( BIND(&if_index); { Comment("integer index"); - EmitGenericElementStore(receiver, receiver_map, instance_type, + EmitGenericElementStore(CAST(receiver), receiver_map, instance_type, var_index.value(), value, context, &slow); } BIND(&if_unique_name); { Comment("key is unique name"); - StoreICParameters p(context, receiver, var_unique.value(), value, nullptr, + StoreICParameters p(context, receiver, var_unique.value(), value, {}, nullptr); ExitPoint direct_exit(this); EmitGenericPropertyStore(CAST(receiver), receiver_map, &p, &direct_exit, @@ -1006,7 +1023,7 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric( BIND(¬_internalized); { if (FLAG_internalize_on_the_fly) { - TryInternalizeString(key, &if_index, &var_index, &if_unique_name, + TryInternalizeString(CAST(key), &if_index, &var_index, &if_unique_name, &var_unique, &slow, &slow); } else { Goto(&slow); @@ -1049,30 +1066,34 @@ void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context, void KeyedStoreGenericAssembler::StoreIC_NoFeedback() { using Descriptor = StoreDescriptor; - Node* receiver = Parameter(Descriptor::kReceiver); + TNode<Object> receiver_maybe_smi = CAST(Parameter(Descriptor::kReceiver)); TNode<Object> name = CAST(Parameter(Descriptor::kName)); - Node* value = Parameter(Descriptor::kValue); - Node* slot = Parameter(Descriptor::kSlot); - Node* context = Parameter(Descriptor::kContext); + TNode<Object> value = CAST(Parameter(Descriptor::kValue)); + TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot)); + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); Label miss(this, Label::kDeferred), store_property(this); - GotoIf(TaggedIsSmi(receiver), &miss); - TNode<Map> receiver_map = LoadMap(receiver); - TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map); - // Receivers requiring non-standard element accesses (interceptors, access - // checks, strings and string wrappers, proxies) are handled in the runtime. - GotoIf(IsSpecialReceiverInstanceType(instance_type), &miss); + GotoIf(TaggedIsSmi(receiver_maybe_smi), &miss); + { - StoreICParameters p(CAST(context), receiver, name, value, slot, - UndefinedConstant()); - EmitGenericPropertyStore(receiver, receiver_map, &p, &miss); + TNode<HeapObject> receiver = CAST(receiver_maybe_smi); + TNode<Map> receiver_map = LoadMap(receiver); + TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map); + // Receivers requiring non-standard element accesses (interceptors, access + // checks, strings and string wrappers, proxies) are handled in the runtime. + GotoIf(IsSpecialReceiverInstanceType(instance_type), &miss); + { + StoreICParameters p(context, receiver, name, value, slot, + UndefinedConstant()); + EmitGenericPropertyStore(CAST(receiver), receiver_map, &p, &miss); + } } BIND(&miss); { TailCallRuntime(Runtime::kStoreIC_Miss, context, value, slot, - UndefinedConstant(), receiver, name); + UndefinedConstant(), receiver_maybe_smi, name); } } @@ -1082,7 +1103,7 @@ void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context, TNode<Name> unique_name, TNode<Object> value, LanguageMode language_mode) { - StoreICParameters p(context, receiver, unique_name, value, nullptr, nullptr); + StoreICParameters p(context, receiver, unique_name, value, {}, nullptr); Label done(this), slow(this, Label::kDeferred); ExitPoint exit_point(this, [&](Node* result) { Goto(&done); }); diff --git a/deps/v8/src/ic/keyed-store-generic.h b/deps/v8/src/ic/keyed-store-generic.h index efee0da80e..8047fe6493 100644 --- a/deps/v8/src/ic/keyed-store-generic.h +++ b/deps/v8/src/ic/keyed-store-generic.h @@ -13,9 +13,6 @@ namespace internal { class KeyedStoreGenericGenerator { public: - template <class T> - using TNode = compiler::TNode<T>; - static void Generate(compiler::CodeAssemblerState* state); // Building block for fast path of Object.assign implementation. diff --git a/deps/v8/src/ic/stub-cache.cc b/deps/v8/src/ic/stub-cache.cc index 04381bf693..c1d9aea374 100644 --- a/deps/v8/src/ic/stub-cache.cc +++ b/deps/v8/src/ic/stub-cache.cc @@ -26,11 +26,10 @@ void StubCache::Initialize() { Clear(); } -// Hash algorithm for the primary table. This algorithm is replicated in -// assembler for every architecture. Returns an index into the table that +// Hash algorithm for the primary table. This algorithm is replicated in +// the AccessorAssembler. Returns an index into the table that // is scaled by 1 << kCacheIndexShift. int StubCache::PrimaryOffset(Name name, Map map) { - STATIC_ASSERT(kCacheIndexShift == Name::kHashShift); // Compute the hash of the name (use entire hash field). DCHECK(name.HasHashCode()); uint32_t field = name.hash_field(); diff --git a/deps/v8/src/ic/stub-cache.h b/deps/v8/src/ic/stub-cache.h index 87acc0e007..dc3317588d 100644 --- a/deps/v8/src/ic/stub-cache.h +++ b/deps/v8/src/ic/stub-cache.h @@ -78,10 +78,15 @@ class V8_EXPORT_PRIVATE StubCache { Isolate* isolate() { return isolate_; } - // Setting the entry size such that the index is shifted by Name::kHashShift - // is convenient; shifting down the length field (to extract the hash code) - // automatically discards the hash bit field. - static const int kCacheIndexShift = Name::kHashShift; + // Ideally we would set kCacheIndexShift to Name::kHashShift, such that + // the bit field inside the hash field gets shifted out implicitly. However, + // sizeof(Entry) needs to be a multiple of 1 << kCacheIndexShift, and it + // isn't clear whether letting one bit of the bit field leak into the index + // computation is bad enough to warrant an additional shift to get rid of it. + static const int kCacheIndexShift = 2; + // The purpose of the static assert is to make us reconsider this choice + // if the bit field ever grows even more. + STATIC_ASSERT(kCacheIndexShift == Name::kHashShift - 1); static const int kPrimaryTableBits = 11; static const int kPrimaryTableSize = (1 << kPrimaryTableBits); @@ -125,7 +130,10 @@ class V8_EXPORT_PRIVATE StubCache { // of sizeof(Entry). This makes it easier to avoid making mistakes // in the hashed offset computations. static Entry* entry(Entry* table, int offset) { - const int multiplier = sizeof(*table) >> Name::kHashShift; + // The size of {Entry} must be a multiple of 1 << kCacheIndexShift. + STATIC_ASSERT((sizeof(*table) >> kCacheIndexShift) << kCacheIndexShift == + sizeof(*table)); + const int multiplier = sizeof(*table) >> kCacheIndexShift; return reinterpret_cast<Entry*>(reinterpret_cast<Address>(table) + offset * multiplier); } |