Remove the OptimizationTier enum
This was mostly unused. We should simply be able to use CodeKind plus related predicates instead. Replace FeedbackVector::optimization_tier with maybe_has_optimized_code, which states whether the optimized code cache is filled. The value is updated lazily and may lag behind the actual code cache state. We only use this field for quick cache-empty? checks from generated code. Bug: v8:7700,v8:12552 Change-Id: Ibfc5c0128eac56167a68ecba5690eab2e9369640 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3460741 Reviewed-by: Leszek Swirski <leszeks@chromium.org> Commit-Queue: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/main@{#79107}
This commit is contained in:
parent
88b931f7ce
commit
8bad451601
@ -842,8 +842,7 @@ V8_WARN_UNUSED_RESULT MaybeHandle<CodeT> GetCodeFromOptimizedCodeCache(
|
||||
if (osr_offset.IsNone() && function->has_feedback_vector()) {
|
||||
FeedbackVector feedback_vector = function->feedback_vector();
|
||||
feedback_vector.EvictOptimizedCodeMarkedForDeoptimization(
|
||||
function->raw_feedback_cell(), function->shared(),
|
||||
"GetCodeFromOptimizedCodeCache");
|
||||
function->shared(), "GetCodeFromOptimizedCodeCache");
|
||||
code = feedback_vector.optimized_code();
|
||||
} else if (!osr_offset.IsNone()) {
|
||||
code = function->context()
|
||||
@ -894,8 +893,7 @@ void InsertCodeIntoOptimizedCodeCache(
|
||||
if (compilation_info->osr_offset().IsNone()) {
|
||||
Handle<FeedbackVector> vector =
|
||||
handle(function->feedback_vector(), isolate);
|
||||
FeedbackVector::SetOptimizedCode(vector, code,
|
||||
function->raw_feedback_cell());
|
||||
FeedbackVector::SetOptimizedCode(vector, code);
|
||||
} else {
|
||||
DCHECK(CodeKindCanOSR(kind));
|
||||
OSROptimizedCodeCache::AddOptimizedCode(native_context, shared, code,
|
||||
@ -3292,8 +3290,7 @@ void Compiler::PostInstantiation(Handle<JSFunction> function) {
|
||||
// deoptimized the code on the feedback vector. So check for any
|
||||
// deoptimized code just before installing it on the funciton.
|
||||
function->feedback_vector().EvictOptimizedCodeMarkedForDeoptimization(
|
||||
function->raw_feedback_cell(), *shared,
|
||||
"new function from shared function info");
|
||||
*shared, "new function from shared function info");
|
||||
CodeT code = function->feedback_vector().optimized_code();
|
||||
if (!code.is_null()) {
|
||||
// Caching of optimized code enabled and optimized code found.
|
||||
|
@ -1685,27 +1685,6 @@ inline std::ostream& operator<<(std::ostream& os,
|
||||
}
|
||||
}
|
||||
|
||||
enum class OptimizationTier {
|
||||
kNone = 0b00,
|
||||
kMidTier = 0b01,
|
||||
kTopTier = 0b10,
|
||||
kLastOptimizationTier = kTopTier
|
||||
};
|
||||
static constexpr uint32_t kNoneOrMidTierMask = 0b10;
|
||||
static constexpr uint32_t kNoneMask = 0b11;
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os,
|
||||
const OptimizationTier& tier) {
|
||||
switch (tier) {
|
||||
case OptimizationTier::kNone:
|
||||
return os << "OptimizationTier::kNone";
|
||||
case OptimizationTier::kMidTier:
|
||||
return os << "OptimizationTier::kMidTier";
|
||||
case OptimizationTier::kTopTier:
|
||||
return os << "OptimizationTier::kTopTier";
|
||||
}
|
||||
}
|
||||
|
||||
enum class SpeculationMode { kAllowSpeculation, kDisallowSpeculation };
|
||||
enum class CallFeedbackContent { kTarget, kReceiver };
|
||||
|
||||
|
@ -3616,7 +3616,7 @@ void EffectControlLinearizer::LowerTierUpCheck(Node* node) {
|
||||
__ Word32And(optimization_state,
|
||||
__ Uint32Constant(
|
||||
FeedbackVector::
|
||||
kHasNoTopTierCodeOrCompileOptimizedMarkerMask)),
|
||||
kHasOptimizedCodeOrCompileOptimizedMarkerMask)),
|
||||
__ Int32Constant(0)),
|
||||
&fallthrough, &has_optimized_code_or_marker, BranchHint::kTrue);
|
||||
|
||||
|
@ -441,8 +441,7 @@ void Deoptimizer::DeoptimizeFunction(JSFunction function, Code code) {
|
||||
// The code in the function's optimized code feedback vector slot might
|
||||
// be different from the code on the function - evict it if necessary.
|
||||
function.feedback_vector().EvictOptimizedCodeMarkedForDeoptimization(
|
||||
function.raw_feedback_cell(), function.shared(),
|
||||
"unlinking code marked for deopt");
|
||||
function.shared(), "unlinking code marked for deopt");
|
||||
if (!code.deopt_already_counted()) {
|
||||
code.set_deopt_already_counted(true);
|
||||
}
|
||||
|
@ -1197,7 +1197,7 @@ void FeedbackVector::FeedbackVectorPrint(std::ostream& os) {
|
||||
os << "\n - no optimized code";
|
||||
}
|
||||
os << "\n - optimization marker: " << optimization_marker();
|
||||
os << "\n - optimization tier: " << optimization_tier();
|
||||
os << "\n - maybe has optimized code: " << maybe_has_optimized_code();
|
||||
os << "\n - invocation count: " << invocation_count();
|
||||
os << "\n - profiler ticks: " << profiler_ticks();
|
||||
os << "\n - closure feedback cell array: ";
|
||||
|
@ -1393,7 +1393,7 @@ void Logger::FeedbackVectorEvent(FeedbackVector vector, AbstractCode code) {
|
||||
<< vector.length();
|
||||
msg << kNext << reinterpret_cast<void*>(code.InstructionStart());
|
||||
msg << kNext << vector.optimization_marker();
|
||||
msg << kNext << vector.optimization_tier();
|
||||
msg << kNext << vector.maybe_has_optimized_code();
|
||||
msg << kNext << vector.invocation_count();
|
||||
msg << kNext << vector.profiler_ticks() << kNext;
|
||||
|
||||
|
@ -93,13 +93,7 @@ inline constexpr bool CodeKindIsStoredInOptimizedCodeCache(CodeKind kind) {
|
||||
return kind == CodeKind::TURBOFAN;
|
||||
}
|
||||
|
||||
inline OptimizationTier GetTierForCodeKind(CodeKind kind) {
|
||||
if (kind == CodeKind::TURBOFAN) return OptimizationTier::kTopTier;
|
||||
return OptimizationTier::kNone;
|
||||
}
|
||||
|
||||
inline CodeKind CodeKindForTopTier() { return CodeKind::TURBOFAN; }
|
||||
|
||||
inline CodeKind CodeKindForOSR() { return CodeKind::TURBOFAN; }
|
||||
|
||||
// The dedicated CodeKindFlag enum represents all code kinds in a format
|
||||
|
@ -132,11 +132,10 @@ CodeT FeedbackVector::optimized_code() const {
|
||||
if (slot->GetHeapObject(&heap_object)) {
|
||||
code = CodeT::cast(heap_object);
|
||||
}
|
||||
// It is possible that the maybe_optimized_code slot is cleared but the
|
||||
// optimization tier hasn't been updated yet. We update the tier when we
|
||||
// execute the function next time / when we create new closure.
|
||||
DCHECK_IMPLIES(!code.is_null(), OptimizationTierBits::decode(flags()) ==
|
||||
GetTierForCodeKind(code.kind()));
|
||||
// It is possible that the maybe_optimized_code slot is cleared but the flags
|
||||
// haven't been updated yet. We update them when we execute the function next
|
||||
// time / when we create new closure.
|
||||
DCHECK_IMPLIES(!code.is_null(), maybe_has_optimized_code());
|
||||
return code;
|
||||
}
|
||||
|
||||
@ -144,17 +143,17 @@ OptimizationMarker FeedbackVector::optimization_marker() const {
|
||||
return OptimizationMarkerBits::decode(flags());
|
||||
}
|
||||
|
||||
OptimizationTier FeedbackVector::optimization_tier() const {
|
||||
OptimizationTier tier = OptimizationTierBits::decode(flags());
|
||||
// It is possible that the optimization tier bits aren't updated when the code
|
||||
// was cleared due to a GC.
|
||||
DCHECK_IMPLIES(tier == OptimizationTier::kNone,
|
||||
maybe_optimized_code(kAcquireLoad)->IsCleared());
|
||||
return tier;
|
||||
bool FeedbackVector::has_optimized_code() const {
|
||||
DCHECK_IMPLIES(!optimized_code().is_null(), maybe_has_optimized_code());
|
||||
return !optimized_code().is_null();
|
||||
}
|
||||
|
||||
bool FeedbackVector::has_optimized_code() const {
|
||||
return !optimized_code().is_null();
|
||||
bool FeedbackVector::maybe_has_optimized_code() const {
|
||||
return MaybeHasOptimizedCodeBit::decode(flags());
|
||||
}
|
||||
|
||||
void FeedbackVector::set_maybe_has_optimized_code(bool value) {
|
||||
set_flags(MaybeHasOptimizedCodeBit::update(flags(), value));
|
||||
}
|
||||
|
||||
bool FeedbackVector::has_optimization_marker() const {
|
||||
|
@ -262,7 +262,7 @@ Handle<FeedbackVector> FeedbackVector::New(
|
||||
|
||||
DCHECK_EQ(vector->shared_function_info(), *shared);
|
||||
DCHECK_EQ(vector->optimization_marker(), OptimizationMarker::kNone);
|
||||
DCHECK_EQ(vector->optimization_tier(), OptimizationTier::kNone);
|
||||
DCHECK(!vector->maybe_has_optimized_code());
|
||||
DCHECK_EQ(vector->invocation_count(), 0);
|
||||
DCHECK_EQ(vector->profiler_ticks(), 0);
|
||||
DCHECK(vector->maybe_optimized_code()->IsCleared());
|
||||
@ -388,8 +388,7 @@ void FeedbackVector::SaturatingIncrementProfilerTicks() {
|
||||
|
||||
// static
|
||||
void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
|
||||
Handle<CodeT> code,
|
||||
FeedbackCell feedback_cell) {
|
||||
Handle<CodeT> code) {
|
||||
DCHECK(CodeKindIsOptimizedJSFunction(code->kind()));
|
||||
// We should set optimized code only when there is no valid optimized code.
|
||||
DCHECK(!vector->has_optimized_code() ||
|
||||
@ -403,8 +402,8 @@ void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
|
||||
vector->set_maybe_optimized_code(HeapObjectReference::Weak(*code),
|
||||
kReleaseStore);
|
||||
int32_t state = vector->flags();
|
||||
state = OptimizationTierBits::update(state, GetTierForCodeKind(code->kind()));
|
||||
state = OptimizationMarkerBits::update(state, OptimizationMarker::kNone);
|
||||
state = MaybeHasOptimizedCodeBit::update(state, true);
|
||||
vector->set_flags(state);
|
||||
}
|
||||
|
||||
@ -415,12 +414,12 @@ void FeedbackVector::SetInterruptBudget(FeedbackCell feedback_cell) {
|
||||
feedback_cell.set_interrupt_budget(FLAG_interrupt_budget);
|
||||
}
|
||||
|
||||
void FeedbackVector::ClearOptimizedCode(FeedbackCell feedback_cell) {
|
||||
void FeedbackVector::ClearOptimizedCode() {
|
||||
DCHECK(has_optimized_code());
|
||||
DCHECK_NE(optimization_tier(), OptimizationTier::kNone);
|
||||
DCHECK(maybe_has_optimized_code());
|
||||
set_maybe_optimized_code(HeapObjectReference::ClearedValue(GetIsolate()),
|
||||
kReleaseStore);
|
||||
ClearOptimizationTier(feedback_cell);
|
||||
set_maybe_has_optimized_code(false);
|
||||
}
|
||||
|
||||
void FeedbackVector::ClearOptimizationMarker() {
|
||||
@ -433,24 +432,16 @@ void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) {
|
||||
set_flags(state);
|
||||
}
|
||||
|
||||
void FeedbackVector::ClearOptimizationTier(FeedbackCell feedback_cell) {
|
||||
int32_t state = flags();
|
||||
state = OptimizationTierBits::update(state, OptimizationTier::kNone);
|
||||
set_flags(state);
|
||||
}
|
||||
|
||||
void FeedbackVector::InitializeOptimizationState() {
|
||||
int32_t state = 0;
|
||||
state = OptimizationMarkerBits::update(state, OptimizationMarker::kNone);
|
||||
state = OptimizationTierBits::update(state, OptimizationTier::kNone);
|
||||
set_flags(state);
|
||||
set_flags(OptimizationMarkerBits::encode(OptimizationMarker::kNone) |
|
||||
MaybeHasOptimizedCodeBit::encode(false));
|
||||
}
|
||||
|
||||
void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
|
||||
FeedbackCell feedback_cell, SharedFunctionInfo shared, const char* reason) {
|
||||
SharedFunctionInfo shared, const char* reason) {
|
||||
MaybeObject slot = maybe_optimized_code(kAcquireLoad);
|
||||
if (slot->IsCleared()) {
|
||||
ClearOptimizationTier(feedback_cell);
|
||||
set_maybe_has_optimized_code(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -460,7 +451,7 @@ void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
|
||||
if (!code.deopt_already_counted()) {
|
||||
code.set_deopt_already_counted(true);
|
||||
}
|
||||
ClearOptimizedCode(feedback_cell);
|
||||
ClearOptimizedCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,8 +205,6 @@ class FeedbackVector
|
||||
DEFINE_TORQUE_GENERATED_FEEDBACK_VECTOR_FLAGS()
|
||||
STATIC_ASSERT(OptimizationMarker::kLastOptimizationMarker <=
|
||||
OptimizationMarkerBits::kMax);
|
||||
STATIC_ASSERT(OptimizationTier::kLastOptimizationTier <=
|
||||
OptimizationTierBits::kMax);
|
||||
|
||||
static const bool kFeedbackVectorMaybeOptimizedCodeIsStoreRelease = true;
|
||||
using TorqueGeneratedFeedbackVector<FeedbackVector,
|
||||
@ -215,11 +213,8 @@ class FeedbackVector
|
||||
|
||||
static constexpr uint32_t kHasCompileOptimizedMarker =
|
||||
kNoneOrInOptimizationQueueMask << OptimizationMarkerBits::kShift;
|
||||
static constexpr uint32_t kHasNoTopTierCodeOrCompileOptimizedMarkerMask =
|
||||
kNoneOrMidTierMask << OptimizationTierBits::kShift |
|
||||
kHasCompileOptimizedMarker;
|
||||
static constexpr uint32_t kHasOptimizedCodeOrCompileOptimizedMarkerMask =
|
||||
OptimizationTierBits::kMask | kHasCompileOptimizedMarker;
|
||||
MaybeHasOptimizedCodeBit::kMask | kHasCompileOptimizedMarker;
|
||||
|
||||
inline bool is_empty() const;
|
||||
|
||||
@ -236,18 +231,22 @@ class FeedbackVector
|
||||
inline void clear_invocation_count(RelaxedStoreTag tag);
|
||||
|
||||
inline CodeT optimized_code() const;
|
||||
// Whether maybe_optimized_code contains a cached Code object.
|
||||
inline bool has_optimized_code() const;
|
||||
// Similar to above, but represented internally as a bit that can be
|
||||
// efficiently checked by generated code. May lag behind the actual state of
|
||||
// the world, thus 'maybe'.
|
||||
inline bool maybe_has_optimized_code() const;
|
||||
inline void set_maybe_has_optimized_code(bool value);
|
||||
|
||||
inline bool has_optimization_marker() const;
|
||||
inline OptimizationMarker optimization_marker() const;
|
||||
inline OptimizationTier optimization_tier() const;
|
||||
void ClearOptimizedCode(FeedbackCell feedback_cell);
|
||||
void EvictOptimizedCodeMarkedForDeoptimization(FeedbackCell feedback_cell,
|
||||
SharedFunctionInfo shared,
|
||||
void EvictOptimizedCodeMarkedForDeoptimization(SharedFunctionInfo shared,
|
||||
const char* reason);
|
||||
static void SetOptimizedCode(Handle<FeedbackVector> vector,
|
||||
Handle<CodeT> code, FeedbackCell feedback_cell);
|
||||
Handle<CodeT> code);
|
||||
void ClearOptimizedCode();
|
||||
void SetOptimizationMarker(OptimizationMarker marker);
|
||||
void ClearOptimizationTier(FeedbackCell feedback_cell);
|
||||
void InitializeOptimizationState();
|
||||
|
||||
// Clears the optimization marker in the feedback vector.
|
||||
|
@ -3,12 +3,14 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
type OptimizationMarker extends uint16 constexpr 'OptimizationMarker';
|
||||
type OptimizationTier extends uint16 constexpr 'OptimizationTier';
|
||||
|
||||
bitfield struct FeedbackVectorFlags extends uint32 {
|
||||
optimization_marker: OptimizationMarker: 2 bit;
|
||||
optimization_tier: OptimizationTier: 2 bit;
|
||||
all_your_bits_are_belong_to_jgruber: uint32: 28 bit;
|
||||
// Whether the maybe_optimized_code field contains a code object. 'maybe',
|
||||
// because they flag may lag behind the actual state of the world when
|
||||
// maybe_optimized_code is cleared (it will be updated in time).
|
||||
maybe_has_optimized_code: bool: 1 bit;
|
||||
all_your_bits_are_belong_to_jgruber: uint32: 29 bit;
|
||||
}
|
||||
|
||||
@generateBodyDescriptor
|
||||
|
@ -114,8 +114,7 @@ RUNTIME_FUNCTION(Runtime_HealOptimizedCodeSlot) {
|
||||
DCHECK(function->shared().is_compiled());
|
||||
|
||||
function->feedback_vector().EvictOptimizedCodeMarkedForDeoptimization(
|
||||
function->raw_feedback_cell(), function->shared(),
|
||||
"Runtime_HealOptimizedCodeSlot");
|
||||
function->shared(), "Runtime_HealOptimizedCodeSlot");
|
||||
return function->code();
|
||||
}
|
||||
|
||||
|
@ -4134,10 +4134,11 @@ TEST(WeakReference) {
|
||||
.Build();
|
||||
CHECK(code->IsCode());
|
||||
|
||||
// Manually inlined version of FeedbackVector::SetOptimizedCode (needed due
|
||||
// to the FOR_TESTING code kind).
|
||||
fv->set_maybe_optimized_code(i::HeapObjectReference::Weak(ToCodeT(*code)),
|
||||
v8::kReleaseStore);
|
||||
fv->set_flags(i::FeedbackVector::OptimizationTierBits::encode(
|
||||
i::OptimizationTier::kTopTier) |
|
||||
fv->set_flags(i::FeedbackVector::MaybeHasOptimizedCodeBit::encode(true) |
|
||||
i::FeedbackVector::OptimizationMarkerBits::encode(
|
||||
i::OptimizationMarker::kNone));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user