diff options
Diffstat (limited to 'deps/v8/src/builtins/ic-dynamic-map-checks.tq')
-rw-r--r-- | deps/v8/src/builtins/ic-dynamic-map-checks.tq | 155 |
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 |