Commit 2cf6ee0b authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[turboprop] Inline monomorphic map check

Instead of loading the map from the feedback vector for monomorphic
access, this CL directly inlines the expected map constant as a static
check.

In case this static check fails, we call out to a builtin which performs
additional dynamic map checks.

There are several dynamic map checks performed by the builtin for various
cases such as:
(a) IC is monomorphic with a map that's different from the initial
static map that we checked, in which case we perform another dynamic
map check.
(b) IC is monomorphic but incoming map is a deprecated map in which case
we call out the runtime to migrate this incoming object to a new map and
then try to handle it.
(c) IC has now transitioned to polymorphic in which we use the old
dynamic polymorphic checks to validate the map and handler.

Bug: v8:10582, v8:9684
Change-Id: Id87265ed513e4aef87b8e66c826afbf10f50a1d0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2429034
Commit-Queue: Sathya Gunasekaran  <gsathya@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarMythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70304}
parent 9137237b
...@@ -52,8 +52,10 @@ type Uninitialized extends Tagged; ...@@ -52,8 +52,10 @@ type Uninitialized extends Tagged;
extern macro MakeWeak(HeapObject): WeakHeapObject; extern macro MakeWeak(HeapObject): WeakHeapObject;
extern macro GetHeapObjectAssumeWeak(WeakHeapObject): extern macro GetHeapObjectAssumeWeak(WeakHeapObject):
HeapObject labels ClearedWeakPointer; HeapObject labels ClearedWeakPointer;
extern macro GetHeapObjectIfStrong(MaybeObject): HeapObject labels IfNotStrong;
extern macro IsWeakOrCleared(MaybeObject): bool; extern macro IsWeakOrCleared(MaybeObject): bool;
extern macro IsWeakReferenceToObject(MaybeObject, Object): bool; extern macro IsWeakReferenceToObject(MaybeObject, Object): bool;
extern macro IsStrong(MaybeObject): bool;
macro StrongToWeak<T: type>(x: T): Weak<T> { macro StrongToWeak<T: type>(x: T): Weak<T> {
return %RawDownCast<Weak<T>>(MakeWeak(x)); return %RawDownCast<Weak<T>>(MakeWeak(x));
...@@ -1559,6 +1561,7 @@ namespace runtime { ...@@ -1559,6 +1561,7 @@ namespace runtime {
extern runtime extern runtime
GetDerivedMap(Context, JSFunction, JSReceiver): Map; GetDerivedMap(Context, JSFunction, JSReceiver): Map;
} }
extern macro IsDeprecatedMap(Map): bool;
transitioning builtin FastCreateDataProperty(implicit context: Context)( transitioning builtin FastCreateDataProperty(implicit context: Context)(
receiver: JSReceiver, key: JSAny, value: JSAny): Object { receiver: JSReceiver, key: JSAny, value: JSAny): Object {
......
...@@ -668,11 +668,18 @@ UnsafeCast<RegExpMatchInfo>(implicit context: Context)(o: Object): ...@@ -668,11 +668,18 @@ UnsafeCast<RegExpMatchInfo>(implicit context: Context)(o: Object):
return %RawDownCast<RegExpMatchInfo>(o); return %RawDownCast<RegExpMatchInfo>(o);
} }
macro CastOrDefault<T: type, Arg: type, Default: type>( macro UnsafeCast<A : type extends WeakHeapObject>(o: A|Object): A {
implicit context: Context)(x: Arg, default: Default): T|Default { assert(IsWeakOrCleared(o));
return %RawDownCast<A>(o);
}
macro
CastOrDefault<T: type, Arg: type, Default: type>(implicit context: Context)(
x: Arg, default: Default): T|Default {
return Cast<T>(x) otherwise return default; return Cast<T>(x) otherwise return default;
} }
// This is required for casting MaybeObject to Object.
Cast<Object>(o: Object): Object Cast<Object>(o: Object): Object
labels _CastError { labels _CastError {
return o; return o;
......
...@@ -10,16 +10,17 @@ const kBailout: constexpr int32 ...@@ -10,16 +10,17 @@ const kBailout: constexpr int32
generates 'static_cast<int>(DynamicMapChecksStatus::kBailout)'; generates 'static_cast<int>(DynamicMapChecksStatus::kBailout)';
const kDeopt: constexpr int32 const kDeopt: constexpr int32
generates 'static_cast<int>(DynamicMapChecksStatus::kDeopt)'; generates 'static_cast<int>(DynamicMapChecksStatus::kDeopt)';
extern runtime TryMigrateInstance(implicit context: Context)(Object): Object;
macro PerformMapAndHandlerCheck( macro PerformMapAndHandlerCheck(
entry: constexpr int32, polymorphicArray: WeakFixedArray, entry: constexpr int32, polymorphicArray: WeakFixedArray,
weakActualMap: WeakHeapObject, actualHandler: Object): void labels Next, weakActualMap: WeakHeapObject,
actualHandler: Smi|DataHandler): void labels Next,
Deopt { Deopt {
const mapIndex = FeedbackIteratorMapIndexForEntry(entry); const mapIndex = FeedbackIteratorMapIndexForEntry(entry);
assert(mapIndex < polymorphicArray.length_intptr); assert(mapIndex < polymorphicArray.length_intptr);
const maybeCachedMap =
Cast<WeakHeapObject>(polymorphicArray[mapIndex]) otherwise unreachable; const maybeCachedMap = UnsafeCast<WeakHeapObject>(polymorphicArray[mapIndex]);
assert(IsWeakOrCleared(maybeCachedMap));
if (maybeCachedMap != weakActualMap) { if (maybeCachedMap != weakActualMap) {
goto Next; goto Next;
} }
...@@ -33,7 +34,7 @@ macro PerformMapAndHandlerCheck( ...@@ -33,7 +34,7 @@ macro PerformMapAndHandlerCheck(
} }
} }
builtin DynamicMapChecks(implicit context: Context)( macro PerformPolymorphicCheck(
expectedPolymorphicArray: HeapObject, actualMap: Map, expectedPolymorphicArray: HeapObject, actualMap: Map,
actualHandler: Smi|DataHandler): int32 { actualHandler: Smi|DataHandler): int32 {
if (!Is<WeakFixedArray>(expectedPolymorphicArray)) { if (!Is<WeakFixedArray>(expectedPolymorphicArray)) {
...@@ -41,7 +42,7 @@ builtin DynamicMapChecks(implicit context: Context)( ...@@ -41,7 +42,7 @@ builtin DynamicMapChecks(implicit context: Context)(
} }
try { try {
const polymorphicArray = const polymorphicArray =
Cast<WeakFixedArray>(expectedPolymorphicArray) otherwise unreachable; UnsafeCast<WeakFixedArray>(expectedPolymorphicArray);
const weakActualMap = MakeWeak(actualMap); const weakActualMap = MakeWeak(actualMap);
const length = polymorphicArray.length_intptr; const length = polymorphicArray.length_intptr;
assert(length > 0); assert(length > 0);
...@@ -80,4 +81,70 @@ builtin DynamicMapChecks(implicit context: Context)( ...@@ -80,4 +81,70 @@ builtin DynamicMapChecks(implicit context: Context)(
return kDeopt; return kDeopt;
} }
} }
macro PerformMonomorphicCheck(
feedbackVector: FeedbackVector, slotIndex: intptr, maybeMap: MaybeObject,
actualMap: Map, actualHandler: Smi|DataHandler): int32 {
if (IsWeakReferenceToObject(maybeMap, 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)(
feedbackVector: FeedbackVector, slotIndex: intptr, actualValue: HeapObject,
actualMap: Map, actualHandler: Smi|DataHandler): int32 {
const feedback = feedbackVector[slotIndex];
try {
const maybePolymorphicArray =
GetHeapObjectIfStrong(feedback) otherwise MigrateAndDoMonomorphicCheck;
return PerformPolymorphicCheck(
maybePolymorphicArray, actualMap, actualHandler);
} label MigrateAndDoMonomorphicCheck {
let newActualMap = actualMap;
if (IsDeprecatedMap(actualMap)) {
// TODO(gsathya): Should this migration happen before the
// polymorphic check?
const result = TryMigrateInstance(actualMap);
if (TaggedIsSmi(result)) {
return kDeopt;
}
newActualMap = actualValue.map;
}
return PerformMonomorphicCheck(
feedbackVector, slotIndex, feedback, newActualMap, actualHandler);
}
} }
} // namespace ic
...@@ -50,10 +50,14 @@ macro IsUninitialized(feedback: MaybeObject): bool { ...@@ -50,10 +50,14 @@ macro IsUninitialized(feedback: MaybeObject): bool {
} }
extern macro LoadFeedbackVectorSlot(FeedbackVector, uintptr): MaybeObject; extern macro LoadFeedbackVectorSlot(FeedbackVector, uintptr): MaybeObject;
extern operator '[]' macro LoadFeedbackVectorSlot(
FeedbackVector, intptr): MaybeObject;
extern macro StoreFeedbackVectorSlot( extern macro StoreFeedbackVectorSlot(
FeedbackVector, uintptr, MaybeObject): void; FeedbackVector, uintptr, MaybeObject): void;
extern macro StoreWeakReferenceInFeedbackVector( extern macro StoreWeakReferenceInFeedbackVector(
FeedbackVector, uintptr, HeapObject): MaybeObject; FeedbackVector, uintptr, HeapObject): MaybeObject;
extern macro ReportFeedbackUpdate(FeedbackVector, uintptr, constexpr string); extern macro ReportFeedbackUpdate(FeedbackVector, uintptr, constexpr string);
extern operator '.length_intptr' macro LoadFeedbackVectorLength(FeedbackVector):
intptr;
} // namespace ic } // namespace ic
This diff is collapsed.
...@@ -17,25 +17,20 @@ f(o); ...@@ -17,25 +17,20 @@ f(o);
%OptimizeFunctionOnNextCall(f); %OptimizeFunctionOnNextCall(f);
f(o); f(o);
assertOptimized(f); assertOptimized(f);
%PrepareFunctionForOptimization(f);
f(o);
// Deprecates O's map. // Deprecates o's map.
o1.b = 10.23; o1.b = 10.23;
// Deoptimizes but retains code.
// Bails out but retains code.
f(o1); f(o1);
assertOptimized(f); assertOptimized(f);
// Deoptimizes and discards code. // Passing in original object should not cause any deopts.
f(o); f(o);
f(o); f(o);
assertUnoptimized(f);
// When we reoptimize we should include code for migrating deprecated maps.
%OptimizeFunctionOnNextCall(f);
f(o);
assertOptimized(f); assertOptimized(f);
// o and o2 have the same Map, so there should be no deopts.
f(o2); f(o2);
f(o2); f(o2);
assertOptimized(f); assertOptimized(f);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment