summaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins/ic-dynamic-map-checks.tq
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/builtins/ic-dynamic-map-checks.tq')
-rw-r--r--deps/v8/src/builtins/ic-dynamic-map-checks.tq155
1 files changed, 155 insertions, 0 deletions
diff --git a/deps/v8/src/builtins/ic-dynamic-map-checks.tq b/deps/v8/src/builtins/ic-dynamic-map-checks.tq
new file mode 100644
index 0000000000..745ab711c1
--- /dev/null
+++ b/deps/v8/src/builtins/ic-dynamic-map-checks.tq
@@ -0,0 +1,155 @@
+// 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>(DynamicMapChecksStatus::kSuccess)';
+const kBailout: constexpr int32
+ generates 'static_cast<int>(DynamicMapChecksStatus::kBailout)';
+const kDeopt: constexpr int32
+ generates 'static_cast<int>(DynamicMapChecksStatus::kDeopt)';
+extern runtime TryMigrateInstance(implicit context: Context)(Object): Object;
+extern macro LoadFeedbackVectorForStub(): FeedbackVector;
+
+macro PerformMapAndHandlerCheck(
+ entry: constexpr int32, polymorphicArray: WeakFixedArray,
+ weakActualMap: WeakHeapObject,
+ actualHandler: Smi|DataHandler): void labels Next,
+ Deopt {
+ const mapIndex = FeedbackIteratorMapIndexForEntry(entry);
+ assert(mapIndex < polymorphicArray.length_intptr);
+
+ const maybeCachedMap = UnsafeCast<WeakHeapObject>(polymorphicArray[mapIndex]);
+ if (maybeCachedMap != weakActualMap) {
+ goto Next;
+ }
+
+ const handlerIndex = FeedbackIteratorHandlerIndexForEntry(entry);
+ assert(handlerIndex < polymorphicArray.length_intptr);
+ const maybeHandler =
+ Cast<Object>(polymorphicArray[handlerIndex]) otherwise unreachable;
+ if (TaggedNotEqual(maybeHandler, actualHandler)) {
+ goto Deopt;
+ }
+}
+
+macro PerformPolymorphicCheck(
+ expectedPolymorphicArray: HeapObject, actualMap: Map,
+ actualHandler: Smi|DataHandler): int32 {
+ if (!Is<WeakFixedArray>(expectedPolymorphicArray)) {
+ return kDeopt;
+ }
+ try {
+ const polymorphicArray =
+ UnsafeCast<WeakFixedArray>(expectedPolymorphicArray);
+ const weakActualMap = MakeWeak(actualMap);
+ const length = polymorphicArray.length_intptr;
+ assert(length > 0);
+
+ try {
+ if (length >= FeedbackIteratorSizeFor(4)) goto Len4;
+ if (length == FeedbackIteratorSizeFor(3)) goto Len3;
+ if (length == FeedbackIteratorSizeFor(2)) goto Len2;
+ if (length == FeedbackIteratorSizeFor(1)) goto Len1;
+
+ unreachable;
+ } label Len4 {
+ PerformMapAndHandlerCheck(
+ 3, polymorphicArray, weakActualMap, actualHandler) otherwise Len3,
+ Deopt;
+ return kSuccess;
+ } label Len3 {
+ PerformMapAndHandlerCheck(
+ 2, polymorphicArray, weakActualMap, actualHandler) otherwise Len2,
+ Deopt;
+ return kSuccess;
+ } label Len2 {
+ PerformMapAndHandlerCheck(
+ 1, polymorphicArray, weakActualMap, actualHandler) otherwise Len1,
+ Deopt;
+ return kSuccess;
+ } label Len1 {
+ PerformMapAndHandlerCheck(
+ 0, polymorphicArray, weakActualMap, actualHandler)
+ otherwise Bailout, Deopt;
+ return kSuccess;
+ }
+ } label Bailout {
+ return kBailout;
+ } label Deopt {
+ return kDeopt;
+ }
+}
+
+macro PerformMonomorphicCheck(
+ feedbackVector: FeedbackVector, slotIndex: intptr, expectedMap: HeapObject,
+ actualMap: Map, actualHandler: Smi|DataHandler): int32 {
+ if (TaggedEqual(expectedMap, actualMap)) {
+ const handlerIndex = slotIndex + 1;
+ assert(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. Otherwise, we
+// bailout to the runtime.
+//
+// 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 any of the map check passes but the associated handler check
+// fails then we return kFailure status.
+//
+// For other cases, we bailout to the runtime.
+builtin DynamicMapChecks(implicit context: Context)(
+ slotIndex: intptr, actualValue: HeapObject,
+ actualHandler: Smi|DataHandler): int32 {
+ const feedbackVector = LoadFeedbackVectorForStub();
+ let actualMap = actualValue.map;
+ const feedback = feedbackVector[slotIndex];
+ try {
+ const maybePolymorphicArray =
+ GetHeapObjectIfStrong(feedback) otherwise MigrateAndDoMonomorphicCheck;
+ return PerformPolymorphicCheck(
+ maybePolymorphicArray, actualMap, actualHandler);
+ } label MigrateAndDoMonomorphicCheck {
+ const expectedMap = GetHeapObjectAssumeWeak(feedback) otherwise Deopt;
+ if (IsDeprecatedMap(actualMap)) {
+ // TODO(gsathya): Should this migration happen before the
+ // polymorphic check?
+ const result = TryMigrateInstance(actualValue);
+ if (TaggedIsSmi(result)) {
+ return kDeopt;
+ }
+ actualMap = actualValue.map;
+ }
+ return PerformMonomorphicCheck(
+ feedbackVector, slotIndex, expectedMap, actualMap, actualHandler);
+ } label Deopt {
+ return kDeopt;
+ }
+}
+
+} // namespace ic