| Index: src/code-stubs.cc
|
| diff --git a/src/code-stubs.cc b/src/code-stubs.cc
|
| index ec9d04a40da4ec7384334b83e6813366f7fa39c5..fb7a9c0d93d0ccb306e5c8bc2d1d908907ac1246 100644
|
| --- a/src/code-stubs.cc
|
| +++ b/src/code-stubs.cc
|
| @@ -1759,6 +1759,179 @@ void CallICStub::PrintState(std::ostream& os) const { // NOLINT
|
| os << convert_mode() << ", " << tail_call_mode();
|
| }
|
|
|
| +void CallICStub::GenerateAssembly(compiler::CodeAssemblerState* state) const {
|
| + typedef CodeStubAssembler::Label Label;
|
| + typedef compiler::Node Node;
|
| + CodeStubAssembler assembler(state);
|
| +
|
| + Node* context = assembler.Parameter(Descriptor::kContext);
|
| + Node* target = assembler.Parameter(Descriptor::kTarget);
|
| + Node* argc = assembler.Parameter(Descriptor::kActualArgumentsCount);
|
| + Node* slot = assembler.Parameter(Descriptor::kSlot);
|
| + Node* vector = assembler.Parameter(Descriptor::kVector);
|
| +
|
| + // TODO(bmeurer): The slot should actually be an IntPtr, but TurboFan's
|
| + // SimplifiedLowering cannot deal with IntPtr machine type properly yet.
|
| + slot = assembler.ChangeInt32ToIntPtr(slot);
|
| +
|
| + // Static checks to assert it is safe to examine the type feedback element.
|
| + // We don't know that we have a weak cell. We might have a private symbol
|
| + // or an AllocationSite, but the memory is safe to examine.
|
| + // AllocationSite::kTransitionInfoOffset - contains a Smi or pointer to
|
| + // FixedArray.
|
| + // WeakCell::kValueOffset - contains a JSFunction or Smi(0)
|
| + // Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not
|
| + // computed, meaning that it can't appear to be a pointer. If the low bit is
|
| + // 0, then hash is computed, but the 0 bit prevents the field from appearing
|
| + // to be a pointer.
|
| + STATIC_ASSERT(WeakCell::kSize >= kPointerSize);
|
| + STATIC_ASSERT(AllocationSite::kTransitionInfoOffset ==
|
| + WeakCell::kValueOffset &&
|
| + WeakCell::kValueOffset == Symbol::kHashFieldSlot);
|
| +
|
| + // Increment the call count.
|
| + // TODO(bmeurer): Would it be beneficial to use Int32Add on 64-bit?
|
| + assembler.Comment("increment call count");
|
| + Node* call_count =
|
| + assembler.LoadFixedArrayElement(vector, slot, 1 * kPointerSize);
|
| + Node* new_count = assembler.SmiAdd(call_count, assembler.SmiConstant(1));
|
| + // Count is Smi, so we don't need a write barrier.
|
| + assembler.StoreFixedArrayElement(vector, slot, new_count, SKIP_WRITE_BARRIER,
|
| + 1 * kPointerSize);
|
| +
|
| + Label call_function(&assembler), extra_checks(&assembler), call(&assembler);
|
| +
|
| + // The checks. First, does function match the recorded monomorphic target?
|
| + Node* feedback_element = assembler.LoadFixedArrayElement(vector, slot);
|
| + Node* feedback_value = assembler.LoadWeakCellValueUnchecked(feedback_element);
|
| + Node* is_monomorphic = assembler.WordEqual(target, feedback_value);
|
| + assembler.GotoUnless(is_monomorphic, &extra_checks);
|
| +
|
| + // The compare above could have been a SMI/SMI comparison. Guard against
|
| + // this convincing us that we have a monomorphic JSFunction.
|
| + Node* is_smi = assembler.TaggedIsSmi(target);
|
| + assembler.Branch(is_smi, &extra_checks, &call_function);
|
| +
|
| + assembler.Bind(&call_function);
|
| + {
|
| + // Call using CallFunction builtin.
|
| + Callable callable =
|
| + CodeFactory::CallFunction(isolate(), convert_mode(), tail_call_mode());
|
| + assembler.TailCallStub(callable, context, target, argc);
|
| + }
|
| +
|
| + assembler.Bind(&extra_checks);
|
| + {
|
| + Label check_initialized(&assembler), mark_megamorphic(&assembler),
|
| + create_allocation_site(&assembler, Label::kDeferred),
|
| + create_weak_cell(&assembler, Label::kDeferred);
|
| +
|
| + assembler.Comment("check if megamorphic");
|
| + // Check if it is a megamorphic target.
|
| + Node* is_megamorphic = assembler.WordEqual(
|
| + feedback_element,
|
| + assembler.HeapConstant(
|
| + TypeFeedbackVector::MegamorphicSentinel(isolate())));
|
| + assembler.GotoIf(is_megamorphic, &call);
|
| +
|
| + assembler.Comment("check if it is an allocation site");
|
| + assembler.GotoUnless(
|
| + assembler.IsAllocationSiteMap(assembler.LoadMap(feedback_element)),
|
| + &check_initialized);
|
| +
|
| + // If it is not the Array() function, mark megamorphic.
|
| + Node* context_slot = assembler.LoadContextElement(
|
| + assembler.LoadNativeContext(context), Context::ARRAY_FUNCTION_INDEX);
|
| + Node* is_array_function = assembler.WordEqual(context_slot, target);
|
| + assembler.GotoUnless(is_array_function, &mark_megamorphic);
|
| +
|
| + // Call ArrayConstructorStub.
|
| + Callable callable = CodeFactory::ArrayConstructor(isolate());
|
| + assembler.TailCallStub(callable, context, target, target, argc,
|
| + feedback_element);
|
| +
|
| + assembler.Bind(&check_initialized);
|
| + {
|
| + assembler.Comment("check if uninitialized");
|
| + // Check if it is uninitialized target first.
|
| + Node* is_uninitialized = assembler.WordEqual(
|
| + feedback_element,
|
| + assembler.HeapConstant(
|
| + TypeFeedbackVector::UninitializedSentinel(isolate())));
|
| + assembler.GotoUnless(is_uninitialized, &mark_megamorphic);
|
| +
|
| + assembler.Comment("handle unitinitialized");
|
| + // If it is not a JSFunction mark it as megamorphic.
|
| + Node* is_smi = assembler.TaggedIsSmi(target);
|
| + assembler.GotoIf(is_smi, &mark_megamorphic);
|
| +
|
| + // Check if function is an object of JSFunction type.
|
| + Node* is_js_function = assembler.IsJSFunction(target);
|
| + assembler.GotoUnless(is_js_function, &mark_megamorphic);
|
| +
|
| + // Check if it is the Array() function.
|
| + Node* context_slot = assembler.LoadContextElement(
|
| + assembler.LoadNativeContext(context), Context::ARRAY_FUNCTION_INDEX);
|
| + Node* is_array_function = assembler.WordEqual(context_slot, target);
|
| + assembler.GotoIf(is_array_function, &create_allocation_site);
|
| +
|
| + // Check if the function belongs to the same native context.
|
| + Node* native_context = assembler.LoadNativeContext(
|
| + assembler.LoadObjectField(target, JSFunction::kContextOffset));
|
| + Node* is_same_native_context = assembler.WordEqual(
|
| + native_context, assembler.LoadNativeContext(context));
|
| + assembler.Branch(is_same_native_context, &create_weak_cell,
|
| + &mark_megamorphic);
|
| + }
|
| +
|
| + assembler.Bind(&create_weak_cell);
|
| + {
|
| + // Wrap the {target} in a WeakCell and remember it.
|
| + assembler.Comment("create weak cell");
|
| + assembler.CreateWeakCellInFeedbackVector(vector, assembler.SmiTag(slot),
|
| + target);
|
| +
|
| + // Call using CallFunction builtin.
|
| + assembler.Goto(&call_function);
|
| + }
|
| +
|
| + assembler.Bind(&create_allocation_site);
|
| + {
|
| + // Create an AllocationSite for the {target}.
|
| + assembler.Comment("create allocation site");
|
| + assembler.CreateAllocationSiteInFeedbackVector(vector,
|
| + assembler.SmiTag(slot));
|
| +
|
| + // Call using CallFunction builtin. CallICs have a PREMONOMORPHIC state.
|
| + // They start collecting feedback only when a call is executed the second
|
| + // time. So, do not pass any feedback here.
|
| + assembler.Goto(&call_function);
|
| + }
|
| +
|
| + assembler.Bind(&mark_megamorphic);
|
| + {
|
| + // Mark it as a megamorphic.
|
| + // MegamorphicSentinel is created as a part of Heap::InitialObjects
|
| + // and will not move during a GC. So it is safe to skip write barrier.
|
| + DCHECK(Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex));
|
| + assembler.StoreFixedArrayElement(
|
| + vector, slot, assembler.HeapConstant(
|
| + TypeFeedbackVector::MegamorphicSentinel(isolate())),
|
| + SKIP_WRITE_BARRIER);
|
| + assembler.Goto(&call);
|
| + }
|
| + }
|
| +
|
| + assembler.Bind(&call);
|
| + {
|
| + // Call using call builtin.
|
| + assembler.Comment("call using Call builtin");
|
| + Callable callable_call =
|
| + CodeFactory::Call(isolate(), convert_mode(), tail_call_mode());
|
| + assembler.TailCallStub(callable_call, context, target, argc);
|
| + }
|
| +}
|
| +
|
| void CallICTrampolineStub::PrintState(std::ostream& os) const { // NOLINT
|
| os << convert_mode() << ", " << tail_call_mode();
|
| }
|
| @@ -1769,7 +1942,7 @@ void CallICTrampolineStub::GenerateAssembly(
|
| CodeStubAssembler assembler(state);
|
|
|
| Node* context = assembler.Parameter(Descriptor::kContext);
|
| - Node* target = assembler.Parameter(Descriptor::kFunction);
|
| + Node* target = assembler.Parameter(Descriptor::kTarget);
|
| Node* argc = assembler.Parameter(Descriptor::kActualArgumentsCount);
|
| Node* slot = assembler.Parameter(Descriptor::kSlot);
|
| Node* vector = assembler.LoadTypeFeedbackVectorForStub();
|
|
|