11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_cinamespace ic { 61cb0ef41Sopenharmony_cinamespace callable { 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ciextern macro IncrementCallCount(FeedbackVector, uintptr): void; 91cb0ef41Sopenharmony_ciconst kCallFeedbackContentFieldMask: constexpr int32 101cb0ef41Sopenharmony_ci generates 'FeedbackNexus::CallFeedbackContentField::kMask'; 111cb0ef41Sopenharmony_ciconst kCallFeedbackContentFieldShift: constexpr uint32 121cb0ef41Sopenharmony_ci generates 'FeedbackNexus::CallFeedbackContentField::kShift'; 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_cimacro IsMonomorphic(feedback: MaybeObject, target: JSAny): bool { 151cb0ef41Sopenharmony_ci return IsWeakReferenceToObject(feedback, target); 161cb0ef41Sopenharmony_ci} 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_cimacro InSameNativeContext(lhs: Context, rhs: Context): bool { 191cb0ef41Sopenharmony_ci return LoadNativeContext(lhs) == LoadNativeContext(rhs); 201cb0ef41Sopenharmony_ci} 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_cimacro MaybeObjectToStrong(maybeObject: MaybeObject): 231cb0ef41Sopenharmony_ci HeapObject labels IfCleared { 241cb0ef41Sopenharmony_ci dcheck(IsWeakOrCleared(maybeObject)); 251cb0ef41Sopenharmony_ci const weakObject = %RawDownCast<Weak<HeapObject>>(maybeObject); 261cb0ef41Sopenharmony_ci return WeakToStrong(weakObject) otherwise IfCleared; 271cb0ef41Sopenharmony_ci} 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_cimacro TryInitializeAsMonomorphic(implicit context: Context)( 301cb0ef41Sopenharmony_ci maybeTarget: JSAny, feedbackVector: FeedbackVector, 311cb0ef41Sopenharmony_ci slotId: uintptr): void labels TransitionToMegamorphic { 321cb0ef41Sopenharmony_ci const targetHeapObject = 331cb0ef41Sopenharmony_ci Cast<HeapObject>(maybeTarget) otherwise TransitionToMegamorphic; 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci let unwrappedTarget = targetHeapObject; 361cb0ef41Sopenharmony_ci while (Is<JSBoundFunction>(unwrappedTarget)) { 371cb0ef41Sopenharmony_ci unwrappedTarget = 381cb0ef41Sopenharmony_ci UnsafeCast<JSBoundFunction>(unwrappedTarget).bound_target_function; 391cb0ef41Sopenharmony_ci } 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci const unwrappedTargetJSFunction = 421cb0ef41Sopenharmony_ci Cast<JSFunction>(unwrappedTarget) otherwise TransitionToMegamorphic; 431cb0ef41Sopenharmony_ci if (!InSameNativeContext(unwrappedTargetJSFunction.context, context)) { 441cb0ef41Sopenharmony_ci goto TransitionToMegamorphic; 451cb0ef41Sopenharmony_ci } 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci StoreWeakReferenceInFeedbackVector(feedbackVector, slotId, targetHeapObject); 481cb0ef41Sopenharmony_ci ReportFeedbackUpdate(feedbackVector, slotId, 'Call:Initialize'); 491cb0ef41Sopenharmony_ci} 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_cimacro TransitionToMegamorphic(implicit context: Context)( 521cb0ef41Sopenharmony_ci feedbackVector: FeedbackVector, slotId: uintptr): void { 531cb0ef41Sopenharmony_ci StoreFeedbackVectorSlot(feedbackVector, slotId, kMegamorphicSymbol); 541cb0ef41Sopenharmony_ci ReportFeedbackUpdate(feedbackVector, slotId, 'Call:TransitionMegamorphic'); 551cb0ef41Sopenharmony_ci} 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_cimacro TaggedEqualPrototypeApplyFunction(implicit context: Context)( 581cb0ef41Sopenharmony_ci target: JSAny): bool { 591cb0ef41Sopenharmony_ci return TaggedEqual(target, GetPrototypeApplyFunction()); 601cb0ef41Sopenharmony_ci} 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_cimacro FeedbackValueIsReceiver(implicit context: Context)( 631cb0ef41Sopenharmony_ci feedbackVector: FeedbackVector, slotId: uintptr): bool { 641cb0ef41Sopenharmony_ci const callCount: intptr = SmiUntag(Cast<Smi>(LoadFeedbackVectorSlot( 651cb0ef41Sopenharmony_ci feedbackVector, slotId, kTaggedSize)) otherwise return false); 661cb0ef41Sopenharmony_ci return (callCount & IntPtrConstant(kCallFeedbackContentFieldMask)) != 671cb0ef41Sopenharmony_ci IntPtrConstant(0); 681cb0ef41Sopenharmony_ci} 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_cimacro SetCallFeedbackContent(implicit context: Context)( 711cb0ef41Sopenharmony_ci feedbackVector: FeedbackVector, slotId: uintptr, 721cb0ef41Sopenharmony_ci callFeedbackContent: constexpr CallFeedbackContent): void { 731cb0ef41Sopenharmony_ci // Load the call count field from the feecback vector. 741cb0ef41Sopenharmony_ci const callCount: intptr = SmiUntag(Cast<Smi>(LoadFeedbackVectorSlot( 751cb0ef41Sopenharmony_ci feedbackVector, slotId, kTaggedSize)) otherwise return ); 761cb0ef41Sopenharmony_ci // The second lowest bits of the call count are used to state whether the 771cb0ef41Sopenharmony_ci // feedback collected is a target or a receiver. Change that bit based on the 781cb0ef41Sopenharmony_ci // callFeedbackContent input. 791cb0ef41Sopenharmony_ci const callFeedbackContentFieldMask: intptr = 801cb0ef41Sopenharmony_ci ~IntPtrConstant(kCallFeedbackContentFieldMask); 811cb0ef41Sopenharmony_ci const newCount: intptr = (callCount & callFeedbackContentFieldMask) | 821cb0ef41Sopenharmony_ci Convert<intptr>(Signed( 831cb0ef41Sopenharmony_ci %RawConstexprCast<constexpr uint32>(callFeedbackContent) 841cb0ef41Sopenharmony_ci << kCallFeedbackContentFieldShift)); 851cb0ef41Sopenharmony_ci StoreFeedbackVectorSlot( 861cb0ef41Sopenharmony_ci feedbackVector, slotId, SmiTag(newCount), SKIP_WRITE_BARRIER, 871cb0ef41Sopenharmony_ci kTaggedSize); 881cb0ef41Sopenharmony_ci ReportFeedbackUpdate(feedbackVector, slotId, 'Call:SetCallFeedbackContent'); 891cb0ef41Sopenharmony_ci} 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_cimacro CollectCallFeedback( 921cb0ef41Sopenharmony_ci maybeTarget: JSAny, maybeReceiver: Lazy<JSAny>, context: Context, 931cb0ef41Sopenharmony_ci maybeFeedbackVector: Undefined|FeedbackVector, slotId: uintptr): void { 941cb0ef41Sopenharmony_ci // TODO(v8:9891): Remove this dcheck once all callers are ported to Torque. 951cb0ef41Sopenharmony_ci // This dcheck ensures correctness of maybeFeedbackVector's type which can 961cb0ef41Sopenharmony_ci // be easily broken for calls from CSA. 971cb0ef41Sopenharmony_ci dcheck( 981cb0ef41Sopenharmony_ci IsUndefined(maybeFeedbackVector) || 991cb0ef41Sopenharmony_ci Is<FeedbackVector>(maybeFeedbackVector)); 1001cb0ef41Sopenharmony_ci const feedbackVector = 1011cb0ef41Sopenharmony_ci Cast<FeedbackVector>(maybeFeedbackVector) otherwise return; 1021cb0ef41Sopenharmony_ci IncrementCallCount(feedbackVector, slotId); 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci try { 1051cb0ef41Sopenharmony_ci const feedback: MaybeObject = 1061cb0ef41Sopenharmony_ci LoadFeedbackVectorSlot(feedbackVector, slotId); 1071cb0ef41Sopenharmony_ci if (IsMonomorphic(feedback, maybeTarget)) return; 1081cb0ef41Sopenharmony_ci if (IsMegamorphic(feedback)) return; 1091cb0ef41Sopenharmony_ci if (IsUninitialized(feedback)) goto TryInitializeAsMonomorphic; 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci // If cleared, we have a new chance to become monomorphic. 1121cb0ef41Sopenharmony_ci const feedbackValue: HeapObject = 1131cb0ef41Sopenharmony_ci MaybeObjectToStrong(feedback) otherwise TryReinitializeAsMonomorphic; 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci if (FeedbackValueIsReceiver(feedbackVector, slotId) && 1161cb0ef41Sopenharmony_ci TaggedEqualPrototypeApplyFunction(maybeTarget)) { 1171cb0ef41Sopenharmony_ci // If the Receiver is recorded and the target is 1181cb0ef41Sopenharmony_ci // Function.prototype.apply, check whether we can stay monomorphic based 1191cb0ef41Sopenharmony_ci // on the receiver. 1201cb0ef41Sopenharmony_ci if (IsMonomorphic(feedback, RunLazy(maybeReceiver))) { 1211cb0ef41Sopenharmony_ci return; 1221cb0ef41Sopenharmony_ci } else { 1231cb0ef41Sopenharmony_ci // If not, reinitialize the feedback with target. 1241cb0ef41Sopenharmony_ci SetCallFeedbackContent( 1251cb0ef41Sopenharmony_ci feedbackVector, slotId, CallFeedbackContent::kTarget); 1261cb0ef41Sopenharmony_ci TryInitializeAsMonomorphic(maybeTarget, feedbackVector, slotId) 1271cb0ef41Sopenharmony_ci otherwise TransitionToMegamorphic; 1281cb0ef41Sopenharmony_ci return; 1291cb0ef41Sopenharmony_ci } 1301cb0ef41Sopenharmony_ci } 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci // Try transitioning to a feedback cell. 1331cb0ef41Sopenharmony_ci // Check if {target}s feedback cell matches the {feedbackValue}. 1341cb0ef41Sopenharmony_ci const target = 1351cb0ef41Sopenharmony_ci Cast<JSFunction>(maybeTarget) otherwise TransitionToMegamorphic; 1361cb0ef41Sopenharmony_ci const targetFeedbackCell: FeedbackCell = target.feedback_cell; 1371cb0ef41Sopenharmony_ci if (TaggedEqual(feedbackValue, targetFeedbackCell)) return; 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ci // Check if {target} and {feedbackValue} are both JSFunctions with 1401cb0ef41Sopenharmony_ci // the same feedback vector cell, and that those functions were 1411cb0ef41Sopenharmony_ci // actually compiled already. 1421cb0ef41Sopenharmony_ci const feedbackValueJSFunction = 1431cb0ef41Sopenharmony_ci Cast<JSFunction>(feedbackValue) otherwise TransitionToMegamorphic; 1441cb0ef41Sopenharmony_ci const feedbackCell: FeedbackCell = feedbackValueJSFunction.feedback_cell; 1451cb0ef41Sopenharmony_ci if (!TaggedEqual(feedbackCell, targetFeedbackCell)) 1461cb0ef41Sopenharmony_ci goto TransitionToMegamorphic; 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci StoreWeakReferenceInFeedbackVector(feedbackVector, slotId, feedbackCell); 1491cb0ef41Sopenharmony_ci ReportFeedbackUpdate(feedbackVector, slotId, 'Call:FeedbackVectorCell'); 1501cb0ef41Sopenharmony_ci } label TryReinitializeAsMonomorphic { 1511cb0ef41Sopenharmony_ci SetCallFeedbackContent( 1521cb0ef41Sopenharmony_ci feedbackVector, slotId, CallFeedbackContent::kTarget); 1531cb0ef41Sopenharmony_ci goto TryInitializeAsMonomorphic; 1541cb0ef41Sopenharmony_ci } label TryInitializeAsMonomorphic { 1551cb0ef41Sopenharmony_ci let recordedFunction = maybeTarget; 1561cb0ef41Sopenharmony_ci if (TaggedEqualPrototypeApplyFunction(maybeTarget)) { 1571cb0ef41Sopenharmony_ci recordedFunction = RunLazy(maybeReceiver); 1581cb0ef41Sopenharmony_ci SetCallFeedbackContent( 1591cb0ef41Sopenharmony_ci feedbackVector, slotId, CallFeedbackContent::kReceiver); 1601cb0ef41Sopenharmony_ci } else { 1611cb0ef41Sopenharmony_ci dcheck(!FeedbackValueIsReceiver(feedbackVector, slotId)); 1621cb0ef41Sopenharmony_ci } 1631cb0ef41Sopenharmony_ci TryInitializeAsMonomorphic(recordedFunction, feedbackVector, slotId) 1641cb0ef41Sopenharmony_ci otherwise TransitionToMegamorphic; 1651cb0ef41Sopenharmony_ci } label TransitionToMegamorphic { 1661cb0ef41Sopenharmony_ci TransitionToMegamorphic(feedbackVector, slotId); 1671cb0ef41Sopenharmony_ci } 1681cb0ef41Sopenharmony_ci} 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_cimacro CollectInstanceOfFeedback( 1711cb0ef41Sopenharmony_ci maybeTarget: JSAny, context: Context, 1721cb0ef41Sopenharmony_ci maybeFeedbackVector: Undefined|FeedbackVector, slotId: uintptr): void { 1731cb0ef41Sopenharmony_ci // TODO(v8:9891): Remove this dcheck once all callers are ported to Torque. 1741cb0ef41Sopenharmony_ci // This dcheck ensures correctness of maybeFeedbackVector's type which can 1751cb0ef41Sopenharmony_ci // be easily broken for calls from CSA. 1761cb0ef41Sopenharmony_ci dcheck( 1771cb0ef41Sopenharmony_ci IsUndefined(maybeFeedbackVector) || 1781cb0ef41Sopenharmony_ci Is<FeedbackVector>(maybeFeedbackVector)); 1791cb0ef41Sopenharmony_ci const feedbackVector = 1801cb0ef41Sopenharmony_ci Cast<FeedbackVector>(maybeFeedbackVector) otherwise return; 1811cb0ef41Sopenharmony_ci // Note: The call count is not incremented. 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ci try { 1841cb0ef41Sopenharmony_ci const feedback: MaybeObject = 1851cb0ef41Sopenharmony_ci LoadFeedbackVectorSlot(feedbackVector, slotId); 1861cb0ef41Sopenharmony_ci if (IsMonomorphic(feedback, maybeTarget)) return; 1871cb0ef41Sopenharmony_ci if (IsMegamorphic(feedback)) return; 1881cb0ef41Sopenharmony_ci if (IsUninitialized(feedback)) goto TryInitializeAsMonomorphic; 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci // If cleared, we have a new chance to become monomorphic. 1911cb0ef41Sopenharmony_ci const _feedbackValue: HeapObject = 1921cb0ef41Sopenharmony_ci MaybeObjectToStrong(feedback) otherwise TryInitializeAsMonomorphic; 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci goto TransitionToMegamorphic; 1951cb0ef41Sopenharmony_ci } label TryInitializeAsMonomorphic { 1961cb0ef41Sopenharmony_ci TryInitializeAsMonomorphic(maybeTarget, feedbackVector, slotId) 1971cb0ef41Sopenharmony_ci otherwise TransitionToMegamorphic; 1981cb0ef41Sopenharmony_ci } label TransitionToMegamorphic { 1991cb0ef41Sopenharmony_ci TransitionToMegamorphic(feedbackVector, slotId); 2001cb0ef41Sopenharmony_ci } 2011cb0ef41Sopenharmony_ci} 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_cimacro BothTaggedEqualArrayFunction(implicit context: Context)( 2041cb0ef41Sopenharmony_ci first: JSAny, second: JSAny): bool { 2051cb0ef41Sopenharmony_ci return TaggedEqual(first, second) && TaggedEqual(second, GetArrayFunction()); 2061cb0ef41Sopenharmony_ci} 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ciextern macro CreateAllocationSiteInFeedbackVector( 2091cb0ef41Sopenharmony_ci FeedbackVector, uintptr): AllocationSite; 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_cimacro CastFeedbackVector( 2121cb0ef41Sopenharmony_ci maybeFeedbackVector: Undefined|FeedbackVector, 2131cb0ef41Sopenharmony_ci updateFeedbackMode: constexpr UpdateFeedbackMode): 2141cb0ef41Sopenharmony_ci FeedbackVector labels Fallback { 2151cb0ef41Sopenharmony_ci if constexpr (updateFeedbackMode == UpdateFeedbackMode::kGuaranteedFeedback) { 2161cb0ef41Sopenharmony_ci return UnsafeCast<FeedbackVector>(maybeFeedbackVector); 2171cb0ef41Sopenharmony_ci } else if constexpr ( 2181cb0ef41Sopenharmony_ci updateFeedbackMode == UpdateFeedbackMode::kOptionalFeedback) { 2191cb0ef41Sopenharmony_ci return Cast<FeedbackVector>(maybeFeedbackVector) otherwise goto Fallback; 2201cb0ef41Sopenharmony_ci } else { 2211cb0ef41Sopenharmony_ci unreachable; 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci} 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_cimacro CollectConstructFeedback(implicit context: Context)( 2261cb0ef41Sopenharmony_ci target: JSAny, newTarget: JSAny, 2271cb0ef41Sopenharmony_ci maybeFeedbackVector: Undefined|FeedbackVector, slotId: uintptr, 2281cb0ef41Sopenharmony_ci updateFeedbackMode: constexpr UpdateFeedbackMode): 2291cb0ef41Sopenharmony_ci never labels ConstructGeneric, 2301cb0ef41Sopenharmony_ci ConstructArray(AllocationSite) { 2311cb0ef41Sopenharmony_ci // TODO(v8:9891): Remove this dcheck once all callers are ported to Torque. 2321cb0ef41Sopenharmony_ci // This dcheck ensures correctness of maybeFeedbackVector's type which can 2331cb0ef41Sopenharmony_ci // be easily broken for calls from CSA. 2341cb0ef41Sopenharmony_ci dcheck( 2351cb0ef41Sopenharmony_ci IsUndefined(maybeFeedbackVector) || 2361cb0ef41Sopenharmony_ci Is<FeedbackVector>(maybeFeedbackVector)); 2371cb0ef41Sopenharmony_ci 2381cb0ef41Sopenharmony_ci const feedbackVector = CastFeedbackVector( 2391cb0ef41Sopenharmony_ci maybeFeedbackVector, updateFeedbackMode) otherwise goto ConstructGeneric; 2401cb0ef41Sopenharmony_ci 2411cb0ef41Sopenharmony_ci IncrementCallCount(feedbackVector, slotId); 2421cb0ef41Sopenharmony_ci 2431cb0ef41Sopenharmony_ci try { 2441cb0ef41Sopenharmony_ci const feedback: MaybeObject = 2451cb0ef41Sopenharmony_ci LoadFeedbackVectorSlot(feedbackVector, slotId); 2461cb0ef41Sopenharmony_ci if (IsMonomorphic(feedback, newTarget)) goto ConstructGeneric; 2471cb0ef41Sopenharmony_ci if (IsMegamorphic(feedback)) goto ConstructGeneric; 2481cb0ef41Sopenharmony_ci if (IsUninitialized(feedback)) goto TryInitializeAsMonomorphic; 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_ci if (!IsWeakOrCleared(feedback)) { 2511cb0ef41Sopenharmony_ci const feedbackAsStrong = %RawDownCast<Object>(feedback); 2521cb0ef41Sopenharmony_ci if (Is<AllocationSite>(feedbackAsStrong)) { 2531cb0ef41Sopenharmony_ci if (BothTaggedEqualArrayFunction(target, newTarget)) { 2541cb0ef41Sopenharmony_ci goto ConstructArray(UnsafeCast<AllocationSite>(feedbackAsStrong)); 2551cb0ef41Sopenharmony_ci } 2561cb0ef41Sopenharmony_ci goto TransitionToMegamorphic; 2571cb0ef41Sopenharmony_ci } 2581cb0ef41Sopenharmony_ci } 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ci // If cleared, we have a new chance to become monomorphic. 2611cb0ef41Sopenharmony_ci const _feedbackValue: HeapObject = 2621cb0ef41Sopenharmony_ci MaybeObjectToStrong(feedback) otherwise TryInitializeAsMonomorphic; 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_ci goto TransitionToMegamorphic; 2651cb0ef41Sopenharmony_ci } label TryInitializeAsMonomorphic { 2661cb0ef41Sopenharmony_ci if (BothTaggedEqualArrayFunction(target, newTarget)) { 2671cb0ef41Sopenharmony_ci // In this case we can skip unwrapping and context validation since we 2681cb0ef41Sopenharmony_ci // know the target is the current context's array function. 2691cb0ef41Sopenharmony_ci const allocationSite = 2701cb0ef41Sopenharmony_ci CreateAllocationSiteInFeedbackVector(feedbackVector, slotId); 2711cb0ef41Sopenharmony_ci ReportFeedbackUpdate( 2721cb0ef41Sopenharmony_ci feedbackVector, slotId, 'Construct:CreateAllocationSite'); 2731cb0ef41Sopenharmony_ci goto ConstructArray(allocationSite); 2741cb0ef41Sopenharmony_ci } 2751cb0ef41Sopenharmony_ci 2761cb0ef41Sopenharmony_ci TryInitializeAsMonomorphic(newTarget, feedbackVector, slotId) 2771cb0ef41Sopenharmony_ci otherwise TransitionToMegamorphic; 2781cb0ef41Sopenharmony_ci } label TransitionToMegamorphic { 2791cb0ef41Sopenharmony_ci TransitionToMegamorphic(feedbackVector, slotId); 2801cb0ef41Sopenharmony_ci } 2811cb0ef41Sopenharmony_ci goto ConstructGeneric; 2821cb0ef41Sopenharmony_ci} 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_ci} // namespace callable 2851cb0ef41Sopenharmony_ci} // namespace ic 286