summaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins/ic-dynamic-check-maps.tq
blob: 3e194116fd8174d2e4ddd4707a2adda0130731e4 (plain)
1
2
3
4
5
6
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be:
// Context found in the LICENSE file.

namespace ic {

const kSuccess: constexpr int32
    generates 'static_cast<int>(DynamicCheckMapsStatus::kSuccess)';
const kBailout: constexpr int32
    generates 'static_cast<int>(DynamicCheckMapsStatus::kBailout)';
const kDeopt: constexpr int32
    generates 'static_cast<int>(DynamicCheckMapsStatus::kDeopt)';
extern macro LoadFeedbackVectorForStubWithTrampoline(): FeedbackVector;

macro PerformPolymorphicCheck(
    expectedPolymorphicArray: HeapObject, actualMap: Map,
    actualHandler: Smi|DataHandler): int32 {
  if (!Is<WeakFixedArray>(expectedPolymorphicArray)) {
    return kDeopt;
  }

  const polymorphicArray = UnsafeCast<WeakFixedArray>(expectedPolymorphicArray);
  const weakActualMap = MakeWeak(actualMap);
  const length = polymorphicArray.length_intptr;
  dcheck(length > 0);

  for (let mapIndex: intptr = 0; mapIndex < length;
       mapIndex += FeedbackIteratorEntrySize()) {
    const maybeCachedMap =
        UnsafeCast<WeakHeapObject>(polymorphicArray[mapIndex]);
    if (maybeCachedMap == weakActualMap) {
      const handlerIndex = mapIndex + FeedbackIteratorHandlerOffset();
      dcheck(handlerIndex < length);
      const maybeHandler =
          Cast<Object>(polymorphicArray[handlerIndex]) otherwise unreachable;
      if (TaggedEqual(maybeHandler, actualHandler)) {
        return kSuccess;
      } else {
        return kDeopt;
      }
    }
  }

  return kBailout;
}

macro PerformMonomorphicCheck(
    feedbackVector: FeedbackVector, slotIndex: intptr, expectedMap: HeapObject,
    actualMap: Map, actualHandler: Smi|DataHandler): int32 {
  if (TaggedEqual(expectedMap, actualMap)) {
    const handlerIndex = slotIndex + 1;
    dcheck(handlerIndex < feedbackVector.length_intptr);
    const maybeHandler =
        Cast<Object>(feedbackVector[handlerIndex]) otherwise unreachable;
    if (TaggedEqual(actualHandler, maybeHandler)) {
      return kSuccess;
    }

    return kDeopt;
  }

  return kBailout;
}

// This builtin performs map checks by dynamically looking at the
// feedback in the feedback vector.
//
// There are two major cases handled by this builtin:
// (a) Monormorphic check
// (b) Polymorphic check
//
// For the monormophic check, the incoming map is migrated and checked
// against the map and handler in the feedback vector.
//
// For the polymorphic check, the feedback vector is iterated over and
// each of the maps & handers are compared against the incoming map and
// handler.
//
// If any of the map and associated handler checks pass then we return
// kSuccess status. If we have never seen the map before, we return kBailout
// status to bailout to the interpreter and update the feedback. If we have seen
// the map, but the associated handler check fails then we return kDeopt status.
@export
macro DynamicCheckMaps(
    actualMap: Map, slotIndex: intptr, actualHandler: Smi|DataHandler): int32 {
  const feedbackVector = LoadFeedbackVectorForStubWithTrampoline();
  return DynamicCheckMapsWithFeedbackVector(
      actualMap, slotIndex, actualHandler, feedbackVector);
}

@export
macro DynamicCheckMapsWithFeedbackVector(
    actualMap: Map, slotIndex: intptr, actualHandler: Smi|DataHandler,
    feedbackVector: FeedbackVector): int32 {
  const feedback = feedbackVector[slotIndex];
  try {
    const maybePolymorphicArray =
        GetHeapObjectIfStrong(feedback) otherwise MigrateAndDoMonomorphicCheck;
    return PerformPolymorphicCheck(
        maybePolymorphicArray, actualMap, actualHandler);
  } label MigrateAndDoMonomorphicCheck {
    const expectedMap = GetHeapObjectAssumeWeak(feedback) otherwise Deopt;
    return PerformMonomorphicCheck(
        feedbackVector, slotIndex, expectedMap, actualMap, actualHandler);
  } label Deopt {
    return kDeopt;
  }
}

}  // namespace ic