| Index: src/interpreter/interpreter-assembler.cc
|
| diff --git a/src/interpreter/interpreter-assembler.cc b/src/interpreter/interpreter-assembler.cc
|
| index 1e2fe88eb52dea6138d3e559f1a26ab414eda929..1a0d8f194d68f3cebb4e8c4210cf42b3ba431b84 100644
|
| --- a/src/interpreter/interpreter-assembler.cc
|
| +++ b/src/interpreter/interpreter-assembler.cc
|
| @@ -546,22 +546,22 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
|
| WeakCell::kValueOffset == Symbol::kHashFieldSlot);
|
|
|
| Variable return_value(this, MachineRepresentation::kTagged);
|
| - Label handle_monomorphic(this), extra_checks(this), end(this), call(this),
|
| - call_function(this);
|
| + Label call_function(this), extra_checks(this, Label::kDeferred), call(this),
|
| + end(this);
|
|
|
| // The checks. First, does function match the recorded monomorphic target?
|
| Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id);
|
| Node* feedback_value = LoadWeakCellValueUnchecked(feedback_element);
|
| Node* is_monomorphic = WordEqual(function, feedback_value);
|
| - Branch(is_monomorphic, &handle_monomorphic, &extra_checks);
|
| + GotoUnless(is_monomorphic, &extra_checks);
|
|
|
| - Bind(&handle_monomorphic);
|
| - {
|
| - // The compare above could have been a SMI/SMI comparison. Guard against
|
| - // this convincing us that we have a monomorphic JSFunction.
|
| - Node* is_smi = TaggedIsSmi(function);
|
| - GotoIf(is_smi, &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 = TaggedIsSmi(function);
|
| + Branch(is_smi, &extra_checks, &call_function);
|
|
|
| + Bind(&call_function);
|
| + {
|
| // Increment the call count.
|
| IncrementCallCount(type_feedback_vector, slot_id);
|
|
|
| @@ -577,56 +577,56 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
|
|
|
| Bind(&extra_checks);
|
| {
|
| - Label check_initialized(this, Label::kDeferred), mark_megamorphic(this),
|
| - check_allocation_site(this),
|
| - create_allocation_site(this, Label::kDeferred);
|
| - // Check if it is a megamorphic target
|
| + Label check_initialized(this), mark_megamorphic(this),
|
| + create_allocation_site(this);
|
| +
|
| + Comment("check if megamorphic");
|
| + // Check if it is a megamorphic target.
|
| Node* is_megamorphic = WordEqual(
|
| feedback_element,
|
| HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())));
|
| - Branch(is_megamorphic, &call, &check_allocation_site);
|
| + GotoIf(is_megamorphic, &call);
|
|
|
| - Bind(&check_allocation_site);
|
| - {
|
| - Node* is_allocation_site =
|
| - WordEqual(LoadMap(feedback_element),
|
| - LoadRoot(Heap::kAllocationSiteMapRootIndex));
|
| - GotoUnless(is_allocation_site, &check_initialized);
|
| + Comment("check if it is an allocation site");
|
| + Node* is_allocation_site = WordEqual(
|
| + LoadMap(feedback_element), LoadRoot(Heap::kAllocationSiteMapRootIndex));
|
| + GotoUnless(is_allocation_site, &check_initialized);
|
|
|
| - // If it is not the Array() function, mark megamorphic.
|
| - Node* context_slot =
|
| - LoadFixedArrayElement(LoadNativeContext(context),
|
| - Int32Constant(Context::ARRAY_FUNCTION_INDEX));
|
| - Node* is_array_function = WordEqual(context_slot, function);
|
| - GotoUnless(is_array_function, &mark_megamorphic);
|
| + // If it is not the Array() function, mark megamorphic.
|
| + Node* context_slot =
|
| + LoadFixedArrayElement(LoadNativeContext(context),
|
| + Int32Constant(Context::ARRAY_FUNCTION_INDEX));
|
| + Node* is_array_function = WordEqual(context_slot, function);
|
| + GotoUnless(is_array_function, &mark_megamorphic);
|
|
|
| - // It is a monomorphic Array function. Increment the call count.
|
| - IncrementCallCount(type_feedback_vector, slot_id);
|
| -
|
| - // Call ArrayConstructorStub.
|
| - Callable callable_call =
|
| - CodeFactory::InterpreterPushArgsAndConstructArray(isolate());
|
| - Node* code_target_call = HeapConstant(callable_call.code());
|
| - Node* ret_value =
|
| - CallStub(callable_call.descriptor(), code_target_call, context,
|
| - arg_count, function, feedback_element, first_arg);
|
| - return_value.Bind(ret_value);
|
| - Goto(&end);
|
| - }
|
| + // It is a monomorphic Array function. Increment the call count.
|
| + IncrementCallCount(type_feedback_vector, slot_id);
|
| +
|
| + // Call ArrayConstructorStub.
|
| + Callable callable_call =
|
| + CodeFactory::InterpreterPushArgsAndConstructArray(isolate());
|
| + Node* code_target_call = HeapConstant(callable_call.code());
|
| + Node* ret_value =
|
| + CallStub(callable_call.descriptor(), code_target_call, context,
|
| + arg_count, function, feedback_element, first_arg);
|
| + return_value.Bind(ret_value);
|
| + Goto(&end);
|
|
|
| Bind(&check_initialized);
|
| {
|
| - Label possibly_monomorphic(this);
|
| - // Check if it is uninitialized.
|
| + Comment("check if uninitialized");
|
| + // Check if it is uninitialized target first.
|
| Node* is_uninitialized = WordEqual(
|
| feedback_element,
|
| HeapConstant(TypeFeedbackVector::UninitializedSentinel(isolate())));
|
| GotoUnless(is_uninitialized, &mark_megamorphic);
|
|
|
| + Comment("handle_unitinitialized");
|
| + // If it is not a JSFunction mark it as megamorphic.
|
| Node* is_smi = TaggedIsSmi(function);
|
| GotoIf(is_smi, &mark_megamorphic);
|
|
|
| - // Check if function is an object of JSFunction type
|
| + // Check if function is an object of JSFunction type.
|
| Node* instance_type = LoadInstanceType(function);
|
| Node* is_js_function =
|
| WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE));
|
| @@ -639,7 +639,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
|
| Node* is_array_function = WordEqual(context_slot, function);
|
| GotoIf(is_array_function, &create_allocation_site);
|
|
|
| - // Check if the function belongs to the same native context
|
| + // Check if the function belongs to the same native context.
|
| Node* native_context = LoadNativeContext(
|
| LoadObjectField(function, JSFunction::kContextOffset));
|
| Node* is_same_native_context =
|
| @@ -678,22 +678,9 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
|
| }
|
| }
|
|
|
| - Bind(&call_function);
|
| - {
|
| - // Increment the call count.
|
| - IncrementCallCount(type_feedback_vector, slot_id);
|
| -
|
| - Callable callable_call = CodeFactory::InterpreterPushArgsAndCall(
|
| - isolate(), tail_call_mode, CallableType::kJSFunction);
|
| - Node* code_target_call = HeapConstant(callable_call.code());
|
| - Node* ret_value = CallStub(callable_call.descriptor(), code_target_call,
|
| - context, arg_count, first_arg, function);
|
| - return_value.Bind(ret_value);
|
| - Goto(&end);
|
| - }
|
| -
|
| Bind(&call);
|
| {
|
| + Comment("Increment call count and call using Call builtin");
|
| // Increment the call count.
|
| IncrementCallCount(type_feedback_vector, slot_id);
|
|
|
| @@ -725,10 +712,10 @@ Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context,
|
| Node* new_target, Node* first_arg,
|
| Node* arg_count, Node* slot_id,
|
| Node* type_feedback_vector) {
|
| - Label call_construct(this), js_function(this), end(this);
|
| Variable return_value(this, MachineRepresentation::kTagged);
|
| Variable allocation_feedback(this, MachineRepresentation::kTagged);
|
| - allocation_feedback.Bind(UndefinedConstant());
|
| + Label call_construct_function(this, &allocation_feedback),
|
| + extra_checks(this, Label::kDeferred), call_construct(this), end(this);
|
|
|
| // Slot id of 0 is used to indicate no type feedback is available.
|
| STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
|
| @@ -743,132 +730,118 @@ Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context,
|
| Node* instance_type = LoadInstanceType(constructor);
|
| Node* is_js_function =
|
| WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE));
|
| - Branch(is_js_function, &js_function, &call_construct);
|
| + GotoUnless(is_js_function, &call_construct);
|
|
|
| - Bind(&js_function);
|
| + // Check if it is a monomorphic constructor.
|
| + Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id);
|
| + Node* feedback_value = LoadWeakCellValueUnchecked(feedback_element);
|
| + Node* is_monomorphic = WordEqual(constructor, feedback_value);
|
| + allocation_feedback.Bind(UndefinedConstant());
|
| + Branch(is_monomorphic, &call_construct_function, &extra_checks);
|
| +
|
| + Bind(&call_construct_function);
|
| + {
|
| + Comment("call using callConstructFunction");
|
| + IncrementCallCount(type_feedback_vector, slot_id);
|
| + Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct(
|
| + isolate(), CallableType::kJSFunction);
|
| + return_value.Bind(CallStub(callable_function.descriptor(),
|
| + HeapConstant(callable_function.code()), context,
|
| + arg_count, new_target, constructor,
|
| + allocation_feedback.value(), first_arg));
|
| + Goto(&end);
|
| + }
|
| +
|
| + Bind(&extra_checks);
|
| {
|
| - // Cache the called function in a feedback vector slot. Cache states
|
| - // are uninitialized, monomorphic (indicated by a JSFunction), and
|
| - // megamorphic.
|
| - // TODO(mythria/v8:5210): Check if it is better to mark extra_checks as a
|
| - // deferred block so that call_construct_function will be scheduled.
|
| - Label extra_checks(this), call_construct_function(this);
|
| -
|
| - Node* feedback_element =
|
| - LoadFixedArrayElement(type_feedback_vector, slot_id);
|
| - Node* feedback_value = LoadWeakCellValueUnchecked(feedback_element);
|
| - Node* is_monomorphic = WordEqual(constructor, feedback_value);
|
| - Branch(is_monomorphic, &call_construct_function, &extra_checks);
|
| -
|
| - Bind(&extra_checks);
|
| + Label check_allocation_site(this), check_initialized(this),
|
| + initialize(this), mark_megamorphic(this);
|
| +
|
| + // Check if it is a megamorphic target.
|
| + Comment("check if megamorphic");
|
| + Node* is_megamorphic = WordEqual(
|
| + feedback_element,
|
| + HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())));
|
| + GotoIf(is_megamorphic, &call_construct_function);
|
| +
|
| + Comment("check if weak cell");
|
| + Node* is_weak_cell = WordEqual(LoadMap(feedback_element),
|
| + LoadRoot(Heap::kWeakCellMapRootIndex));
|
| + GotoUnless(is_weak_cell, &check_allocation_site);
|
| +
|
| + // If the weak cell is cleared, we have a new chance to become
|
| + // monomorphic.
|
| + Comment("check if weak cell is cleared");
|
| + Node* is_smi = TaggedIsSmi(feedback_value);
|
| + Branch(is_smi, &initialize, &mark_megamorphic);
|
| +
|
| + Bind(&check_allocation_site);
|
| {
|
| - Label mark_megamorphic(this), initialize(this),
|
| - check_allocation_site(this), check_initialized(this),
|
| - set_alloc_feedback_and_call(this);
|
| - {
|
| - // Check if it is a megamorphic target
|
| - Comment("check if megamorphic");
|
| - Node* is_megamorphic = WordEqual(
|
| - feedback_element,
|
| - HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())));
|
| - GotoIf(is_megamorphic, &call_construct_function);
|
| -
|
| - Comment("check if weak cell");
|
| - Node* is_weak_cell = WordEqual(LoadMap(feedback_element),
|
| - LoadRoot(Heap::kWeakCellMapRootIndex));
|
| - GotoUnless(is_weak_cell, &check_allocation_site);
|
| - // If the weak cell is cleared, we have a new chance to become
|
| - // monomorphic.
|
| - Comment("check if weak cell is cleared");
|
| - Node* is_smi = TaggedIsSmi(feedback_value);
|
| - Branch(is_smi, &initialize, &mark_megamorphic);
|
| - }
|
| + Comment("check if it is an allocation site");
|
| + Node* is_allocation_site =
|
| + WordEqual(LoadObjectField(feedback_element, 0),
|
| + LoadRoot(Heap::kAllocationSiteMapRootIndex));
|
| + GotoUnless(is_allocation_site, &check_initialized);
|
|
|
| - Bind(&check_allocation_site);
|
| - {
|
| - Comment("check if it is an allocation site");
|
| - Node* is_allocation_site =
|
| - WordEqual(LoadObjectField(feedback_element, 0),
|
| - LoadRoot(Heap::kAllocationSiteMapRootIndex));
|
| - GotoUnless(is_allocation_site, &check_initialized);
|
| -
|
| - // Make sure the function is the Array() function
|
| - Node* context_slot =
|
| - LoadFixedArrayElement(LoadNativeContext(context),
|
| - Int32Constant(Context::ARRAY_FUNCTION_INDEX));
|
| - Node* is_array_function = WordEqual(context_slot, constructor);
|
| - Branch(is_array_function, &set_alloc_feedback_and_call,
|
| - &mark_megamorphic);
|
| - }
|
| + // Make sure the function is the Array() function.
|
| + Node* context_slot =
|
| + LoadFixedArrayElement(LoadNativeContext(context),
|
| + Int32Constant(Context::ARRAY_FUNCTION_INDEX));
|
| + Node* is_array_function = WordEqual(context_slot, constructor);
|
| + GotoUnless(is_array_function, &mark_megamorphic);
|
|
|
| - Bind(&set_alloc_feedback_and_call);
|
| - {
|
| - allocation_feedback.Bind(feedback_element);
|
| - Goto(&call_construct_function);
|
| - }
|
| + allocation_feedback.Bind(feedback_element);
|
| + Goto(&call_construct_function);
|
| + }
|
|
|
| - Bind(&check_initialized);
|
| - {
|
| - // Check if it is uninitialized.
|
| - Comment("check if uninitialized");
|
| - Node* is_uninitialized = WordEqual(
|
| - feedback_element, LoadRoot(Heap::kuninitialized_symbolRootIndex));
|
| - Branch(is_uninitialized, &initialize, &mark_megamorphic);
|
| - }
|
| + Bind(&check_initialized);
|
| + {
|
| + // Check if it is uninitialized.
|
| + Comment("check if uninitialized");
|
| + Node* is_uninitialized = WordEqual(
|
| + feedback_element, LoadRoot(Heap::kuninitialized_symbolRootIndex));
|
| + Branch(is_uninitialized, &initialize, &mark_megamorphic);
|
| + }
|
|
|
| - Bind(&initialize);
|
| - {
|
| - Label create_weak_cell(this), create_allocation_site(this);
|
| - Comment("initialize the feedback element");
|
| - // Check that it is the Array() function.
|
| - Node* context_slot =
|
| - LoadFixedArrayElement(LoadNativeContext(context),
|
| - Int32Constant(Context::ARRAY_FUNCTION_INDEX));
|
| - Node* is_array_function = WordEqual(context_slot, constructor);
|
| - Branch(is_array_function, &create_allocation_site, &create_weak_cell);
|
| -
|
| - Bind(&create_allocation_site);
|
| - {
|
| - Node* site = CreateAllocationSiteInFeedbackVector(
|
| - type_feedback_vector, SmiTag(slot_id));
|
| - allocation_feedback.Bind(site);
|
| - Goto(&call_construct_function);
|
| - }
|
| + Bind(&initialize);
|
| + {
|
| + Label create_allocation_site(this), create_weak_cell(this);
|
| + Comment("initialize the feedback element");
|
| + // Create an allocation site if the function is an array function,
|
| + // otherwise create a weak cell.
|
| + Node* context_slot =
|
| + LoadFixedArrayElement(LoadNativeContext(context),
|
| + Int32Constant(Context::ARRAY_FUNCTION_INDEX));
|
| + Node* is_array_function = WordEqual(context_slot, constructor);
|
| + Branch(is_array_function, &create_allocation_site, &create_weak_cell);
|
|
|
| - Bind(&create_weak_cell);
|
| - {
|
| - CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id),
|
| - constructor);
|
| - Goto(&call_construct_function);
|
| - }
|
| + Bind(&create_allocation_site);
|
| + {
|
| + Node* site = CreateAllocationSiteInFeedbackVector(type_feedback_vector,
|
| + SmiTag(slot_id));
|
| + allocation_feedback.Bind(site);
|
| + Goto(&call_construct_function);
|
| }
|
|
|
| - Bind(&mark_megamorphic);
|
| + Bind(&create_weak_cell);
|
| {
|
| - // MegamorphicSentinel is an immortal immovable object so
|
| - // write-barrier is not needed.
|
| - Comment("transition to megamorphic");
|
| - DCHECK(
|
| - Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex));
|
| - StoreFixedArrayElement(
|
| - type_feedback_vector, slot_id,
|
| - HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())),
|
| - SKIP_WRITE_BARRIER);
|
| + CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id),
|
| + constructor);
|
| Goto(&call_construct_function);
|
| }
|
| }
|
|
|
| - Bind(&call_construct_function);
|
| + Bind(&mark_megamorphic);
|
| {
|
| - Comment("call using callConstructFunction");
|
| - IncrementCallCount(type_feedback_vector, slot_id);
|
| - Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct(
|
| - isolate(), CallableType::kJSFunction);
|
| - return_value.Bind(CallStub(callable_function.descriptor(),
|
| - HeapConstant(callable_function.code()),
|
| - context, arg_count, new_target, constructor,
|
| - allocation_feedback.value(), first_arg));
|
| - Goto(&end);
|
| + // MegamorphicSentinel is an immortal immovable object so
|
| + // write-barrier is not needed.
|
| + Comment("transition to megamorphic");
|
| + DCHECK(Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex));
|
| + StoreFixedArrayElement(
|
| + type_feedback_vector, slot_id,
|
| + HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())),
|
| + SKIP_WRITE_BARRIER);
|
| + Goto(&call_construct_function);
|
| }
|
| }
|
|
|
|
|