// 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(DynamicCheckMapsStatus::kSuccess)'; const kBailout: constexpr int32 generates 'static_cast(DynamicCheckMapsStatus::kBailout)'; const kDeopt: constexpr int32 generates 'static_cast(DynamicCheckMapsStatus::kDeopt)'; extern macro LoadFeedbackVectorForStubWithTrampoline(): FeedbackVector; macro PerformPolymorphicCheck( expectedPolymorphicArray: HeapObject, actualMap: Map, actualHandler: Smi|DataHandler): int32 { if (!Is(expectedPolymorphicArray)) { return kDeopt; } const polymorphicArray = UnsafeCast(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(polymorphicArray[mapIndex]); if (maybeCachedMap == weakActualMap) { const handlerIndex = mapIndex + FeedbackIteratorHandlerOffset(); dcheck(handlerIndex < length); const maybeHandler = Cast(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(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