// 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
