| Index: src/ic/accessor-assembler.cc
|
| diff --git a/src/ic/accessor-assembler.cc b/src/ic/accessor-assembler.cc
|
| index 5645124ccdfa622305fa6eab89f28700f06d83b2..9e40a37fe1710824e5de29e5d0fbbe9e672523d7 100644
|
| --- a/src/ic/accessor-assembler.cc
|
| +++ b/src/ic/accessor-assembler.cc
|
| @@ -61,6 +61,10 @@ void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map,
|
| Comment("HandlePolymorphicCase");
|
| DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
|
|
|
| + // Deferred so the unrolled case can omit frame construction in bytecode
|
| + // handler.
|
| + Label loop(this, Label::kDeferred);
|
| +
|
| // Iterate {feedback} array.
|
| const int kEntrySize = 2;
|
|
|
| @@ -77,8 +81,10 @@ void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map,
|
|
|
| Bind(&next_entry);
|
| }
|
| + Goto(&loop);
|
|
|
| // Loop from {unroll_count}*kEntrySize to {length}.
|
| + Bind(&loop);
|
| Node* init = IntPtrConstant(unroll_count * kEntrySize);
|
| Node* length = LoadAndUntagFixedArrayBaseLength(feedback);
|
| BuildFastLoop(
|
| @@ -141,9 +147,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 +165,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 +278,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);
|
| GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForFields)),
|
| &field);
|
|
|
| @@ -664,7 +668,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 +1326,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 +1374,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);
|
| {
|
| @@ -1576,54 +1582,136 @@ void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver,
|
|
|
| //////////////////// Entry points into private implementation (one per stub).
|
|
|
| +void AccessorAssembler::LoadIC_BytecodeHandler(const LoadICParameters* p,
|
| + ExitPoint* exit_point) {
|
| + // Must be kept in sync with LoadIC.
|
| +
|
| + // This function is hand-tuned to omit frame construction for common cases,
|
| + // e.g.: monomorphic field and constant loads through smi handlers.
|
| + // Polymorphic ICs with a hit in the first two entries also omit frames.
|
| + // TODO(jgruber): Frame omission is fragile and can be affected by minor
|
| + // changes in control flow and logic. We currently have no way of ensuring
|
| + // that no frame is constructed, so it's easy to break this optimization by
|
| + // accident.
|
| + Label stub_call(this, Label::kDeferred), miss(this, Label::kDeferred);
|
| +
|
| + // Inlined fast path.
|
| + {
|
| + Comment("LoadIC_BytecodeHandler_fast");
|
| +
|
| + Node* recv_map = LoadReceiverMap(p->receiver);
|
| + GotoIf(IsDeprecatedMap(recv_map), &miss);
|
| +
|
| + Variable var_handler(this, MachineRepresentation::kTagged);
|
| + Label try_polymorphic(this), if_handler(this, &var_handler);
|
| +
|
| + Node* feedback =
|
| + TryMonomorphicCase(p->slot, p->vector, recv_map, &if_handler,
|
| + &var_handler, &try_polymorphic);
|
| +
|
| + Bind(&if_handler);
|
| + HandleLoadICHandlerCase(p, var_handler.value(), &miss, exit_point);
|
| +
|
| + Bind(&try_polymorphic);
|
| + {
|
| + GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
|
| + &stub_call);
|
| + HandlePolymorphicCase(recv_map, feedback, &if_handler, &var_handler,
|
| + &miss, 2);
|
| + }
|
| + }
|
| +
|
| + Bind(&stub_call);
|
| + {
|
| + Comment("LoadIC_BytecodeHandler_noninlined");
|
| +
|
| + // Call into the stub that implements the non-inlined parts of LoadIC.
|
| + Callable ic = CodeFactory::LoadICInOptimizedCode_Noninlined(isolate());
|
| + Node* code_target = HeapConstant(ic.code());
|
| + exit_point->ReturnCallStub(ic.descriptor(), code_target, p->context,
|
| + p->receiver, p->name, p->slot, p->vector);
|
| + }
|
| +
|
| + Bind(&miss);
|
| + {
|
| + Comment("LoadIC_BytecodeHandler_miss");
|
| +
|
| + exit_point->ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context,
|
| + p->receiver, p->name, p->slot, p->vector);
|
| + }
|
| +}
|
| +
|
| void AccessorAssembler::LoadIC(const LoadICParameters* p) {
|
| + // Must be kept in sync with LoadIC_BytecodeHandler.
|
| +
|
| + 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_inlined(this, Label::kDeferred),
|
| + try_polymorphic(this), 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); }
|
| + HandleLoadICHandlerCase(p, var_handler.value(), &miss, &direct_exit);
|
|
|
| Bind(&try_polymorphic);
|
| {
|
| // Check polymorphic case.
|
| Comment("LoadIC_try_polymorphic");
|
| GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
|
| - &try_megamorphic);
|
| + &non_inlined);
|
| HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
|
| &miss, 2);
|
| }
|
|
|
| - Bind(&try_megamorphic);
|
| + Bind(&non_inlined);
|
| + 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,
|
| + Node* receiver_map, Node* feedback,
|
| + Variable* var_handler,
|
| + Label* if_handler, Label* miss,
|
| + ExitPoint* exit_point) {
|
| + Label 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)));
|
| + CSA_ASSERT(this, WordNotEqual(LoadMap(feedback), FixedArrayMapConstant()));
|
| + DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
|
| +
|
| {
|
| // Check megamorphic case.
|
| GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
|
| &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 +1855,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 +1871,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 +1880,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 +1919,8 @@ 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 =
|
| + LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS);
|
| HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss,
|
| 1);
|
| }
|
| @@ -1881,7 +1974,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 +2025,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 +2106,8 @@ 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 = LoadFixedArrayElement(p->vector, p->slot, kPointerSize,
|
| + SMI_PARAMETERS);
|
| HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler,
|
| &miss, 1);
|
| }
|
| @@ -2044,6 +2135,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 = LoadFixedArrayElement(vector, slot, 0, SMI_PARAMETERS);
|
| +
|
| + 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;
|
|
|
|
|