Commit 36df34cc authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[torque] Port CollectConstructFeedback

Previously implemented directly in InterpreterAssembler::Construct,
this will soon also be needed to implement a Construct_WithFeedback
builtin.

Bug: v8:8888
Change-Id: I01a00914c6554a5b83f414a93d85a15ec02df662
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2193717
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67753}
parent eb23cef0
......@@ -2,46 +2,47 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
extern macro IsAllocationSite(HeapObject): bool;
extern macro IsBigInt(HeapObject): bool;
extern macro IsConstructor(HeapObject): bool;
extern macro IsContext(HeapObject): bool;
extern macro IsCustomElementsReceiverInstanceType(int32): bool;
extern macro IsExtensibleMap(Map): bool;
extern macro IsFeedbackCell(HeapObject): bool;
extern macro IsFeedbackVector(HeapObject): bool;
extern macro IsFixedArray(HeapObject): bool;
extern macro IsHeapNumber(HeapObject): bool;
extern macro IsJSAggregateError(HeapObject): bool;
extern macro IsJSArray(HeapObject): bool;
extern macro IsJSProxy(HeapObject): bool;
extern macro IsJSRegExp(HeapObject): bool;
extern macro IsJSRegExpStringIterator(HeapObject): bool;
extern macro IsMap(HeapObject): bool;
extern macro IsJSFunction(HeapObject): bool;
extern macro IsJSArrayMap(Map): bool;
extern macro IsJSBoundFunction(HeapObject): bool;
extern macro IsJSObject(HeapObject): bool;
extern macro IsJSFinalizationRegistry(HeapObject): bool;
extern macro IsJSFunction(HeapObject): bool;
extern macro IsJSObject(HeapObject): bool;
extern macro IsJSPrimitiveWrapper(HeapObject): bool;
extern macro IsJSPromise(HeapObject): bool;
extern macro IsJSTypedArray(HeapObject): bool;
extern macro IsNumberDictionary(HeapObject): bool;
extern macro IsContext(HeapObject): bool;
extern macro IsNativeContext(HeapObject): bool;
extern macro IsJSProxy(HeapObject): bool;
extern macro IsJSReceiver(HeapObject): bool;
extern macro IsHeapNumber(HeapObject): bool;
extern macro IsBigInt(HeapObject): bool;
extern macro IsFixedArray(HeapObject): bool;
extern macro IsJSRegExp(HeapObject): bool;
extern macro IsJSRegExpStringIterator(HeapObject): bool;
extern macro IsJSTypedArray(HeapObject): bool;
extern macro IsMap(HeapObject): bool;
extern macro IsName(HeapObject): bool;
extern macro IsPrivateSymbol(HeapObject): bool;
extern macro IsNumber(Object): bool;
extern macro IsNativeContext(HeapObject): bool;
extern macro IsNumberDictionary(HeapObject): bool;
extern macro IsNumberNormalized(Number): bool;
extern macro IsSafeInteger(Object): bool;
extern macro IsNumber(Object): bool;
extern macro IsOddball(HeapObject): bool;
extern macro IsSymbol(HeapObject): bool;
extern macro IsTuple2(HeapObject): bool;
extern macro IsJSArrayMap(Map): bool;
extern macro IsExtensibleMap(Map): bool;
extern macro IsJSPrimitiveWrapper(HeapObject): bool;
extern macro IsPrivateSymbol(HeapObject): bool;
extern macro IsPromiseCapability(HeapObject): bool;
extern macro IsPromiseFulfillReactionJobTask(HeapObject): bool;
extern macro IsPromiseReaction(HeapObject): bool;
extern macro IsPromiseReactionJobTask(HeapObject): bool;
extern macro IsPromiseRejectReactionJobTask(HeapObject): bool;
extern macro IsPromiseFulfillReactionJobTask(HeapObject): bool;
extern macro IsSafeInteger(Object): bool;
extern macro IsSharedFunctionInfo(HeapObject): bool;
extern macro IsCustomElementsReceiverInstanceType(int32): bool;
extern macro IsSymbol(HeapObject): bool;
extern macro IsTuple2(HeapObject): bool;
extern macro HeapObjectToJSDataView(HeapObject): JSDataView
labels CastError;
......@@ -282,6 +283,12 @@ Cast<Undefined>(o: HeapObject): Undefined
return Cast<Undefined>(o) otherwise CastError;
}
Cast<AllocationSite>(o: HeapObject): AllocationSite
labels CastError {
if (IsAllocationSite(o)) return %RawDownCast<AllocationSite>(o);
goto CastError;
}
Cast<FixedArray>(o: HeapObject): FixedArray
labels CastError {
return HeapObjectToFixedArray(o) otherwise CastError;
......
......@@ -121,5 +121,63 @@ macro CollectInstanceOfFeedback(
}
}
macro BothTaggedEqualArrayFunction(implicit context: Context)(
first: JSAny, second: JSAny): bool {
return TaggedEqual(first, second) && TaggedEqual(second, GetArrayFunction());
}
extern macro CreateAllocationSiteInFeedbackVector(
FeedbackVector, uintptr): AllocationSite;
macro CollectConstructFeedback(implicit context: Context)(
target: JSAny, newTarget: JSAny,
maybeFeedbackVector: Undefined|FeedbackVector,
slotId: uintptr): never labels ConstructGeneric,
ConstructArray(AllocationSite) {
const feedbackVector = Cast<FeedbackVector>(maybeFeedbackVector)
otherwise goto ConstructGeneric;
IncrementCallCount(feedbackVector, slotId);
try {
const feedback: MaybeObject =
LoadFeedbackVectorSlot(feedbackVector, slotId);
if (IsMonomorphic(feedback, newTarget)) goto ConstructGeneric;
if (IsMegamorphic(feedback)) goto ConstructGeneric;
if (IsUninitialized(feedback)) goto TryInitializeAsMonomorphic;
if (!IsWeakOrCleared(feedback)) {
const feedbackAsStrong = %RawDownCast<Object>(feedback);
if (Is<AllocationSite>(feedbackAsStrong)) {
if (BothTaggedEqualArrayFunction(target, newTarget)) {
goto ConstructArray(UnsafeCast<AllocationSite>(feedbackAsStrong));
}
goto TransitionToMegamorphic;
}
}
// If cleared, we have a new chance to become monomorphic.
const _feedbackValue: HeapObject =
MaybeObjectToStrong(feedback) otherwise TryInitializeAsMonomorphic;
goto TransitionToMegamorphic;
} label TryInitializeAsMonomorphic {
if (BothTaggedEqualArrayFunction(target, newTarget)) {
// In this case we can skip unwrapping and context validation since we
// know the target is the current context's array function.
const allocationSite =
CreateAllocationSiteInFeedbackVector(feedbackVector, slotId);
ReportFeedbackUpdate(
feedbackVector, slotId, 'Construct:CreateAllocationSite');
goto ConstructArray(allocationSite);
}
TryInitializeAsMonomorphic(newTarget, feedbackVector, slotId)
otherwise TransitionToMegamorphic;
} label TransitionToMegamorphic {
TransitionToMegamorphic(feedbackVector, slotId);
}
goto ConstructGeneric;
}
} // namespace callable
} // namespace ic
......@@ -22,6 +22,17 @@ macro CollectInstanceOfFeedback(
maybeTarget, context, maybeFeedbackVector, slotId);
}
@export
macro CollectConstructFeedback(implicit context: Context)(
target: JSAny, newTarget: JSAny,
maybeFeedbackVector: Undefined|FeedbackVector,
slotId: uintptr): never labels ConstructGeneric,
ConstructArray(AllocationSite) {
callable::CollectConstructFeedback(
target, newTarget, maybeFeedbackVector, slotId)
otherwise ConstructGeneric, ConstructArray;
}
// --- Common functionality.
extern macro MegamorphicSymbolConstant(): Symbol;
......@@ -44,4 +55,5 @@ extern macro StoreFeedbackVectorSlot(
extern macro StoreWeakReferenceInFeedbackVector(
FeedbackVector, uintptr, HeapObject): MaybeObject;
extern macro ReportFeedbackUpdate(FeedbackVector, uintptr, constexpr string);
}
} // namespace ic
......@@ -832,149 +832,24 @@ TNode<Object> InterpreterAssembler::Construct(
DCHECK(Bytecodes::MakesCallAlongCriticalPath(bytecode_));
TVARIABLE(Object, var_result);
TVARIABLE(AllocationSite, var_site);
Label extra_checks(this, Label::kDeferred), return_result(this, &var_result),
construct(this), construct_array(this, &var_site);
GotoIf(IsUndefined(maybe_feedback_vector), &construct);
TNode<FeedbackVector> feedback_vector = CAST(maybe_feedback_vector);
// Increment the call count.
IncrementCallCount(feedback_vector, slot_id);
// Check if we have monomorphic {new_target} feedback already.
TNode<MaybeObject> feedback =
LoadFeedbackVectorSlot(feedback_vector, slot_id);
Branch(IsWeakReferenceToObject(feedback, new_target), &construct,
&extra_checks);
BIND(&extra_checks);
{
Label check_allocation_site(this), check_initialized(this),
initialize(this), mark_megamorphic(this);
// Check if it is a megamorphic {new_target}..
Comment("check if megamorphic");
TNode<BoolT> is_megamorphic = TaggedEqual(
feedback, HeapConstant(FeedbackVector::MegamorphicSentinel(isolate())));
GotoIf(is_megamorphic, &construct);
Comment("check if weak reference");
GotoIfNot(IsWeakOrCleared(feedback), &check_allocation_site);
// If the weak reference is cleared, we have a new chance to become
// monomorphic.
Comment("check if weak reference is cleared");
Branch(IsCleared(feedback), &initialize, &mark_megamorphic);
BIND(&check_allocation_site);
{
// Check if it is an AllocationSite.
Comment("check if allocation site");
TNode<HeapObject> strong_feedback = CAST(feedback);
GotoIfNot(IsAllocationSite(strong_feedback), &check_initialized);
// Make sure that {target} and {new_target} are the Array constructor.
TNode<Object> array_function = LoadContextElement(
LoadNativeContext(context), Context::ARRAY_FUNCTION_INDEX);
GotoIfNot(TaggedEqual(target, array_function), &mark_megamorphic);
GotoIfNot(TaggedEqual(new_target, array_function), &mark_megamorphic);
var_site = CAST(strong_feedback);
Goto(&construct_array);
}
BIND(&check_initialized);
{
// Check if it is uninitialized.
Comment("check if uninitialized");
TNode<BoolT> is_uninitialized =
TaggedEqual(feedback, UninitializedSymbolConstant());
Branch(is_uninitialized, &initialize, &mark_megamorphic);
}
Label return_result(this), construct_generic(this),
construct_array(this, &var_site);
BIND(&initialize);
{
Comment("check if function in same native context");
GotoIf(TaggedIsSmi(new_target), &mark_megamorphic);
// Check if the {new_target} is a JSFunction or JSBoundFunction
// in the current native context.
TVARIABLE(HeapObject, var_current, CAST(new_target));
Label loop(this, &var_current), done_loop(this);
Goto(&loop);
BIND(&loop);
{
Label if_boundfunction(this), if_function(this);
TNode<HeapObject> current = var_current.value();
TNode<Uint16T> current_instance_type = LoadInstanceType(current);
GotoIf(InstanceTypeEqual(current_instance_type, JS_BOUND_FUNCTION_TYPE),
&if_boundfunction);
Branch(InstanceTypeEqual(current_instance_type, JS_FUNCTION_TYPE),
&if_function, &mark_megamorphic);
CollectConstructFeedback(context, target, new_target, maybe_feedback_vector,
slot_id, &construct_generic, &construct_array,
&var_site);
BIND(&if_function);
BIND(&construct_generic);
{
// Check that the JSFunction {current} is in the current native
// context.
TNode<Context> current_context =
CAST(LoadObjectField(current, JSFunction::kContextOffset));
TNode<NativeContext> current_native_context =
LoadNativeContext(current_context);
Branch(
TaggedEqual(LoadNativeContext(context), current_native_context),
&done_loop, &mark_megamorphic);
}
BIND(&if_boundfunction);
{
// Continue with the [[BoundTargetFunction]] of {current}.
var_current = LoadObjectField<HeapObject>(
current, JSBoundFunction::kBoundTargetFunctionOffset);
Goto(&loop);
}
}
BIND(&done_loop);
// Create an AllocationSite if {target} and {new_target} refer
// to the current native context's Array constructor.
Label create_allocation_site(this), store_weak_reference(this);
GotoIfNot(TaggedEqual(target, new_target), &store_weak_reference);
TNode<Object> array_function = LoadContextElement(
LoadNativeContext(context), Context::ARRAY_FUNCTION_INDEX);
Branch(TaggedEqual(target, array_function), &create_allocation_site,
&store_weak_reference);
BIND(&create_allocation_site);
{
var_site =
CreateAllocationSiteInFeedbackVector(feedback_vector, slot_id);
ReportFeedbackUpdate(feedback_vector, slot_id,
"Construct:CreateAllocationSite");
Goto(&construct_array);
}
BIND(&store_weak_reference);
{
StoreWeakReferenceInFeedbackVector(feedback_vector, slot_id,
CAST(new_target));
ReportFeedbackUpdate(feedback_vector, slot_id,
"Construct:StoreWeakReference");
Goto(&construct);
}
}
BIND(&mark_megamorphic);
{
// MegamorphicSentinel is an immortal immovable object so
// write-barrier is not needed.
Comment("transition to megamorphic");
DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kmegamorphic_symbol));
StoreFeedbackVectorSlot(
feedback_vector, slot_id,
HeapConstant(FeedbackVector::MegamorphicSentinel(isolate())),
SKIP_WRITE_BARRIER);
ReportFeedbackUpdate(feedback_vector, slot_id,
"Construct:TransitionMegamorphic");
Goto(&construct);
}
// TODO(bmeurer): Remove the generic type_info parameter from the Construct.
Comment("call using Construct builtin");
Callable callable = CodeFactory::InterpreterPushArgsThenConstruct(
isolate(), InterpreterPushArgsMode::kOther);
TNode<Code> code_target = HeapConstant(callable.code());
var_result = CallStub(callable.descriptor(), code_target, context,
args.reg_count(), args.base_reg_location(), target,
new_target, UndefinedConstant());
Goto(&return_result);
}
BIND(&construct_array);
......@@ -991,19 +866,6 @@ TNode<Object> InterpreterAssembler::Construct(
Goto(&return_result);
}
BIND(&construct);
{
// TODO(bmeurer): Remove the generic type_info parameter from the Construct.
Comment("call using Construct builtin");
Callable callable = CodeFactory::InterpreterPushArgsThenConstruct(
isolate(), InterpreterPushArgsMode::kOther);
TNode<Code> code_target = HeapConstant(callable.code());
var_result = CallStub(callable.descriptor(), code_target, context,
args.reg_count(), args.base_reg_location(), target,
new_target, UndefinedConstant());
Goto(&return_result);
}
BIND(&return_result);
return var_result.value();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment