blob: 745ab711c14e3bd9c5a929d7fef81dbe43794594 [file] [log] [blame]
// 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