ic-callable.tq 6.94 KB
Newer Older
1 2 3 4
// 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.

5 6
namespace ic {
namespace callable {
7

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
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;
35 36
  }

37 38 39 40
  const unwrappedTargetJSFunction =
      Cast<JSFunction>(unwrappedTarget) otherwise TransitionToMegamorphic;
  if (!InSameNativeContext(unwrappedTargetJSFunction.context, context)) {
    goto TransitionToMegamorphic;
41 42
  }

43 44
  StoreWeakReferenceInFeedbackVector(feedbackVector, slotId, targetHeapObject);
  ReportFeedbackUpdate(feedbackVector, slotId, 'Call:Initialize');
45 46 47 48
}

macro TransitionToMegamorphic(implicit context: Context)(
    feedbackVector: FeedbackVector, slotId: uintptr): void {
49 50
  StoreFeedbackVectorSlot(feedbackVector, slotId, kMegamorphicSymbol);
  ReportFeedbackUpdate(feedbackVector, slotId, 'Call:TransitionMegamorphic');
51 52 53 54 55 56 57 58 59 60 61
}

macro CollectCallFeedback(
    maybeTarget: JSAny, context: Context,
    maybeFeedbackVector: Undefined|FeedbackVector, slotId: uintptr): void {
  const feedbackVector =
      Cast<FeedbackVector>(maybeFeedbackVector) otherwise return;
  IncrementCallCount(feedbackVector, slotId);

  try {
    const feedback: MaybeObject =
62
        LoadFeedbackVectorSlot(feedbackVector, slotId);
63
    if (IsMonomorphic(feedback, maybeTarget)) return;
64 65
    if (IsMegamorphic(feedback)) return;
    if (IsUninitialized(feedback)) goto TryInitializeAsMonomorphic;
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

    // 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))
85 86
      goto TransitionToMegamorphic;

87 88
    StoreWeakReferenceInFeedbackVector(feedbackVector, slotId, feedbackCell);
    ReportFeedbackUpdate(feedbackVector, slotId, 'Call:FeedbackVectorCell');
89 90 91 92 93
  } label TryInitializeAsMonomorphic {
    TryInitializeAsMonomorphic(maybeTarget, feedbackVector, slotId)
        otherwise TransitionToMegamorphic;
  } label TransitionToMegamorphic {
    TransitionToMegamorphic(feedbackVector, slotId);
94
  }
95 96 97 98 99 100 101 102 103 104 105
}

macro CollectInstanceOfFeedback(
    maybeTarget: JSAny, context: Context,
    maybeFeedbackVector: Undefined|FeedbackVector, slotId: uintptr): void {
  const feedbackVector =
      Cast<FeedbackVector>(maybeFeedbackVector) otherwise return;
  // Note: The call count is not incremented.

  try {
    const feedback: MaybeObject =
106
        LoadFeedbackVectorSlot(feedbackVector, slotId);
107
    if (IsMonomorphic(feedback, maybeTarget)) return;
108 109
    if (IsMegamorphic(feedback)) return;
    if (IsUninitialized(feedback)) goto TryInitializeAsMonomorphic;
110 111 112 113 114 115 116 117 118 119 120

    // 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);
121
  }
122
}
123

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
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;
}

182 183
}  // namespace callable
}  // namespace ic