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:
Jakob Gruber 2022-02-15 15:19:17 +01:00 committed by V8 LUCI CQ
parent 88b931f7ce
commit 8bad451601
13 changed files with 51 additions and 91 deletions

View File

@ -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.

View File

@ -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 };

View File

@ -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);

View File

@ -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);
}

View File

@ -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: ";

View File

@ -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;

View File

@ -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

View File

@ -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 {

View File

@ -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();
}
}

View File

@ -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.

View File

@ -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

View File

@ -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();
}

View File

@ -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));