blob: 8ee7fab17a8105fb5a9fd2e69d4a0d7c177ff613 [file] [log] [blame]
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
namespace ic {
namespace callable {
extern macro IncrementCallCount(FeedbackVector, uintptr): void;
macro IsMonomorphic(feedback: MaybeObject, target: JSAny): bool {
return IsWeakReferenceToObject(feedback, target);
}
macro InSameNativeContext(lhs: Context, rhs: Context): bool {
return LoadNativeContext(lhs) == LoadNativeContext(rhs);
}
macro MaybeObjectToStrong(maybeObject: MaybeObject):
HeapObject labels IfCleared {
assert(IsWeakOrCleared(maybeObject));
const weakObject = %RawDownCast<Weak<HeapObject>>(maybeObject);
return WeakToStrong(weakObject) otherwise IfCleared;
}
macro TryInitializeAsMonomorphic(implicit context: Context)(
maybeTarget: JSAny, feedbackVector: FeedbackVector,
slotId: uintptr): void labels TransitionToMegamorphic {
const targetHeapObject =
Cast<HeapObject>(maybeTarget) otherwise TransitionToMegamorphic;
let unwrappedTarget = targetHeapObject;
while (Is<JSBoundFunction>(unwrappedTarget)) {
unwrappedTarget =
UnsafeCast<JSBoundFunction>(unwrappedTarget).bound_target_function;
}
const unwrappedTargetJSFunction =
Cast<JSFunction>(unwrappedTarget) otherwise TransitionToMegamorphic;
if (!InSameNativeContext(unwrappedTargetJSFunction.context, context)) {
goto TransitionToMegamorphic;
}
StoreWeakReferenceInFeedbackVector(feedbackVector, slotId, targetHeapObject);
ReportFeedbackUpdate(feedbackVector, slotId, 'Call:Initialize');
}
macro TransitionToMegamorphic(implicit context: Context)(
feedbackVector: FeedbackVector, slotId: uintptr): void {
StoreFeedbackVectorSlot(feedbackVector, slotId, kMegamorphicSymbol);
ReportFeedbackUpdate(feedbackVector, slotId, 'Call:TransitionMegamorphic');
}
macro CollectCallFeedback(
maybeTarget: JSAny, context: Context,
maybeFeedbackVector: Undefined|FeedbackVector, slotId: uintptr): void {
// TODO(v8:9891): Remove this assert once all callers are ported to Torque.
// This assert ensures correctness of maybeFeedbackVector's type which can
// be easily broken for calls from CSA.
assert(
IsUndefined(maybeFeedbackVector) ||
Is<FeedbackVector>(maybeFeedbackVector));
const feedbackVector =
Cast<FeedbackVector>(maybeFeedbackVector) otherwise return;
IncrementCallCount(feedbackVector, slotId);
try {
const feedback: MaybeObject =
LoadFeedbackVectorSlot(feedbackVector, slotId);
if (IsMonomorphic(feedback, maybeTarget)) return;
if (IsMegamorphic(feedback)) return;
if (IsUninitialized(feedback)) goto TryInitializeAsMonomorphic;
// If cleared, we have a new chance to become monomorphic.
const feedbackValue: HeapObject =
MaybeObjectToStrong(feedback) otherwise TryInitializeAsMonomorphic;
// Try transitioning to a feedback cell.
// Check if {target}s feedback cell matches the {feedbackValue}.
const target =
Cast<JSFunction>(maybeTarget) otherwise TransitionToMegamorphic;
const targetFeedbackCell: FeedbackCell = target.feedback_cell;
if (TaggedEqual(feedbackValue, targetFeedbackCell)) return;
// Check if {target} and {feedbackValue} are both JSFunctions with
// the same feedback vector cell, and that those functions were
// actually compiled already.
const feedbackValueJSFunction =
Cast<JSFunction>(feedbackValue) otherwise TransitionToMegamorphic;
const feedbackCell: FeedbackCell = feedbackValueJSFunction.feedback_cell;
if (!TaggedEqual(feedbackCell, targetFeedbackCell))
goto TransitionToMegamorphic;
StoreWeakReferenceInFeedbackVector(feedbackVector, slotId, feedbackCell);
ReportFeedbackUpdate(feedbackVector, slotId, 'Call:FeedbackVectorCell');
} label TryInitializeAsMonomorphic {
TryInitializeAsMonomorphic(maybeTarget, feedbackVector, slotId)
otherwise TransitionToMegamorphic;
} label TransitionToMegamorphic {
TransitionToMegamorphic(feedbackVector, slotId);
}
}
macro CollectInstanceOfFeedback(
maybeTarget: JSAny, context: Context,
maybeFeedbackVector: Undefined|FeedbackVector, slotId: uintptr): void {
// TODO(v8:9891): Remove this assert once all callers are ported to Torque.
// This assert ensures correctness of maybeFeedbackVector's type which can
// be easily broken for calls from CSA.
assert(
IsUndefined(maybeFeedbackVector) ||
Is<FeedbackVector>(maybeFeedbackVector));
const feedbackVector =
Cast<FeedbackVector>(maybeFeedbackVector) otherwise return;
// Note: The call count is not incremented.
try {
const feedback: MaybeObject =
LoadFeedbackVectorSlot(feedbackVector, slotId);
if (IsMonomorphic(feedback, maybeTarget)) return;
if (IsMegamorphic(feedback)) return;
if (IsUninitialized(feedback)) goto TryInitializeAsMonomorphic;
// If cleared, we have a new chance to become monomorphic.
const _feedbackValue: HeapObject =
MaybeObjectToStrong(feedback) otherwise TryInitializeAsMonomorphic;
goto TransitionToMegamorphic;
} label TryInitializeAsMonomorphic {
TryInitializeAsMonomorphic(maybeTarget, feedbackVector, slotId)
otherwise TransitionToMegamorphic;
} label TransitionToMegamorphic {
TransitionToMegamorphic(feedbackVector, slotId);
}
}
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) {
// TODO(v8:9891): Remove this assert once all callers are ported to Torque.
// This assert ensures correctness of maybeFeedbackVector's type which can
// be easily broken for calls from CSA.
assert(
IsUndefined(maybeFeedbackVector) ||
Is<FeedbackVector>(maybeFeedbackVector));
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