current commit
261007.21 · deps: update V8 to 15.5.35.20
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_OBJECTS_JS_FUNCTION_INL_H_
#define V8_OBJECTS_JS_FUNCTION_INL_H_

#include "src/objects/js-function.h"
// Include the non-inl header before the rest of the headers.

#include <atomic>
#include <optional>

// Include other inline headers *after* including js-function.h, such that e.g.
// the definition of JSFunction is available (and this comment prevents
// clang-format from merging that include into the following ones).
#include "src/debug/debug.h"
#include "src/diagnostics/code-tracer.h"
#include "src/heap/heap-write-barrier-inl.h"
#include "src/ic/ic.h"
#include "src/init/bootstrapper.h"
#include "src/objects/abstract-code.h"
#include "src/objects/contexts-inl.h"
#include "src/objects/feedback-cell-inl.h"
#include "src/objects/feedback-vector-inl.h"
#include "src/objects/instance-type-inl.h"
#include "src/objects/map-updater.h"
#include "src/objects/shared-function-info-inl.h"
#include "src/sandbox/js-dispatch-table-inl.h"
#include "src/snapshot/embedded/embedded-data.h"

// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"

namespace v8::internal {

// JSBoundFunction accessors.
Tagged<JSCallable> JSBoundFunction::bound_target_function() const {
  return bound_target_function_.load();
}
void JSBoundFunction::set_bound_target_function(Tagged<JSCallable> value,
                                                WriteBarrierMode mode) {
  bound_target_function_.store(this, value, mode);
}
Tagged<Object> JSBoundFunction::bound_this() const {
  return bound_this_.load();
}
void JSBoundFunction::set_bound_this(Tagged<Object> value,
                                     WriteBarrierMode mode) {
  bound_this_.store(this, value, mode);
}
Tagged<FixedArray> JSBoundFunction::bound_arguments() const {
  return Cast<FixedArray>(bound_arguments_.load());
}
void JSBoundFunction::set_bound_arguments(Tagged<FixedArray> value,
                                          WriteBarrierMode mode) {
  bound_arguments_.store(this, value, mode);
}

// JSWrappedFunction accessors.
Tagged<JSCallable> JSWrappedFunction::wrapped_target_function() const {
  return wrapped_target_function_.load();
}
void JSWrappedFunction::set_wrapped_target_function(Tagged<JSCallable> value,
                                                    WriteBarrierMode mode) {
  wrapped_target_function_.store(this, value, mode);
}
Tagged<NativeContext> JSWrappedFunction::context() const {
  return Cast<NativeContext>(context_.load());
}
void JSWrappedFunction::set_context(Tagged<NativeContext> value,
                                    WriteBarrierMode mode) {
  context_.store(this, value, mode);
}

Tagged<FeedbackCell> JSFunction::raw_feedback_cell() const {
  return Cast<FeedbackCell>(feedback_cell_.load());
}
void JSFunction::set_raw_feedback_cell(Tagged<FeedbackCell> value,
                                       WriteBarrierMode mode) {
  feedback_cell_.store(this, value, mode);
}
Tagged<FeedbackCell> JSFunction::raw_feedback_cell(AcquireLoadTag) const {
  return Cast<FeedbackCell>(feedback_cell_.Acquire_Load());
}
void JSFunction::set_raw_feedback_cell(Tagged<FeedbackCell> value,
                                       ReleaseStoreTag, WriteBarrierMode mode) {
  feedback_cell_.Release_Store(this, value, mode);
}

Tagged<FeedbackVector> JSFunction::feedback_vector() const {
  DCHECK(has_feedback_vector());
  return Cast<FeedbackVector>(raw_feedback_cell()->value());
}

Tagged<ClosureFeedbackCellArray> JSFunction::closure_feedback_cell_array()
    const {
  DCHECK(has_closure_feedback_cell_array());
  return Cast<ClosureFeedbackCellArray>(raw_feedback_cell()->value());
}

bool JSFunction::ChecksTieringState(IsolateForSandbox isolate) {
  return code(isolate)->checks_tiering_state();
}

void JSFunction::CompleteInobjectSlackTrackingIfActive(Isolate* isolate) {
  if (!has_prototype_slot()) return;
  Tagged<Map> initial_map;
  if (TryGetInitialMap(&initial_map) &&
      initial_map->IsInobjectSlackTrackingInProgress()) {
    MapUpdater::CompleteInobjectSlackTracking(isolate, initial_map);
  }
}

template <typename IsolateT>
Tagged<AbstractCode> JSFunction::abstract_code(IsolateT* isolate) {
  if (ActiveTierIsIgnition(isolate)) {
    return Cast<AbstractCode>(shared()->GetBytecodeArray(isolate));
  } else {
    return Cast<AbstractCode>(code(isolate, kAcquireLoad));
  }
}

uint32_t JSFunction::length() { return shared()->length(); }

void JSFunction::UpdateOptimizedCode(Isolate* isolate, Tagged<Code> code,
                                     WriteBarrierMode mode) {
  DisallowGarbageCollection no_gc;
  DCHECK(code->is_optimized_code());
  if (code->is_context_specialized()) {
    // We can only set context-specialized code for single-closure cells.
    if (raw_feedback_cell()->map() !=
        ReadOnlyRoots(isolate).one_closure_cell_map()) {
      return;
    }
  }
  // Required for being able to deoptimize this code.
  code->set_js_dispatch_handle(dispatch_handle());
  UpdateCodeImpl(isolate, code, mode, false);
}

void JSFunction::UpdateCodeImpl(Isolate* isolate, Tagged<Code> value,
                                WriteBarrierMode mode,
                                bool keep_tiering_request) {
  DisallowGarbageCollection no_gc;

  JSDispatchHandle handle = dispatch_handle();
  if (handle == kNullJSDispatchHandle) {
    handle = raw_feedback_cell()->dispatch_handle();
    DCHECK_NE(handle, kNullJSDispatchHandle);
    set_dispatch_handle(handle, mode);
  }
  if (keep_tiering_request) {
    UpdateDispatchEntryKeepTieringRequest(isolate, value, mode);
  } else {
    UpdateDispatchEntry(isolate, value, mode);
  }

  if (V8_UNLIKELY(v8_flags.log_function_events)) {
    isolate->js_dispatch_table().SetTieringRequest(
        dispatch_handle(), TieringBuiltin::kFunctionLogNextExecution, isolate);
  }
}

void JSFunction::UpdateCode(Isolate* isolate, Tagged<Code> code,
                            WriteBarrierMode mode) {
  // Optimized code must go through UpdateOptimized code, which sets a
  // back-reference in the code object to the dispatch handle for
  // deoptimization.
  CHECK(!code->is_optimized_code());
  UpdateCodeImpl(isolate, code, mode, false);
}

inline void JSFunction::UpdateCodeKeepTieringRequests(Isolate* isolate,
                                                      Tagged<Code> code,
                                                      WriteBarrierMode mode) {
  CHECK(!code->is_optimized_code());
  UpdateCodeImpl(isolate, code, mode, true);
}

Tagged<Code> JSFunction::code(IsolateForSandbox isolate) const {
  return Isolate::Current()->js_dispatch_table().GetCode(dispatch_handle());
}

Tagged<Code> JSFunction::code(IsolateForSandbox isolate,
                              AcquireLoadTag tag) const {
  return Isolate::Current()->js_dispatch_table().GetCode(dispatch_handle(tag));
}

Tagged<Union<Smi, Code>> JSFunction::raw_code(IsolateForSandbox isolate) const {
  JSDispatchHandle handle = dispatch_handle();
  if (handle == kNullJSDispatchHandle) return Smi::zero();
  return Isolate::Current()->js_dispatch_table().GetCode(handle);
}

Tagged<Union<Smi, Code>> JSFunction::raw_code(IsolateForSandbox isolate,
                                              AcquireLoadTag tag) const {
  JSDispatchHandle handle = dispatch_handle(tag);
  if (handle == kNullJSDispatchHandle) return Smi::zero();
  return Isolate::Current()->js_dispatch_table().GetCode(handle);
}

// static
JSDispatchHandle JSFunction::AllocateDispatchHandle(
    DirectHandle<JSFunction> function, Isolate* isolate,
    uint16_t parameter_count, DirectHandle<Code> code, WriteBarrierMode mode) {
  DCHECK_EQ(function->raw_feedback_cell()->dispatch_handle(),
            kNullJSDispatchHandle);
  return HeapObject::AllocateAndInstallJSDispatchHandle(
      function, offsetof(JSFunction, dispatch_handle_), isolate,
      parameter_count, code, mode);
}

void JSFunction::clear_dispatch_handle() { dispatch_handle_.Relaxed_Clear(); }
void JSFunction::set_dispatch_handle(JSDispatchHandle handle,
                                     WriteBarrierMode mode) {
  dispatch_handle_.Relaxed_Store(this, handle, mode);
}
void JSFunction::UpdateDispatchEntry(Isolate* isolate, Tagged<Code> new_code,
                                     WriteBarrierMode mode) {
  isolate->js_dispatch_table().SetCode(dispatch_handle(), new_code, this,
                                       isolate, mode);
}
void JSFunction::UpdateDispatchEntryKeepTieringRequest(Isolate* isolate,
                                                       Tagged<Code> new_code,
                                                       WriteBarrierMode mode) {
  isolate->js_dispatch_table().SetCodeKeepTieringRequest(
      dispatch_handle(), new_code, this, isolate, mode);
}
JSDispatchHandle JSFunction::dispatch_handle() const {
  return dispatch_handle_.Relaxed_Load();
}

JSDispatchHandle JSFunction::dispatch_handle(AcquireLoadTag) const {
  return dispatch_handle_.Acquire_Load();
}

Tagged<Context> JSFunction::context(AcquireLoadTag) const {
  return Cast<Context>(context_.Acquire_Load());
}
void JSFunction::set_context(Tagged<Context> value, ReleaseStoreTag,
                             WriteBarrierMode mode) {
  context_.Release_Store(this, value, mode);
}
void JSFunction::set_context(Tagged<Context> value, WriteBarrierMode mode) {
  context_.store(this, value, mode);
}

Address JSFunction::instruction_start(IsolateForSandbox isolate) const {
  return code(isolate)->instruction_start();
}

// TODO(ishell): Why relaxed read but release store?
Tagged<SharedFunctionInfo> JSFunction::shared() const {
  return Cast<SharedFunctionInfo>(shared_function_info_.Relaxed_Load());
}

Tagged<SharedFunctionInfo> JSFunction::shared(RelaxedLoadTag) const {
  return Cast<SharedFunctionInfo>(shared_function_info_.Relaxed_Load());
}

void JSFunction::set_shared(Tagged<SharedFunctionInfo> value,
                            WriteBarrierMode mode) {
  // Release semantics to support acquire read in NeedsResetDueToFlushedBytecode
  shared_function_info_.Release_Store(this, value, mode);
}

bool JSFunction::tiering_in_progress() const {
  if (!has_feedback_vector()) return false;
  return feedback_vector()->tiering_in_progress();
}

bool JSFunction::IsTieringRequestedOrInProgress(Isolate* isolate) const {
  if (!has_feedback_vector()) return false;
  return tiering_in_progress() ||
         isolate->js_dispatch_table().IsTieringRequested(dispatch_handle());
}

bool JSFunction::IsLoggingRequested(Isolate* isolate) const {
  return isolate->js_dispatch_table().IsTieringRequested(
      dispatch_handle(), TieringBuiltin::kFunctionLogNextExecution, isolate);
}

bool JSFunction::IsMaglevRequested(Isolate* isolate) const {
  JSDispatchTable& jdt = isolate->js_dispatch_table();
  Address entrypoint = jdt.GetEntrypoint(dispatch_handle());
  const EmbeddedData& embedded_data = EmbeddedData::FromBlob(isolate);
#define CASE(name, ...)                                                       \
  if (entrypoint == embedded_data.InstructionStartOf(Builtin::k##name)) {     \
    DCHECK(jdt.IsTieringRequested(dispatch_handle(), TieringBuiltin::k##name, \
                                  isolate));                                  \
    return TieringBuiltin::k##name !=                                         \
           TieringBuiltin::kFunctionLogNextExecution;                         \
  }
  BUILTIN_LIST_BASE_TIERING_MAGLEV(CASE)
#undef CASE
  return {};
}

bool JSFunction::IsTurbofanRequested(Isolate* isolate) const {
  JSDispatchTable& jdt = isolate->js_dispatch_table();
  Address entrypoint = jdt.GetEntrypoint(dispatch_handle());
  const EmbeddedData& embedded_data = EmbeddedData::FromBlob(isolate);
#define CASE(name, ...)                                                       \
  if (entrypoint == embedded_data.InstructionStartOf(Builtin::k##name)) {     \
    DCHECK(jdt.IsTieringRequested(dispatch_handle(), TieringBuiltin::k##name, \
                                  isolate));                                  \
    return TieringBuiltin::k##name !=                                         \
           TieringBuiltin::kFunctionLogNextExecution;                         \
  }
  BUILTIN_LIST_BASE_TIERING_TURBOFAN(CASE)
#undef CASE
  return {};
}

bool JSFunction::IsOptimizationRequested(Isolate* isolate) const {
  return IsMaglevRequested(isolate) || IsTurbofanRequested(isolate);
}

std::optional<CodeKind> JSFunction::GetRequestedOptimizationIfAny(
    Isolate* isolate, ConcurrencyMode mode) const {
  JSDispatchTable& jdt = isolate->js_dispatch_table();
  Address entrypoint = jdt.GetEntrypoint(dispatch_handle());
  const EmbeddedData& embedded_data = EmbeddedData::FromBlob(isolate);
  auto builtin = ([&]() -> std::optional<TieringBuiltin> {
#define CASE(name, ...)                                                       \
  if (entrypoint == embedded_data.InstructionStartOf(Builtin::k##name)) {     \
    DCHECK(jdt.IsTieringRequested(dispatch_handle(), TieringBuiltin::k##name, \
                                  isolate));                                  \
    return TieringBuiltin::k##name;                                           \
  }
    BUILTIN_LIST_BASE_TIERING(CASE)
#undef CASE
    DCHECK(!jdt.IsTieringRequested(dispatch_handle()));
    return {};
  })();
  if (V8_LIKELY(!builtin)) return {};
  switch (*builtin) {
    case TieringBuiltin::kOptimizeMaglevEager:
      if (mode == ConcurrencyMode::kSynchronous) return CodeKind::MAGLEV;
      break;
    case TieringBuiltin::kStartMaglevOptimizeJob:
      if (mode == ConcurrencyMode::kConcurrent) return CodeKind::MAGLEV;
      break;
    case TieringBuiltin::kOptimizeTurbofanEager:
      if (mode == ConcurrencyMode::kSynchronous) return CodeKind::TURBOFAN_JS;
      break;
    case TieringBuiltin::kStartTurbofanOptimizeJob:
      if (mode == ConcurrencyMode::kConcurrent) return CodeKind::TURBOFAN_JS;
      break;
    case TieringBuiltin::kMarkLazyDeoptimized:
    case TieringBuiltin::kMarkReoptimizeLazyDeoptimized:
    case TieringBuiltin::kMarkFlushed:
    case TieringBuiltin::kFunctionLogNextExecution:
      break;
  }
  return {};
}

void JSFunction::ResetTieringRequests(Isolate* isolate) {
  if (has_feedback_vector()) feedback_vector()->reset_osr_urgency();
  isolate->js_dispatch_table().ResetTieringRequest(dispatch_handle());
}

void JSFunction::SetTieringInProgress(Isolate* isolate, bool in_progress,
                                      BytecodeOffset osr_offset) {
  if (!has_feedback_vector()) return;
  if (osr_offset.IsNone()) {
    feedback_vector()->set_tiering_in_progress(in_progress);
    SetInterruptBudget(isolate, BudgetModification::kReset);
  } else {
    feedback_vector()->set_osr_tiering_in_progress(in_progress);
  }
}

bool JSFunction::osr_tiering_in_progress() {
  DCHECK(has_feedback_vector());
  return feedback_vector()->osr_tiering_in_progress();
}

bool JSFunction::has_feedback_vector() const {
  return shared()->is_compiled() &&
         IsFeedbackVector(raw_feedback_cell()->value());
}

bool JSFunction::has_closure_feedback_cell_array() const {
  return shared()->is_compiled() &&
         IsClosureFeedbackCellArray(raw_feedback_cell()->value());
}

Tagged<Context> JSFunction::context() { return Cast<Context>(context_.load()); }

Tagged<Context> JSFunction::context(RelaxedLoadTag) const {
  return Cast<Context>(context_.Relaxed_Load());
}

bool JSFunction::has_context() const { return IsContext(context_.load()); }

Tagged<JSGlobalProxy> JSFunction::global_proxy() {
  return context()->global_proxy();
}

Tagged<NativeContext> JSFunction::native_context() {
  return context()->native_context();
}

Tagged<UnionOf<JSReceiver, Map, Tuple2, TheHole>>
JSFunctionWithPrototype::prototype_or_initial_map(AcquireLoadTag) const {
  return Cast<UnionOf<JSReceiver, Map, Tuple2, TheHole>>(
      prototype_or_initial_map_.Acquire_Load());
}
void JSFunctionWithPrototype::set_prototype_or_initial_map(
    Tagged<UnionOf<JSReceiver, Map, Tuple2, TheHole>> value, ReleaseStoreTag,
    WriteBarrierMode mode) {
  prototype_or_initial_map_.Release_Store(this, value, mode);
}

Tagged<UnionOf<JSReceiver, Map, Tuple2, TheHole>>
JSFunction::prototype_or_initial_map(AcquireLoadTag tag) const {
  DCHECK(has_prototype_slot());
  return Cast<JSFunctionWithPrototype>(this)->prototype_or_initial_map(tag);
}
void JSFunction::set_prototype_or_initial_map(
    Tagged<UnionOf<JSReceiver, Map, Tuple2, TheHole>> value,
    ReleaseStoreTag tag, WriteBarrierMode mode) {
  DCHECK(has_prototype_slot());
  Cast<JSFunctionWithPrototype>(this)->set_prototype_or_initial_map(value, tag,
                                                                    mode);
}

bool JSFunction::has_prototype_slot() const {
  // It's slightly cheaper to check for JSFunctionWithoutPrototype because
  // there's only one such instance type.
  return !IsJSFunctionWithoutPrototypeMap(map());
}

// This struct is defined outside of JSFunction class because the V8_OBJECT
// macro enables "-Wpadded" warning (requirement for explicit padding) which
// we don't need for this struct.
struct JSFunction::PrototypeOrInitialMapData {
  Tagged<JSPrototype> instance_prototype;
  Tagged<Tuple2> non_instance_prototype_tuple;
  Tagged<JSAny> non_instance_prototype;
  Tagged<Map> initial_map;
  bool has_instance_prototype = false;
  bool has_non_instance_prototype = false;
  bool has_initial_map = false;
};

bool JSFunction::TryGetPrototypeOrInitialMap(
    PrototypeOrInitialMapData* out) const {
  DCHECK(has_prototype_slot());
  Tagged<HeapObject> proto_or_map = prototype_or_initial_map(kAcquireLoad);
  if (IsTheHole(proto_or_map)) return false;

  out->has_instance_prototype = false;
  out->has_non_instance_prototype = false;
  out->has_initial_map = false;

  if (Tagged<Tuple2> tuple; TryCast<Tuple2>(proto_or_map, &tuple)) {
    out->non_instance_prototype_tuple = tuple;
    out->has_non_instance_prototype = true;
    out->non_instance_prototype = Cast<JSAny>(tuple->value2());
    proto_or_map = Cast<HeapObject>(tuple->value1());
  }
  if (Tagged<Map> initial_map; TryCast<Map>(proto_or_map, &initial_map)) {
    out->instance_prototype = initial_map->prototype();
    out->has_initial_map = true;
    out->initial_map = initial_map;
    // Constructors from https://tc39.es/proposal-structs/ do not have
    // instance prototypes yet. Per-Realm prototypes is currently an open
    // design question and not included in this draft. Thus, once bootstrapper
    // is done, this is the only "legitimate" case of a function without an
    // instance prototype.
    out->has_instance_prototype = !IsNull(out->instance_prototype);
    DCHECK_IMPLIES(!out->has_instance_prototype,
                   Isolate::Current()->bootstrapper()->IsActive() ||
                       v8_flags.harmony_struct);
    return true;
  }
  DCHECK(IsJSReceiver(proto_or_map));
  out->has_instance_prototype = true;
  out->instance_prototype = Cast<JSReceiver>(proto_or_map);
  return true;
}

bool JSFunction::TryGetInitialMap(Tagged<Map>* out_initial_map) const {
  PrototypeOrInitialMapData pomd;
  if (!TryGetPrototypeOrInitialMap(&pomd)) return false;
  if (pomd.has_initial_map) {
    *out_initial_map = pomd.initial_map;
    return true;
  }
  return false;
}

Tagged<Map> JSFunction::initial_map() const {
  DCHECK(has_prototype_slot());
  Tagged<Map> initial_map;
  bool succeeded = TryGetInitialMap(&initial_map);
  DCHECK(succeeded);
  USE(succeeded);
  return initial_map;
}

bool JSFunction::has_initial_map() const {
  DCHECK(has_prototype_slot());
  Tagged<Map> initial_map;
  return TryGetInitialMap(&initial_map);
}

bool JSFunction::has_instance_prototype() const {
  DCHECK(has_prototype_slot());
  PrototypeOrInitialMapData pomd;
  if (!TryGetPrototypeOrInitialMap(&pomd)) return false;
  return pomd.has_instance_prototype;
}

bool JSFunction::has_non_instance_prototype() const {
  DCHECK(has_prototype_slot());
  PrototypeOrInitialMapData pomd;
  if (!TryGetPrototypeOrInitialMap(&pomd)) return false;
  return pomd.has_non_instance_prototype;
}

bool JSFunction::has_prototype() const {
  DCHECK(has_prototype_slot());
  PrototypeOrInitialMapData pomd;
  return TryGetPrototypeOrInitialMap(&pomd);
}

bool JSFunction::has_prototype_property() const {
  return (has_prototype_slot() && map()->is_constructor()) ||
         IsGeneratorFunction(shared()->kind());
}

bool JSFunction::PrototypeRequiresRuntimeLookup() const {
  if (!has_prototype_property()) return true;
  Tagged<Object> proto_or_map = prototype_or_initial_map(kAcquireLoad);
  return IsTuple2(proto_or_map);
}

Tagged<JSReceiver> JSFunction::GetIntrinsicDefaultProto() const {
  FunctionKind kind = shared()->kind();
  Tagged<NativeContext> native_context =
      context(kAcquireLoad)->native_context();
  return IsGeneratorFunction(kind)
             ? IsAsyncFunction(kind)
                   ? native_context->initial_async_generator_prototype()
                   : native_context->initial_generator_prototype()
             : native_context->initial_object_prototype();
}

Tagged<JSReceiver> JSFunction::instance_prototype() const {
  DCHECK(has_instance_prototype());
  PrototypeOrInitialMapData pomd;
  bool succeeded = TryGetPrototypeOrInitialMap(&pomd);
  DCHECK(succeeded);
  USE(succeeded);
  // By the time of this query, the instance prototype must already be fully
  // set (initial map's prototype might be temporarily set to Null during
  // bootstrapping and creation of builtins prototypes).
  DCHECK(IsJSReceiver(pomd.instance_prototype));
  return Cast<JSReceiver>(pomd.instance_prototype);
}

Tagged<JSAny> JSFunction::prototype() const {
  DCHECK(has_prototype());
  PrototypeOrInitialMapData pomd;
  bool succeeded = TryGetPrototypeOrInitialMap(&pomd);
  DCHECK(succeeded);
  USE(succeeded);
  if (pomd.has_non_instance_prototype) {
    return pomd.non_instance_prototype;
  }
  return pomd.instance_prototype;
}

bool JSFunction::is_compiled(IsolateForSandbox isolate) const {
  return code(isolate, kAcquireLoad)->builtin_id() != Builtin::kCompileLazy &&
         shared()->is_compiled();
}

bool JSFunction::NeedsResetDueToFlushedBytecode(Isolate* isolate) {
  // The function is only used sequentially. Concurrent cases need to take care
  // of loading the fields themselves.
  Tagged<SharedFunctionInfo> sfi = TrustedCast<SharedFunctionInfo>(shared());
  Tagged<Code> code = TrustedCast<Code>(raw_code(isolate));
  return NeedsResetDueToFlushedBytecode(isolate, sfi, code);
}

bool JSFunction::NeedsResetDueToFlushedBytecode(Isolate* isolate,
                                                Tagged<SharedFunctionInfo> sfi,
                                                Tagged<Code> code) {
  return !sfi->is_compiled() &&
         (code->builtin_id() != Builtin::kCompileLazy ||
          // With leaptiering we can have CompileLazy as the code object but
          // still an optimization trampoline installed.
          IsOptimizationRequested(isolate));
}

bool JSFunction::NeedsResetDueToFlushedBaselineCode(IsolateForSandbox isolate) {
  return code(isolate)->kind() == CodeKind::BASELINE &&
         !shared()->HasBaselineCode();
}

void JSFunction::ResetIfCodeFlushed(
    Isolate* isolate,
    std::optional<std::function<void(Tagged<HeapObject> object, ObjectSlot slot,
                                     Tagged<HeapObject> target)>>
        gc_notify_updated_slot) {
  const bool kBytecodeCanFlush =
      v8_flags.flush_bytecode || v8_flags.stress_snapshot;
  const bool kBaselineCodeCanFlush =
      v8_flags.flush_baseline_code || v8_flags.stress_snapshot;
  if (!kBytecodeCanFlush && !kBaselineCodeCanFlush) return;

  DCHECK_IMPLIES(NeedsResetDueToFlushedBytecode(isolate), kBytecodeCanFlush);
  if (kBytecodeCanFlush && NeedsResetDueToFlushedBytecode(isolate)) {
    // Bytecode was flushed and function is now uncompiled, reset JSFunction
    // by setting code to CompileLazy and clearing the feedback vector.
    ResetTieringRequests(isolate);
    UpdateCode(isolate, *BUILTIN_CODE(isolate, CompileLazy),
               SKIP_WRITE_BARRIER);
    raw_feedback_cell()->reset_feedback_vector(gc_notify_updated_slot);
    return;
  }

  DCHECK_IMPLIES(NeedsResetDueToFlushedBaselineCode(isolate),
                 kBaselineCodeCanFlush);
  if (kBaselineCodeCanFlush && NeedsResetDueToFlushedBaselineCode(isolate)) {
    // Flush baseline code from the closure if required
    ResetTieringRequests(isolate);
    UpdateCode(isolate, *BUILTIN_CODE(isolate, InterpreterEntryTrampoline),
               SKIP_WRITE_BARRIER);
  }
}

}  // namespace v8::internal

#include "src/objects/object-macros-undef.h"

#endif  // V8_OBJECTS_JS_FUNCTION_INL_H_