Chromium Code Reviews| Index: src/ic/accessor-assembler.cc |
| diff --git a/src/ic/accessor-assembler.cc b/src/ic/accessor-assembler.cc |
| index 5645124ccdfa622305fa6eab89f28700f06d83b2..a3e11cd8f447d965e991b4b6bb68f2bccabd23e9 100644 |
| --- a/src/ic/accessor-assembler.cc |
| +++ b/src/ic/accessor-assembler.cc |
| @@ -19,14 +19,42 @@ using compiler::Node; |
| //////////////////// Private helpers. |
| +Node* AccessorAssembler::LoadFeedbackSlot(Node* vector, Node* slot, |
|
jgruber
2017/03/03 13:31:14
This is basically LoadFixedArrayElement but with t
|
| + int additional_offset) { |
| + int32_t header_size = |
| + FixedArray::kHeaderSize - kHeapObjectTag + additional_offset; |
| + |
| + // Adding |header_size| with a separate IntPtrAdd rather than passing it |
| + // into ElementOffsetFromIndex() allows it to be folded into a single |
| + // [base, index, offset] indirect memory access on x64. |
| + Node* offset = |
| + ElementOffsetFromIndex(slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS); |
| + return Load(MachineType::AnyTagged(), vector, |
| + IntPtrAdd(offset, IntPtrConstant(header_size))); |
| +} |
| + |
| 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()); |
| + Node* feedback = nullptr; |
| + Node* handler = nullptr; |
| + std::tie(feedback, handler) = |
| + TryMonomorphicCase(slot, vector, receiver_map, if_miss); |
| + |
| + var_handler->Bind(handler); |
| + Goto(if_handler); |
| + |
| + return feedback; |
| +} |
| + |
| +std::pair<Node*, Node*> AccessorAssembler::TryMonomorphicCase( |
|
jgruber
2017/03/03 13:31:14
This version avoids needs a variable and a label l
|
| + Node* slot, Node* vector, Node* receiver_map, Label* if_miss) { |
| + Comment("TryMonomorphicCase"); |
| + |
| // TODO(ishell): add helper class that hides offset computations for a series |
| // of loads. |
| int32_t header_size = FixedArray::kHeaderSize - kHeapObjectTag; |
| @@ -48,9 +76,7 @@ Node* AccessorAssembler::TryMonomorphicCase(Node* slot, Node* vector, |
| Load(MachineType::AnyTagged(), vector, |
| IntPtrAdd(offset, IntPtrConstant(header_size + kPointerSize))); |
| - var_handler->Bind(handler); |
| - Goto(if_handler); |
| - return feedback; |
| + return std::make_pair(feedback, handler); |
| } |
| void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map, |
| @@ -141,9 +167,8 @@ void AccessorAssembler::HandleKeyedStorePolymorphicCase( |
| void AccessorAssembler::HandleLoadICHandlerCase( |
| const LoadICParameters* p, Node* handler, Label* miss, |
| - ElementSupport support_elements) { |
| + ExitPoint* exit_point, ElementSupport support_elements) { |
| Comment("have_handler"); |
| - ExitPoint direct_exit(this); |
| Variable var_holder(this, MachineRepresentation::kTagged, p->receiver); |
| Variable var_smi_handler(this, MachineRepresentation::kTagged, handler); |
| @@ -160,21 +185,21 @@ void AccessorAssembler::HandleLoadICHandlerCase( |
| Bind(&if_smi_handler); |
| { |
| HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(), |
| - miss, &direct_exit, support_elements); |
| + miss, exit_point, support_elements); |
| } |
| Bind(&try_proto_handler); |
| { |
| GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); |
| HandleLoadICProtoHandlerCase(p, handler, &var_holder, &var_smi_handler, |
| - &if_smi_handler, miss, &direct_exit, false); |
| + &if_smi_handler, miss, exit_point, false); |
| } |
| Bind(&call_handler); |
| { |
| typedef LoadWithVectorDescriptor Descriptor; |
| - TailCallStub(Descriptor(isolate()), handler, p->context, p->receiver, |
| - p->name, p->slot, p->vector); |
| + exit_point->ReturnCallStub(Descriptor(isolate()), handler, p->context, |
| + p->receiver, p->name, p->slot, p->vector); |
| } |
| } |
| @@ -273,8 +298,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase( |
| Comment("property_load"); |
| } |
| - Label constant(this, Label::kDeferred), field(this), |
| - normal(this, Label::kDeferred); |
| + Label constant(this), field(this), normal(this, Label::kDeferred); |
|
jgruber
2017/03/03 13:31:14
Both constant and field cases can omit frame const
|
| GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForFields)), |
| &field); |
| @@ -664,7 +688,7 @@ void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p, |
| Node* transition = var_transition.value(); |
| Node* handler_word = SmiUntag(smi_handler); |
| - GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(transition)), miss); |
| + GotoIf(IsDeprecatedMap(transition), miss); |
| Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word); |
| GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kStoreNormal)), |
| @@ -1322,6 +1346,8 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, |
| const LoadICParameters* p, |
| Label* slow, |
| UseStubCache use_stub_cache) { |
| + ExitPoint direct_exit(this); |
| + |
| Comment("key is unique name"); |
| Label if_found_on_receiver(this), if_property_dictionary(this), |
| lookup_prototype_chain(this); |
| @@ -1368,7 +1394,7 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, |
| TryProbeStubCache(isolate()->load_stub_cache(), receiver, key, |
| &found_handler, &var_handler, &stub_cache_miss); |
| Bind(&found_handler); |
| - { HandleLoadICHandlerCase(p, var_handler.value(), slow); } |
| + { HandleLoadICHandlerCase(p, var_handler.value(), slow, &direct_exit); } |
| Bind(&stub_cache_miss); |
| { |
| @@ -1577,29 +1603,55 @@ void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver, |
| //////////////////// Entry points into private implementation (one per stub). |
| void AccessorAssembler::LoadIC(const LoadICParameters* p) { |
| + // Must be kept in sync with Interpreter::BuildLoadIC. |
| + |
| + ExitPoint direct_exit(this); |
| + |
| Variable var_handler(this, MachineRepresentation::kTagged); |
| - Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred), |
| - try_megamorphic(this, Label::kDeferred), |
| - try_uninitialized(this, Label::kDeferred), miss(this, Label::kDeferred); |
| + Label if_handler(this, &var_handler), non_monomorphic(this, Label::kDeferred), |
| + miss(this, Label::kDeferred); |
| Node* receiver_map = LoadReceiverMap(p->receiver); |
| - GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss); |
| + GotoIf(IsDeprecatedMap(receiver_map), &miss); |
| // Check monomorphic case. |
| Node* feedback = |
| TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler, |
| - &var_handler, &try_polymorphic); |
| + &var_handler, &non_monomorphic); |
| Bind(&if_handler); |
| - { HandleLoadICHandlerCase(p, var_handler.value(), &miss); } |
| + HandleLoadICHandlerCase(p, var_handler.value(), &miss, &direct_exit); |
| + |
| + Bind(&non_monomorphic); |
| + LoadIC_Noninlined(p, receiver_map, feedback, &var_handler, &if_handler, &miss, |
| + &direct_exit); |
| + |
| + Bind(&miss); |
| + direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, |
| + p->name, p->slot, p->vector); |
| +} |
| + |
| +void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p, |
|
jgruber
2017/03/03 13:31:14
I don't have a better name for this. Right now it'
|
| + Node* receiver_map, Node* feedback, |
| + Variable* var_handler, |
| + Label* if_handler, Label* miss, |
| + ExitPoint* exit_point) { |
| + Label try_megamorphic(this, Label::kDeferred), |
| + try_uninitialized(this, Label::kDeferred); |
| + |
| + // Neither deprecated map nor monomorphic. These cases are handled in the |
| + // bytecode handler. |
| + CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(receiver_map))); |
| + CSA_ASSERT(this, |
| + WordNotEqual(receiver_map, LoadWeakCellValueUnchecked(feedback))); |
| + DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep()); |
| - Bind(&try_polymorphic); |
| { |
| // Check polymorphic case. |
| Comment("LoadIC_try_polymorphic"); |
| GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()), |
| &try_megamorphic); |
| - HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler, |
| - &miss, 2); |
| + HandlePolymorphicCase(receiver_map, feedback, if_handler, var_handler, miss, |
| + 2); |
| } |
| Bind(&try_megamorphic); |
| @@ -1609,21 +1661,18 @@ void AccessorAssembler::LoadIC(const LoadICParameters* p) { |
| &try_uninitialized); |
| TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name, |
| - &if_handler, &var_handler, &miss); |
| + if_handler, var_handler, miss); |
| } |
| + |
| Bind(&try_uninitialized); |
| { |
| // Check uninitialized case. |
| GotoIfNot( |
| WordEqual(feedback, LoadRoot(Heap::kuninitialized_symbolRootIndex)), |
| - &miss); |
| - TailCallStub(CodeFactory::LoadIC_Uninitialized(isolate()), p->context, |
| - p->receiver, p->name, p->slot, p->vector); |
| - } |
| - Bind(&miss); |
| - { |
| - TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name, |
| - p->slot, p->vector); |
| + miss); |
| + exit_point->ReturnCallStub(CodeFactory::LoadIC_Uninitialized(isolate()), |
| + p->context, p->receiver, p->name, p->slot, |
| + p->vector); |
| } |
| } |
| @@ -1767,6 +1816,8 @@ void AccessorAssembler::LoadGlobalIC_MissCase(const LoadICParameters* p, |
| void AccessorAssembler::LoadGlobalIC(const LoadICParameters* p, |
| TypeofMode typeof_mode) { |
| + // Must be kept in sync with Interpreter::BuildLoadGlobal. |
| + |
| ExitPoint direct_exit(this); |
| Label try_handler(this), miss(this); |
| @@ -1781,6 +1832,8 @@ void AccessorAssembler::LoadGlobalIC(const LoadICParameters* p, |
| } |
| void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) { |
| + ExitPoint direct_exit(this); |
| + |
| Variable var_handler(this, MachineRepresentation::kTagged); |
| Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred), |
| try_megamorphic(this, Label::kDeferred), |
| @@ -1788,14 +1841,17 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) { |
| miss(this, Label::kDeferred); |
| Node* receiver_map = LoadReceiverMap(p->receiver); |
| - GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss); |
| + GotoIf(IsDeprecatedMap(receiver_map), &miss); |
| // Check monomorphic case. |
| Node* feedback = |
| TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler, |
| &var_handler, &try_polymorphic); |
| Bind(&if_handler); |
| - { HandleLoadICHandlerCase(p, var_handler.value(), &miss, kSupportElements); } |
| + { |
| + HandleLoadICHandlerCase(p, var_handler.value(), &miss, &direct_exit, |
| + kSupportElements); |
| + } |
| Bind(&try_polymorphic); |
| { |
| @@ -1824,10 +1880,7 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) { |
| 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( |
| - p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS, |
| - FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag); |
| - Node* array = Load(MachineType::AnyTagged(), p->vector, offset); |
| + Node* array = LoadFeedbackSlot(p->vector, p->slot, kPointerSize); |
| HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss, |
| 1); |
| } |
| @@ -1881,7 +1934,7 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) { |
| try_megamorphic(this, Label::kDeferred), miss(this, Label::kDeferred); |
| Node* receiver_map = LoadReceiverMap(p->receiver); |
| - GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss); |
| + GotoIf(IsDeprecatedMap(receiver_map), &miss); |
| // Check monomorphic case. |
| Node* feedback = |
| @@ -1932,7 +1985,7 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p, |
| try_polymorphic_name(this, Label::kDeferred); |
| Node* receiver_map = LoadReceiverMap(p->receiver); |
| - GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss); |
| + GotoIf(IsDeprecatedMap(receiver_map), &miss); |
| // Check monomorphic case. |
| Node* feedback = |
| @@ -2013,10 +2066,7 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p, |
| 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( |
| - p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS, |
| - FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag); |
| - Node* array = Load(MachineType::AnyTagged(), p->vector, offset); |
| + Node* array = LoadFeedbackSlot(p->vector, p->slot, kPointerSize); |
| HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, |
| &miss, 1); |
| } |
| @@ -2044,6 +2094,34 @@ void AccessorAssembler::GenerateLoadIC() { |
| LoadIC(&p); |
| } |
| +void AccessorAssembler::GenerateLoadIC_Noninlined() { |
| + typedef LoadWithVectorDescriptor Descriptor; |
| + |
| + Node* receiver = Parameter(Descriptor::kReceiver); |
| + Node* name = Parameter(Descriptor::kName); |
| + Node* slot = Parameter(Descriptor::kSlot); |
| + Node* vector = Parameter(Descriptor::kVector); |
| + Node* context = Parameter(Descriptor::kContext); |
| + |
| + ExitPoint direct_exit(this); |
| + Variable var_handler(this, MachineRepresentation::kTagged); |
| + Label if_handler(this, &var_handler), miss(this, Label::kDeferred); |
| + |
| + Node* receiver_map = LoadReceiverMap(receiver); |
| + Node* feedback = LoadFeedbackSlot(vector, slot, 0); |
|
jgruber
2017/03/03 13:31:14
We could avoid these two loads if we pass the map
|
| + |
| + LoadICParameters p(context, receiver, name, slot, vector); |
| + LoadIC_Noninlined(&p, receiver_map, feedback, &var_handler, &if_handler, |
| + &miss, &direct_exit); |
| + |
| + Bind(&if_handler); |
| + HandleLoadICHandlerCase(&p, var_handler.value(), &miss, &direct_exit); |
| + |
| + Bind(&miss); |
| + direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name, |
| + slot, vector); |
| +} |
| + |
| void AccessorAssembler::GenerateLoadIC_Uninitialized() { |
| typedef LoadWithVectorDescriptor Descriptor; |