diff options
author | Michaël Zasso <targos@protonmail.com> | 2017-05-02 10:50:00 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2017-05-06 20:02:35 +0200 |
commit | 60d1aac8d225e844e68ae48e8f3d58802e635fbe (patch) | |
tree | 922f347dd054db18d88666fad7181e5a777f4022 /deps/v8/src/ic | |
parent | 73d9c0f903ae371cd5011af64c3a6f69a1bda978 (diff) | |
download | node-new-60d1aac8d225e844e68ae48e8f3d58802e635fbe.tar.gz |
deps: update V8 to 5.8.283.38
PR-URL: https://github.com/nodejs/node/pull/12784
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Diffstat (limited to 'deps/v8/src/ic')
38 files changed, 1681 insertions, 2031 deletions
diff --git a/deps/v8/src/ic/access-compiler.cc b/deps/v8/src/ic/access-compiler.cc index d92f9c0c53..d210ea8c71 100644 --- a/deps/v8/src/ic/access-compiler.cc +++ b/deps/v8/src/ic/access-compiler.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "src/ic/access-compiler.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { diff --git a/deps/v8/src/ic/accessor-assembler-impl.h b/deps/v8/src/ic/accessor-assembler-impl.h deleted file mode 100644 index 1699b5c855..0000000000 --- a/deps/v8/src/ic/accessor-assembler-impl.h +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_SRC_IC_ACCESSOR_ASSEMBLER_IMPL_H_ -#define V8_SRC_IC_ACCESSOR_ASSEMBLER_IMPL_H_ - -#include "src/code-stub-assembler.h" - -namespace v8 { -namespace internal { - -namespace compiler { -class CodeAssemblerState; -} - -using compiler::Node; - -#define ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE(V) \ - V(LoadIC) \ - V(LoadField) \ - V(LoadICTrampoline) \ - V(KeyedLoadICTF) \ - V(KeyedLoadICTrampolineTF) \ - V(KeyedLoadICMegamorphic) \ - V(StoreIC) \ - V(StoreICTrampoline) -// The other IC entry points need custom handling because of additional -// parameters like "typeof_mode" or "language_mode". - -class AccessorAssemblerImpl : public CodeStubAssembler { - public: - explicit AccessorAssemblerImpl(compiler::CodeAssemblerState* state) - : CodeStubAssembler(state) {} - -#define DECLARE_PUBLIC_METHOD(Name) void Generate##Name(); - - ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE(DECLARE_PUBLIC_METHOD) -#undef DECLARE_PUBLIC_METHOD - - void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent); - - void GenerateLoadGlobalIC(TypeofMode typeof_mode); - void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode); - - void GenerateKeyedStoreICTF(LanguageMode language_mode); - void GenerateKeyedStoreICTrampolineTF(LanguageMode language_mode); - - void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name, - Label* if_handler, Variable* var_handler, - Label* if_miss); - - Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) { - return StubCachePrimaryOffset(name, map); - } - Node* StubCacheSecondaryOffsetForTesting(Node* name, Node* map) { - return StubCacheSecondaryOffset(name, map); - } - - protected: - struct LoadICParameters { - LoadICParameters(Node* context, Node* receiver, Node* name, Node* slot, - Node* vector) - : context(context), - receiver(receiver), - name(name), - slot(slot), - vector(vector) {} - - Node* context; - Node* receiver; - Node* name; - Node* slot; - Node* vector; - }; - - struct StoreICParameters : public LoadICParameters { - StoreICParameters(Node* context, Node* receiver, Node* name, Node* value, - Node* slot, Node* vector) - : LoadICParameters(context, receiver, name, slot, vector), - value(value) {} - Node* value; - }; - - enum ElementSupport { kOnlyProperties, kSupportElements }; - void HandleStoreICHandlerCase( - const StoreICParameters* p, Node* handler, Label* miss, - ElementSupport support_elements = kOnlyProperties); - - private: - // Stub generation entry points. - - void LoadIC(const LoadICParameters* p); - void LoadICProtoArray(const LoadICParameters* p, Node* handler, - bool throw_reference_error_if_nonexistent); - void LoadGlobalIC(const LoadICParameters* p, TypeofMode typeof_mode); - void KeyedLoadIC(const LoadICParameters* p); - void KeyedLoadICGeneric(const LoadICParameters* p); - void StoreIC(const StoreICParameters* p); - void KeyedStoreIC(const StoreICParameters* p, LanguageMode language_mode); - - // IC dispatcher behavior. - - // Checks monomorphic case. Returns {feedback} entry of the vector. - Node* TryMonomorphicCase(Node* slot, Node* vector, Node* receiver_map, - Label* if_handler, Variable* var_handler, - Label* if_miss); - void HandlePolymorphicCase(Node* receiver_map, Node* feedback, - Label* if_handler, Variable* var_handler, - Label* if_miss, int unroll_count); - void HandleKeyedStorePolymorphicCase(Node* receiver_map, Node* feedback, - Label* if_handler, Variable* var_handler, - Label* if_transition_handler, - Variable* var_transition_map_cell, - Label* if_miss); - - // LoadIC implementation. - - void HandleLoadICHandlerCase( - const LoadICParameters* p, Node* handler, Label* miss, - ElementSupport support_elements = kOnlyProperties); - - void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder, - Node* smi_handler, Label* miss, - ElementSupport support_elements); - - void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler, - Variable* var_holder, - Variable* var_smi_handler, - Label* if_smi_handler, Label* miss, - bool throw_reference_error_if_nonexistent); - - Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler, - Node* handler_length, Node* handler_flags, - Label* miss, - bool throw_reference_error_if_nonexistent); - - // LoadGlobalIC implementation. - - void HandleLoadGlobalICHandlerCase(const LoadICParameters* p, Node* handler, - Label* miss, - bool throw_reference_error_if_nonexistent); - - // StoreIC implementation. - - void HandleStoreICElementHandlerCase(const StoreICParameters* p, - Node* handler, Label* miss); - - void HandleStoreICProtoHandler(const StoreICParameters* p, Node* handler, - Label* miss); - // If |transition| is nullptr then the normal field store is generated or - // transitioning store otherwise. - void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder, - Node* value, Node* transition, Label* miss); - // If |transition| is nullptr then the normal field store is generated or - // transitioning store otherwise. - void HandleStoreFieldAndReturn(Node* handler_word, Node* holder, - Representation representation, Node* value, - Node* transition, Label* miss); - - // Low-level helpers. - - Node* PrepareValueForStore(Node* handler_word, Node* holder, - Representation representation, Node* transition, - Node* value, Label* bailout); - - // Extends properties backing store by JSObject::kFieldsAdded elements. - void ExtendPropertiesBackingStore(Node* object); - - void StoreNamedField(Node* handler_word, Node* object, bool is_inobject, - Representation representation, Node* value, - bool transition_to_field); - - void EmitFastElementsBoundsCheck(Node* object, Node* elements, - Node* intptr_index, - Node* is_jsarray_condition, Label* miss); - void EmitElementLoad(Node* object, Node* elements, Node* elements_kind, - Node* key, Node* is_jsarray_condition, Label* if_hole, - Label* rebox_double, Variable* var_double_value, - Label* unimplemented_elements_kind, Label* out_of_bounds, - Label* miss); - void CheckPrototype(Node* prototype_cell, Node* name, Label* miss); - void NameDictionaryNegativeLookup(Node* object, Node* name, Label* miss); - - // Stub cache access helpers. - - // This enum is used here as a replacement for StubCache::Table to avoid - // including stub cache header. - enum StubCacheTable : int; - - Node* StubCachePrimaryOffset(Node* name, Node* map); - Node* StubCacheSecondaryOffset(Node* name, Node* seed); - - void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id, - Node* entry_offset, Node* name, Node* map, - Label* if_handler, Variable* var_handler, - Label* if_miss); -}; - -} // namespace internal -} // namespace v8 - -#endif // V8_SRC_IC_ACCESSOR_ASSEMBLER_IMPL_H_ diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc index c2b2d17950..d3379ab6d2 100644 --- a/deps/v8/src/ic/accessor-assembler.cc +++ b/deps/v8/src/ic/accessor-assembler.cc @@ -3,25 +3,27 @@ // found in the LICENSE file. #include "src/ic/accessor-assembler.h" -#include "src/ic/accessor-assembler-impl.h" #include "src/code-factory.h" #include "src/code-stubs.h" +#include "src/counters.h" #include "src/ic/handler-configuration.h" #include "src/ic/stub-cache.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { using compiler::CodeAssemblerState; +using compiler::Node; //////////////////// Private helpers. -Node* AccessorAssemblerImpl::TryMonomorphicCase(Node* slot, Node* vector, - Node* receiver_map, - Label* if_handler, - Variable* var_handler, - Label* if_miss) { +Node* AccessorAssembler::TryMonomorphicCase(Node* slot, Node* vector, + Node* receiver_map, + Label* if_handler, + Variable* var_handler, + Label* if_miss) { Comment("TryMonomorphicCase"); DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep()); @@ -51,9 +53,11 @@ Node* AccessorAssemblerImpl::TryMonomorphicCase(Node* slot, Node* vector, return feedback; } -void AccessorAssemblerImpl::HandlePolymorphicCase( - Node* receiver_map, Node* feedback, Label* if_handler, - Variable* var_handler, Label* if_miss, int unroll_count) { +void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map, + Node* feedback, Label* if_handler, + Variable* var_handler, + Label* if_miss, + int unroll_count) { Comment("HandlePolymorphicCase"); DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep()); @@ -78,7 +82,7 @@ void AccessorAssemblerImpl::HandlePolymorphicCase( Node* init = IntPtrConstant(unroll_count * kEntrySize); Node* length = LoadAndUntagFixedArrayBaseLength(feedback); BuildFastLoop( - MachineType::PointerRepresentation(), init, length, + init, length, [this, receiver_map, feedback, if_handler, var_handler](Node* index) { Node* cached_map = LoadWeakCellValue(LoadFixedArrayElement(feedback, index)); @@ -93,12 +97,12 @@ void AccessorAssemblerImpl::HandlePolymorphicCase( Bind(&next_entry); }, - kEntrySize, IndexAdvanceMode::kPost); + kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost); // The loop falls through if no handler was found. Goto(if_miss); } -void AccessorAssemblerImpl::HandleKeyedStorePolymorphicCase( +void AccessorAssembler::HandleKeyedStorePolymorphicCase( Node* receiver_map, Node* feedback, Label* if_handler, Variable* var_handler, Label* if_transition_handler, Variable* var_transition_map_cell, Label* if_miss) { @@ -109,7 +113,7 @@ void AccessorAssemblerImpl::HandleKeyedStorePolymorphicCase( Node* init = IntPtrConstant(0); Node* length = LoadAndUntagFixedArrayBaseLength(feedback); - BuildFastLoop(MachineType::PointerRepresentation(), init, length, + BuildFastLoop(init, length, [this, receiver_map, feedback, if_handler, var_handler, if_transition_handler, var_transition_map_cell](Node* index) { Node* cached_map = @@ -130,15 +134,17 @@ void AccessorAssemblerImpl::HandleKeyedStorePolymorphicCase( Bind(&next_entry); }, - kEntrySize, IndexAdvanceMode::kPost); + kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost); // The loop falls through if no handler was found. Goto(if_miss); } -void AccessorAssemblerImpl::HandleLoadICHandlerCase( +void AccessorAssembler::HandleLoadICHandlerCase( const LoadICParameters* p, Node* handler, Label* miss, ElementSupport support_elements) { Comment("have_handler"); + ExitPoint direct_exit(this); + Variable var_holder(this, MachineRepresentation::kTagged); var_holder.Bind(p->receiver); Variable var_smi_handler(this, MachineRepresentation::kTagged); @@ -155,14 +161,14 @@ void AccessorAssemblerImpl::HandleLoadICHandlerCase( Bind(&if_smi_handler); { HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(), - miss, support_elements); + miss, &direct_exit, support_elements); } Bind(&try_proto_handler); { GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); HandleLoadICProtoHandlerCase(p, handler, &var_holder, &var_smi_handler, - &if_smi_handler, miss, false); + &if_smi_handler, miss, &direct_exit, false); } Bind(&call_handler); @@ -173,9 +179,9 @@ void AccessorAssemblerImpl::HandleLoadICHandlerCase( } } -void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase( +void AccessorAssembler::HandleLoadICSmiHandlerCase( const LoadICParameters* p, Node* holder, Node* smi_handler, Label* miss, - ElementSupport support_elements) { + ExitPoint* exit_point, ElementSupport support_elements) { Variable var_double_value(this, MachineRepresentation::kFloat64); Label rebox_double(this, &var_double_value); @@ -183,7 +189,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase( Node* handler_kind = DecodeWord<LoadHandler::KindBits>(handler_word); if (support_elements == kSupportElements) { Label property(this); - GotoUnless( + GotoIfNot( WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForElements)), &property); @@ -199,7 +205,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase( EmitElementLoad(holder, elements, elements_kind, intptr_index, is_jsarray_condition, &if_hole, &rebox_double, &var_double_value, &unimplemented_elements_kind, - out_of_bounds, miss); + out_of_bounds, miss, exit_point); Bind(&unimplemented_elements_kind); { @@ -212,14 +218,14 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase( Bind(&if_hole); { Comment("convert hole"); - GotoUnless(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss); + GotoIfNot(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss); Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex); DCHECK(isolate()->heap()->array_protector()->IsPropertyCell()); - GotoUnless( + GotoIfNot( WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset), SmiConstant(Smi::FromInt(Isolate::kProtectorValid))), miss); - Return(UndefinedConstant()); + exit_point->Return(UndefinedConstant()); } Bind(&property); @@ -243,7 +249,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase( { Label is_double(this); GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double); - Return(LoadObjectField(holder, offset)); + exit_point->Return(LoadObjectField(holder, offset)); Bind(&is_double); if (FLAG_unbox_double_fields) { @@ -262,7 +268,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase( Node* properties = LoadProperties(holder); Node* value = LoadObjectField(properties, offset); GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double); - Return(value); + exit_point->Return(value); Bind(&is_double); var_double_value.Bind(LoadHeapNumberValue(value)); @@ -270,7 +276,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase( } Bind(&rebox_double); - Return(AllocateHeapNumberWithValue(var_double_value.value())); + exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value())); } Bind(&constant); @@ -287,18 +293,19 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase( Label if_accessor_info(this); GotoIf(IsSetWord<LoadHandler::IsAccessorInfoBits>(handler_word), &if_accessor_info); - Return(value); + exit_point->Return(value); Bind(&if_accessor_info); Callable callable = CodeFactory::ApiGetter(isolate()); - TailCallStub(callable, p->context, p->receiver, holder, value); + exit_point->ReturnCallStub(callable, p->context, p->receiver, holder, + value); } } -void AccessorAssemblerImpl::HandleLoadICProtoHandlerCase( +void AccessorAssembler::HandleLoadICProtoHandlerCase( const LoadICParameters* p, Node* handler, Variable* var_holder, Variable* var_smi_handler, Label* if_smi_handler, Label* miss, - bool throw_reference_error_if_nonexistent) { + ExitPoint* exit_point, bool throw_reference_error_if_nonexistent) { DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep()); DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep()); @@ -327,7 +334,7 @@ void AccessorAssemblerImpl::HandleLoadICProtoHandlerCase( Node* handler_flags = SmiUntag(smi_handler); Label check_prototypes(this); - GotoUnless( + GotoIfNot( IsSetWord<LoadHandler::DoNegativeLookupOnReceiverBits>(handler_flags), &check_prototypes); { @@ -350,9 +357,10 @@ void AccessorAssemblerImpl::HandleLoadICProtoHandlerCase( GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), &load_existent); // This is a handler for a load of a non-existent value. if (throw_reference_error_if_nonexistent) { - TailCallRuntime(Runtime::kThrowReferenceError, p->context, p->name); + exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context, + p->name); } else { - Return(UndefinedConstant()); + exit_point->Return(UndefinedConstant()); } Bind(&load_existent); @@ -368,15 +376,14 @@ void AccessorAssemblerImpl::HandleLoadICProtoHandlerCase( Bind(&array_handler); { - typedef LoadICProtoArrayDescriptor Descriptor; - LoadICProtoArrayStub stub(isolate(), throw_reference_error_if_nonexistent); - Node* target = HeapConstant(stub.GetCode()); - TailCallStub(Descriptor(isolate()), target, p->context, p->receiver, - p->name, p->slot, p->vector, handler); + exit_point->ReturnCallStub( + CodeFactory::LoadICProtoArray(isolate(), + throw_reference_error_if_nonexistent), + p->context, p->receiver, p->name, p->slot, p->vector, handler); } } -Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck( +Node* AccessorAssembler::EmitLoadICProtoArrayCheck( const LoadICParameters* p, Node* handler, Node* handler_length, Node* handler_flags, Label* miss, bool throw_reference_error_if_nonexistent) { @@ -384,8 +391,8 @@ Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck( start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex)); Label can_access(this); - GotoUnless(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags), - &can_access); + GotoIfNot(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags), + &can_access); { // Skip this entry of a handler. start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex + 1)); @@ -399,7 +406,7 @@ Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck( Node* native_context = LoadNativeContext(p->context); GotoIf(WordEqual(expected_native_context, native_context), &can_access); // If the receiver is not a JSGlobalProxy then we miss. - GotoUnless(IsJSGlobalProxy(p->receiver), miss); + GotoIfNot(IsJSGlobalProxy(p->receiver), miss); // For JSGlobalProxy receiver try to compare security tokens of current // and expected native contexts. Node* expected_token = LoadContextElement(expected_native_context, @@ -410,13 +417,13 @@ Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck( } Bind(&can_access); - BuildFastLoop( - MachineType::PointerRepresentation(), start_index.value(), handler_length, - [this, p, handler, miss](Node* current) { - Node* prototype_cell = LoadFixedArrayElement(handler, current); - CheckPrototype(prototype_cell, p->name, miss); - }, - 1, IndexAdvanceMode::kPost); + BuildFastLoop(start_index.value(), handler_length, + [this, p, handler, miss](Node* current) { + Node* prototype_cell = + LoadFixedArrayElement(handler, current); + CheckPrototype(prototype_cell, p->name, miss); + }, + 1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost); Node* maybe_holder_cell = LoadFixedArrayElement(handler, LoadHandler::kHolderCellIndex); @@ -438,9 +445,9 @@ Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck( return holder; } -void AccessorAssemblerImpl::HandleLoadGlobalICHandlerCase( +void AccessorAssembler::HandleLoadGlobalICHandlerCase( const LoadICParameters* pp, Node* handler, Label* miss, - bool throw_reference_error_if_nonexistent) { + ExitPoint* exit_point, bool throw_reference_error_if_nonexistent) { LoadICParameters p = *pp; DCHECK_NULL(p.receiver); Node* native_context = LoadNativeContext(p.context); @@ -450,14 +457,14 @@ void AccessorAssemblerImpl::HandleLoadGlobalICHandlerCase( Variable var_smi_handler(this, MachineRepresentation::kTagged); Label if_smi_handler(this); HandleLoadICProtoHandlerCase(&p, handler, &var_holder, &var_smi_handler, - &if_smi_handler, miss, + &if_smi_handler, miss, exit_point, throw_reference_error_if_nonexistent); Bind(&if_smi_handler); HandleLoadICSmiHandlerCase(&p, var_holder.value(), var_smi_handler.value(), - miss, kOnlyProperties); + miss, exit_point, kOnlyProperties); } -void AccessorAssemblerImpl::HandleStoreICHandlerCase( +void AccessorAssembler::HandleStoreICHandlerCase( const StoreICParameters* p, Node* handler, Label* miss, ElementSupport support_elements) { Label if_smi_handler(this), if_nonsmi_handler(this); @@ -504,7 +511,7 @@ void AccessorAssemblerImpl::HandleStoreICHandlerCase( } } -void AccessorAssemblerImpl::HandleStoreICElementHandlerCase( +void AccessorAssembler::HandleStoreICElementHandlerCase( const StoreICParameters* p, Node* handler, Label* miss) { Comment("HandleStoreICElementHandlerCase"); Node* validity_cell = LoadObjectField(handler, Tuple2::kValue1Offset); @@ -521,8 +528,8 @@ void AccessorAssemblerImpl::HandleStoreICElementHandlerCase( p->value, p->slot, p->vector); } -void AccessorAssemblerImpl::HandleStoreICProtoHandler( - const StoreICParameters* p, Node* handler, Label* miss) { +void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p, + Node* handler, Label* miss) { // IC dispatchers rely on these assumptions to be held. STATIC_ASSERT(FixedArray::kLengthOffset == StoreHandler::kTransitionCellOffset); @@ -564,14 +571,13 @@ void AccessorAssemblerImpl::HandleStoreICProtoHandler( Bind(&array_handler); { Node* length = SmiUntag(maybe_transition_cell); - BuildFastLoop(MachineType::PointerRepresentation(), - IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length, + BuildFastLoop(IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length, [this, p, handler, miss](Node* current) { Node* prototype_cell = LoadFixedArrayElement(handler, current); CheckPrototype(prototype_cell, p->name, miss); }, - 1, IndexAdvanceMode::kPost); + 1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost); Node* maybe_transition_cell = LoadFixedArrayElement(handler, StoreHandler::kTransitionCellIndex); @@ -613,11 +619,10 @@ void AccessorAssemblerImpl::HandleStoreICProtoHandler( } } -void AccessorAssemblerImpl::HandleStoreICSmiHandlerCase(Node* handler_word, - Node* holder, - Node* value, - Node* transition, - Label* miss) { +void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word, + Node* holder, Node* value, + Node* transition, + Label* miss) { Comment(transition ? "transitioning field store" : "field store"); #ifdef DEBUG @@ -631,8 +636,17 @@ void AccessorAssemblerImpl::HandleStoreICSmiHandlerCase(Node* handler_word, WordEqual(handler_kind, IntPtrConstant(StoreHandler::kTransitionToConstant)))); } else { - CSA_ASSERT(this, WordEqual(handler_kind, - IntPtrConstant(StoreHandler::kStoreField))); + if (FLAG_track_constant_fields) { + CSA_ASSERT( + this, + Word32Or(WordEqual(handler_kind, + IntPtrConstant(StoreHandler::kStoreField)), + WordEqual(handler_kind, + IntPtrConstant(StoreHandler::kStoreConstField)))); + } else { + CSA_ASSERT(this, WordEqual(handler_kind, + IntPtrConstant(StoreHandler::kStoreField))); + } } #endif @@ -683,9 +697,11 @@ void AccessorAssemblerImpl::HandleStoreICSmiHandlerCase(Node* handler_word, } } -void AccessorAssemblerImpl::HandleStoreFieldAndReturn( - Node* handler_word, Node* holder, Representation representation, - Node* value, Node* transition, Label* miss) { +void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word, + Node* holder, + Representation representation, + Node* value, Node* transition, + Label* miss) { bool transition_to_field = transition != nullptr; Node* prepared_value = PrepareValueForStore( handler_word, holder, representation, transition, value, miss); @@ -697,7 +713,7 @@ void AccessorAssemblerImpl::HandleStoreFieldAndReturn( Bind(&if_inobject); { StoreNamedField(handler_word, holder, true, representation, prepared_value, - transition_to_field); + transition_to_field, miss); if (transition_to_field) { StoreMap(holder, transition); } @@ -708,8 +724,8 @@ void AccessorAssemblerImpl::HandleStoreFieldAndReturn( { if (transition_to_field) { Label storage_extended(this); - GotoUnless(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word), - &storage_extended); + GotoIfNot(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word), + &storage_extended); Comment("[ Extend storage"); ExtendPropertiesBackingStore(holder); Comment("] Extend storage"); @@ -719,7 +735,7 @@ void AccessorAssemblerImpl::HandleStoreFieldAndReturn( } StoreNamedField(handler_word, holder, false, representation, prepared_value, - transition_to_field); + transition_to_field, miss); if (transition_to_field) { StoreMap(holder, transition); } @@ -727,16 +743,24 @@ void AccessorAssemblerImpl::HandleStoreFieldAndReturn( } } -Node* AccessorAssemblerImpl::PrepareValueForStore(Node* handler_word, - Node* holder, - Representation representation, - Node* transition, Node* value, - Label* bailout) { +Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder, + Representation representation, + Node* transition, Node* value, + Label* bailout) { if (representation.IsDouble()) { value = TryTaggedToFloat64(value, bailout); } else if (representation.IsHeapObject()) { GotoIf(TaggedIsSmi(value), bailout); + + Label done(this); + if (FLAG_track_constant_fields && !transition) { + // Skip field type check in favor of constant value check when storing + // to constant field. + GotoIf(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word), + IntPtrConstant(StoreHandler::kStoreConstField)), + &done); + } Node* value_index_in_descriptor = DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word); Node* descriptors = @@ -744,7 +768,6 @@ Node* AccessorAssemblerImpl::PrepareValueForStore(Node* handler_word, Node* maybe_field_type = LoadFixedArrayElement(descriptors, value_index_in_descriptor); - Label done(this); GotoIf(TaggedIsSmi(maybe_field_type), &done); // Check that value type matches the field type. { @@ -754,7 +777,7 @@ Node* AccessorAssemblerImpl::PrepareValueForStore(Node* handler_word, Bind(&done); } else if (representation.IsSmi()) { - GotoUnless(TaggedIsSmi(value), bailout); + GotoIfNot(TaggedIsSmi(value), bailout); } else { DCHECK(representation.IsTagged()); @@ -762,7 +785,7 @@ Node* AccessorAssemblerImpl::PrepareValueForStore(Node* handler_word, return value; } -void AccessorAssemblerImpl::ExtendPropertiesBackingStore(Node* object) { +void AccessorAssembler::ExtendPropertiesBackingStore(Node* object) { Node* properties = LoadProperties(object); Node* length = LoadFixedArrayBaseLength(properties); @@ -798,11 +821,11 @@ void AccessorAssemblerImpl::ExtendPropertiesBackingStore(Node* object) { StoreObjectField(object, JSObject::kPropertiesOffset, new_properties); } -void AccessorAssemblerImpl::StoreNamedField(Node* handler_word, Node* object, - bool is_inobject, - Representation representation, - Node* value, - bool transition_to_field) { +void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object, + bool is_inobject, + Representation representation, + Node* value, bool transition_to_field, + Label* bailout) { bool store_value_as_double = representation.IsDouble(); Node* property_storage = object; if (!is_inobject) { @@ -826,6 +849,27 @@ void AccessorAssemblerImpl::StoreNamedField(Node* handler_word, Node* object, } } + // Do constant value check if necessary. + if (FLAG_track_constant_fields && !transition_to_field) { + Label done(this); + GotoIfNot(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word), + IntPtrConstant(StoreHandler::kStoreConstField)), + &done); + { + if (store_value_as_double) { + Node* current_value = + LoadObjectField(property_storage, offset, MachineType::Float64()); + GotoIfNot(Float64Equal(current_value, value), bailout); + } else { + Node* current_value = LoadObjectField(property_storage, offset); + GotoIfNot(WordEqual(current_value, value), bailout); + } + Goto(&done); + } + Bind(&done); + } + + // Do the store. if (store_value_as_double) { StoreObjectFieldNoWriteBarrier(property_storage, offset, value, MachineRepresentation::kFloat64); @@ -836,9 +880,11 @@ void AccessorAssemblerImpl::StoreNamedField(Node* handler_word, Node* object, } } -void AccessorAssemblerImpl::EmitFastElementsBoundsCheck( - Node* object, Node* elements, Node* intptr_index, - Node* is_jsarray_condition, Label* miss) { +void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object, + Node* elements, + Node* intptr_index, + Node* is_jsarray_condition, + Label* miss) { Variable var_length(this, MachineType::PointerRepresentation()); Comment("Fast elements bounds check"); Label if_array(this), length_loaded(this, &var_length); @@ -853,14 +899,14 @@ void AccessorAssemblerImpl::EmitFastElementsBoundsCheck( Goto(&length_loaded); } Bind(&length_loaded); - GotoUnless(UintPtrLessThan(intptr_index, var_length.value()), miss); + GotoIfNot(UintPtrLessThan(intptr_index, var_length.value()), miss); } -void AccessorAssemblerImpl::EmitElementLoad( +void AccessorAssembler::EmitElementLoad( Node* object, Node* elements, Node* elements_kind, Node* intptr_index, Node* is_jsarray_condition, Label* if_hole, Label* rebox_double, Variable* var_double_value, Label* unimplemented_elements_kind, - Label* out_of_bounds, Label* miss) { + Label* out_of_bounds, Label* miss, ExitPoint* exit_point) { Label if_typed_array(this), if_fast_packed(this), if_fast_holey(this), if_fast_double(this), if_fast_holey_double(this), if_nonfast(this), if_dictionary(this); @@ -892,7 +938,7 @@ void AccessorAssemblerImpl::EmitElementLoad( Bind(&if_fast_packed); { Comment("fast packed elements"); - Return(LoadFixedArrayElement(elements, intptr_index)); + exit_point->Return(LoadFixedArrayElement(elements, intptr_index)); } Bind(&if_fast_holey); @@ -900,7 +946,7 @@ void AccessorAssemblerImpl::EmitElementLoad( Comment("fast holey elements"); Node* element = LoadFixedArrayElement(elements, intptr_index); GotoIf(WordEqual(element, TheHoleConstant()), if_hole); - Return(element); + exit_point->Return(element); } Bind(&if_fast_double); @@ -943,16 +989,15 @@ void AccessorAssemblerImpl::EmitElementLoad( elements, intptr_index, &if_found, &var_entry, if_hole); Bind(&if_found); // Check that the value is a data property. - Node* details_index = EntryToIndex<SeededNumberDictionary>( - var_entry.value(), SeededNumberDictionary::kEntryDetailsIndex); - Node* details = SmiToWord32(LoadFixedArrayElement(elements, details_index)); + Node* index = EntryToIndex<SeededNumberDictionary>(var_entry.value()); + Node* details = + LoadDetailsByKeyIndex<SeededNumberDictionary>(elements, index); Node* kind = DecodeWord32<PropertyDetails::KindField>(details); // TODO(jkummerow): Support accessors without missing? - GotoUnless(Word32Equal(kind, Int32Constant(kData)), miss); + GotoIfNot(Word32Equal(kind, Int32Constant(kData)), miss); // Finally, load the value. - Node* value_index = EntryToIndex<SeededNumberDictionary>( - var_entry.value(), SeededNumberDictionary::kEntryValueIndex); - Return(LoadFixedArrayElement(elements, value_index)); + exit_point->Return( + LoadValueByKeyIndex<SeededNumberDictionary>(elements, index)); } Bind(&if_typed_array); @@ -965,7 +1010,7 @@ void AccessorAssemblerImpl::EmitElementLoad( // Bounds check. Node* length = SmiUntag(LoadObjectField(object, JSTypedArray::kLengthOffset)); - GotoUnless(UintPtrLessThan(intptr_index, length), out_of_bounds); + GotoIfNot(UintPtrLessThan(intptr_index, length), out_of_bounds); // Backing store = external_pointer + base_pointer. Node* external_pointer = @@ -998,41 +1043,41 @@ void AccessorAssemblerImpl::EmitElementLoad( { Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too. Node* element = Load(MachineType::Uint8(), backing_store, intptr_index); - Return(SmiFromWord32(element)); + exit_point->Return(SmiFromWord32(element)); } Bind(&int8_elements); { Comment("INT8_ELEMENTS"); Node* element = Load(MachineType::Int8(), backing_store, intptr_index); - Return(SmiFromWord32(element)); + exit_point->Return(SmiFromWord32(element)); } Bind(&uint16_elements); { Comment("UINT16_ELEMENTS"); Node* index = WordShl(intptr_index, IntPtrConstant(1)); Node* element = Load(MachineType::Uint16(), backing_store, index); - Return(SmiFromWord32(element)); + exit_point->Return(SmiFromWord32(element)); } Bind(&int16_elements); { Comment("INT16_ELEMENTS"); Node* index = WordShl(intptr_index, IntPtrConstant(1)); Node* element = Load(MachineType::Int16(), backing_store, index); - Return(SmiFromWord32(element)); + exit_point->Return(SmiFromWord32(element)); } Bind(&uint32_elements); { Comment("UINT32_ELEMENTS"); Node* index = WordShl(intptr_index, IntPtrConstant(2)); Node* element = Load(MachineType::Uint32(), backing_store, index); - Return(ChangeUint32ToTagged(element)); + exit_point->Return(ChangeUint32ToTagged(element)); } Bind(&int32_elements); { Comment("INT32_ELEMENTS"); Node* index = WordShl(intptr_index, IntPtrConstant(2)); Node* element = Load(MachineType::Int32(), backing_store, index); - Return(ChangeInt32ToTagged(element)); + exit_point->Return(ChangeInt32ToTagged(element)); } Bind(&float32_elements); { @@ -1053,8 +1098,8 @@ void AccessorAssemblerImpl::EmitElementLoad( } } -void AccessorAssemblerImpl::CheckPrototype(Node* prototype_cell, Node* name, - Label* miss) { +void AccessorAssembler::CheckPrototype(Node* prototype_cell, Node* name, + Label* miss) { Node* maybe_prototype = LoadWeakCellValue(prototype_cell, miss); Label done(this); @@ -1083,9 +1128,8 @@ void AccessorAssemblerImpl::CheckPrototype(Node* prototype_cell, Node* name, Bind(&done); } -void AccessorAssemblerImpl::NameDictionaryNegativeLookup(Node* object, - Node* name, - Label* miss) { +void AccessorAssembler::NameDictionaryNegativeLookup(Node* object, Node* name, + Label* miss) { CSA_ASSERT(this, IsDictionaryMap(LoadMap(object))); Node* properties = LoadProperties(object); // Ensure the property does not exist in a dictionary-mode object. @@ -1096,14 +1140,199 @@ void AccessorAssemblerImpl::NameDictionaryNegativeLookup(Node* object, Bind(&done); } +void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map, + Node* instance_type, Node* index, + Label* slow) { + Comment("integer index"); + + ExitPoint direct_exit(this); + + Label if_element_hole(this), if_oob(this); + // Receivers requiring non-standard element accesses (interceptors, access + // checks, strings and string wrappers, proxies) are handled in the runtime. + GotoIf(Int32LessThanOrEqual(instance_type, + Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)), + slow); + Node* elements = LoadElements(receiver); + Node* elements_kind = LoadMapElementsKind(receiver_map); + Node* is_jsarray_condition = + Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)); + Variable var_double_value(this, MachineRepresentation::kFloat64); + Label rebox_double(this, &var_double_value); + + // Unimplemented elements kinds fall back to a runtime call. + Label* unimplemented_elements_kind = slow; + IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1); + EmitElementLoad(receiver, elements, elements_kind, index, + is_jsarray_condition, &if_element_hole, &rebox_double, + &var_double_value, unimplemented_elements_kind, &if_oob, slow, + &direct_exit); + + Bind(&rebox_double); + Return(AllocateHeapNumberWithValue(var_double_value.value())); + + Bind(&if_oob); + { + Comment("out of bounds"); + // Negative keys can't take the fast OOB path. + GotoIf(IntPtrLessThan(index, IntPtrConstant(0)), slow); + // Positive OOB indices are effectively the same as hole loads. + Goto(&if_element_hole); + } + + Bind(&if_element_hole); + { + Comment("found the hole"); + Label return_undefined(this); + BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, slow); + + Bind(&return_undefined); + Return(UndefinedConstant()); + } +} + +void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, + Node* instance_type, Node* key, + const LoadICParameters* p, + Label* slow) { + Comment("key is unique name"); + Label if_found_on_receiver(this), if_property_dictionary(this), + lookup_prototype_chain(this); + Variable var_details(this, MachineRepresentation::kWord32); + Variable var_value(this, MachineRepresentation::kTagged); + + // Receivers requiring non-standard accesses (interceptors, access + // checks, strings and string wrappers, proxies) are handled in the runtime. + GotoIf(Int32LessThanOrEqual(instance_type, + Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)), + slow); + + // Check if the receiver has fast or slow properties. + Node* properties = LoadProperties(receiver); + Node* properties_map = LoadMap(properties); + GotoIf(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)), + &if_property_dictionary); + + // Try looking up the property on the receiver; if unsuccessful, look + // for a handler in the stub cache. + Node* bitfield3 = LoadMapBitField3(receiver_map); + Node* descriptors = LoadMapDescriptors(receiver_map); + + Label if_descriptor_found(this), stub_cache(this); + Variable var_name_index(this, MachineType::PointerRepresentation()); + DescriptorLookup(key, descriptors, bitfield3, &if_descriptor_found, + &var_name_index, &stub_cache); + + Bind(&if_descriptor_found); + { + LoadPropertyFromFastObject(receiver, receiver_map, descriptors, + var_name_index.value(), &var_details, + &var_value); + Goto(&if_found_on_receiver); + } + + Bind(&stub_cache); + { + Comment("stub cache probe for fast property load"); + Variable var_handler(this, MachineRepresentation::kTagged); + Label found_handler(this, &var_handler), stub_cache_miss(this); + TryProbeStubCache(isolate()->load_stub_cache(), receiver, key, + &found_handler, &var_handler, &stub_cache_miss); + Bind(&found_handler); + { HandleLoadICHandlerCase(p, var_handler.value(), slow); } + + Bind(&stub_cache_miss); + { + // TODO(jkummerow): Check if the property exists on the prototype + // chain. If it doesn't, then there's no point in missing. + Comment("KeyedLoadGeneric_miss"); + TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver, + p->name, p->slot, p->vector); + } + } + + Bind(&if_property_dictionary); + { + Comment("dictionary property load"); + // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out + // seeing global objects here (which would need special handling). + + Variable var_name_index(this, MachineType::PointerRepresentation()); + Label dictionary_found(this, &var_name_index); + NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found, + &var_name_index, + &lookup_prototype_chain); + Bind(&dictionary_found); + { + LoadPropertyFromNameDictionary(properties, var_name_index.value(), + &var_details, &var_value); + Goto(&if_found_on_receiver); + } + } + + Bind(&if_found_on_receiver); + { + Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(), + p->context, receiver, slow); + IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1); + Return(value); + } + + Bind(&lookup_prototype_chain); + { + Variable var_holder_map(this, MachineRepresentation::kTagged); + Variable var_holder_instance_type(this, MachineRepresentation::kWord32); + Label return_undefined(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_instance_type.Bind(instance_type); + // Private symbols must not be looked up on the prototype chain. + GotoIf(IsPrivateSymbol(key), &return_undefined); + Goto(&loop); + Bind(&loop); + { + // Bailout if it can be an integer indexed exotic case. + GotoIf(Word32Equal(var_holder_instance_type.value(), + Int32Constant(JS_TYPED_ARRAY_TYPE)), + slow); + Node* proto = LoadMapPrototype(var_holder_map.value()); + GotoIf(WordEqual(proto, NullConstant()), &return_undefined); + Node* proto_map = LoadMap(proto); + Node* proto_instance_type = LoadMapInstanceType(proto_map); + var_holder_map.Bind(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, + proto_instance_type, key, &return_value, &var_value, + &next_proto, &goto_slow); + + // This trampoline and the next are required to appease Turbofan's + // variable merging. + Bind(&next_proto); + Goto(&loop); + + Bind(&goto_slow); + Goto(slow); + + Bind(&return_value); + Return(var_value.value()); + } + + Bind(&return_undefined); + Return(UndefinedConstant()); + } +} + //////////////////// Stub cache access helpers. -enum AccessorAssemblerImpl::StubCacheTable : int { +enum AccessorAssembler::StubCacheTable : int { kPrimary = static_cast<int>(StubCache::kPrimary), kSecondary = static_cast<int>(StubCache::kSecondary) }; -Node* AccessorAssemblerImpl::StubCachePrimaryOffset(Node* name, Node* map) { +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). @@ -1125,7 +1354,7 @@ Node* AccessorAssemblerImpl::StubCachePrimaryOffset(Node* name, Node* map) { return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask))); } -Node* AccessorAssemblerImpl::StubCacheSecondaryOffset(Node* name, Node* seed) { +Node* AccessorAssembler::StubCacheSecondaryOffset(Node* name, Node* seed) { // See v8::internal::StubCache::SecondaryOffset(). // Use the seed from the primary cache in the secondary cache. @@ -1137,10 +1366,12 @@ Node* AccessorAssemblerImpl::StubCacheSecondaryOffset(Node* name, Node* seed) { return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask))); } -void AccessorAssemblerImpl::TryProbeStubCacheTable( - StubCache* stub_cache, StubCacheTable table_id, Node* entry_offset, - Node* name, Node* map, Label* if_handler, Variable* var_handler, - Label* if_miss) { +void AccessorAssembler::TryProbeStubCacheTable(StubCache* stub_cache, + StubCacheTable table_id, + Node* entry_offset, Node* name, + Node* map, Label* if_handler, + Variable* var_handler, + Label* if_miss) { StubCache::Table table = static_cast<StubCache::Table>(table_id); #ifdef DEBUG if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { @@ -1180,11 +1411,10 @@ void AccessorAssemblerImpl::TryProbeStubCacheTable( Goto(if_handler); } -void AccessorAssemblerImpl::TryProbeStubCache(StubCache* stub_cache, - Node* receiver, Node* name, - Label* if_handler, - Variable* var_handler, - Label* if_miss) { +void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver, + Node* name, Label* if_handler, + Variable* var_handler, + Label* if_miss) { Label try_secondary(this), miss(this); Counters* counters = isolate()->counters(); @@ -1217,7 +1447,7 @@ void AccessorAssemblerImpl::TryProbeStubCache(StubCache* stub_cache, //////////////////// Entry points into private implementation (one per stub). -void AccessorAssemblerImpl::LoadIC(const LoadICParameters* p) { +void AccessorAssembler::LoadIC(const LoadICParameters* p) { Variable var_handler(this, MachineRepresentation::kTagged); // TODO(ishell): defer blocks when it works. Label if_handler(this, &var_handler), try_polymorphic(this), @@ -1238,8 +1468,8 @@ void AccessorAssemblerImpl::LoadIC(const LoadICParameters* p) { { // Check polymorphic case. Comment("LoadIC_try_polymorphic"); - GotoUnless(WordEqual(LoadMap(feedback), FixedArrayMapConstant()), - &try_megamorphic); + GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()), + &try_megamorphic); HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler, &miss, 2); } @@ -1247,9 +1477,8 @@ void AccessorAssemblerImpl::LoadIC(const LoadICParameters* p) { Bind(&try_megamorphic); { // Check megamorphic case. - GotoUnless( - WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)), - &miss); + GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)), + &miss); TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name, &if_handler, &var_handler, &miss); @@ -1261,13 +1490,15 @@ void AccessorAssemblerImpl::LoadIC(const LoadICParameters* p) { } } -void AccessorAssemblerImpl::LoadICProtoArray( +void AccessorAssembler::LoadICProtoArray( const LoadICParameters* p, Node* handler, bool throw_reference_error_if_nonexistent) { Label miss(this); CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler))); CSA_ASSERT(this, IsFixedArrayMap(LoadMap(handler))); + ExitPoint direct_exit(this); + Node* smi_handler = LoadObjectField(handler, LoadHandler::kSmiHandlerOffset); Node* handler_flags = SmiUntag(smi_handler); @@ -1277,7 +1508,8 @@ void AccessorAssemblerImpl::LoadICProtoArray( EmitLoadICProtoArrayCheck(p, handler, handler_length, handler_flags, &miss, throw_reference_error_if_nonexistent); - HandleLoadICSmiHandlerCase(p, holder, smi_handler, &miss, kOnlyProperties); + HandleLoadICSmiHandlerCase(p, holder, smi_handler, &miss, &direct_exit, + kOnlyProperties); Bind(&miss); { @@ -1286,36 +1518,41 @@ void AccessorAssemblerImpl::LoadICProtoArray( } } -void AccessorAssemblerImpl::LoadGlobalIC(const LoadICParameters* p, - TypeofMode typeof_mode) { - Label try_handler(this), call_handler(this), miss(this); - Node* weak_cell = - LoadFixedArrayElement(p->vector, p->slot, 0, SMI_PARAMETERS); +void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase( + Node* vector, Node* slot, ExitPoint* exit_point, Label* try_handler, + Label* miss, ParameterMode slot_mode) { + Comment("LoadGlobalIC_TryPropertyCellCase"); + + Node* weak_cell = LoadFixedArrayElement(vector, slot, 0, slot_mode); CSA_ASSERT(this, HasInstanceType(weak_cell, WEAK_CELL_TYPE)); // Load value or try handler case if the {weak_cell} is cleared. - Node* property_cell = LoadWeakCellValue(weak_cell, &try_handler); + Node* property_cell = LoadWeakCellValue(weak_cell, try_handler); CSA_ASSERT(this, HasInstanceType(property_cell, PROPERTY_CELL_TYPE)); Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset); - GotoIf(WordEqual(value, TheHoleConstant()), &miss); - Return(value); + GotoIf(WordEqual(value, TheHoleConstant()), miss); + exit_point->Return(value); +} - Node* handler; - Bind(&try_handler); - { - handler = - LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS); - CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler))); - GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)), - &miss); - GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); +void AccessorAssembler::LoadGlobalIC_TryHandlerCase(const LoadICParameters* p, + TypeofMode typeof_mode, + ExitPoint* exit_point, + Label* miss) { + Comment("LoadGlobalIC_TryHandlerCase"); - bool throw_reference_error_if_nonexistent = - typeof_mode == NOT_INSIDE_TYPEOF; - HandleLoadGlobalICHandlerCase(p, handler, &miss, - throw_reference_error_if_nonexistent); - } + Label call_handler(this); + + Node* handler = + LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS); + CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler))); + GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)), + miss); + GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); + + bool throw_reference_error_if_nonexistent = typeof_mode == NOT_INSIDE_TYPEOF; + HandleLoadGlobalICHandlerCase(p, handler, miss, exit_point, + throw_reference_error_if_nonexistent); Bind(&call_handler); { @@ -1323,17 +1560,35 @@ void AccessorAssemblerImpl::LoadGlobalIC(const LoadICParameters* p, Node* native_context = LoadNativeContext(p->context); Node* receiver = LoadContextElement(native_context, Context::EXTENSION_INDEX); - TailCallStub(descriptor, handler, p->context, receiver, p->name, p->slot, - p->vector); + exit_point->ReturnCallStub(descriptor, handler, p->context, receiver, + p->name, p->slot, p->vector); } +} + +void AccessorAssembler::LoadGlobalIC_MissCase(const LoadICParameters* p, + ExitPoint* exit_point) { + Comment("LoadGlobalIC_MissCase"); + + exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Miss, p->context, + p->name, p->slot, p->vector); +} + +void AccessorAssembler::LoadGlobalIC(const LoadICParameters* p, + TypeofMode typeof_mode) { + ExitPoint direct_exit(this); + + Label try_handler(this), miss(this); + LoadGlobalIC_TryPropertyCellCase(p->vector, p->slot, &direct_exit, + &try_handler, &miss); + + Bind(&try_handler); + LoadGlobalIC_TryHandlerCase(p, typeof_mode, &direct_exit, &miss); + Bind(&miss); - { - TailCallRuntime(Runtime::kLoadGlobalIC_Miss, p->context, p->name, p->slot, - p->vector); - } + LoadGlobalIC_MissCase(p, &direct_exit); } -void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) { +void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) { Variable var_handler(this, MachineRepresentation::kTagged); // TODO(ishell): defer blocks when it works. Label if_handler(this, &var_handler), try_polymorphic(this), @@ -1355,8 +1610,8 @@ void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) { { // Check polymorphic case. Comment("KeyedLoadIC_try_polymorphic"); - GotoUnless(WordEqual(LoadMap(feedback), FixedArrayMapConstant()), - &try_megamorphic); + GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()), + &try_megamorphic); HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler, &miss, 2); } @@ -1365,9 +1620,8 @@ void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) { { // Check megamorphic case. Comment("KeyedLoadIC_try_megamorphic"); - GotoUnless( - WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)), - &try_polymorphic_name); + GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)), + &try_polymorphic_name); // TODO(jkummerow): Inline this? Or some of it? TailCallStub(CodeFactory::KeyedLoadIC_Megamorphic(isolate()), p->context, p->receiver, p->name, p->slot, p->vector); @@ -1376,7 +1630,7 @@ void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) { { // We might have a name in feedback, and a fixed array in the next slot. Comment("KeyedLoadIC_try_polymorphic_name"); - GotoUnless(WordEqual(feedback, p->name), &miss); + GotoIfNot(WordEqual(feedback, p->name), &miss); // If the name comparison succeeded, we know we have a fixed array with // at least one map/handler pair. Node* offset = ElementOffsetFromIndex( @@ -1394,150 +1648,30 @@ void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) { } } -void AccessorAssemblerImpl::KeyedLoadICGeneric(const LoadICParameters* p) { +void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) { Variable var_index(this, MachineType::PointerRepresentation()); - Variable var_details(this, MachineRepresentation::kWord32); - Variable var_value(this, MachineRepresentation::kTagged); - Label if_index(this), if_unique_name(this), if_element_hole(this), - if_oob(this), slow(this), stub_cache_miss(this), - if_property_dictionary(this), if_found_on_receiver(this); + Variable var_unique(this, MachineRepresentation::kTagged); + var_unique.Bind(p->name); // Dummy initialization. + Label if_index(this), if_unique_name(this), slow(this); Node* receiver = p->receiver; GotoIf(TaggedIsSmi(receiver), &slow); Node* receiver_map = LoadMap(receiver); Node* 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(Int32LessThanOrEqual(instance_type, - Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)), - &slow); - Node* key = p->name; - TryToName(key, &if_index, &var_index, &if_unique_name, &slow); + TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique, + &slow); Bind(&if_index); { - Comment("integer index"); - Node* index = var_index.value(); - Node* elements = LoadElements(receiver); - Node* elements_kind = LoadMapElementsKind(receiver_map); - Node* is_jsarray_condition = - Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)); - Variable var_double_value(this, MachineRepresentation::kFloat64); - Label rebox_double(this, &var_double_value); - - // Unimplemented elements kinds fall back to a runtime call. - Label* unimplemented_elements_kind = &slow; - IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1); - EmitElementLoad(receiver, elements, elements_kind, index, - is_jsarray_condition, &if_element_hole, &rebox_double, - &var_double_value, unimplemented_elements_kind, &if_oob, - &slow); - - Bind(&rebox_double); - Return(AllocateHeapNumberWithValue(var_double_value.value())); - } - - Bind(&if_oob); - { - Comment("out of bounds"); - Node* index = var_index.value(); - // Negative keys can't take the fast OOB path. - GotoIf(IntPtrLessThan(index, IntPtrConstant(0)), &slow); - // Positive OOB indices are effectively the same as hole loads. - Goto(&if_element_hole); - } - - Bind(&if_element_hole); - { - Comment("found the hole"); - Label return_undefined(this); - BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, &slow); - - Bind(&return_undefined); - Return(UndefinedConstant()); + GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(), + &slow); } - Node* properties = nullptr; Bind(&if_unique_name); { - Comment("key is unique name"); - // Check if the receiver has fast or slow properties. - properties = LoadProperties(receiver); - Node* properties_map = LoadMap(properties); - GotoIf(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)), - &if_property_dictionary); - - // Try looking up the property on the receiver; if unsuccessful, look - // for a handler in the stub cache. - Comment("DescriptorArray lookup"); - - // Skip linear search if there are too many descriptors. - // TODO(jkummerow): Consider implementing binary search. - // See also TryLookupProperty() which has the same limitation. - const int32_t kMaxLinear = 210; - Label stub_cache(this); - Node* bitfield3 = LoadMapBitField3(receiver_map); - Node* nof = - DecodeWordFromWord32<Map::NumberOfOwnDescriptorsBits>(bitfield3); - GotoIf(UintPtrLessThan(IntPtrConstant(kMaxLinear), nof), &stub_cache); - Node* descriptors = LoadMapDescriptors(receiver_map); - Variable var_name_index(this, MachineType::PointerRepresentation()); - Label if_descriptor_found(this); - DescriptorLookupLinear(key, descriptors, nof, &if_descriptor_found, - &var_name_index, &stub_cache); - - Bind(&if_descriptor_found); - { - LoadPropertyFromFastObject(receiver, receiver_map, descriptors, - var_name_index.value(), &var_details, - &var_value); - Goto(&if_found_on_receiver); - } - - Bind(&stub_cache); - { - Comment("stub cache probe for fast property load"); - Variable var_handler(this, MachineRepresentation::kTagged); - Label found_handler(this, &var_handler), stub_cache_miss(this); - TryProbeStubCache(isolate()->load_stub_cache(), receiver, key, - &found_handler, &var_handler, &stub_cache_miss); - Bind(&found_handler); - { HandleLoadICHandlerCase(p, var_handler.value(), &slow); } - - Bind(&stub_cache_miss); - { - Comment("KeyedLoadGeneric_miss"); - TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver, - p->name, p->slot, p->vector); - } - } - } - - Bind(&if_property_dictionary); - { - Comment("dictionary property load"); - // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out - // seeing global objects here (which would need special handling). - - Variable var_name_index(this, MachineType::PointerRepresentation()); - Label dictionary_found(this, &var_name_index); - NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found, - &var_name_index, &slow); - Bind(&dictionary_found); - { - LoadPropertyFromNameDictionary(properties, var_name_index.value(), - &var_details, &var_value); - Goto(&if_found_on_receiver); - } - } - - Bind(&if_found_on_receiver); - { - Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(), - p->context, receiver, &slow); - IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1); - Return(value); + GenericPropertyLoad(receiver, receiver_map, instance_type, + var_unique.value(), p, &slow); } Bind(&slow); @@ -1550,7 +1684,7 @@ void AccessorAssemblerImpl::KeyedLoadICGeneric(const LoadICParameters* p) { } } -void AccessorAssemblerImpl::StoreIC(const StoreICParameters* p) { +void AccessorAssembler::StoreIC(const StoreICParameters* p) { Variable var_handler(this, MachineRepresentation::kTagged); // TODO(ishell): defer blocks when it works. Label if_handler(this, &var_handler), try_polymorphic(this), @@ -1574,7 +1708,7 @@ void AccessorAssemblerImpl::StoreIC(const StoreICParameters* p) { { // Check polymorphic case. Comment("StoreIC_try_polymorphic"); - GotoUnless( + GotoIfNot( WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)), &try_megamorphic); HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler, @@ -1584,9 +1718,8 @@ void AccessorAssemblerImpl::StoreIC(const StoreICParameters* p) { Bind(&try_megamorphic); { // Check megamorphic case. - GotoUnless( - WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)), - &miss); + GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)), + &miss); TryProbeStubCache(isolate()->store_stub_cache(), p->receiver, p->name, &if_handler, &var_handler, &miss); @@ -1598,8 +1731,8 @@ void AccessorAssemblerImpl::StoreIC(const StoreICParameters* p) { } } -void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p, - LanguageMode language_mode) { +void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p, + LanguageMode language_mode) { // TODO(ishell): defer blocks when it works. Label miss(this /*, Label::kDeferred*/); { @@ -1627,7 +1760,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p, { // CheckPolymorphic case. Comment("KeyedStoreIC_try_polymorphic"); - GotoUnless( + GotoIfNot( WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)), &try_megamorphic); Label if_transition_handler(this); @@ -1643,7 +1776,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p, Label call_handler(this); Variable var_code_handler(this, MachineRepresentation::kTagged); var_code_handler.Bind(handler); - GotoUnless(IsTuple2Map(LoadMap(handler)), &call_handler); + GotoIfNot(IsTuple2Map(LoadMap(handler)), &call_handler); { CSA_ASSERT(this, IsTuple2Map(LoadMap(handler))); @@ -1677,7 +1810,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p, { // Check megamorphic case. Comment("KeyedStoreIC_try_megamorphic"); - GotoUnless( + GotoIfNot( WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)), &try_polymorphic_name); TailCallStub( @@ -1689,7 +1822,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p, { // We might have a name in feedback, and a fixed array in the next slot. Comment("KeyedStoreIC_try_polymorphic_name"); - GotoUnless(WordEqual(feedback, p->name), &miss); + GotoIfNot(WordEqual(feedback, p->name), &miss); // If the name comparison succeeded, we know we have a FixedArray with // at least one map/handler pair. Node* offset = ElementOffsetFromIndex( @@ -1710,7 +1843,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p, //////////////////// Public methods. -void AccessorAssemblerImpl::GenerateLoadIC() { +void AccessorAssembler::GenerateLoadIC() { typedef LoadWithVectorDescriptor Descriptor; Node* receiver = Parameter(Descriptor::kReceiver); @@ -1723,7 +1856,7 @@ void AccessorAssemblerImpl::GenerateLoadIC() { LoadIC(&p); } -void AccessorAssemblerImpl::GenerateLoadICTrampoline() { +void AccessorAssembler::GenerateLoadICTrampoline() { typedef LoadDescriptor Descriptor; Node* receiver = Parameter(Descriptor::kReceiver); @@ -1736,9 +1869,9 @@ void AccessorAssemblerImpl::GenerateLoadICTrampoline() { LoadIC(&p); } -void AccessorAssemblerImpl::GenerateLoadICProtoArray( +void AccessorAssembler::GenerateLoadICProtoArray( bool throw_reference_error_if_nonexistent) { - typedef LoadICProtoArrayStub::Descriptor Descriptor; + typedef LoadICProtoArrayDescriptor Descriptor; Node* receiver = Parameter(Descriptor::kReceiver); Node* name = Parameter(Descriptor::kName); @@ -1751,8 +1884,8 @@ void AccessorAssemblerImpl::GenerateLoadICProtoArray( LoadICProtoArray(&p, handler, throw_reference_error_if_nonexistent); } -void AccessorAssemblerImpl::GenerateLoadField() { - typedef LoadFieldStub::Descriptor Descriptor; +void AccessorAssembler::GenerateLoadField() { + typedef LoadFieldDescriptor Descriptor; Node* receiver = Parameter(Descriptor::kReceiver); Node* name = nullptr; @@ -1761,11 +1894,13 @@ void AccessorAssemblerImpl::GenerateLoadField() { Node* context = Parameter(Descriptor::kContext); LoadICParameters p(context, receiver, name, slot, vector); + ExitPoint direct_exit(this); + HandleLoadICSmiHandlerCase(&p, receiver, Parameter(Descriptor::kSmiHandler), - nullptr, kOnlyProperties); + nullptr, &direct_exit, kOnlyProperties); } -void AccessorAssemblerImpl::GenerateLoadGlobalIC(TypeofMode typeof_mode) { +void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) { typedef LoadGlobalWithVectorDescriptor Descriptor; Node* name = Parameter(Descriptor::kName); @@ -1777,8 +1912,7 @@ void AccessorAssemblerImpl::GenerateLoadGlobalIC(TypeofMode typeof_mode) { LoadGlobalIC(&p, typeof_mode); } -void AccessorAssemblerImpl::GenerateLoadGlobalICTrampoline( - TypeofMode typeof_mode) { +void AccessorAssembler::GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode) { typedef LoadGlobalDescriptor Descriptor; Node* name = Parameter(Descriptor::kName); @@ -1790,7 +1924,7 @@ void AccessorAssemblerImpl::GenerateLoadGlobalICTrampoline( LoadGlobalIC(&p, typeof_mode); } -void AccessorAssemblerImpl::GenerateKeyedLoadICTF() { +void AccessorAssembler::GenerateKeyedLoadIC() { typedef LoadWithVectorDescriptor Descriptor; Node* receiver = Parameter(Descriptor::kReceiver); @@ -1803,7 +1937,7 @@ void AccessorAssemblerImpl::GenerateKeyedLoadICTF() { KeyedLoadIC(&p); } -void AccessorAssemblerImpl::GenerateKeyedLoadICTrampolineTF() { +void AccessorAssembler::GenerateKeyedLoadICTrampoline() { typedef LoadDescriptor Descriptor; Node* receiver = Parameter(Descriptor::kReceiver); @@ -1816,7 +1950,7 @@ void AccessorAssemblerImpl::GenerateKeyedLoadICTrampolineTF() { KeyedLoadIC(&p); } -void AccessorAssemblerImpl::GenerateKeyedLoadICMegamorphic() { +void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() { typedef LoadWithVectorDescriptor Descriptor; Node* receiver = Parameter(Descriptor::kReceiver); @@ -1829,7 +1963,7 @@ void AccessorAssemblerImpl::GenerateKeyedLoadICMegamorphic() { KeyedLoadICGeneric(&p); } -void AccessorAssemblerImpl::GenerateStoreIC() { +void AccessorAssembler::GenerateStoreIC() { typedef StoreWithVectorDescriptor Descriptor; Node* receiver = Parameter(Descriptor::kReceiver); @@ -1843,7 +1977,7 @@ void AccessorAssemblerImpl::GenerateStoreIC() { StoreIC(&p); } -void AccessorAssemblerImpl::GenerateStoreICTrampoline() { +void AccessorAssembler::GenerateStoreICTrampoline() { typedef StoreDescriptor Descriptor; Node* receiver = Parameter(Descriptor::kReceiver); @@ -1857,7 +1991,7 @@ void AccessorAssemblerImpl::GenerateStoreICTrampoline() { StoreIC(&p); } -void AccessorAssemblerImpl::GenerateKeyedStoreICTF(LanguageMode language_mode) { +void AccessorAssembler::GenerateKeyedStoreIC(LanguageMode language_mode) { typedef StoreWithVectorDescriptor Descriptor; Node* receiver = Parameter(Descriptor::kReceiver); @@ -1871,7 +2005,7 @@ void AccessorAssemblerImpl::GenerateKeyedStoreICTF(LanguageMode language_mode) { KeyedStoreIC(&p, language_mode); } -void AccessorAssemblerImpl::GenerateKeyedStoreICTrampolineTF( +void AccessorAssembler::GenerateKeyedStoreICTrampoline( LanguageMode language_mode) { typedef StoreDescriptor Descriptor; @@ -1886,48 +2020,5 @@ void AccessorAssemblerImpl::GenerateKeyedStoreICTrampolineTF( KeyedStoreIC(&p, language_mode); } -//////////////////// AccessorAssembler implementation. - -#define DISPATCH_TO_IMPL(Name) \ - void AccessorAssembler::Generate##Name(CodeAssemblerState* state) { \ - AccessorAssemblerImpl assembler(state); \ - assembler.Generate##Name(); \ - } - -ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE(DISPATCH_TO_IMPL) -#undef DISPATCH_TO_IMPL - -void AccessorAssembler::GenerateLoadICProtoArray( - CodeAssemblerState* state, bool throw_reference_error_if_nonexistent) { - AccessorAssemblerImpl assembler(state); - assembler.GenerateLoadICProtoArray(throw_reference_error_if_nonexistent); -} - -void AccessorAssembler::GenerateLoadGlobalIC(CodeAssemblerState* state, - TypeofMode typeof_mode) { - AccessorAssemblerImpl assembler(state); - assembler.GenerateLoadGlobalIC(typeof_mode); -} - -void AccessorAssembler::GenerateLoadGlobalICTrampoline( - CodeAssemblerState* state, TypeofMode typeof_mode) { - AccessorAssemblerImpl assembler(state); - assembler.GenerateLoadGlobalICTrampoline(typeof_mode); -} - -void AccessorAssembler::GenerateKeyedStoreICTF(CodeAssemblerState* state, - LanguageMode language_mode) { - AccessorAssemblerImpl assembler(state); - assembler.GenerateKeyedStoreICTF(language_mode); -} - -void AccessorAssembler::GenerateKeyedStoreICTrampolineTF( - CodeAssemblerState* state, LanguageMode language_mode) { - AccessorAssemblerImpl assembler(state); - assembler.GenerateKeyedStoreICTrampolineTF(language_mode); -} - -#undef ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE - } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/accessor-assembler.h b/deps/v8/src/ic/accessor-assembler.h index 3b75c2e54d..9bc2873f85 100644 --- a/deps/v8/src/ic/accessor-assembler.h +++ b/deps/v8/src/ic/accessor-assembler.h @@ -5,7 +5,7 @@ #ifndef V8_SRC_IC_ACCESSOR_ASSEMBLER_H_ #define V8_SRC_IC_ACCESSOR_ASSEMBLER_H_ -#include "src/globals.h" +#include "src/code-stub-assembler.h" namespace v8 { namespace internal { @@ -14,29 +14,268 @@ namespace compiler { class CodeAssemblerState; } -class AccessorAssembler { +class ExitPoint; + +class AccessorAssembler : public CodeStubAssembler { + public: + typedef compiler::Node Node; + + explicit AccessorAssembler(compiler::CodeAssemblerState* state) + : CodeStubAssembler(state) {} + + void GenerateLoadIC(); + void GenerateLoadField(); + void GenerateLoadICTrampoline(); + void GenerateKeyedLoadIC(); + void GenerateKeyedLoadICTrampoline(); + void GenerateKeyedLoadIC_Megamorphic(); + void GenerateStoreIC(); + void GenerateStoreICTrampoline(); + + void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent); + + void GenerateLoadGlobalIC(TypeofMode typeof_mode); + void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode); + + void GenerateKeyedStoreIC(LanguageMode language_mode); + void GenerateKeyedStoreICTrampoline(LanguageMode language_mode); + + void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name, + Label* if_handler, Variable* var_handler, + Label* if_miss); + + Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) { + return StubCachePrimaryOffset(name, map); + } + Node* StubCacheSecondaryOffsetForTesting(Node* name, Node* map) { + return StubCacheSecondaryOffset(name, map); + } + + struct LoadICParameters { + LoadICParameters(Node* context, Node* receiver, Node* name, Node* slot, + Node* vector) + : context(context), + receiver(receiver), + name(name), + slot(slot), + vector(vector) {} + + Node* context; + Node* receiver; + Node* name; + Node* slot; + Node* vector; + }; + + void LoadGlobalIC_TryPropertyCellCase( + Node* vector, Node* slot, ExitPoint* exit_point, Label* try_handler, + Label* miss, ParameterMode slot_mode = SMI_PARAMETERS); + void LoadGlobalIC_TryHandlerCase(const LoadICParameters* p, + TypeofMode typeof_mode, + ExitPoint* exit_point, Label* miss); + void LoadGlobalIC_MissCase(const LoadICParameters* p, ExitPoint* exit_point); + + protected: + struct StoreICParameters : public LoadICParameters { + StoreICParameters(Node* context, Node* receiver, Node* name, Node* value, + Node* slot, Node* vector) + : LoadICParameters(context, receiver, name, slot, vector), + value(value) {} + Node* value; + }; + + enum ElementSupport { kOnlyProperties, kSupportElements }; + void HandleStoreICHandlerCase( + const StoreICParameters* p, Node* handler, Label* miss, + ElementSupport support_elements = kOnlyProperties); + + private: + // Stub generation entry points. + + void LoadIC(const LoadICParameters* p); + void LoadICProtoArray(const LoadICParameters* p, Node* handler, + bool throw_reference_error_if_nonexistent); + void LoadGlobalIC(const LoadICParameters* p, TypeofMode typeof_mode); + void KeyedLoadIC(const LoadICParameters* p); + void KeyedLoadICGeneric(const LoadICParameters* p); + void StoreIC(const StoreICParameters* p); + void KeyedStoreIC(const StoreICParameters* p, LanguageMode language_mode); + + // IC dispatcher behavior. + + // Checks monomorphic case. Returns {feedback} entry of the vector. + Node* TryMonomorphicCase(Node* slot, Node* vector, Node* receiver_map, + Label* if_handler, Variable* var_handler, + Label* if_miss); + void HandlePolymorphicCase(Node* receiver_map, Node* feedback, + Label* if_handler, Variable* var_handler, + Label* if_miss, int unroll_count); + void HandleKeyedStorePolymorphicCase(Node* receiver_map, Node* feedback, + Label* if_handler, Variable* var_handler, + Label* if_transition_handler, + Variable* var_transition_map_cell, + Label* if_miss); + + // LoadIC implementation. + + void HandleLoadICHandlerCase( + const LoadICParameters* p, Node* handler, Label* miss, + ElementSupport support_elements = kOnlyProperties); + + void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder, + Node* smi_handler, Label* miss, + ExitPoint* exit_point, + ElementSupport support_elements); + + void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler, + Variable* var_holder, + Variable* var_smi_handler, + Label* if_smi_handler, Label* miss, + ExitPoint* exit_point, + bool throw_reference_error_if_nonexistent); + + Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler, + Node* handler_length, Node* handler_flags, + Label* miss, + bool throw_reference_error_if_nonexistent); + + // LoadGlobalIC implementation. + + void HandleLoadGlobalICHandlerCase(const LoadICParameters* p, Node* handler, + Label* miss, ExitPoint* exit_point, + bool throw_reference_error_if_nonexistent); + + // StoreIC implementation. + + void HandleStoreICElementHandlerCase(const StoreICParameters* p, + Node* handler, Label* miss); + + void HandleStoreICProtoHandler(const StoreICParameters* p, Node* handler, + Label* miss); + // If |transition| is nullptr then the normal field store is generated or + // transitioning store otherwise. + void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder, + Node* value, Node* transition, Label* miss); + // If |transition| is nullptr then the normal field store is generated or + // transitioning store otherwise. + void HandleStoreFieldAndReturn(Node* handler_word, Node* holder, + Representation representation, Node* value, + Node* transition, Label* miss); + + // KeyedLoadIC_Generic implementation. + + void GenericElementLoad(Node* receiver, Node* receiver_map, + Node* instance_type, Node* index, Label* slow); + + void GenericPropertyLoad(Node* receiver, Node* receiver_map, + Node* instance_type, Node* key, + const LoadICParameters* p, Label* slow); + + // Low-level helpers. + + Node* PrepareValueForStore(Node* handler_word, Node* holder, + Representation representation, Node* transition, + Node* value, Label* bailout); + + // Extends properties backing store by JSObject::kFieldsAdded elements. + void ExtendPropertiesBackingStore(Node* object); + + void StoreNamedField(Node* handler_word, Node* object, bool is_inobject, + Representation representation, Node* value, + bool transition_to_field, Label* bailout); + + void EmitFastElementsBoundsCheck(Node* object, Node* elements, + Node* intptr_index, + Node* is_jsarray_condition, Label* miss); + void EmitElementLoad(Node* object, Node* elements, Node* elements_kind, + Node* key, Node* is_jsarray_condition, Label* if_hole, + Label* rebox_double, Variable* var_double_value, + Label* unimplemented_elements_kind, Label* out_of_bounds, + Label* miss, ExitPoint* exit_point); + void CheckPrototype(Node* prototype_cell, Node* name, Label* miss); + void NameDictionaryNegativeLookup(Node* object, Node* name, Label* miss); + + // Stub cache access helpers. + + // This enum is used here as a replacement for StubCache::Table to avoid + // including stub cache header. + enum StubCacheTable : int; + + Node* StubCachePrimaryOffset(Node* name, Node* map); + Node* StubCacheSecondaryOffset(Node* name, Node* seed); + + void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id, + Node* entry_offset, Node* name, Node* map, + Label* if_handler, Variable* var_handler, + Label* if_miss); +}; + +// Abstraction over direct and indirect exit points. Direct exits correspond to +// tailcalls and Return, while indirect exits store the result in a variable +// and then jump to an exit label. +class ExitPoint { + private: + typedef compiler::Node Node; + typedef compiler::CodeAssemblerLabel CodeAssemblerLabel; + typedef compiler::CodeAssemblerVariable CodeAssemblerVariable; + public: - static void GenerateLoadIC(compiler::CodeAssemblerState* state); - static void GenerateLoadICTrampoline(compiler::CodeAssemblerState* state); - static void GenerateLoadICProtoArray( - compiler::CodeAssemblerState* state, - bool throw_reference_error_if_nonexistent); - static void GenerateLoadGlobalIC(compiler::CodeAssemblerState* state, - TypeofMode typeof_mode); - static void GenerateLoadGlobalICTrampoline( - compiler::CodeAssemblerState* state, TypeofMode typeof_mode); - static void GenerateKeyedLoadICTF(compiler::CodeAssemblerState* state); - static void GenerateKeyedLoadICTrampolineTF( - compiler::CodeAssemblerState* state); - static void GenerateKeyedLoadICMegamorphic( - compiler::CodeAssemblerState* state); - static void GenerateLoadField(compiler::CodeAssemblerState* state); - static void GenerateStoreIC(compiler::CodeAssemblerState* state); - static void GenerateStoreICTrampoline(compiler::CodeAssemblerState* state); - static void GenerateKeyedStoreICTF(compiler::CodeAssemblerState* state, - LanguageMode language_mode); - static void GenerateKeyedStoreICTrampolineTF( - compiler::CodeAssemblerState* state, LanguageMode language_mode); + explicit ExitPoint(CodeStubAssembler* assembler) + : ExitPoint(assembler, nullptr, nullptr) {} + ExitPoint(CodeStubAssembler* assembler, CodeAssemblerLabel* out, + CodeAssemblerVariable* var_result) + : out_(out), var_result_(var_result), asm_(assembler) { + DCHECK_EQ(out != nullptr, var_result != nullptr); + } + + template <class... TArgs> + void ReturnCallRuntime(Runtime::FunctionId function, Node* context, + TArgs... args) { + if (IsDirect()) { + asm_->TailCallRuntime(function, context, args...); + } else { + IndirectReturn(asm_->CallRuntime(function, context, args...)); + } + } + + template <class... TArgs> + void ReturnCallStub(Callable const& callable, Node* context, TArgs... args) { + if (IsDirect()) { + asm_->TailCallStub(callable, context, args...); + } else { + IndirectReturn(asm_->CallStub(callable, context, args...)); + } + } + + template <class... TArgs> + void ReturnCallStub(const CallInterfaceDescriptor& descriptor, Node* target, + Node* context, TArgs... args) { + if (IsDirect()) { + asm_->TailCallStub(descriptor, target, context, args...); + } else { + IndirectReturn(asm_->CallStub(descriptor, target, context, args...)); + } + } + + void Return(Node* const result) { + if (IsDirect()) { + asm_->Return(result); + } else { + IndirectReturn(result); + } + } + + bool IsDirect() const { return out_ == nullptr; } + + private: + void IndirectReturn(Node* const result) { + var_result_->Bind(result); + asm_->Goto(out_); + } + + CodeAssemblerLabel* const out_; + CodeAssemblerVariable* const var_result_; + CodeStubAssembler* const asm_; }; } // namespace internal diff --git a/deps/v8/src/ic/arm/handler-compiler-arm.cc b/deps/v8/src/ic/arm/handler-compiler-arm.cc index 3f2d0e42de..ebef63ca66 100644 --- a/deps/v8/src/ic/arm/handler-compiler-arm.cc +++ b/deps/v8/src/ic/arm/handler-compiler-arm.cc @@ -181,15 +181,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); } -void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( - MacroAssembler* masm, Register receiver, Register scratch1, - Register scratch2, Label* miss_label) { - __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); - __ mov(r0, scratch1); - __ Ret(); -} - - // Generate code to check that a global property cell is empty. Create // the property cell at compilation time if no cell exists for the // property. @@ -208,10 +199,12 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ b(ne, miss); } +static void CompileCallLoadPropertyWithInterceptor( + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, Runtime::FunctionId id) { + DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == + Runtime::FunctionForId(id)->nargs); -static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, - Register holder, Register name, - Handle<JSObject> holder_obj) { STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); @@ -219,15 +212,7 @@ static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, __ push(name); __ push(receiver); __ push(holder); -} - -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); __ CallRuntime(id); } @@ -530,8 +515,18 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { // Call the runtime system to load the interceptor. DCHECK(holder()->HasNamedInterceptor()); DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), - holder()); + + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); + __ Push(name(), receiver(), holder_reg); + // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. + if (holder_reg.is(receiver())) { + __ Push(slot(), vector()); + } else { + __ Push(scratch3(), scratch2()); // slot, vector + } __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); } diff --git a/deps/v8/src/ic/arm/ic-arm.cc b/deps/v8/src/ic/arm/ic-arm.cc index fad0737a1c..b749027ebe 100644 --- a/deps/v8/src/ic/arm/ic-arm.cc +++ b/deps/v8/src/ic/arm/ic-arm.cc @@ -6,45 +6,12 @@ #include "src/codegen.h" #include "src/ic/ic.h" -#include "src/ic/ic-compiler.h" #include "src/ic/stub-cache.h" namespace v8 { namespace internal { -// ---------------------------------------------------------------------------- -// Static IC stub generators. -// - -#define __ ACCESS_MASM(masm) - -static void StoreIC_PushArgs(MacroAssembler* masm) { - __ Push(StoreWithVectorDescriptor::ValueRegister(), - StoreWithVectorDescriptor::SlotRegister(), - StoreWithVectorDescriptor::VectorRegister(), - StoreWithVectorDescriptor::ReceiverRegister(), - StoreWithVectorDescriptor::NameRegister()); -} - - -void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { - StoreIC_PushArgs(masm); - - __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); -} - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - StoreIC_PushArgs(masm); - - // 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. - __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow); -} - -#undef __ - - Condition CompareIC::ComputeCondition(Token::Value op) { switch (op) { case Token::EQ_STRICT: @@ -100,9 +67,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address, } if (FLAG_trace_ic) { - PrintF("[ patching ic at %p, cmp=%p, delta=%d\n", - static_cast<void*>(address), - static_cast<void*>(cmp_instruction_address), delta); + LOG(isolate, PatchIC(address, cmp_instruction_address, delta)); } Address patch_address = diff --git a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc index 8c89908f4e..b7dc58974f 100644 --- a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc +++ b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc @@ -83,19 +83,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); } -void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( - MacroAssembler* masm, Register receiver, Register scratch1, - Register scratch2, Label* miss_label) { - __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); - // TryGetFunctionPrototype can't put the result directly in x0 because the - // 3 inputs registers can't alias and we call this function from - // LoadIC::GenerateFunctionPrototype, where receiver is x0. So we explicitly - // move the result in x0. - __ Mov(x0, scratch1); - __ Ret(); -} - - // Generate code to check that a global property cell is empty. Create // the property cell at compilation time if no cell exists for the // property. @@ -112,25 +99,18 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss); } +static void CompileCallLoadPropertyWithInterceptor( + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, Runtime::FunctionId id) { + DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == + Runtime::FunctionForId(id)->nargs); -static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, - Register holder, Register name, - Handle<JSObject> holder_obj) { STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name, receiver, holder); -} - -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); __ CallRuntime(id); } @@ -566,8 +546,18 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { // Call the runtime system to load the interceptor. DCHECK(holder()->HasNamedInterceptor()); DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), - holder()); + + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); + __ Push(name(), receiver(), holder_reg); + // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. + if (holder_reg.is(receiver())) { + __ Push(slot(), vector()); + } else { + __ Push(scratch3(), scratch2()); // slot, vector + } __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); } diff --git a/deps/v8/src/ic/arm64/ic-arm64.cc b/deps/v8/src/ic/arm64/ic-arm64.cc index 04fdff76e1..8c7d4f2241 100644 --- a/deps/v8/src/ic/arm64/ic-arm64.cc +++ b/deps/v8/src/ic/arm64/ic-arm64.cc @@ -6,39 +6,12 @@ #include "src/codegen.h" #include "src/ic/ic.h" -#include "src/ic/ic-compiler.h" #include "src/ic/stub-cache.h" namespace v8 { namespace internal { -#define __ ACCESS_MASM(masm) - -static void StoreIC_PushArgs(MacroAssembler* masm) { - __ Push(StoreWithVectorDescriptor::ValueRegister(), - StoreWithVectorDescriptor::SlotRegister(), - StoreWithVectorDescriptor::VectorRegister(), - StoreWithVectorDescriptor::ReceiverRegister(), - StoreWithVectorDescriptor::NameRegister()); -} - - -void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { - ASM_LOCATION("KeyedStoreIC::GenerateMiss"); - StoreIC_PushArgs(masm); - __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); -} - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - ASM_LOCATION("KeyedStoreIC::GenerateSlow"); - StoreIC_PushArgs(masm); - - // 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. - __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow); -} - Condition CompareIC::ComputeCondition(Token::Value op) { switch (op) { case Token::EQ_STRICT: @@ -86,9 +59,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address, } if (FLAG_trace_ic) { - PrintF("[ Patching ic at %p, marker=%p, SMI check=%p\n", - static_cast<void*>(address), static_cast<void*>(info_address), - static_cast<void*>(info.SmiCheck())); + LOG(isolate, PatchIC(address, info_address, info.SmiCheckDelta())); } // Patch and activate code generated by JumpPatchSite::EmitJumpIfNotSmi() diff --git a/deps/v8/src/ic/call-optimization.cc b/deps/v8/src/ic/call-optimization.cc index f7a1f6982f..6780ac4ca4 100644 --- a/deps/v8/src/ic/call-optimization.cc +++ b/deps/v8/src/ic/call-optimization.cc @@ -3,7 +3,7 @@ // found in the LICENSE file. #include "src/ic/call-optimization.h" - +#include "src/objects-inl.h" namespace v8 { namespace internal { diff --git a/deps/v8/src/ic/handler-compiler.cc b/deps/v8/src/ic/handler-compiler.cc index 16aec0b494..6a9734d5eb 100644 --- a/deps/v8/src/ic/handler-compiler.cc +++ b/deps/v8/src/ic/handler-compiler.cc @@ -283,8 +283,7 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor( Handle<Object> smi_handler = LoadIC::SimpleFieldLoad(isolate(), it->GetFieldIndex()); __ Move(LoadFieldDescriptor::SmiHandlerRegister(), smi_handler); - LoadFieldStub stub(isolate()); - GenerateTailCall(masm(), stub.GetCode()); + GenerateTailCall(masm(), isolate()->builtins()->LoadField()); break; } case LookupIterator::ACCESSOR: @@ -353,7 +352,7 @@ Handle<Object> ElementHandlerCompiler::GetKeyedLoadHandler( } if (receiver_map->IsStringMap()) { TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedStringStub); - return LoadIndexedStringStub(isolate).GetCode(); + return isolate->builtins()->KeyedLoadIC_IndexedString(); } InstanceType instance_type = receiver_map->instance_type(); if (instance_type < FIRST_JS_RECEIVER_TYPE) { diff --git a/deps/v8/src/ic/handler-compiler.h b/deps/v8/src/ic/handler-compiler.h index 65f6fbbef3..a37375abfb 100644 --- a/deps/v8/src/ic/handler-compiler.h +++ b/deps/v8/src/ic/handler-compiler.h @@ -158,12 +158,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { no_reg); } - static void GenerateLoadFunctionPrototype(MacroAssembler* masm, - Register receiver, - Register scratch1, - Register scratch2, - Label* miss_label); - // These constants describe the structure of the interceptor arguments on the // stack. The arguments are pushed by the (platform-specific) // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and diff --git a/deps/v8/src/ic/handler-configuration-inl.h b/deps/v8/src/ic/handler-configuration-inl.h index 8aa887d2b6..437c5288fb 100644 --- a/deps/v8/src/ic/handler-configuration-inl.h +++ b/deps/v8/src/ic/handler-configuration-inl.h @@ -103,7 +103,8 @@ Handle<Object> StoreHandler::StoreField(Isolate* isolate, Kind kind, } int value_index = DescriptorArray::ToValueIndex(descriptor); - DCHECK(kind == kStoreField || kind == kTransitionToField); + DCHECK(kind == kStoreField || kind == kTransitionToField || + (kind == kStoreConstField && FLAG_track_constant_fields)); DCHECK_IMPLIES(extend_storage, kind == kTransitionToField); DCHECK_IMPLIES(field_index.is_inobject(), !extend_storage); @@ -118,9 +119,12 @@ Handle<Object> StoreHandler::StoreField(Isolate* isolate, Kind kind, Handle<Object> StoreHandler::StoreField(Isolate* isolate, int descriptor, FieldIndex field_index, + PropertyConstness constness, Representation representation) { - return StoreField(isolate, kStoreField, descriptor, field_index, - representation, false); + DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable); + Kind kind = constness == kMutable ? kStoreField : kStoreConstField; + return StoreField(isolate, kind, descriptor, field_index, representation, + false); } Handle<Object> StoreHandler::TransitionToField(Isolate* isolate, int descriptor, @@ -133,6 +137,7 @@ Handle<Object> StoreHandler::TransitionToField(Isolate* isolate, int descriptor, Handle<Object> StoreHandler::TransitionToConstant(Isolate* isolate, int descriptor) { + DCHECK(!FLAG_track_constant_fields); int value_index = DescriptorArray::ToValueIndex(descriptor); int config = StoreHandler::KindBits::encode(StoreHandler::kTransitionToConstant) | diff --git a/deps/v8/src/ic/handler-configuration.h b/deps/v8/src/ic/handler-configuration.h index a5291736dc..539d448008 100644 --- a/deps/v8/src/ic/handler-configuration.h +++ b/deps/v8/src/ic/handler-configuration.h @@ -121,8 +121,10 @@ class StoreHandler { enum Kind { kStoreElement, kStoreField, + kStoreConstField, kTransitionToField, - kTransitionToConstant + // TODO(ishell): remove once constant field tracking is done. + kTransitionToConstant = kStoreConstField }; class KindBits : public BitField<Kind, 0, 2> {}; @@ -175,6 +177,7 @@ class StoreHandler { // Creates a Smi-handler for storing a field to fast object. static inline Handle<Object> StoreField(Isolate* isolate, int descriptor, FieldIndex field_index, + PropertyConstness constness, Representation representation); // Creates a Smi-handler for transitioning store to a field. diff --git a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc index b63e82b70a..f0f8faddde 100644 --- a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc +++ b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc @@ -122,15 +122,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( __ DecrementCounter(counters->negative_lookups_miss(), 1); } -void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( - MacroAssembler* masm, Register receiver, Register scratch1, - Register scratch2, Label* miss_label) { - // TODO(mvstanton): This isn't used on ia32. Move all the other - // platform implementations into a code stub so this method can be removed. - UNREACHABLE(); -} - - // Generate call to api function. // This function uses push() to generate smaller, faster code than // the version above. It is an optimization that should will be removed @@ -302,10 +293,12 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter( } } +static void CompileCallLoadPropertyWithInterceptor( + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, Runtime::FunctionId id) { + DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == + Runtime::FunctionForId(id)->nargs); -static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, - Register holder, Register name, - Handle<JSObject> holder_obj) { STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); @@ -313,15 +306,7 @@ static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, __ push(name); __ push(receiver); __ push(holder); -} - -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); __ CallRuntime(id); } @@ -538,10 +523,26 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { DCHECK(holder()->HasNamedInterceptor()); DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); // Call the runtime system to load the interceptor. - __ pop(scratch2()); // save old return address - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), - holder()); - __ push(scratch2()); // restore old return address + + // Stack: + // return address + + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); + __ push(receiver()); + __ push(holder_reg); + // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. + if (holder_reg.is(receiver())) { + __ push(slot()); + __ push(vector()); + } else { + __ push(scratch3()); // slot + __ push(scratch2()); // vector + } + __ push(Operand(esp, 4 * kPointerSize)); // return address + __ mov(Operand(esp, 5 * kPointerSize), name()); __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); } diff --git a/deps/v8/src/ic/ia32/ic-ia32.cc b/deps/v8/src/ic/ia32/ic-ia32.cc index 4bf0eaee92..c4b4cdcc2b 100644 --- a/deps/v8/src/ic/ia32/ic-ia32.cc +++ b/deps/v8/src/ic/ia32/ic-ia32.cc @@ -6,54 +6,11 @@ #include "src/codegen.h" #include "src/ic/ic.h" -#include "src/ic/ic-compiler.h" #include "src/ic/stub-cache.h" namespace v8 { namespace internal { -// ---------------------------------------------------------------------------- -// Static IC stub generators. -// - -#define __ ACCESS_MASM(masm) - -static void StoreIC_PushArgs(MacroAssembler* masm) { - Register receiver = StoreWithVectorDescriptor::ReceiverRegister(); - Register name = StoreWithVectorDescriptor::NameRegister(); - - STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3); - // Current stack layout: - // - esp[12] -- value - // - esp[8] -- slot - // - esp[4] -- vector - // - esp[0] -- return address - - Register return_address = StoreWithVectorDescriptor::SlotRegister(); - __ pop(return_address); - __ push(receiver); - __ push(name); - __ push(return_address); -} - -void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { - // Return address is on the stack. - StoreIC_PushArgs(masm); - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); -} - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - // Return address is on the stack. - StoreIC_PushArgs(masm); - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow); -} - -#undef __ - Condition CompareIC::ComputeCondition(Token::Value op) { switch (op) { @@ -104,9 +61,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address, // condition code uses at the patched jump. uint8_t delta = *reinterpret_cast<uint8_t*>(delta_address); if (FLAG_trace_ic) { - PrintF("[ patching ic at %p, test=%p, delta=%d\n", - static_cast<void*>(address), - static_cast<void*>(test_instruction_address), delta); + LOG(isolate, PatchIC(address, test_instruction_address, delta)); } // Patch with a short conditional jump. Enabling means switching from a short diff --git a/deps/v8/src/ic/ic-compiler.cc b/deps/v8/src/ic/ic-compiler.cc deleted file mode 100644 index fcda0c1fa3..0000000000 --- a/deps/v8/src/ic/ic-compiler.cc +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2014 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "src/ic/ic-compiler.h" - -#include "src/ic/handler-compiler.h" -#include "src/ic/ic-inl.h" - -namespace v8 { -namespace internal { - -Handle<Object> PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler( - Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) { - Isolate* isolate = receiver_map->GetIsolate(); - - DCHECK(store_mode == STANDARD_STORE || - store_mode == STORE_AND_GROW_NO_TRANSITION || - store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || - store_mode == STORE_NO_TRANSITION_HANDLE_COW); - - PropertyICCompiler compiler(isolate); - Handle<Object> handler = - compiler.CompileKeyedStoreMonomorphicHandler(receiver_map, store_mode); - return handler; -} - -void PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers( - MapHandleList* receiver_maps, MapHandleList* transitioned_maps, - List<Handle<Object>>* handlers, KeyedAccessStoreMode store_mode) { - Isolate* isolate = receiver_maps->at(0)->GetIsolate(); - DCHECK(store_mode == STANDARD_STORE || - store_mode == STORE_AND_GROW_NO_TRANSITION || - store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || - store_mode == STORE_NO_TRANSITION_HANDLE_COW); - PropertyICCompiler compiler(isolate); - compiler.CompileKeyedStorePolymorphicHandlers( - receiver_maps, transitioned_maps, handlers, store_mode); -} - -void PropertyICCompiler::CompileKeyedStorePolymorphicHandlers( - MapHandleList* receiver_maps, MapHandleList* transitioned_maps, - List<Handle<Object>>* handlers, KeyedAccessStoreMode store_mode) { - for (int i = 0; i < receiver_maps->length(); ++i) { - Handle<Map> receiver_map(receiver_maps->at(i)); - Handle<Object> handler; - Handle<Map> transitioned_map; - { - Map* tmap = receiver_map->FindElementsKindTransitionedMap(receiver_maps); - if (tmap != nullptr) transitioned_map = handle(tmap); - } - - // TODO(mvstanton): The code below is doing pessimistic elements - // transitions. I would like to stop doing that and rely on Allocation Site - // Tracking to do a better job of ensuring the data types are what they need - // to be. Not all the elements are in place yet, pessimistic elements - // transitions are still important for performance. - if (!transitioned_map.is_null()) { - bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; - ElementsKind elements_kind = receiver_map->elements_kind(); - TRACE_HANDLER_STATS(isolate(), - KeyedStoreIC_ElementsTransitionAndStoreStub); - Handle<Code> stub = - ElementsTransitionAndStoreStub(isolate(), elements_kind, - transitioned_map->elements_kind(), - is_js_array, store_mode) - .GetCode(); - Handle<Object> validity_cell = - Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); - if (validity_cell.is_null()) { - handler = stub; - } else { - handler = isolate()->factory()->NewTuple2(validity_cell, stub); - } - - } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) { - // TODO(mvstanton): Consider embedding store_mode in the state of the slow - // keyed store ic for uniformity. - TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub); - handler = isolate()->builtins()->KeyedStoreIC_Slow(); - } else { - handler = CompileKeyedStoreMonomorphicHandler(receiver_map, store_mode); - } - DCHECK(!handler.is_null()); - handlers->Add(handler); - transitioned_maps->Add(transitioned_map); - } -} - - -#define __ ACCESS_MASM(masm()) - -Handle<Object> PropertyICCompiler::CompileKeyedStoreMonomorphicHandler( - Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) { - ElementsKind elements_kind = receiver_map->elements_kind(); - bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; - Handle<Code> stub; - if (receiver_map->has_sloppy_arguments_elements()) { - TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub); - stub = KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode(); - } else if (receiver_map->has_fast_elements() || - receiver_map->has_fixed_typed_array_elements()) { - TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub); - stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind, - store_mode).GetCode(); - } else { - TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub); - stub = StoreElementStub(isolate(), elements_kind, store_mode).GetCode(); - } - Handle<Object> validity_cell = - Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); - if (validity_cell.is_null()) { - return stub; - } - return isolate()->factory()->NewTuple2(validity_cell, stub); -} - - -#undef __ -} // namespace internal -} // namespace v8 diff --git a/deps/v8/src/ic/ic-compiler.h b/deps/v8/src/ic/ic-compiler.h deleted file mode 100644 index b8d6635ae0..0000000000 --- a/deps/v8/src/ic/ic-compiler.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2014 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_IC_IC_COMPILER_H_ -#define V8_IC_IC_COMPILER_H_ - -#include "src/ic/access-compiler.h" - -namespace v8 { -namespace internal { - - -class PropertyICCompiler : public PropertyAccessCompiler { - public: - // Keyed - static Handle<Object> ComputeKeyedStoreMonomorphicHandler( - Handle<Map> receiver_map, KeyedAccessStoreMode store_mode); - static void ComputeKeyedStorePolymorphicHandlers( - MapHandleList* receiver_maps, MapHandleList* transitioned_maps, - List<Handle<Object>>* handlers, KeyedAccessStoreMode store_mode); - - private: - explicit PropertyICCompiler(Isolate* isolate) - : PropertyAccessCompiler(isolate, Code::KEYED_STORE_IC, - kCacheOnReceiver) {} - - Handle<Object> CompileKeyedStoreMonomorphicHandler( - Handle<Map> receiver_map, KeyedAccessStoreMode store_mode); - void CompileKeyedStorePolymorphicHandlers(MapHandleList* receiver_maps, - MapHandleList* transitioned_maps, - List<Handle<Object>>* handlers, - KeyedAccessStoreMode store_mode); -}; - - -} // namespace internal -} // namespace v8 - -#endif // V8_IC_IC_COMPILER_H_ diff --git a/deps/v8/src/ic/ic-inl.h b/deps/v8/src/ic/ic-inl.h index b286315c01..aacb69091e 100644 --- a/deps/v8/src/ic/ic-inl.h +++ b/deps/v8/src/ic/ic-inl.h @@ -7,6 +7,7 @@ #include "src/ic/ic.h" +#include "src/assembler-inl.h" #include "src/debug/debug.h" #include "src/macro-assembler.h" #include "src/prototype.h" @@ -45,7 +46,10 @@ Code* IC::GetTargetAtAddress(Address address, Address constant_pool) { // Convert target address to the code object. Code::GetCodeFromTargetAddress // is safe for use during GC where the map might be marked. Code* result = Code::GetCodeFromTargetAddress(target); - DCHECK(result->is_inline_cache_stub()); + // The result can be an IC dispatcher (for vector-based ICs), an IC handler + // (for old-style patching ICs) or CEntryStub (for IC dispatchers inlined to + // bytecode handlers). + DCHECK(result->is_inline_cache_stub() || result->is_stub()); return result; } @@ -54,25 +58,13 @@ void IC::SetTargetAtAddress(Address address, Code* target, Address constant_pool) { if (AddressIsDeoptimizedCode(target->GetIsolate(), address)) return; - DCHECK(target->is_inline_cache_stub() || target->is_compare_ic_stub()); - - DCHECK(!target->is_inline_cache_stub() || - (target->kind() != Code::LOAD_IC && - target->kind() != Code::KEYED_LOAD_IC && - target->kind() != Code::CALL_IC && target->kind() != Code::STORE_IC && - target->kind() != Code::KEYED_STORE_IC)); + // Only these three old-style ICs still do code patching. + DCHECK(target->is_binary_op_stub() || target->is_compare_ic_stub() || + target->is_to_boolean_ic_stub()); Heap* heap = target->GetHeap(); Code* old_target = GetTargetAtAddress(address, constant_pool); -#ifdef DEBUG - // STORE_IC and KEYED_STORE_IC use Code::extra_ic_state() to mark - // ICs as language mode. The language mode of the IC must be preserved. - if (old_target->kind() == Code::STORE_IC || - old_target->kind() == Code::KEYED_STORE_IC) { - DCHECK(StoreICState::GetLanguageMode(old_target->extra_ic_state()) == - StoreICState::GetLanguageMode(target->extra_ic_state())); - } -#endif + Assembler::set_target_address_at(heap->isolate(), address, constant_pool, target->instruction_start()); if (heap->gc_state() == Heap::MARK_COMPACT) { @@ -132,14 +124,6 @@ Handle<Map> IC::GetICCacheHolder(Handle<Map> map, Isolate* isolate, } -Code* IC::get_host() { - return isolate() - ->inner_pointer_to_code_cache() - ->GetCacheEntry(address()) - ->code; -} - - bool IC::AddressIsDeoptimizedCode() const { return AddressIsDeoptimizedCode(isolate(), address()); } diff --git a/deps/v8/src/ic/ic-state.cc b/deps/v8/src/ic/ic-state.cc index 7439ecd2c0..a217b115fd 100644 --- a/deps/v8/src/ic/ic-state.cc +++ b/deps/v8/src/ic/ic-state.cc @@ -4,7 +4,10 @@ #include "src/ic/ic-state.h" +#include "src/ast/ast-types.h" +#include "src/feedback-vector.h" #include "src/ic/ic.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { @@ -16,11 +19,6 @@ void ICUtility::Clear(Isolate* isolate, Address address, } -std::ostream& operator<<(std::ostream& os, const CallICState& s) { - return os << "(" << s.convert_mode() << ", " << s.tail_call_mode() << ")"; -} - - // static STATIC_CONST_MEMBER_DEFINITION const int BinaryOpICState::FIRST_TOKEN; diff --git a/deps/v8/src/ic/ic-state.h b/deps/v8/src/ic/ic-state.h index 836979c4f0..16651c5623 100644 --- a/deps/v8/src/ic/ic-state.h +++ b/deps/v8/src/ic/ic-state.h @@ -11,6 +11,7 @@ namespace v8 { namespace internal { +class AstType; const int kMaxKeyedPolymorphism = 4; @@ -22,38 +23,6 @@ class ICUtility : public AllStatic { }; -class CallICState final BASE_EMBEDDED { - public: - explicit CallICState(ExtraICState extra_ic_state) - : bit_field_(extra_ic_state) {} - CallICState(ConvertReceiverMode convert_mode, TailCallMode tail_call_mode) - : bit_field_(ConvertModeBits::encode(convert_mode) | - TailCallModeBits::encode(tail_call_mode)) {} - - ExtraICState GetExtraICState() const { return bit_field_; } - - static void GenerateAheadOfTime(Isolate*, - void (*Generate)(Isolate*, - const CallICState&)); - - ConvertReceiverMode convert_mode() const { - return ConvertModeBits::decode(bit_field_); - } - TailCallMode tail_call_mode() const { - return TailCallModeBits::decode(bit_field_); - } - - private: - typedef BitField<ConvertReceiverMode, 0, 2> ConvertModeBits; - typedef BitField<TailCallMode, ConvertModeBits::kNext, 1> TailCallModeBits; - - int const bit_field_; -}; - - -std::ostream& operator<<(std::ostream& os, const CallICState& s); - - class BinaryOpICState final BASE_EMBEDDED { public: BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state); @@ -213,67 +182,6 @@ class CompareICState { Handle<Object> y); }; -class LoadGlobalICState final BASE_EMBEDDED { - private: - class TypeofModeBits : public BitField<TypeofMode, 0, 1> {}; - STATIC_ASSERT(static_cast<int>(INSIDE_TYPEOF) == 0); - const ExtraICState state_; - - public: - static const uint32_t kNextBitFieldOffset = TypeofModeBits::kNext; - - explicit LoadGlobalICState(ExtraICState extra_ic_state) - : state_(extra_ic_state) {} - - explicit LoadGlobalICState(TypeofMode typeof_mode) - : state_(TypeofModeBits::encode(typeof_mode)) {} - - ExtraICState GetExtraICState() const { return state_; } - - TypeofMode typeof_mode() const { return TypeofModeBits::decode(state_); } - - static TypeofMode GetTypeofMode(ExtraICState state) { - return LoadGlobalICState(state).typeof_mode(); - } - - // For convenience, a statically declared encoding of typeof mode - // IC state. - static const ExtraICState kInsideTypeOfState = INSIDE_TYPEOF - << TypeofModeBits::kShift; - static const ExtraICState kNotInsideTypeOfState = NOT_INSIDE_TYPEOF - << TypeofModeBits::kShift; -}; - - -class StoreICState final BASE_EMBEDDED { - public: - explicit StoreICState(ExtraICState extra_ic_state) : state_(extra_ic_state) {} - - explicit StoreICState(LanguageMode mode) - : state_(LanguageModeState::encode(mode)) {} - - ExtraICState GetExtraICState() const { return state_; } - - LanguageMode language_mode() const { - return LanguageModeState::decode(state_); - } - - static LanguageMode GetLanguageMode(ExtraICState state) { - return StoreICState(state).language_mode(); - } - - class LanguageModeState : public BitField<LanguageMode, 1, 1> {}; - STATIC_ASSERT(i::LANGUAGE_END == 2); - - // For convenience, a statically declared encoding of strict mode extra - // IC state. - static const ExtraICState kStrictModeState = STRICT - << LanguageModeState::kShift; - - private: - const ExtraICState state_; -}; - } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc index d328b3cb2c..f11f94a770 100644 --- a/deps/v8/src/ic/ic.cc +++ b/deps/v8/src/ic/ic.cc @@ -19,7 +19,6 @@ #include "src/ic/call-optimization.h" #include "src/ic/handler-compiler.h" #include "src/ic/handler-configuration-inl.h" -#include "src/ic/ic-compiler.h" #include "src/ic/ic-inl.h" #include "src/ic/ic-stats.h" #include "src/ic/stub-cache.h" @@ -66,30 +65,7 @@ const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) { return ""; } - -#ifdef DEBUG - -#define TRACE_GENERIC_IC(isolate, type, reason) \ - do { \ - if (FLAG_trace_ic) { \ - PrintF("[%s patching generic stub in ", type); \ - JavaScriptFrame::PrintTop(isolate, stdout, false, true); \ - PrintF(" (%s)]\n", reason); \ - } \ - } while (false) - -#else - -#define TRACE_GENERIC_IC(isolate, type, reason) \ - do { \ - if (FLAG_trace_ic) { \ - PrintF("[%s patching generic stub in ", type); \ - PrintF("(see below) (%s)]\n", reason); \ - } \ - } while (false) - -#endif // DEBUG - +#define TRACE_GENERIC_IC(reason) set_slow_stub_reason(reason); void IC::TraceIC(const char* type, Handle<Object> name) { if (FLAG_ic_stats) { @@ -100,107 +76,110 @@ void IC::TraceIC(const char* type, Handle<Object> name) { } } +Address IC::GetAbstractPC(int* line, int* column) const { + JavaScriptFrameIterator it(isolate()); -void IC::TraceIC(const char* type, Handle<Object> name, State old_state, - State new_state) { - if (V8_LIKELY(!FLAG_ic_stats)) return; + JavaScriptFrame* frame = it.frame(); + DCHECK(!frame->is_builtin()); + int position = frame->position(); - if (FLAG_ic_stats & - v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { - ICStats::instance()->Begin(); - ICInfo& ic_info = ICStats::instance()->Current(); - ic_info.type = is_keyed() ? "Keyed" : ""; - ic_info.type += type; + Object* maybe_script = frame->function()->shared()->script(); + if (maybe_script->IsScript()) { + Handle<Script> script(Script::cast(maybe_script), isolate()); + Script::PositionInfo info; + Script::GetPositionInfo(script, position, &info, Script::WITH_OFFSET); + *line = info.line + 1; + *column = info.column + 1; } else { - PrintF("[%s%s in ", is_keyed() ? "Keyed" : "", type); + *line = position; + *column = -1; } - // TODO(jkummerow): Add support for "apply". The logic is roughly: - // marker = [fp_ + kMarkerOffset]; - // if marker is smi and marker.value == INTERNAL and - // the frame's code == builtin(Builtins::kFunctionApply): - // then print "apply from" and advance one frame + if (frame->is_interpreted()) { + InterpretedFrame* iframe = static_cast<InterpretedFrame*>(frame); + Address bytecode_start = + reinterpret_cast<Address>(iframe->GetBytecodeArray()) - kHeapObjectTag + + BytecodeArray::kHeaderSize; + return bytecode_start + iframe->GetBytecodeOffset(); + } - Object* maybe_function = - Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset); - if (maybe_function->IsJSFunction()) { - JSFunction* function = JSFunction::cast(maybe_function); - int code_offset = 0; - if (function->IsInterpreted()) { - code_offset = InterpretedFrame::GetBytecodeOffset(fp()); - } else { - code_offset = - static_cast<int>(pc() - function->code()->instruction_start()); - } - if (FLAG_ic_stats & - v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { - JavaScriptFrame::CollectFunctionAndOffsetForICStats( - function, function->abstract_code(), code_offset); - } else { - JavaScriptFrame::PrintFunctionAndOffset( - function, function->abstract_code(), code_offset, stdout, true); - } + return frame->pc(); +} + +void IC::TraceIC(const char* type, Handle<Object> name, State old_state, + State new_state) { + if (V8_LIKELY(!FLAG_ic_stats)) return; + + Map* map = nullptr; + if (!receiver_map().is_null()) { + map = *receiver_map(); } const char* modifier = ""; - if (kind() == Code::KEYED_STORE_IC) { + if (IsKeyedStoreIC()) { KeyedAccessStoreMode mode = casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode(); modifier = GetTransitionMarkModifier(mode); } - Map* map = nullptr; - if (!receiver_map().is_null()) { - map = *receiver_map(); + + if (!(FLAG_ic_stats & + v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) { + int line; + int column; + Address pc = GetAbstractPC(&line, &column); + LOG(isolate(), ICEvent(type, is_keyed(), pc, line, column, map, *name, + TransitionMarkFromState(old_state), + TransitionMarkFromState(new_state), modifier, + slow_stub_reason_)); + return; } - if (FLAG_ic_stats & - v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { - ICInfo& ic_info = ICStats::instance()->Current(); - // Reverse enough space for IC transition state, the longest length is 17. - ic_info.state.reserve(17); - ic_info.state = "("; - ic_info.state += TransitionMarkFromState(old_state); - ic_info.state += "->"; - ic_info.state += TransitionMarkFromState(new_state); - ic_info.state += modifier; - ic_info.state += ")"; - ic_info.map = reinterpret_cast<void*>(map); + + ICStats::instance()->Begin(); + ICInfo& ic_info = ICStats::instance()->Current(); + ic_info.type = is_keyed() ? "Keyed" : ""; + ic_info.type += type; + + Object* maybe_function = + Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset); + DCHECK(maybe_function->IsJSFunction()); + JSFunction* function = JSFunction::cast(maybe_function); + int code_offset = 0; + if (function->IsInterpreted()) { + code_offset = InterpretedFrame::GetBytecodeOffset(fp()); } else { - PrintF(" (%c->%c%s) map=(%p", TransitionMarkFromState(old_state), - TransitionMarkFromState(new_state), modifier, - reinterpret_cast<void*>(map)); - } + code_offset = + static_cast<int>(pc() - function->code()->instruction_start()); + } + JavaScriptFrame::CollectFunctionAndOffsetForICStats( + function, function->abstract_code(), code_offset); + + // Reserve enough space for IC transition state, the longest length is 17. + ic_info.state.reserve(17); + ic_info.state = "("; + ic_info.state += TransitionMarkFromState(old_state); + ic_info.state += "->"; + ic_info.state += TransitionMarkFromState(new_state); + ic_info.state += modifier; + ic_info.state += ")"; + ic_info.map = reinterpret_cast<void*>(map); if (map != nullptr) { - if (FLAG_ic_stats & - v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { - ICInfo& ic_info = ICStats::instance()->Current(); - ic_info.is_dictionary_map = map->is_dictionary_map(); - ic_info.number_of_own_descriptors = map->NumberOfOwnDescriptors(); - ic_info.instance_type = std::to_string(map->instance_type()); - } else { - PrintF(" dict=%u own=%u type=", map->is_dictionary_map(), - map->NumberOfOwnDescriptors()); - std::cout << map->instance_type(); - } - } - if (FLAG_ic_stats & - v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { - // TODO(lpy) Add name as key field in ICStats. - ICStats::instance()->End(); - } else { - PrintF(") "); - name->ShortPrint(stdout); - PrintF("]\n"); + ic_info.is_dictionary_map = map->is_dictionary_map(); + ic_info.number_of_own_descriptors = map->NumberOfOwnDescriptors(); + ic_info.instance_type = std::to_string(map->instance_type()); } + // TODO(lpy) Add name as key field in ICStats. + ICStats::instance()->End(); } #define TRACE_IC(type, name) TraceIC(type, name) - IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus) : isolate_(isolate), vector_set_(false), + kind_(FeedbackSlotKind::kInvalid), target_maps_set_(false), + slow_stub_reason_(nullptr), nexus_(nexus) { // To improve the performance of the (much used) IC code, we unfold a few // levels of the stack frame iteration code. This yields a ~35% speedup when @@ -237,9 +216,9 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus) // function's frame. Check if the there is an additional frame, and if there // is skip this frame. However, the pc should not be updated. The call to // ICs happen from bytecode handlers. - Object* frame_type = - Memory::Object_at(fp + TypedFrameConstants::kFrameTypeOffset); - if (frame_type == Smi::FromInt(StackFrame::STUB)) { + intptr_t frame_marker = + Memory::intptr_at(fp + TypedFrameConstants::kFrameTypeOffset); + if (frame_marker == StackFrame::TypeToMarker(StackFrame::STUB)) { fp = Memory::Address_at(fp + TypedFrameConstants::kCallerFPOffset); } fp_ = fp; @@ -247,18 +226,36 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus) constant_pool_address_ = constant_pool; } pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address); - Code* target = this->target(); - kind_ = target->kind(); - state_ = UseVector() ? nexus->StateFromFeedback() : StateFromCode(target); + if (nexus) { + kind_ = nexus->kind(); + DCHECK(UseVector()); + state_ = nexus->StateFromFeedback(); + extra_ic_state_ = kNoExtraICState; + } else { + Code* target = this->target(); + Code::Kind kind = target->kind(); + if (kind == Code::BINARY_OP_IC) { + kind_ = FeedbackSlotKind::kBinaryOp; + } else if (kind == Code::COMPARE_IC) { + kind_ = FeedbackSlotKind::kCompareOp; + } else if (kind == Code::TO_BOOLEAN_IC) { + kind_ = FeedbackSlotKind::kToBoolean; + } else { + UNREACHABLE(); + kind_ = FeedbackSlotKind::kInvalid; + } + DCHECK(!UseVector()); + state_ = StateFromCode(target); + extra_ic_state_ = target->extra_ic_state(); + } old_state_ = state_; - extra_ic_state_ = target->extra_ic_state(); } // The ICs that don't pass slot and vector through the stack have to // save/restore them in the dispatcher. bool IC::ShouldPushPopSlotAndVector(Code::Kind kind) { if (kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC || - kind == Code::KEYED_LOAD_IC || kind == Code::CALL_IC) { + kind == Code::KEYED_LOAD_IC) { return true; } if (kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC) { @@ -289,7 +286,7 @@ InlineCacheState IC::StateFromCode(Code* code) { } } -SharedFunctionInfo* IC::GetSharedFunctionInfo() const { +JSFunction* IC::GetHostFunction() const { // Compute the JavaScript frame for the frame pointer of this IC // structure. We need this to be able to find the function // corresponding to the frame. @@ -298,16 +295,7 @@ SharedFunctionInfo* IC::GetSharedFunctionInfo() const { JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame()); // Find the function on the stack and both the active code for the // function and the original code. - JSFunction* function = frame->function(); - return function->shared(); -} - - -Code* IC::GetCode() const { - HandleScope scope(isolate()); - Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate()); - Code* code = shared->code(); - return code; + return frame->function(); } static void LookupForRead(LookupIterator* it) { @@ -350,7 +338,7 @@ bool IC::ShouldRecomputeHandler(Handle<String> name) { // This is a contextual access, always just update the handler and stay // monomorphic. - if (kind() == Code::LOAD_GLOBAL_IC) return true; + if (IsLoadGlobalIC()) return true; // The current map wasn't handled yet. There's no reason to stay monomorphic, // *unless* we're moving from a deprecated map to its replacement, or @@ -447,12 +435,14 @@ static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state, } // static -void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host) { - if (host->kind() != Code::FUNCTION) return; +void IC::OnFeedbackChanged(Isolate* isolate, JSFunction* host_function) { + Code* host = host_function->shared()->code(); - TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info()); - info->change_own_type_change_checksum(); - host->set_profiler_ticks(0); + if (host->kind() == Code::FUNCTION) { + TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info()); + info->change_own_type_change_checksum(); + host->set_profiler_ticks(0); + } isolate->runtime_profiler()->NotifyICChanged(); // TODO(2029): When an optimized function is patched, it would // be nice to propagate the corresponding type information to its @@ -462,6 +452,7 @@ void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host) { void IC::PostPatching(Address address, Code* target, Code* old_target) { // Type vector based ICs update these statistics at a different time because // they don't always patch on state change. + // TODO(ishell): DCHECK if (ICUseVector(target->kind())) return; DCHECK(old_target->is_inline_cache_stub()); @@ -507,58 +498,6 @@ void IC::Clear(Isolate* isolate, Address address, Address constant_pool) { } } - -void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) { - if (IsCleared(nexus)) return; - // Make sure to also clear the map used in inline fast cases. If we - // do not clear these maps, cached code can keep objects alive - // through the embedded maps. - nexus->ConfigurePremonomorphic(); - OnTypeFeedbackChanged(isolate, host); -} - - -void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) { - // Determine our state. - Object* feedback = nexus->vector()->Get(nexus->slot()); - State state = nexus->StateFromFeedback(); - - if (state != UNINITIALIZED && !feedback->IsAllocationSite()) { - nexus->ConfigureUninitialized(); - // The change in state must be processed. - OnTypeFeedbackChanged(isolate, host); - } -} - - -void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) { - if (IsCleared(nexus)) return; - nexus->ConfigurePremonomorphic(); - OnTypeFeedbackChanged(isolate, host); -} - -void LoadGlobalIC::Clear(Isolate* isolate, Code* host, - LoadGlobalICNexus* nexus) { - if (IsCleared(nexus)) return; - nexus->ConfigureUninitialized(); - OnTypeFeedbackChanged(isolate, host); -} - -void StoreIC::Clear(Isolate* isolate, Code* host, StoreICNexus* nexus) { - if (IsCleared(nexus)) return; - nexus->ConfigurePremonomorphic(); - OnTypeFeedbackChanged(isolate, host); -} - - -void KeyedStoreIC::Clear(Isolate* isolate, Code* host, - KeyedStoreICNexus* nexus) { - if (IsCleared(nexus)) return; - nexus->ConfigurePremonomorphic(); - OnTypeFeedbackChanged(isolate, host); -} - - void CompareIC::Clear(Isolate* isolate, Address address, Code* target, Address constant_pool) { DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC); @@ -583,13 +522,13 @@ void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) { if (new_state == PREMONOMORPHIC) { nexus()->ConfigurePremonomorphic(); } else if (new_state == MEGAMORPHIC) { - if (kind() == Code::LOAD_IC || kind() == Code::STORE_IC) { + if (IsLoadIC() || IsStoreIC() || IsStoreOwnIC()) { nexus()->ConfigureMegamorphic(); - } else if (kind() == Code::KEYED_LOAD_IC) { + } else if (IsKeyedLoadIC()) { KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT); } else { - DCHECK(kind() == Code::KEYED_STORE_IC); + DCHECK(IsKeyedStoreIC()); KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT); } @@ -598,66 +537,117 @@ void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) { } vector_set_ = true; - OnTypeFeedbackChanged(isolate(), get_host()); + OnFeedbackChanged(isolate(), GetHostFunction()); } void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map, Handle<Object> handler) { DCHECK(UseVector()); - if (kind() == Code::LOAD_IC) { - LoadICNexus* nexus = casted_nexus<LoadICNexus>(); - nexus->ConfigureMonomorphic(map, handler); - } else if (kind() == Code::LOAD_GLOBAL_IC) { - LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>(); - nexus->ConfigureHandlerMode(handler); - } else if (kind() == Code::KEYED_LOAD_IC) { - KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); - nexus->ConfigureMonomorphic(name, map, handler); - } else if (kind() == Code::STORE_IC) { - StoreICNexus* nexus = casted_nexus<StoreICNexus>(); - nexus->ConfigureMonomorphic(map, handler); - } else { - DCHECK(kind() == Code::KEYED_STORE_IC); - KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); - nexus->ConfigureMonomorphic(name, map, handler); + switch (kind_) { + case FeedbackSlotKind::kLoadProperty: { + LoadICNexus* nexus = casted_nexus<LoadICNexus>(); + nexus->ConfigureMonomorphic(map, handler); + break; + } + case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: + case FeedbackSlotKind::kLoadGlobalInsideTypeof: { + LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>(); + nexus->ConfigureHandlerMode(handler); + break; + } + case FeedbackSlotKind::kLoadKeyed: { + KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); + nexus->ConfigureMonomorphic(name, map, handler); + break; + } + case FeedbackSlotKind::kStoreNamedSloppy: + case FeedbackSlotKind::kStoreNamedStrict: + case FeedbackSlotKind::kStoreOwnNamed: { + StoreICNexus* nexus = casted_nexus<StoreICNexus>(); + nexus->ConfigureMonomorphic(map, handler); + break; + } + case FeedbackSlotKind::kStoreKeyedSloppy: + case FeedbackSlotKind::kStoreKeyedStrict: { + KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); + nexus->ConfigureMonomorphic(name, map, handler); + break; + } + case FeedbackSlotKind::kCall: + case FeedbackSlotKind::kBinaryOp: + case FeedbackSlotKind::kCompareOp: + case FeedbackSlotKind::kToBoolean: + case FeedbackSlotKind::kCreateClosure: + case FeedbackSlotKind::kLiteral: + case FeedbackSlotKind::kGeneral: + case FeedbackSlotKind::kStoreDataPropertyInLiteral: + case FeedbackSlotKind::kInvalid: + case FeedbackSlotKind::kKindsNumber: + UNREACHABLE(); + break; } vector_set_ = true; - OnTypeFeedbackChanged(isolate(), get_host()); + OnFeedbackChanged(isolate(), GetHostFunction()); } void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps, List<Handle<Object>>* handlers) { DCHECK(UseVector()); - if (kind() == Code::LOAD_IC) { - LoadICNexus* nexus = casted_nexus<LoadICNexus>(); - nexus->ConfigurePolymorphic(maps, handlers); - } else if (kind() == Code::KEYED_LOAD_IC) { - KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); - nexus->ConfigurePolymorphic(name, maps, handlers); - } else if (kind() == Code::STORE_IC) { - StoreICNexus* nexus = casted_nexus<StoreICNexus>(); - nexus->ConfigurePolymorphic(maps, handlers); - } else { - DCHECK(kind() == Code::KEYED_STORE_IC); - KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); - nexus->ConfigurePolymorphic(name, maps, handlers); + switch (kind_) { + case FeedbackSlotKind::kLoadProperty: { + LoadICNexus* nexus = casted_nexus<LoadICNexus>(); + nexus->ConfigurePolymorphic(maps, handlers); + break; + } + case FeedbackSlotKind::kLoadKeyed: { + KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); + nexus->ConfigurePolymorphic(name, maps, handlers); + break; + } + case FeedbackSlotKind::kStoreNamedSloppy: + case FeedbackSlotKind::kStoreNamedStrict: + case FeedbackSlotKind::kStoreOwnNamed: { + StoreICNexus* nexus = casted_nexus<StoreICNexus>(); + nexus->ConfigurePolymorphic(maps, handlers); + break; + } + case FeedbackSlotKind::kStoreKeyedSloppy: + case FeedbackSlotKind::kStoreKeyedStrict: { + KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); + nexus->ConfigurePolymorphic(name, maps, handlers); + break; + } + case FeedbackSlotKind::kCall: + case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: + case FeedbackSlotKind::kLoadGlobalInsideTypeof: + case FeedbackSlotKind::kBinaryOp: + case FeedbackSlotKind::kCompareOp: + case FeedbackSlotKind::kToBoolean: + case FeedbackSlotKind::kCreateClosure: + case FeedbackSlotKind::kLiteral: + case FeedbackSlotKind::kGeneral: + case FeedbackSlotKind::kStoreDataPropertyInLiteral: + case FeedbackSlotKind::kInvalid: + case FeedbackSlotKind::kKindsNumber: + UNREACHABLE(); + break; } vector_set_ = true; - OnTypeFeedbackChanged(isolate(), get_host()); + OnFeedbackChanged(isolate(), GetHostFunction()); } void IC::ConfigureVectorState(MapHandleList* maps, MapHandleList* transitioned_maps, List<Handle<Object>>* handlers) { DCHECK(UseVector()); - DCHECK(kind() == Code::KEYED_STORE_IC); + DCHECK(IsKeyedStoreIC()); KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); nexus->ConfigurePolymorphic(maps, transitioned_maps, handlers); vector_set_ = true; - OnTypeFeedbackChanged(isolate(), get_host()); + OnFeedbackChanged(isolate(), GetHostFunction()); } @@ -843,12 +833,8 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) { void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { DCHECK(IsHandler(*handler)); - // Currently only LoadIC and KeyedLoadIC support non-code handlers. - DCHECK_IMPLIES(!handler->IsCode(), kind() == Code::LOAD_IC || - kind() == Code::LOAD_GLOBAL_IC || - kind() == Code::KEYED_LOAD_IC || - kind() == Code::STORE_IC || - kind() == Code::KEYED_STORE_IC); + // Currently only load and store ICs support non-code handlers. + DCHECK_IMPLIES(!handler->IsCode(), IsAnyLoad() || IsAnyStore()); switch (state()) { case UNINITIALIZED: case PREMONOMORPHIC: @@ -856,7 +842,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { break; case RECOMPUTE_HANDLER: case MONOMORPHIC: - if (kind() == Code::LOAD_GLOBAL_IC) { + if (IsLoadGlobalIC()) { UpdateMonomorphicIC(handler, name); break; } @@ -1101,7 +1087,7 @@ bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) { void LoadIC::UpdateCaches(LookupIterator* lookup) { - if (state() == UNINITIALIZED && kind() != Code::LOAD_GLOBAL_IC) { + if (state() == UNINITIALIZED && !IsLoadGlobalIC()) { // This is the first time we execute this inline cache. Set the target to // the pre monomorphic stub to delay setting the monomorphic state. TRACE_HANDLER_STATS(isolate(), LoadIC_Premonomorphic); @@ -1115,15 +1101,10 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { lookup->state() == LookupIterator::ACCESS_CHECK) { code = slow_stub(); } else if (!lookup->IsFound()) { - if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC) { - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH); - code = LoadNonExistent(receiver_map(), lookup->name()); - } else { - code = slow_stub(); - } + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH); + code = LoadNonExistent(receiver_map(), lookup->name()); } else { - if (kind() == Code::LOAD_GLOBAL_IC && - lookup->state() == LookupIterator::DATA && + if (IsLoadGlobalIC() && lookup->state() == LookupIterator::DATA && lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) { DCHECK(lookup->GetReceiver()->IsJSGlobalObject()); // Now update the cell in the feedback vector. @@ -1133,7 +1114,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { return; } else if (lookup->state() == LookupIterator::ACCESSOR) { if (!IsCompatibleReceiver(lookup, receiver_map())) { - TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type"); + TRACE_GENERIC_IC("incompatible receiver type"); code = slow_stub(); } } else if (lookup->state() == LookupIterator::INTERCEPTOR) { @@ -1144,7 +1125,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { LookupForRead(&it); if (it.state() == LookupIterator::ACCESSOR && !IsCompatibleReceiver(&it, receiver_map())) { - TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type"); + TRACE_GENERIC_IC("incompatible receiver type"); code = slow_stub(); } } @@ -1156,20 +1137,12 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { } StubCache* IC::stub_cache() { - switch (kind()) { - case Code::LOAD_IC: - case Code::KEYED_LOAD_IC: - return isolate()->load_stub_cache(); - - case Code::STORE_IC: - case Code::KEYED_STORE_IC: - return isolate()->store_stub_cache(); - - default: - break; + if (IsAnyLoad()) { + return isolate()->load_stub_cache(); + } else { + DCHECK(IsAnyStore()); + return isolate()->store_stub_cache(); } - UNREACHABLE(); - return nullptr; } void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* handler) { @@ -1179,8 +1152,7 @@ void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* handler) { void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) { if (!FLAG_runtime_call_stats) return; - if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC || - kind() == Code::KEYED_LOAD_IC) { + if (IsAnyLoad()) { switch (lookup->state()) { case LookupIterator::ACCESS_CHECK: TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_AccessCheck); @@ -1207,7 +1179,7 @@ void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) { TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Transition); break; } - } else if (kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC) { + } else if (IsAnyStore()) { switch (lookup->state()) { case LookupIterator::ACCESS_CHECK: TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_AccessCheck); @@ -1254,19 +1226,18 @@ Handle<Object> IC::ComputeHandler(LookupIterator* lookup, lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>()); CacheHolderFlag flag; Handle<Map> stub_holder_map; - if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC || - kind() == Code::KEYED_LOAD_IC) { + if (IsAnyLoad()) { stub_holder_map = IC::GetHandlerCacheHolder( receiver_map(), receiver_is_holder, isolate(), &flag); } else { - DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC); + DCHECK(IsAnyStore()); // Store handlers cannot be cached on prototypes. flag = kCacheOnReceiver; stub_holder_map = receiver_map(); } Handle<Object> handler = PropertyHandlerCompiler::Find( - lookup->name(), stub_holder_map, kind(), flag); + lookup->name(), stub_holder_map, handler_kind(), flag); // Use the cached value if it exists, and if it is different from the // handler that just missed. if (!handler.is_null()) { @@ -1329,8 +1300,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { ->has_non_instance_prototype()) { Handle<Code> stub; TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub); - FunctionPrototypeStub function_prototype_stub(isolate()); - return function_prototype_stub.GetCode(); + return isolate()->builtins()->LoadIC_FunctionPrototype(); } Handle<Map> map = receiver_map(); @@ -1359,7 +1329,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { return slow_stub(); } // When debugging we need to go the slow path to flood the accessor. - if (GetSharedFunctionInfo()->HasDebugInfo()) { + if (GetHostFunction()->shared()->HasDebugInfo()) { TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); return slow_stub(); } @@ -1384,7 +1354,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH); return smi_handler; } - if (kind() != Code::LOAD_GLOBAL_IC) { + if (!IsLoadGlobalIC()) { TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH); return LoadFromPrototype(map, holder, lookup->name(), smi_handler); } @@ -1398,7 +1368,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { case LookupIterator::DATA: { DCHECK_EQ(kData, lookup->property_details().kind()); if (lookup->is_dictionary_holder()) { - if (kind() != Code::LOAD_IC && kind() != Code::LOAD_GLOBAL_IC) { + if (!IsLoadIC() && !IsLoadGlobalIC()) { // IsKeyedLoadIC()? TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); return slow_stub(); } @@ -1505,7 +1475,7 @@ Handle<Object> LoadIC::CompileHandler(LookupIterator* lookup, return ComputeHandler(lookup); } DCHECK(holder->HasFastProperties()); - DCHECK(!GetSharedFunctionInfo()->HasDebugInfo()); + DCHECK(!GetHostFunction()->shared()->HasDebugInfo()); Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(), isolate()); CallOptimization call_optimization(getter); @@ -1542,7 +1512,7 @@ Handle<Object> LoadIC::CompileHandler(LookupIterator* lookup, case LookupIterator::DATA: { DCHECK(lookup->is_dictionary_holder()); - DCHECK(kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC); + DCHECK(IsLoadIC() || IsLoadGlobalIC()); DCHECK(holder->IsJSGlobalObject()); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobal); NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); @@ -1579,6 +1549,8 @@ static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { } } else if (key->IsUndefined(isolate)) { key = isolate->factory()->undefined_string(); + } else if (key->IsString()) { + key = isolate->factory()->InternalizeString(Handle<String>::cast(key)); } return key; } @@ -1600,11 +1572,11 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) { Handle<Map> map = target_receiver_maps.at(i); if (map.is_null()) continue; if (map->instance_type() == JS_VALUE_TYPE) { - TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "JSValue"); + TRACE_GENERIC_IC("JSValue"); return; } if (map->instance_type() == JS_PROXY_TYPE) { - TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "JSProxy"); + TRACE_GENERIC_IC("JSProxy"); return; } } @@ -1632,14 +1604,14 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) { if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) { // If the miss wasn't due to an unseen map, a polymorphic stub // won't help, use the generic stub. - TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice"); + TRACE_GENERIC_IC("same map added twice"); return; } // If the maximum number of receiver maps has been exceeded, use the generic // version of the IC. if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { - TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded"); + TRACE_GENERIC_IC("max polymorph exceeded"); return; } @@ -1686,7 +1658,6 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object, if (!is_vector_set()) { ConfigureVectorState(MEGAMORPHIC, key); - TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic"); TRACE_IC("LoadIC", key); } @@ -1852,12 +1823,13 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, return; } - bool use_ic = LookupForWrite(lookup, value, store_mode); - if (!use_ic) { - TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'"); + Handle<Object> handler; + if (LookupForWrite(lookup, value, store_mode)) { + handler = ComputeHandler(lookup, value); + } else { + TRACE_GENERIC_IC("LookupForWrite said 'false'"); + handler = slow_stub(); } - Handle<Object> handler = use_ic ? ComputeHandler(lookup, value) - : Handle<Object>::cast(slow_stub()); PatchCache(lookup->name(), handler); TRACE_IC("StoreIC", lookup->name()); @@ -1955,7 +1927,7 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { } // Currently not handled by CompileStoreTransition. if (!holder->HasFastProperties()) { - TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow"); + TRACE_GENERIC_IC("transition from slow"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); return slow_stub(); } @@ -1975,7 +1947,7 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { case LookupIterator::ACCESSOR: { if (!holder->HasFastProperties()) { - TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map"); + TRACE_GENERIC_IC("accessor on slow map"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); return slow_stub(); } @@ -1983,20 +1955,19 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { if (accessors->IsAccessorInfo()) { Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); if (v8::ToCData<Address>(info->setter()) == nullptr) { - TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == nullptr"); + TRACE_GENERIC_IC("setter == nullptr"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); return slow_stub(); } if (AccessorInfo::cast(*accessors)->is_special_data_property() && !lookup->HolderIsReceiverOrHiddenPrototype()) { - TRACE_GENERIC_IC(isolate(), "StoreIC", - "special data property in prototype chain"); + TRACE_GENERIC_IC("special data property in prototype chain"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); return slow_stub(); } if (!AccessorInfo::IsCompatibleReceiverMap(isolate(), info, receiver_map())) { - TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type"); + TRACE_GENERIC_IC("incompatible receiver type"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); return slow_stub(); } @@ -2009,7 +1980,7 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(), isolate()); if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) { - TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function"); + TRACE_GENERIC_IC("setter not a function"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); return slow_stub(); } @@ -2018,7 +1989,7 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { if (call_optimization.IsCompatibleReceiver(receiver, holder)) { break; // Custom-compiled handler. } - TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver"); + TRACE_GENERIC_IC("incompatible receiver"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); return slow_stub(); } @@ -2045,12 +2016,13 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { int descriptor = lookup->GetFieldDescriptorIndex(); FieldIndex index = lookup->GetFieldIndex(); return StoreHandler::StoreField(isolate(), descriptor, index, + lookup->constness(), lookup->representation()); } // -------------- Constant properties -------------- DCHECK_EQ(kDescriptor, lookup->property_details().location()); - TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property"); + TRACE_GENERIC_IC("constant property"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); return slow_stub(); } @@ -2106,6 +2078,11 @@ Handle<Object> StoreIC::CompileHandler(LookupIterator* lookup, DCHECK(!info->is_sloppy() || receiver->IsJSReceiver()); TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback); NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder); + // TODO(ishell): don't hard-code language mode into the handler because + // this handler can be re-used through megamorphic stub cache for wrong + // language mode. + // Better pass vector/slot to Runtime::kStoreCallbackProperty and + // let it decode the language mode from the IC kind. Handle<Code> code = compiler.CompileStoreCallback( receiver, lookup->name(), info, language_mode()); return code; @@ -2167,16 +2144,14 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver_map, store_mode); store_mode = GetNonTransitioningStoreMode(store_mode); - Handle<Object> handler = - PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(monomorphic_map, - store_mode); + Handle<Object> handler = StoreElementHandler(monomorphic_map, store_mode); return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler); } for (int i = 0; i < target_receiver_maps.length(); i++) { if (!target_receiver_maps.at(i).is_null() && target_receiver_maps.at(i)->instance_type() == JS_VALUE_TYPE) { - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "JSValue"); + TRACE_GENERIC_IC("JSValue"); return; } } @@ -2202,8 +2177,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, // stay MONOMORPHIC and use the map for the most generic ElementsKind. store_mode = GetNonTransitioningStoreMode(store_mode); Handle<Object> handler = - PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler( - transitioned_receiver_map, store_mode); + StoreElementHandler(transitioned_receiver_map, store_mode); ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler); return; } @@ -2215,9 +2189,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, // A "normal" IC that handles stores can switch to a version that can // grow at the end of the array, handle OOB accesses or copy COW arrays // and still stay MONOMORPHIC. - Handle<Object> handler = - PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(receiver_map, - store_mode); + Handle<Object> handler = StoreElementHandler(receiver_map, store_mode); return ConfigureVectorState(Handle<Name>(), receiver_map, handler); } } @@ -2237,7 +2209,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, if (!map_added) { // If the miss wasn't due to an unseen map, a polymorphic stub // won't help, use the megamorphic stub which can handle everything. - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice"); + TRACE_GENERIC_IC("same map added twice"); return; } @@ -2252,7 +2224,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, if (store_mode == STANDARD_STORE) { store_mode = old_store_mode; } else if (store_mode != old_store_mode) { - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch"); + TRACE_GENERIC_IC("store mode mismatch"); return; } } @@ -2269,16 +2241,15 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, } if (external_arrays != 0 && external_arrays != target_receiver_maps.length()) { - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", - "unsupported combination of external and normal arrays"); + TRACE_GENERIC_IC("unsupported combination of external and normal arrays"); return; } } MapHandleList transitioned_maps(target_receiver_maps.length()); List<Handle<Object>> handlers(target_receiver_maps.length()); - PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers( - &target_receiver_maps, &transitioned_maps, &handlers, store_mode); + StoreElementPolymorphicHandlers(&target_receiver_maps, &transitioned_maps, + &handlers, store_mode); ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers); } @@ -2312,6 +2283,91 @@ Handle<Map> KeyedStoreIC::ComputeTransitionedMap( return MaybeHandle<Map>().ToHandleChecked(); } +Handle<Object> KeyedStoreIC::StoreElementHandler( + Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) { + DCHECK(store_mode == STANDARD_STORE || + store_mode == STORE_AND_GROW_NO_TRANSITION || + store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || + store_mode == STORE_NO_TRANSITION_HANDLE_COW); + + ElementsKind elements_kind = receiver_map->elements_kind(); + bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; + Handle<Code> stub; + if (receiver_map->has_sloppy_arguments_elements()) { + TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub); + stub = KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode(); + } else if (receiver_map->has_fast_elements() || + receiver_map->has_fixed_typed_array_elements()) { + TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub); + stub = + StoreFastElementStub(isolate(), is_jsarray, elements_kind, store_mode) + .GetCode(); + } else { + TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub); + DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind); + stub = StoreSlowElementStub(isolate(), store_mode).GetCode(); + } + Handle<Object> validity_cell = + Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); + if (validity_cell.is_null()) { + return stub; + } + return isolate()->factory()->NewTuple2(validity_cell, stub); +} + +void KeyedStoreIC::StoreElementPolymorphicHandlers( + MapHandleList* receiver_maps, MapHandleList* transitioned_maps, + List<Handle<Object>>* handlers, KeyedAccessStoreMode store_mode) { + DCHECK(store_mode == STANDARD_STORE || + store_mode == STORE_AND_GROW_NO_TRANSITION || + store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || + store_mode == STORE_NO_TRANSITION_HANDLE_COW); + + for (int i = 0; i < receiver_maps->length(); ++i) { + Handle<Map> receiver_map(receiver_maps->at(i)); + Handle<Object> handler; + Handle<Map> transitioned_map; + { + Map* tmap = receiver_map->FindElementsKindTransitionedMap(receiver_maps); + if (tmap != nullptr) transitioned_map = handle(tmap); + } + + // TODO(mvstanton): The code below is doing pessimistic elements + // transitions. I would like to stop doing that and rely on Allocation Site + // Tracking to do a better job of ensuring the data types are what they need + // to be. Not all the elements are in place yet, pessimistic elements + // transitions are still important for performance. + if (!transitioned_map.is_null()) { + bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; + ElementsKind elements_kind = receiver_map->elements_kind(); + TRACE_HANDLER_STATS(isolate(), + KeyedStoreIC_ElementsTransitionAndStoreStub); + Handle<Code> stub = + ElementsTransitionAndStoreStub(isolate(), elements_kind, + transitioned_map->elements_kind(), + is_js_array, store_mode) + .GetCode(); + Handle<Object> validity_cell = + Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); + if (validity_cell.is_null()) { + handler = stub; + } else { + handler = isolate()->factory()->NewTuple2(validity_cell, stub); + } + + } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) { + // TODO(mvstanton): Consider embedding store_mode in the state of the slow + // keyed store ic for uniformity. + TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub); + handler = isolate()->builtins()->KeyedStoreIC_Slow(); + } else { + handler = StoreElementHandler(receiver_map, store_mode); + } + DCHECK(!handler.is_null()); + handlers->Add(handler); + transitioned_maps->Add(transitioned_map); + } +} bool IsOutOfBoundsAccess(Handle<JSObject> receiver, uint32_t index) { uint32_t length = 0; @@ -2404,8 +2460,7 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, Object); if (!is_vector_set()) { ConfigureVectorState(MEGAMORPHIC, key); - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", - "unhandled internalized string key"); + TRACE_GENERIC_IC("unhandled internalized string key"); TRACE_IC("StoreIC", key); } return store_handle; @@ -2419,7 +2474,7 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, // the runtime to enable optimization of element hole access. Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); if (heap_object->map()->IsMapInArrayPrototypeChain()) { - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "map in array prototype"); + TRACE_GENERIC_IC("map in array prototype"); use_ic = false; } } @@ -2450,7 +2505,7 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, if (use_ic) { if (!old_receiver_map.is_null()) { if (is_arguments) { - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver"); + TRACE_GENERIC_IC("arguments receiver"); } else if (key_is_valid_index) { // We should go generic if receiver isn't a dictionary, but our // prototype chain does have dictionary elements. This ensures that @@ -2459,20 +2514,18 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly()) { UpdateStoreElement(old_receiver_map, store_mode); } else { - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", - "dictionary or proxy prototype"); + TRACE_GENERIC_IC("dictionary or proxy prototype"); } } else { - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-smi-like key"); + TRACE_GENERIC_IC("non-smi-like key"); } } else { - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-JSObject receiver"); + TRACE_GENERIC_IC("non-JSObject receiver"); } } if (!is_vector_set()) { ConfigureVectorState(MEGAMORPHIC, key); - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic"); } TRACE_IC("StoreIC", key); @@ -2480,48 +2533,6 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, } -void CallIC::HandleMiss(Handle<Object> function) { - Handle<Object> name = isolate()->factory()->empty_string(); - CallICNexus* nexus = casted_nexus<CallICNexus>(); - Object* feedback = nexus->GetFeedback(); - - // Hand-coded MISS handling is easier if CallIC slots don't contain smis. - DCHECK(!feedback->IsSmi()); - - if (feedback->IsWeakCell() || !function->IsJSFunction() || - feedback->IsAllocationSite()) { - // We are going generic. - nexus->ConfigureMegamorphic(); - } else { - DCHECK(feedback == *FeedbackVector::UninitializedSentinel(isolate())); - Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); - - Handle<JSFunction> array_function = - Handle<JSFunction>(isolate()->native_context()->array_function()); - if (array_function.is_identical_to(js_function)) { - // Alter the slot. - nexus->ConfigureMonomorphicArray(); - } else if (js_function->context()->native_context() != - *isolate()->native_context()) { - // Don't collect cross-native context feedback for the CallIC. - // TODO(bmeurer): We should collect the SharedFunctionInfo as - // feedback in this case instead. - nexus->ConfigureMegamorphic(); - } else { - nexus->ConfigureMonomorphic(js_function); - } - } - - if (function->IsJSFunction()) { - Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); - name = handle(js_function->shared()->name(), isolate()); - } - - OnTypeFeedbackChanged(isolate(), get_host()); - TRACE_IC("CallIC", name); -} - - #undef TRACE_IC @@ -2530,22 +2541,6 @@ void CallIC::HandleMiss(Handle<Object> function) { // // Used from ic-<arch>.cc. -RUNTIME_FUNCTION(Runtime_CallIC_Miss) { - HandleScope scope(isolate); - DCHECK_EQ(3, args.length()); - // Runtime functions don't follow the IC's calling convention. - Handle<Object> function = args.at(0); - Handle<FeedbackVector> vector = args.at<FeedbackVector>(1); - Handle<Smi> slot = args.at<Smi>(2); - FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); - CallICNexus nexus(vector, vector_slot); - CallIC ic(isolate, &nexus); - ic.HandleMiss(function); - return *function; -} - - -// Used from ic-<arch>.cc. RUNTIME_FUNCTION(Runtime_LoadIC_Miss) { HandleScope scope(isolate); DCHECK_EQ(4, args.length()); @@ -2554,28 +2549,28 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) { Handle<Name> key = args.at<Name>(1); Handle<Smi> slot = args.at<Smi>(2); Handle<FeedbackVector> vector = args.at<FeedbackVector>(3); - FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); + FeedbackSlot vector_slot = vector->ToSlot(slot->value()); // A monomorphic or polymorphic KeyedLoadIC with a string key can call the // LoadIC miss handler if the handler misses. Since the vector Nexus is // set up outside the IC, handle that here. - FeedbackVectorSlotKind kind = vector->GetKind(vector_slot); - if (kind == FeedbackVectorSlotKind::LOAD_IC) { + FeedbackSlotKind kind = vector->GetKind(vector_slot); + if (IsLoadICKind(kind)) { LoadICNexus nexus(vector, vector_slot); - LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); + LoadIC ic(isolate, &nexus); ic.UpdateState(receiver, key); RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key)); - } else if (kind == FeedbackVectorSlotKind::LOAD_GLOBAL_IC) { + } else if (IsLoadGlobalICKind(kind)) { DCHECK_EQ(*isolate->global_object(), *receiver); LoadGlobalICNexus nexus(vector, vector_slot); - LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); + LoadGlobalIC ic(isolate, &nexus); ic.UpdateState(receiver, key); RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key)); } else { - DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, kind); + DCHECK(IsKeyedLoadICKind(kind)); KeyedLoadICNexus nexus(vector, vector_slot); - KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); + KeyedLoadIC ic(isolate, &nexus); ic.UpdateState(receiver, key); RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key)); } @@ -2590,10 +2585,10 @@ RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) { Handle<String> name = args.at<String>(0); Handle<Smi> slot = args.at<Smi>(1); Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); - FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); + FeedbackSlot vector_slot = vector->ToSlot(slot->value()); LoadGlobalICNexus nexus(vector, vector_slot); - LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); + LoadGlobalIC ic(isolate, &nexus); ic.UpdateState(global, name); Handle<Object> result; @@ -2603,7 +2598,7 @@ RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) { RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) { HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); + DCHECK_EQ(3, args.length()); CONVERT_ARG_HANDLE_CHECKED(String, name, 0); Handle<Context> native_context = isolate->native_context(); @@ -2630,11 +2625,13 @@ RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) { isolate, result, Runtime::GetObjectProperty(isolate, global, name, &is_found)); if (!is_found) { - LoadICNexus nexus(isolate); - LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); + Handle<Smi> slot = args.at<Smi>(1); + Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); + FeedbackSlot vector_slot = vector->ToSlot(slot->value()); + FeedbackSlotKind kind = vector->GetKind(vector_slot); // It is actually a LoadGlobalICs here but the predicate handles this case // properly. - if (ic.ShouldThrowReferenceError()) { + if (LoadIC::ShouldThrowReferenceError(kind)) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewReferenceError(MessageTemplate::kNotDefined, name)); } @@ -2651,31 +2648,13 @@ RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) { Handle<Object> key = args.at(1); Handle<Smi> slot = args.at<Smi>(2); Handle<FeedbackVector> vector = args.at<FeedbackVector>(3); - FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); - KeyedLoadICNexus nexus(vector, vector_slot); - KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); - ic.UpdateState(receiver, key); - RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key)); -} - - -RUNTIME_FUNCTION(Runtime_KeyedLoadIC_MissFromStubFailure) { - HandleScope scope(isolate); - typedef LoadWithVectorDescriptor Descriptor; - DCHECK_EQ(Descriptor::kParameterCount, args.length()); - Handle<Object> receiver = args.at(Descriptor::kReceiver); - Handle<Object> key = args.at(Descriptor::kName); - Handle<Smi> slot = args.at<Smi>(Descriptor::kSlot); - Handle<FeedbackVector> vector = - args.at<FeedbackVector>(Descriptor::kVector); - FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); + FeedbackSlot vector_slot = vector->ToSlot(slot->value()); KeyedLoadICNexus nexus(vector, vector_slot); - KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus); + KeyedLoadIC ic(isolate, &nexus); ic.UpdateState(receiver, key); RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key)); } - // Used from ic-<arch>.cc. RUNTIME_FUNCTION(Runtime_StoreIC_Miss) { HandleScope scope(isolate); @@ -2686,23 +2665,22 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) { Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); Handle<Object> receiver = args.at(3); Handle<Name> key = args.at<Name>(4); - FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); - if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) { + FeedbackSlot vector_slot = vector->ToSlot(slot->value()); + FeedbackSlotKind kind = vector->GetKind(vector_slot); + if (IsStoreICKind(kind) || IsStoreOwnICKind(kind)) { StoreICNexus nexus(vector, vector_slot); - StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); + StoreIC ic(isolate, &nexus); ic.UpdateState(receiver, key); RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); } else { - DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC, - vector->GetKind(vector_slot)); + DCHECK(IsKeyedStoreICKind(kind)); KeyedStoreICNexus nexus(vector, vector_slot); - KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); + KeyedStoreIC ic(isolate, &nexus); ic.UpdateState(receiver, key); RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); } } - // Used from ic-<arch>.cc. RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) { HandleScope scope(isolate); @@ -2713,9 +2691,9 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) { Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); Handle<Object> receiver = args.at(3); Handle<Object> key = args.at(4); - FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); + FeedbackSlot vector_slot = vector->ToSlot(slot->value()); KeyedStoreICNexus nexus(vector, vector_slot); - KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); + KeyedStoreIC ic(isolate, &nexus); ic.UpdateState(receiver, key); RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); } @@ -2726,13 +2704,12 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) { DCHECK_EQ(5, args.length()); // Runtime functions don't follow the IC's calling convention. Handle<Object> value = args.at(0); - // slot and vector parameters are not used. + Handle<Smi> slot = args.at<Smi>(1); + Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); Handle<Object> object = args.at(3); Handle<Object> key = args.at(4); - LanguageMode language_mode; - KeyedStoreICNexus nexus(isolate); - KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); - language_mode = ic.language_mode(); + FeedbackSlot vector_slot = vector->ToSlot(slot->value()); + LanguageMode language_mode = vector->GetLanguageMode(vector_slot); RETURN_RESULT_OR_FAILURE( isolate, Runtime::SetObjectProperty(isolate, object, key, value, language_mode)); @@ -2741,15 +2718,16 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) { RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) { HandleScope scope(isolate); + DCHECK_EQ(6, args.length()); // Runtime functions don't follow the IC's calling convention. Handle<Object> object = args.at(0); Handle<Object> key = args.at(1); Handle<Object> value = args.at(2); Handle<Map> map = args.at<Map>(3); - LanguageMode language_mode; - KeyedStoreICNexus nexus(isolate); - KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); - language_mode = ic.language_mode(); + Handle<Smi> slot = args.at<Smi>(4); + Handle<FeedbackVector> vector = args.at<FeedbackVector>(5); + FeedbackSlot vector_slot = vector->ToSlot(slot->value()); + LanguageMode language_mode = vector->GetLanguageMode(vector_slot); if (object->IsJSObject()) { JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), map->elements_kind()); @@ -2867,15 +2845,13 @@ MaybeHandle<Object> BinaryOpIC::Transition( JavaScriptFrame::CollectTopFrameForICStats(isolate()); ic_stats->End(); } else if (FLAG_ic_stats) { - // if (FLAG_trace_ic) { - OFStream os(stdout); - os << "[BinaryOpIC" << old_state << " => " << state << " @ " - << static_cast<void*>(*new_target) << " <- "; - JavaScriptFrame::PrintTop(isolate(), stdout, false, true); - if (!allocation_site.is_null()) { - os << " using allocation site " << static_cast<void*>(*allocation_site); - } - os << "]" << std::endl; + int line; + int column; + Address pc = GetAbstractPC(&line, &column); + LOG(isolate(), + BinaryOpIC(pc, line, column, *new_target, old_state.ToString().c_str(), + state.ToString().c_str(), + allocation_site.is_null() ? nullptr : *allocation_site)); } // Patch the inlined smi code as necessary. @@ -2964,17 +2940,17 @@ Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { ic_info.state += Token::Name(op_); ic_stats->End(); } else if (FLAG_ic_stats) { - // if (FLAG_trace_ic) { - PrintF("[CompareIC in "); - JavaScriptFrame::PrintTop(isolate(), stdout, false, true); - PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n", - CompareICState::GetStateName(old_stub.left()), - CompareICState::GetStateName(old_stub.right()), - CompareICState::GetStateName(old_stub.state()), - CompareICState::GetStateName(new_left), - CompareICState::GetStateName(new_right), - CompareICState::GetStateName(state), Token::Name(op_), - static_cast<void*>(*stub.GetCode())); + int line; + int column; + Address pc = GetAbstractPC(&line, &column); + LOG(isolate(), + CompareIC(pc, line, column, *stub.GetCode(), Token::Name(op_), + CompareICState::GetStateName(old_stub.left()), + CompareICState::GetStateName(old_stub.right()), + CompareICState::GetStateName(old_stub.state()), + CompareICState::GetStateName(new_left), + CompareICState::GetStateName(new_right), + CompareICState::GetStateName(state))); } // Activate inlined smi code. @@ -3004,9 +2980,36 @@ RUNTIME_FUNCTION(Runtime_Unreachable) { Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) { ToBooleanICStub stub(isolate(), extra_ic_state()); + ToBooleanHints old_hints = stub.hints(); bool to_boolean_value = stub.UpdateStatus(object); + ToBooleanHints new_hints = stub.hints(); Handle<Code> code = stub.GetCode(); set_target(*code); + + // Note: Although a no-op transition is semantically OK, it is hinting at a + // bug somewhere in our state transition machinery. + DCHECK_NE(old_hints, new_hints); + if (V8_UNLIKELY(FLAG_ic_stats)) { + if (FLAG_ic_stats & + v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { + auto ic_stats = ICStats::instance(); + ic_stats->Begin(); + ICInfo& ic_info = ic_stats->Current(); + ic_info.type = "ToBooleanIC"; + ic_info.state = ToString(old_hints); + ic_info.state += "=>"; + ic_info.state += ToString(new_hints); + ic_stats->End(); + } else { + int line; + int column; + Address pc = GetAbstractPC(&line, &column); + LOG(isolate(), + ToBooleanIC(pc, line, column, *code, ToString(old_hints).c_str(), + ToString(new_hints).c_str())); + } + } + return isolate()->factory()->ToBoolean(to_boolean_value); } @@ -3101,7 +3104,7 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) { */ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) { HandleScope scope(isolate); - DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength); + DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength + 2); Handle<Name> name = args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex); Handle<Object> receiver = @@ -3140,11 +3143,13 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) { if (it.IsFound()) return *result; - LoadICNexus nexus(isolate); - LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); - // It could actually be any kind of LoadICs here but the predicate handles - // all the cases properly. - if (!ic.ShouldThrowReferenceError()) { + Handle<Smi> slot = args.at<Smi>(3); + Handle<FeedbackVector> vector = args.at<FeedbackVector>(4); + FeedbackSlot vector_slot = vector->ToSlot(slot->value()); + FeedbackSlotKind slot_kind = vector->GetKind(vector_slot); + // It could actually be any kind of load IC slot here but the predicate + // handles all the cases properly. + if (!LoadIC::ShouldThrowReferenceError(slot_kind)) { return isolate->heap()->undefined_value(); } @@ -3156,12 +3161,15 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) { RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) { HandleScope scope(isolate); - DCHECK(args.length() == 3); - StoreICNexus nexus(isolate); - StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); - Handle<JSObject> receiver = args.at<JSObject>(0); - Handle<Name> name = args.at<Name>(1); - Handle<Object> value = args.at(2); + DCHECK_EQ(5, args.length()); + // Runtime functions don't follow the IC's calling convention. + Handle<Object> value = args.at(0); + Handle<Smi> slot = args.at<Smi>(1); + Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); + Handle<JSObject> receiver = args.at<JSObject>(3); + Handle<Name> name = args.at<Name>(4); + FeedbackSlot vector_slot = vector->ToSlot(slot->value()); + LanguageMode language_mode = vector->GetLanguageMode(vector_slot); DCHECK(receiver->HasNamedInterceptor()); InterceptorInfo* interceptor = receiver->GetNamedInterceptor(); @@ -3186,7 +3194,7 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) { DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); it.Next(); - MAYBE_RETURN(Object::SetProperty(&it, value, ic.language_mode(), + MAYBE_RETURN(Object::SetProperty(&it, value, language_mode, JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED), isolate->heap()->exception()); return *value; diff --git a/deps/v8/src/ic/ic.h b/deps/v8/src/ic/ic.h index 74a034d0e7..c9818f5a5b 100644 --- a/deps/v8/src/ic/ic.h +++ b/deps/v8/src/ic/ic.h @@ -5,6 +5,8 @@ #ifndef V8_IC_H_ #define V8_IC_H_ +#include "src/factory.h" +#include "src/feedback-vector.h" #include "src/ic/ic-state.h" #include "src/macro-assembler.h" #include "src/messages.h" @@ -45,16 +47,12 @@ class IC { // Clear the inline cache to initial state. static void Clear(Isolate* isolate, Address address, Address constant_pool); -#ifdef DEBUG - bool IsLoadStub() const { - return kind_ == Code::LOAD_IC || kind_ == Code::LOAD_GLOBAL_IC || - kind_ == Code::KEYED_LOAD_IC; + bool IsAnyLoad() const { + return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC(); } - bool IsStoreStub() const { - return kind_ == Code::STORE_IC || kind_ == Code::KEYED_STORE_IC; + bool IsAnyStore() const { + return IsStoreIC() || IsStoreOwnIC() || IsKeyedStoreIC(); } - bool IsCallStub() const { return kind_ == Code::CALL_IC; } -#endif static inline Handle<Map> GetHandlerCacheHolder(Handle<Map> receiver_map, bool receiver_is_holder, @@ -64,15 +62,15 @@ class IC { Isolate* isolate, CacheHolderFlag* flag); - static bool IsCleared(FeedbackNexus* nexus) { - InlineCacheState state = nexus->StateFromFeedback(); - return !FLAG_use_ic || state == UNINITIALIZED || state == PREMONOMORPHIC; - } - static bool ICUseVector(Code::Kind kind) { return kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC || - kind == Code::KEYED_LOAD_IC || kind == Code::CALL_IC || - kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC; + kind == Code::KEYED_LOAD_IC || kind == Code::STORE_IC || + kind == Code::KEYED_STORE_IC; + } + static bool ICUseVector(FeedbackSlotKind kind) { + return IsLoadICKind(kind) || IsLoadGlobalICKind(kind) || + IsKeyedLoadICKind(kind) || IsStoreICKind(kind) || + IsStoreOwnICKind(kind) || IsKeyedStoreICKind(kind); } // The ICs that don't pass slot and vector through the stack have to @@ -83,15 +81,20 @@ class IC { static inline bool IsHandler(Object* object); + // Nofity the IC system that a feedback has changed. + static void OnFeedbackChanged(Isolate* isolate, JSFunction* host_function); + protected: Address fp() const { return fp_; } Address pc() const { return *pc_address_; } + + void set_slow_stub_reason(const char* reason) { slow_stub_reason_ = reason; } + + Address GetAbstractPC(int* line, int* column) const; Isolate* isolate() const { return isolate_; } - // Get the shared function info of the caller. - SharedFunctionInfo* GetSharedFunctionInfo() const; - // Get the code object of the caller. - Code* GetCode() const; + // Get the caller function object. + JSFunction* GetHostFunction() const; inline bool AddressIsDeoptimizedCode() const; inline static bool AddressIsDeoptimizedCode(Isolate* isolate, @@ -136,8 +139,6 @@ class IC { Address constant_pool); static inline void SetTargetAtAddress(Address address, Code* target, Address constant_pool); - // As a vector-based IC, type feedback must be updated differently. - static void OnTypeFeedbackChanged(Isolate* isolate, Code* host); static void PostPatching(Address address, Code* target, Code* old_target); void TraceHandlerCacheHitStats(LookupIterator* lookup); @@ -165,15 +166,18 @@ class IC { void CopyICToMegamorphicCache(Handle<Name> name); bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map); void PatchCache(Handle<Name> name, Handle<Object> code); - Code::Kind kind() const { return kind_; } - bool is_keyed() const { - return kind_ == Code::KEYED_LOAD_IC || kind_ == Code::KEYED_STORE_IC; - } + FeedbackSlotKind kind() const { return kind_; } + bool IsLoadIC() const { return IsLoadICKind(kind_); } + bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); } + bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); } + bool IsStoreIC() const { return IsStoreICKind(kind_); } + bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); } + bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); } + bool is_keyed() const { return IsKeyedLoadIC() || IsKeyedStoreIC(); } Code::Kind handler_kind() const { - if (kind_ == Code::KEYED_LOAD_IC) return Code::LOAD_IC; - DCHECK(kind_ == Code::LOAD_IC || kind_ == Code::STORE_IC || - kind_ == Code::KEYED_STORE_IC); - return kind_; + if (IsAnyLoad()) return Code::LOAD_IC; + DCHECK(IsAnyStore()); + return Code::STORE_IC; } bool ShouldRecomputeHandler(Handle<String> name); @@ -201,7 +205,7 @@ class IC { } Handle<FeedbackVector> vector() const { return nexus()->vector_handle(); } - FeedbackVectorSlot slot() const { return nexus()->slot(); } + FeedbackSlot slot() const { return nexus()->slot(); } State saved_state() const { return state() == RECOMPUTE_HANDLER ? old_state_ : state(); } @@ -212,7 +216,6 @@ class IC { } FeedbackNexus* nexus() const { return nexus_; } - inline Code* get_host(); inline Code* target() const; private: @@ -244,7 +247,7 @@ class IC { bool vector_set_; State old_state_; // For saving if we marked as prototype failure. State state_; - Code::Kind kind_; + FeedbackSlotKind kind_; Handle<Map> receiver_map_; MaybeHandle<Object> maybe_handler_; @@ -252,6 +255,8 @@ class IC { MapHandleList target_maps_; bool target_maps_set_; + const char* slow_stub_reason_; + FeedbackNexus* nexus_; DISALLOW_IMPLICIT_CONSTRUCTORS(IC); @@ -264,32 +269,28 @@ class CallIC : public IC { : IC(EXTRA_CALL_FRAME, isolate, nexus) { DCHECK(nexus != NULL); } - - void HandleMiss(Handle<Object> function); - - static void Clear(Isolate* isolate, Code* host, CallICNexus* nexus); }; class LoadIC : public IC { public: - LoadIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL) - : IC(depth, isolate, nexus) { + LoadIC(Isolate* isolate, FeedbackNexus* nexus) + : IC(NO_EXTRA_FRAME, isolate, nexus) { DCHECK(nexus != NULL); - DCHECK(IsLoadStub()); + DCHECK(IsAnyLoad()); + } + + static bool ShouldThrowReferenceError(FeedbackSlotKind kind) { + return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof; } bool ShouldThrowReferenceError() const { - return kind() == Code::LOAD_GLOBAL_IC && - LoadGlobalICState::GetTypeofMode(extra_ic_state()) == - NOT_INSIDE_TYPEOF; + return ShouldThrowReferenceError(kind()); } MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object, Handle<Name> name); - static void Clear(Isolate* isolate, Code* host, LoadICNexus* nexus); - protected: virtual Handle<Code> slow_stub() const { return isolate()->builtins()->LoadIC_Slow(); @@ -324,13 +325,11 @@ class LoadIC : public IC { class LoadGlobalIC : public LoadIC { public: - LoadGlobalIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL) - : LoadIC(depth, isolate, nexus) {} + LoadGlobalIC(Isolate* isolate, FeedbackNexus* nexus) + : LoadIC(isolate, nexus) {} MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Name> name); - static void Clear(Isolate* isolate, Code* host, LoadGlobalICNexus* nexus); - protected: Handle<Code> slow_stub() const override { return isolate()->builtins()->LoadGlobalIC_Slow(); @@ -339,17 +338,14 @@ class LoadGlobalIC : public LoadIC { class KeyedLoadIC : public LoadIC { public: - KeyedLoadIC(FrameDepth depth, Isolate* isolate, - KeyedLoadICNexus* nexus = NULL) - : LoadIC(depth, isolate, nexus) { + KeyedLoadIC(Isolate* isolate, KeyedLoadICNexus* nexus) + : LoadIC(isolate, nexus) { DCHECK(nexus != NULL); } MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object, Handle<Object> key); - static void Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus); - protected: // receiver is HeapObject because it could be a String or a JSObject void UpdateLoadElement(Handle<HeapObject> receiver); @@ -361,13 +357,13 @@ class KeyedLoadIC : public LoadIC { class StoreIC : public IC { public: - StoreIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL) - : IC(depth, isolate, nexus) { - DCHECK(IsStoreStub()); + StoreIC(Isolate* isolate, FeedbackNexus* nexus) + : IC(NO_EXTRA_FRAME, isolate, nexus) { + DCHECK(IsAnyStore()); } LanguageMode language_mode() const { - return StoreICState::GetLanguageMode(extra_ic_state()); + return nexus()->vector()->GetLanguageMode(nexus()->slot()); } MUST_USE_RESULT MaybeHandle<Object> Store( @@ -378,20 +374,11 @@ class StoreIC : public IC { bool LookupForWrite(LookupIterator* it, Handle<Object> value, JSReceiver::StoreFromKeyed store_mode); - static void Clear(Isolate* isolate, Code* host, StoreICNexus* nexus); - protected: // Stub accessors. Handle<Code> slow_stub() const { - switch (language_mode()) { - case SLOPPY: - return isolate()->builtins()->StoreIC_SlowSloppy(); - case STRICT: - return isolate()->builtins()->StoreIC_SlowStrict(); - default: - UNREACHABLE(); - return Handle<Code>(); - } + // StoreIC and KeyedStoreIC share the same slow stub. + return isolate()->builtins()->KeyedStoreIC_Slow(); } // Update the inline cache and the global stub cache based on the @@ -423,22 +410,13 @@ class KeyedStoreIC : public StoreIC { return casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode(); } - KeyedStoreIC(FrameDepth depth, Isolate* isolate, - KeyedStoreICNexus* nexus = NULL) - : StoreIC(depth, isolate, nexus) {} + KeyedStoreIC(Isolate* isolate, KeyedStoreICNexus* nexus) + : StoreIC(isolate, nexus) {} MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object, Handle<Object> name, Handle<Object> value); - // Code generators for stub routines. Only called once at startup. - static void GenerateMiss(MacroAssembler* masm); - static void GenerateSlow(MacroAssembler* masm); - static void GenerateMegamorphic(MacroAssembler* masm, - LanguageMode language_mode); - - static void Clear(Isolate* isolate, Code* host, KeyedStoreICNexus* nexus); - protected: void UpdateStoreElement(Handle<Map> receiver_map, KeyedAccessStoreMode store_mode); @@ -447,6 +425,14 @@ class KeyedStoreIC : public StoreIC { Handle<Map> ComputeTransitionedMap(Handle<Map> map, KeyedAccessStoreMode store_mode); + Handle<Object> StoreElementHandler(Handle<Map> receiver_map, + KeyedAccessStoreMode store_mode); + + void StoreElementPolymorphicHandlers(MapHandleList* receiver_maps, + MapHandleList* transitioned_maps, + List<Handle<Object>>* handlers, + KeyedAccessStoreMode store_mode); + friend class IC; }; diff --git a/deps/v8/src/ic/keyed-store-generic.cc b/deps/v8/src/ic/keyed-store-generic.cc index 81ce3a6a1f..8962386c93 100644 --- a/deps/v8/src/ic/keyed-store-generic.cc +++ b/deps/v8/src/ic/keyed-store-generic.cc @@ -7,19 +7,20 @@ #include "src/code-factory.h" #include "src/code-stub-assembler.h" #include "src/contexts.h" -#include "src/ic/accessor-assembler-impl.h" +#include "src/ic/accessor-assembler.h" #include "src/interface-descriptors.h" #include "src/isolate.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { using compiler::Node; -class KeyedStoreGenericAssembler : public AccessorAssemblerImpl { +class KeyedStoreGenericAssembler : public AccessorAssembler { public: explicit KeyedStoreGenericAssembler(compiler::CodeAssemblerState* state) - : AccessorAssemblerImpl(state) {} + : AccessorAssembler(state) {} void KeyedStoreGeneric(LanguageMode language_mode); @@ -72,6 +73,13 @@ class KeyedStoreGenericAssembler : public AccessorAssemblerImpl { Variable* var_accessor_pair, Variable* var_accessor_holder, Label* readonly, Label* bailout); + + void CheckFieldType(Node* descriptors, Node* name_index, Node* representation, + Node* value, Label* bailout); + void OverwriteExistingFastProperty(Node* object, Node* object_map, + Node* properties, Node* descriptors, + Node* descriptor_name_index, Node* details, + Node* value, Label* slow); }; void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state, @@ -266,7 +274,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( // can always be stored. { Label non_smi_value(this); - GotoUnless(TaggedIsSmi(value), &non_smi_value); + GotoIfNot(TaggedIsSmi(value), &non_smi_value); // If we're about to introduce holes, ensure holey elements. if (update_length == kBumpLengthWithGap) { TryChangeToHoleyMapMulti(receiver, receiver_map, elements_kind, context, @@ -461,6 +469,8 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore( // Out-of-capacity accesses (index >= capacity) jump here. Additionally, // an ElementsKind transition might be necessary. + // The index can also be negative at this point! Jump to the runtime in that + // case to convert it to a named property. Bind(&if_grow); { Comment("Grow backing store"); @@ -537,16 +547,12 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( { Node* descriptors = var_meta_storage.value(); Node* name_index = var_entry.value(); - // TODO(jkummerow): Add helper functions for accessing value and - // details by entry. - const int kNameToDetailsOffset = (DescriptorArray::kDescriptorDetails - - DescriptorArray::kDescriptorKey) * - kPointerSize; - Node* details = LoadAndUntagToWord32FixedArrayElement( - descriptors, name_index, kNameToDetailsOffset); + Node* details = + LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index); JumpIfDataProperty(details, &ok_to_write, readonly); // Accessor case. + // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject. Variable var_details(this, MachineRepresentation::kWord32); LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index, &var_details, var_accessor_pair); @@ -558,19 +564,13 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( { Node* dictionary = var_meta_storage.value(); Node* entry = var_entry.value(); - const int kNameToDetailsOffset = (NameDictionary::kEntryDetailsIndex - - NameDictionary::kEntryKeyIndex) * - kPointerSize; - Node* details = LoadAndUntagToWord32FixedArrayElement( - dictionary, entry, kNameToDetailsOffset); + Node* details = + LoadDetailsByKeyIndex<NameDictionary>(dictionary, entry); JumpIfDataProperty(details, &ok_to_write, readonly); // Accessor case. - const int kNameToValueOffset = (NameDictionary::kEntryValueIndex - - NameDictionary::kEntryKeyIndex) * - kPointerSize; var_accessor_pair->Bind( - LoadFixedArrayElement(dictionary, entry, kNameToValueOffset)); + LoadValueByKeyIndex<NameDictionary>(dictionary, entry)); var_accessor_holder->Bind(holder); Goto(accessor); } @@ -579,13 +579,8 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( { Node* dictionary = var_meta_storage.value(); Node* entry = var_entry.value(); - const int kNameToValueOffset = (GlobalDictionary::kEntryValueIndex - - GlobalDictionary::kEntryKeyIndex) * - kPointerSize; - Node* property_cell = - LoadFixedArrayElement(dictionary, entry, kNameToValueOffset); - + LoadValueByKeyIndex<GlobalDictionary>(dictionary, entry); Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset); GotoIf(WordEqual(value, TheHoleConstant()), &next_proto); @@ -613,6 +608,146 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( Bind(&ok_to_write); } +void KeyedStoreGenericAssembler::CheckFieldType(Node* descriptors, + Node* name_index, + Node* representation, + Node* value, Label* bailout) { + Label r_smi(this), r_double(this), r_heapobject(this), all_fine(this); + // Ignore FLAG_track_fields etc. and always emit code for all checks, + // because this builtin is part of the snapshot and therefore should + // be flag independent. + GotoIf(Word32Equal(representation, Int32Constant(Representation::kSmi)), + &r_smi); + GotoIf(Word32Equal(representation, Int32Constant(Representation::kDouble)), + &r_double); + GotoIf( + Word32Equal(representation, Int32Constant(Representation::kHeapObject)), + &r_heapobject); + GotoIf(Word32Equal(representation, Int32Constant(Representation::kNone)), + bailout); + CSA_ASSERT(this, Word32Equal(representation, + Int32Constant(Representation::kTagged))); + Goto(&all_fine); + + Bind(&r_smi); + { Branch(TaggedIsSmi(value), &all_fine, bailout); } + + Bind(&r_double); + { + GotoIf(TaggedIsSmi(value), &all_fine); + Node* value_map = LoadMap(value); + // While supporting mutable HeapNumbers would be straightforward, such + // objects should not end up here anyway. + CSA_ASSERT(this, + WordNotEqual(value_map, + LoadRoot(Heap::kMutableHeapNumberMapRootIndex))); + Branch(IsHeapNumberMap(value_map), &all_fine, bailout); + } + + Bind(&r_heapobject); + { + GotoIf(TaggedIsSmi(value), bailout); + Node* field_type = + LoadValueByKeyIndex<DescriptorArray>(descriptors, name_index); + intptr_t kNoneType = reinterpret_cast<intptr_t>(FieldType::None()); + intptr_t kAnyType = reinterpret_cast<intptr_t>(FieldType::Any()); + // FieldType::None can't hold any value. + GotoIf(WordEqual(field_type, IntPtrConstant(kNoneType)), bailout); + // FieldType::Any can hold any value. + GotoIf(WordEqual(field_type, IntPtrConstant(kAnyType)), &all_fine); + CSA_ASSERT(this, IsWeakCell(field_type)); + // Cleared WeakCells count as FieldType::None, which can't hold any value. + field_type = LoadWeakCellValue(field_type, bailout); + // FieldType::Class(...) performs a map check. + CSA_ASSERT(this, IsMap(field_type)); + Branch(WordEqual(LoadMap(value), field_type), &all_fine, bailout); + } + + Bind(&all_fine); +} + +void KeyedStoreGenericAssembler::OverwriteExistingFastProperty( + Node* object, Node* object_map, Node* properties, Node* descriptors, + Node* descriptor_name_index, Node* details, Node* value, Label* slow) { + // Properties in descriptors can't be overwritten without map transition. + GotoIf(Word32NotEqual(DecodeWord32<PropertyDetails::LocationField>(details), + Int32Constant(kField)), + slow); + + if (FLAG_track_constant_fields) { + // TODO(ishell): Taking the slow path is not necessary if new and old + // values are identical. + GotoIf(Word32Equal(DecodeWord32<PropertyDetails::ConstnessField>(details), + Int32Constant(kConst)), + slow); + } + + Label done(this); + Node* representation = + DecodeWord32<PropertyDetails::RepresentationField>(details); + + CheckFieldType(descriptors, descriptor_name_index, representation, value, + slow); + Node* field_index = + DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details); + Node* inobject_properties = LoadMapInobjectProperties(object_map); + + Label inobject(this), backing_store(this); + Branch(UintPtrLessThan(field_index, inobject_properties), &inobject, + &backing_store); + + Bind(&inobject); + { + Node* field_offset = + IntPtrMul(IntPtrSub(LoadMapInstanceSize(object_map), + IntPtrSub(inobject_properties, field_index)), + IntPtrConstant(kPointerSize)); + Label tagged_rep(this), double_rep(this); + Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)), + &double_rep, &tagged_rep); + Bind(&double_rep); + { + Node* double_value = ChangeNumberToFloat64(value); + if (FLAG_unbox_double_fields) { + StoreObjectFieldNoWriteBarrier(object, field_offset, double_value, + MachineRepresentation::kFloat64); + } else { + Node* mutable_heap_number = LoadObjectField(object, field_offset); + StoreHeapNumberValue(mutable_heap_number, double_value); + } + Goto(&done); + } + + Bind(&tagged_rep); + { + StoreObjectField(object, field_offset, value); + Goto(&done); + } + } + + Bind(&backing_store); + { + Node* backing_store_index = IntPtrSub(field_index, inobject_properties); + Label tagged_rep(this), double_rep(this); + Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)), + &double_rep, &tagged_rep); + Bind(&double_rep); + { + Node* double_value = ChangeNumberToFloat64(value); + Node* mutable_heap_number = + LoadFixedArrayElement(properties, backing_store_index); + StoreHeapNumberValue(mutable_heap_number, double_value); + Goto(&done); + } + Bind(&tagged_rep); + { + StoreFixedArrayElement(properties, backing_store_index, value); + Goto(&done); + } + } + Bind(&done); +} + void KeyedStoreGenericAssembler::EmitGenericPropertyStore( Node* receiver, Node* receiver_map, const StoreICParameters* p, Label* slow, LanguageMode language_mode) { @@ -627,10 +762,40 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( Bind(&fast_properties); { - // TODO(jkummerow): Does it make sense to support some cases here inline? - // Maybe overwrite existing writable properties? - // Maybe support map transitions? - Goto(&stub_cache); + Comment("fast property store"); + Node* bitfield3 = LoadMapBitField3(receiver_map); + Node* descriptors = LoadMapDescriptors(receiver_map); + Label descriptor_found(this); + Variable var_name_index(this, MachineType::PointerRepresentation()); + // TODO(jkummerow): Maybe look for existing map transitions? + Label* notfound = &stub_cache; + DescriptorLookup(p->name, descriptors, bitfield3, &descriptor_found, + &var_name_index, notfound); + + Bind(&descriptor_found); + { + Node* name_index = var_name_index.value(); + Node* details = + LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index); + Label data_property(this); + JumpIfDataProperty(details, &data_property, &readonly); + + // Accessor case. + // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject. + Variable var_details(this, MachineRepresentation::kWord32); + LoadPropertyFromFastObject(receiver, receiver_map, descriptors, + name_index, &var_details, &var_accessor_pair); + var_accessor_holder.Bind(receiver); + Goto(&accessor); + + Bind(&data_property); + { + OverwriteExistingFastProperty(receiver, receiver_map, properties, + descriptors, name_index, details, + p->value, slow); + Return(p->value); + } + } } Bind(&dictionary_properties); @@ -646,26 +811,20 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( Bind(&dictionary_found); { Label overwrite(this); - const int kNameToDetailsOffset = (NameDictionary::kEntryDetailsIndex - - NameDictionary::kEntryKeyIndex) * - kPointerSize; - Node* details = LoadAndUntagToWord32FixedArrayElement( - properties, var_name_index.value(), kNameToDetailsOffset); + Node* details = LoadDetailsByKeyIndex<NameDictionary>( + properties, var_name_index.value()); JumpIfDataProperty(details, &overwrite, &readonly); // Accessor case. - const int kNameToValueOffset = - (NameDictionary::kEntryValueIndex - NameDictionary::kEntryKeyIndex) * - kPointerSize; - var_accessor_pair.Bind(LoadFixedArrayElement( - properties, var_name_index.value(), kNameToValueOffset)); + var_accessor_pair.Bind(LoadValueByKeyIndex<NameDictionary>( + properties, var_name_index.value())); var_accessor_holder.Bind(receiver); Goto(&accessor); Bind(&overwrite); { - StoreFixedArrayElement(properties, var_name_index.value(), p->value, - UPDATE_WRITE_BARRIER, kNameToValueOffset); + StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(), + p->value); Return(p->value); } } @@ -690,7 +849,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( Node* setter_map = LoadMap(setter); // FunctionTemplateInfo setters are not supported yet. GotoIf(IsFunctionTemplateInfoMap(setter_map), slow); - GotoUnless(IsCallableMap(setter_map), ¬_callable); + GotoIfNot(IsCallableMap(setter_map), ¬_callable); Callable callable = CodeFactory::Call(isolate()); CallJS(callable, p->context, setter, receiver, p->value); @@ -734,7 +893,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( Bind(&found_handler); { Comment("KeyedStoreGeneric found handler"); - HandleStoreICHandlerCase(p, var_handler.value(), slow); + HandleStoreICHandlerCase(p, var_handler.value(), &stub_cache_miss); } Bind(&stub_cache_miss); { @@ -756,6 +915,8 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) { Node* context = Parameter(Descriptor::kContext); Variable var_index(this, MachineType::PointerRepresentation()); + Variable var_unique(this, MachineRepresentation::kTagged); + var_unique.Bind(name); // Dummy initialization. Label if_index(this), if_unique_name(this), slow(this); GotoIf(TaggedIsSmi(receiver), &slow); @@ -767,7 +928,7 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) { Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)), &slow); - TryToName(name, &if_index, &var_index, &if_unique_name, &slow); + TryToName(name, &if_index, &var_index, &if_unique_name, &var_unique, &slow); Bind(&if_index); { @@ -779,8 +940,8 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) { Bind(&if_unique_name); { Comment("key is unique name"); - KeyedStoreGenericAssembler::StoreICParameters p(context, receiver, name, - value, slot, vector); + StoreICParameters p(context, receiver, var_unique.value(), value, slot, + vector); EmitGenericPropertyStore(receiver, receiver_map, &p, &slow, language_mode); } diff --git a/deps/v8/src/ic/mips/handler-compiler-mips.cc b/deps/v8/src/ic/mips/handler-compiler-mips.cc index 43588b707a..c14652cf47 100644 --- a/deps/v8/src/ic/mips/handler-compiler-mips.cc +++ b/deps/v8/src/ic/mips/handler-compiler-mips.cc @@ -173,15 +173,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); } -void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( - MacroAssembler* masm, Register receiver, Register scratch1, - Register scratch2, Label* miss_label) { - __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); - __ Ret(USE_DELAY_SLOT); - __ mov(v0, scratch1); -} - - // Generate code to check that a global property cell is empty. Create // the property cell at compilation time if no cell exists for the // property. @@ -199,24 +190,18 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ Branch(miss, ne, scratch, Operand(at)); } +static void CompileCallLoadPropertyWithInterceptor( + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, Runtime::FunctionId id) { + DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == + Runtime::FunctionForId(id)->nargs); -static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, - Register holder, Register name, - Handle<JSObject> holder_obj) { STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); __ Push(name, receiver, holder); -} - -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); __ CallRuntime(id); } @@ -512,8 +497,18 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { // Call the runtime system to load the interceptor. DCHECK(holder()->HasNamedInterceptor()); DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), - holder()); + + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); + __ Push(name(), receiver(), holder_reg); + // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. + if (holder_reg.is(receiver())) { + __ Push(slot(), vector()); + } else { + __ Push(scratch3(), scratch2()); // slot, vector + } __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); } diff --git a/deps/v8/src/ic/mips/ic-mips.cc b/deps/v8/src/ic/mips/ic-mips.cc index e31aab1d76..fd39972f0e 100644 --- a/deps/v8/src/ic/mips/ic-mips.cc +++ b/deps/v8/src/ic/mips/ic-mips.cc @@ -6,45 +6,12 @@ #include "src/codegen.h" #include "src/ic/ic.h" -#include "src/ic/ic-compiler.h" #include "src/ic/stub-cache.h" namespace v8 { namespace internal { -// ---------------------------------------------------------------------------- -// Static IC stub generators. -// - -#define __ ACCESS_MASM(masm) - -static void StoreIC_PushArgs(MacroAssembler* masm) { - __ Push(StoreWithVectorDescriptor::ValueRegister(), - StoreWithVectorDescriptor::SlotRegister(), - StoreWithVectorDescriptor::VectorRegister(), - StoreWithVectorDescriptor::ReceiverRegister(), - StoreWithVectorDescriptor::NameRegister()); -} - - -void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { - StoreIC_PushArgs(masm); - - __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); -} - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - StoreIC_PushArgs(masm); - - // 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. - __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow); -} - -#undef __ - - Condition CompareIC::ComputeCondition(Token::Value op) { switch (op) { case Token::EQ_STRICT: @@ -102,9 +69,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address, } if (FLAG_trace_ic) { - PrintF("[ patching ic at %p, andi=%p, delta=%d\n", - static_cast<void*>(address), - static_cast<void*>(andi_instruction_address), delta); + LOG(isolate, PatchIC(address, andi_instruction_address, delta)); } Address patch_address = diff --git a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc index 06af88d19e..1a38d329e7 100644 --- a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc +++ b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc @@ -173,15 +173,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); } -void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( - MacroAssembler* masm, Register receiver, Register scratch1, - Register scratch2, Label* miss_label) { - __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); - __ Ret(USE_DELAY_SLOT); - __ mov(v0, scratch1); -} - - // Generate code to check that a global property cell is empty. Create // the property cell at compilation time if no cell exists for the // property. @@ -199,24 +190,18 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ Branch(miss, ne, scratch, Operand(at)); } +static void CompileCallLoadPropertyWithInterceptor( + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, Runtime::FunctionId id) { + DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == + Runtime::FunctionForId(id)->nargs); -static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, - Register holder, Register name, - Handle<JSObject> holder_obj) { STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); __ Push(name, receiver, holder); -} - -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); __ CallRuntime(id); } @@ -512,8 +497,18 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { // Call the runtime system to load the interceptor. DCHECK(holder()->HasNamedInterceptor()); DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), - holder()); + + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); + __ Push(name(), receiver(), holder_reg); + // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. + if (holder_reg.is(receiver())) { + __ Push(slot(), vector()); + } else { + __ Push(scratch3(), scratch2()); // slot, vector + } __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); } diff --git a/deps/v8/src/ic/mips64/ic-mips64.cc b/deps/v8/src/ic/mips64/ic-mips64.cc index fa351ba5a3..0e2032a41d 100644 --- a/deps/v8/src/ic/mips64/ic-mips64.cc +++ b/deps/v8/src/ic/mips64/ic-mips64.cc @@ -6,45 +6,12 @@ #include "src/codegen.h" #include "src/ic/ic.h" -#include "src/ic/ic-compiler.h" #include "src/ic/stub-cache.h" namespace v8 { namespace internal { -// ---------------------------------------------------------------------------- -// Static IC stub generators. -// - -#define __ ACCESS_MASM(masm) - -static void StoreIC_PushArgs(MacroAssembler* masm) { - __ Push(StoreWithVectorDescriptor::ValueRegister(), - StoreWithVectorDescriptor::SlotRegister(), - StoreWithVectorDescriptor::VectorRegister(), - StoreWithVectorDescriptor::ReceiverRegister(), - StoreWithVectorDescriptor::NameRegister()); -} - - -void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { - StoreIC_PushArgs(masm); - - __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); -} - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - StoreIC_PushArgs(masm); - - // 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. - __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow); -} - -#undef __ - - Condition CompareIC::ComputeCondition(Token::Value op) { switch (op) { case Token::EQ_STRICT: @@ -102,9 +69,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address, } if (FLAG_trace_ic) { - PrintF("[ patching ic at %p, andi=%p, delta=%d\n", - static_cast<void*>(address), - static_cast<void*>(andi_instruction_address), delta); + LOG(isolate, PatchIC(address, andi_instruction_address, delta)); } Address patch_address = diff --git a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc index d4edcc1ec9..3da558d10e 100644 --- a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc +++ b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc @@ -176,15 +176,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); } -void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( - MacroAssembler* masm, Register receiver, Register scratch1, - Register scratch2, Label* miss_label) { - __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); - __ mr(r3, scratch1); - __ Ret(); -} - - // Generate code to check that a global property cell is empty. Create // the property cell at compilation time if no cell exists for the // property. @@ -204,25 +195,18 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( } -static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, - Register holder, Register name, - Handle<JSObject> holder_obj) { - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ push(name); - __ push(receiver); - __ push(holder); -} - - static void CompileCallLoadPropertyWithInterceptor( MacroAssembler* masm, Register receiver, Register holder, Register name, Handle<JSObject> holder_obj, Runtime::FunctionId id) { DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == Runtime::FunctionForId(id)->nargs); - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); + + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); + __ Push(name, receiver, holder); + __ CallRuntime(id); } @@ -530,8 +514,18 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { // Call the runtime system to load the interceptor. DCHECK(holder()->HasNamedInterceptor()); DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), - holder()); + + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); + __ Push(name(), receiver(), holder_reg); + // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. + if (holder_reg.is(receiver())) { + __ Push(slot(), vector()); + } else { + __ Push(scratch3(), scratch2()); // slot, vector + } __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); } diff --git a/deps/v8/src/ic/ppc/ic-ppc.cc b/deps/v8/src/ic/ppc/ic-ppc.cc index 3c325d8f92..0f25846870 100644 --- a/deps/v8/src/ic/ppc/ic-ppc.cc +++ b/deps/v8/src/ic/ppc/ic-ppc.cc @@ -6,45 +6,12 @@ #include "src/codegen.h" #include "src/ic/ic.h" -#include "src/ic/ic-compiler.h" #include "src/ic/stub-cache.h" namespace v8 { namespace internal { -// ---------------------------------------------------------------------------- -// Static IC stub generators. -// - -#define __ ACCESS_MASM(masm) - -static void StoreIC_PushArgs(MacroAssembler* masm) { - __ Push(StoreWithVectorDescriptor::ValueRegister(), - StoreWithVectorDescriptor::SlotRegister(), - StoreWithVectorDescriptor::VectorRegister(), - StoreWithVectorDescriptor::ReceiverRegister(), - StoreWithVectorDescriptor::NameRegister()); -} - - -void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { - StoreIC_PushArgs(masm); - - __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); -} - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - StoreIC_PushArgs(masm); - - // 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. - __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow); -} - -#undef __ - - Condition CompareIC::ComputeCondition(Token::Value op) { switch (op) { case Token::EQ_STRICT: @@ -103,9 +70,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address, } if (FLAG_trace_ic) { - PrintF("[ patching ic at %p, cmp=%p, delta=%d\n", - static_cast<void*>(address), - static_cast<void*>(cmp_instruction_address), delta); + LOG(isolate, PatchIC(address, cmp_instruction_address, delta)); } Address patch_address = diff --git a/deps/v8/src/ic/s390/handler-compiler-s390.cc b/deps/v8/src/ic/s390/handler-compiler-s390.cc index 40a8c310d8..9f087977a1 100644 --- a/deps/v8/src/ic/s390/handler-compiler-s390.cc +++ b/deps/v8/src/ic/s390/handler-compiler-s390.cc @@ -169,14 +169,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); } -void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( - MacroAssembler* masm, Register receiver, Register scratch1, - Register scratch2, Label* miss_label) { - __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); - __ LoadRR(r2, scratch1); - __ Ret(); -} - // Generate code to check that a global property cell is empty. Create // the property cell at compilation time if no cell exists for the // property. @@ -194,24 +186,18 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ bne(miss); } -static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, - Register holder, Register name, - Handle<JSObject> holder_obj) { - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name); - __ Push(receiver); - __ Push(holder); -} - static void CompileCallLoadPropertyWithInterceptor( MacroAssembler* masm, Register receiver, Register holder, Register name, Handle<JSObject> holder_obj, Runtime::FunctionId id) { DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == Runtime::FunctionForId(id)->nargs); - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); + + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); + __ Push(name, receiver, holder); + __ CallRuntime(id); } @@ -508,8 +494,18 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { // Call the runtime system to load the interceptor. DCHECK(holder()->HasNamedInterceptor()); DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), - holder()); + + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); + __ Push(name(), receiver(), holder_reg); + // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. + if (holder_reg.is(receiver())) { + __ Push(slot(), vector()); + } else { + __ Push(scratch3(), scratch2()); // slot, vector + } __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); } diff --git a/deps/v8/src/ic/s390/ic-s390.cc b/deps/v8/src/ic/s390/ic-s390.cc index 6438cfca47..494a4cd1d7 100644 --- a/deps/v8/src/ic/s390/ic-s390.cc +++ b/deps/v8/src/ic/s390/ic-s390.cc @@ -6,41 +6,11 @@ #include "src/ic/ic.h" #include "src/codegen.h" -#include "src/ic/ic-compiler.h" #include "src/ic/stub-cache.h" namespace v8 { namespace internal { -// ---------------------------------------------------------------------------- -// Static IC stub generators. -// - -#define __ ACCESS_MASM(masm) - -static void StoreIC_PushArgs(MacroAssembler* masm) { - __ Push(StoreWithVectorDescriptor::ValueRegister(), - StoreWithVectorDescriptor::SlotRegister(), - StoreWithVectorDescriptor::VectorRegister(), - StoreWithVectorDescriptor::ReceiverRegister(), - StoreWithVectorDescriptor::NameRegister()); -} - -void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { - StoreIC_PushArgs(masm); - - __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); -} - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - StoreIC_PushArgs(masm); - - // 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. - __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow); -} - -#undef __ Condition CompareIC::ComputeCondition(Token::Value op) { switch (op) { @@ -100,9 +70,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address, } if (FLAG_trace_ic) { - PrintF("[ patching ic at %p, cmp=%p, delta=%d\n", - static_cast<void*>(address), - static_cast<void*>(cmp_instruction_address), delta); + LOG(isolate, PatchIC(address, cmp_instruction_address, delta)); } // Expected sequence to enable by changing the following diff --git a/deps/v8/src/ic/stub-cache.cc b/deps/v8/src/ic/stub-cache.cc index 84dbf48436..5fc8cc318d 100644 --- a/deps/v8/src/ic/stub-cache.cc +++ b/deps/v8/src/ic/stub-cache.cc @@ -6,6 +6,8 @@ #include "src/ast/ast.h" #include "src/base/bits.h" +#include "src/counters.h" +#include "src/heap/heap.h" #include "src/ic/ic-inl.h" #include "src/type-info.h" @@ -99,12 +101,12 @@ void StubCache::Clear() { Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal); for (int i = 0; i < kPrimaryTableSize; i++) { primary_[i].key = isolate()->heap()->empty_string(); - primary_[i].map = NULL; + primary_[i].map = nullptr; primary_[i].value = empty; } for (int j = 0; j < kSecondaryTableSize; j++) { secondary_[j].key = isolate()->heap()->empty_string(); - secondary_[j].map = NULL; + secondary_[j].map = nullptr; secondary_[j].value = empty; } } @@ -116,9 +118,9 @@ void StubCache::CollectMatchingMaps(SmallMapList* types, Handle<Name> name, for (int i = 0; i < kPrimaryTableSize; i++) { if (primary_[i].key == *name) { Map* map = primary_[i].map; - // Map can be NULL, if the stub is constant function call + // Map can be nullptr, if the stub is constant function call // with a primitive receiver. - if (map == NULL) continue; + if (map == nullptr) continue; int offset = PrimaryOffset(*name, map); if (entry(primary_, offset) == &primary_[i] && @@ -131,9 +133,9 @@ void StubCache::CollectMatchingMaps(SmallMapList* types, Handle<Name> name, for (int i = 0; i < kSecondaryTableSize; i++) { if (secondary_[i].key == *name) { Map* map = secondary_[i].map; - // Map can be NULL, if the stub is constant function call + // Map can be nullptr, if the stub is constant function call // with a primitive receiver. - if (map == NULL) continue; + if (map == nullptr) continue; // Lookup in primary table and skip duplicates. int primary_offset = PrimaryOffset(*name, map); diff --git a/deps/v8/src/ic/stub-cache.h b/deps/v8/src/ic/stub-cache.h index e8df26d37b..4054b329d3 100644 --- a/deps/v8/src/ic/stub-cache.h +++ b/deps/v8/src/ic/stub-cache.h @@ -74,7 +74,7 @@ class StubCache { return StubCache::secondary_; } UNREACHABLE(); - return NULL; + return nullptr; } Isolate* isolate() { return isolate_; } @@ -92,7 +92,7 @@ class StubCache { // Some magic number used in primary and secondary hash computations. static const int kPrimaryMagic = 0x3d532433; - static const int kSecondaryMagic = 0xb16b00b5; + static const int kSecondaryMagic = 0xb16ca6e5; static int PrimaryOffsetForTesting(Name* name, Map* map) { return PrimaryOffset(name, map); diff --git a/deps/v8/src/ic/x64/access-compiler-x64.cc b/deps/v8/src/ic/x64/access-compiler-x64.cc index 9e95b9506c..4bbbba5b5a 100644 --- a/deps/v8/src/ic/x64/access-compiler-x64.cc +++ b/deps/v8/src/ic/x64/access-compiler-x64.cc @@ -5,6 +5,7 @@ #if V8_TARGET_ARCH_X64 #include "src/ic/access-compiler.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { diff --git a/deps/v8/src/ic/x64/handler-compiler-x64.cc b/deps/v8/src/ic/x64/handler-compiler-x64.cc index a89afa8a7e..425ed4762e 100644 --- a/deps/v8/src/ic/x64/handler-compiler-x64.cc +++ b/deps/v8/src/ic/x64/handler-compiler-x64.cc @@ -83,18 +83,12 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( __ DecrementCounter(counters->negative_lookups_miss(), 1); } -void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( - MacroAssembler* masm, Register receiver, Register result, Register scratch, - Label* miss_label) { - __ TryGetFunctionPrototype(receiver, result, miss_label); - if (!result.is(rax)) __ movp(rax, result); - __ ret(0); -} - +static void CompileCallLoadPropertyWithInterceptor( + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, Runtime::FunctionId id) { + DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == + Runtime::FunctionForId(id)->nargs); -static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, - Register holder, Register name, - Handle<JSObject> holder_obj) { STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); @@ -102,15 +96,7 @@ static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, __ Push(name); __ Push(receiver); __ Push(holder); -} - -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); __ CallRuntime(id); } @@ -524,10 +510,26 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { // Call the runtime system to load the interceptor. DCHECK(holder()->HasNamedInterceptor()); DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - __ PopReturnAddressTo(scratch2()); - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), - holder()); - __ PushReturnAddressFrom(scratch2()); + + // Stack: + // return address + + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); + __ Push(receiver()); + __ Push(holder_reg); + // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. + if (holder_reg.is(receiver())) { + __ Push(slot()); + __ Push(vector()); + } else { + __ Push(scratch3()); // slot + __ Push(scratch2()); // vector + } + __ Push(Operand(rsp, 4 * kPointerSize)); // return address + __ movp(Operand(rsp, 5 * kPointerSize), name()); __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); } diff --git a/deps/v8/src/ic/x64/ic-x64.cc b/deps/v8/src/ic/x64/ic-x64.cc index 587ebd3daa..3b87bc9b6a 100644 --- a/deps/v8/src/ic/x64/ic-x64.cc +++ b/deps/v8/src/ic/x64/ic-x64.cc @@ -6,54 +6,12 @@ #include "src/codegen.h" #include "src/ic/ic.h" -#include "src/ic/ic-compiler.h" #include "src/ic/stub-cache.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { -// ---------------------------------------------------------------------------- -// Static IC stub generators. -// - -#define __ ACCESS_MASM(masm) - -static void StoreIC_PushArgs(MacroAssembler* masm) { - Register receiver = StoreWithVectorDescriptor::ReceiverRegister(); - Register name = StoreWithVectorDescriptor::NameRegister(); - Register value = StoreWithVectorDescriptor::ValueRegister(); - Register slot = StoreWithVectorDescriptor::SlotRegister(); - Register vector = StoreWithVectorDescriptor::VectorRegister(); - Register temp = r11; - DCHECK(!AreAliased(receiver, name, value, slot, vector, temp)); - - __ PopReturnAddressTo(temp); - __ Push(value); - __ Push(slot); - __ Push(vector); - __ Push(receiver); - __ Push(name); - __ PushReturnAddressFrom(temp); -} - -void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { - // Return address is on the stack. - StoreIC_PushArgs(masm); - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); -} - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - // Return address is on the stack. - StoreIC_PushArgs(masm); - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow); -} - -#undef __ - Condition CompareIC::ComputeCondition(Token::Value op) { switch (op) { @@ -104,9 +62,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address, // condition code uses at the patched jump. uint8_t delta = *reinterpret_cast<uint8_t*>(delta_address); if (FLAG_trace_ic) { - PrintF("[ patching ic at %p, test=%p, delta=%d\n", - static_cast<void*>(address), - static_cast<void*>(test_instruction_address), delta); + LOG(isolate, PatchIC(address, test_instruction_address, delta)); } // Patch with a short conditional jump. Enabling means switching from a short diff --git a/deps/v8/src/ic/x87/handler-compiler-x87.cc b/deps/v8/src/ic/x87/handler-compiler-x87.cc index 4a521b76d3..5a61eee163 100644 --- a/deps/v8/src/ic/x87/handler-compiler-x87.cc +++ b/deps/v8/src/ic/x87/handler-compiler-x87.cc @@ -122,15 +122,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( __ DecrementCounter(counters->negative_lookups_miss(), 1); } -void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( - MacroAssembler* masm, Register receiver, Register scratch1, - Register scratch2, Label* miss_label) { - // TODO(mvstanton): This isn't used on ia32. Move all the other - // platform implementations into a code stub so this method can be removed. - UNREACHABLE(); -} - - // Generate call to api function. // This function uses push() to generate smaller, faster code than // the version above. It is an optimization that should will be removed @@ -302,10 +293,12 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter( } } +static void CompileCallLoadPropertyWithInterceptor( + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, Runtime::FunctionId id) { + DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == + Runtime::FunctionForId(id)->nargs); -static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, - Register holder, Register name, - Handle<JSObject> holder_obj) { STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); @@ -313,15 +306,7 @@ static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, __ push(name); __ push(receiver); __ push(holder); -} - -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); __ CallRuntime(id); } @@ -538,10 +523,26 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { DCHECK(holder()->HasNamedInterceptor()); DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); // Call the runtime system to load the interceptor. - __ pop(scratch2()); // save old return address - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), - holder()); - __ push(scratch2()); // restore old return address + + // Stack: + // return address + + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); + __ push(receiver()); + __ push(holder_reg); + // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. + if (holder_reg.is(receiver())) { + __ push(slot()); + __ push(vector()); + } else { + __ push(scratch3()); // slot + __ push(scratch2()); // vector + } + __ push(Operand(esp, 4 * kPointerSize)); // return address + __ mov(Operand(esp, 5 * kPointerSize), name()); __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); } diff --git a/deps/v8/src/ic/x87/ic-x87.cc b/deps/v8/src/ic/x87/ic-x87.cc index 049a85e92e..7564c006b8 100644 --- a/deps/v8/src/ic/x87/ic-x87.cc +++ b/deps/v8/src/ic/x87/ic-x87.cc @@ -6,54 +6,11 @@ #include "src/codegen.h" #include "src/ic/ic.h" -#include "src/ic/ic-compiler.h" #include "src/ic/stub-cache.h" namespace v8 { namespace internal { -// ---------------------------------------------------------------------------- -// Static IC stub generators. -// - -#define __ ACCESS_MASM(masm) - -static void StoreIC_PushArgs(MacroAssembler* masm) { - Register receiver = StoreWithVectorDescriptor::ReceiverRegister(); - Register name = StoreWithVectorDescriptor::NameRegister(); - - STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3); - // Current stack layout: - // - esp[12] -- value - // - esp[8] -- slot - // - esp[4] -- vector - // - esp[0] -- return address - - Register return_address = StoreWithVectorDescriptor::SlotRegister(); - __ pop(return_address); - __ push(receiver); - __ push(name); - __ push(return_address); -} - -void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { - // Return address is on the stack. - StoreIC_PushArgs(masm); - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); -} - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - // Return address is on the stack. - StoreIC_PushArgs(masm); - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow); -} - -#undef __ - Condition CompareIC::ComputeCondition(Token::Value op) { switch (op) { @@ -104,9 +61,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address, // condition code uses at the patched jump. uint8_t delta = *reinterpret_cast<uint8_t*>(delta_address); if (FLAG_trace_ic) { - PrintF("[ patching ic at %p, test=%p, delta=%d\n", - static_cast<void*>(address), - static_cast<void*>(test_instruction_address), delta); + LOG(isolate, PatchIC(address, test_instruction_address, delta)); } // Patch with a short conditional jump. Enabling means switching from a short |