blob: 691f793b56f0876c6a92b9092798bd15d20a4841 [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>(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;
assert(length > 0);
for (let mapIndex: intptr = 0; mapIndex < length;
mapIndex += FeedbackIteratorEntrySize()) {
const maybeCachedMap =
UnsafeCast<WeakHeapObject>(polymorphicArray[mapIndex]);
if (maybeCachedMap == weakActualMap) {
const handlerIndex = mapIndex + FeedbackIteratorHandlerOffset();
assert(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;
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.
//
// 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