current commit
261007.21 · deps: update V8 to 15.5.35.20
// Copyright 2016 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_API_API_ARGUMENTS_INL_H_
#define V8_API_API_ARGUMENTS_INL_H_

#include "src/api/api-arguments.h"
// Include the non-inl header before the rest of the headers.

#include "src/api/api-inl.h"
#include "src/debug/debug.h"
#include "src/execution/vm-state-inl.h"
#include "src/logging/runtime-call-stats-scope.h"
#include "src/objects/api-callbacks.h"
#include "src/objects/instance-type.h"
#include "src/objects/slots-inl.h"

namespace v8 {
namespace internal {

template <typename T>
Handle<T> PropertyCallbackArguments::GetReturnValue() const {
  // Check the ReturnValue.
  FullObjectSlot slot = slot_at(kReturnValueIndex);
  DCHECK(Is<JSAny>(*slot));
  return Cast<T>(Handle<Object>(slot.location()));
}

bool PropertyCallbackArguments::is_named() const {
  int frame_type = Smi::ToInt(Tagged<Object>(values_[T::kFrameTypeIndex]));
  DCHECK(frame_type == StackFrame::API_NAMED_ACCESSOR_EXIT ||
         frame_type == StackFrame::API_INDEXED_ACCESSOR_EXIT);
  return frame_type == StackFrame::API_NAMED_ACCESSOR_EXIT;
}

void PropertyCallbackArguments::set_property_key(Tagged<Name> name) {
  values_[T::kPropertyKeyIndex] = name->ptr();
  values_[T::kFrameTypeIndex] =
      Smi::FromInt(StackFrame::API_NAMED_ACCESSOR_EXIT).ptr();
}

void PropertyCallbackArguments::set_property_key(uint32_t index) {
  values_[T::kPropertyKeyIndex] = index;
  values_[T::kFrameTypeIndex] =
      Smi::FromInt(StackFrame::API_INDEXED_ACCESSOR_EXIT).ptr();
}

DirectHandle<JSObject> PropertyCallbackArguments::holder() const {
  return DirectHandle<JSObject>::FromSlot(slot_at(T::kHolderIndex).location());
}

#define DCHECK_NAME_COMPATIBLE(interceptor, name) \
  DCHECK(interceptor->is_named());                \
  DCHECK(!name->IsAnyPrivate());                  \
  DCHECK_IMPLIES(IsSymbol(*name), interceptor->can_intercept_symbols());

#define PREPARE_CALLBACK_INFO_ACCESSOR(ISOLATE, F, API_RETURN_TYPE,          \
                                       ACCESSOR_INFO, HOLDER, ACCESSOR_KIND, \
                                       EXCEPTION_CONTEXT)                    \
  if (ISOLATE->should_check_side_effects() &&                                \
      !ISOLATE->debug()->PerformSideEffectCheckForAccessor(                  \
          ACCESSOR_INFO, HOLDER, ACCESSOR_KIND)) {                           \
    return {};                                                               \
  }                                                                          \
  const PropertyCallbackInfo<API_RETURN_TYPE>& callback_info =               \
      GetPropertyCallbackInfo<API_RETURN_TYPE>();                            \
  ExternalCallbackScope call_scope(ISOLATE, FUNCTION_ADDR(F),                \
                                   EXCEPTION_CONTEXT, &callback_info);

#define PREPARE_CALLBACK_INFO_INTERCEPTOR(ISOLATE, F, API_RETURN_TYPE,         \
                                          INTERCEPTOR_INFO, EXCEPTION_CONTEXT) \
  if (ISOLATE->should_check_side_effects() &&                                  \
      !ISOLATE->debug()->PerformSideEffectCheckForInterceptor(                 \
          INTERCEPTOR_INFO)) {                                                 \
    return {};                                                                 \
  }                                                                            \
  const PropertyCallbackInfo<API_RETURN_TYPE>& callback_info =                 \
      GetPropertyCallbackInfo<API_RETURN_TYPE>();                              \
  ExternalCallbackScope call_scope(ISOLATE, FUNCTION_ADDR(F),                  \
                                   EXCEPTION_CONTEXT, &callback_info);

template <typename ArgT>
FunctionCallbackArguments::FunctionCallbackArguments(
    Isolate* isolate, Tagged<FunctionTemplateInfo> target,
    Tagged<Object> receiver, const base::Vector<const ArgT> args)
    : Relocatable(isolate) {
  Initialize<false>(isolate, target, Smi::zero(), receiver, args);
}

template <typename ArgT>
FunctionCallbackArguments::FunctionCallbackArguments(
    Isolate* isolate, Tagged<FunctionTemplateInfo> target,
    Tagged<HeapObject> new_target, Tagged<Object> receiver,
    const base::Vector<const ArgT> args)
    : Relocatable(isolate) {
  Initialize<true>(isolate, target, new_target, receiver, args);
}

template <bool is_construct, typename ArgT>
  requires(std::is_same_v<ArgT, DirectHandle<Object>> ||
           std::is_same_v<ArgT, Address>)
void FunctionCallbackArguments::Initialize(
    Isolate* isolate, Tagged<FunctionTemplateInfo> target,
    Tagged<Object> new_target, Tagged<Object> receiver,
    const base::Vector<const ArgT> args) {
  uint32_t argc = static_cast<uint32_t>(args.size());
  values_.resize(argc + T::kArgsLength + T::kOptionalArgsLength);

  Address* values = &values_.data()[T::kOptionalArgsLength];

  // Initialize frame part.
  values[T::kNewTargetIndex] = is_construct ? new_target.ptr() : 0;
  values[T::kArgcIndex] = argc;
  values[T::kFrameTypeIndex] =
      Smi::FromInt(is_construct ? StackFrame::API_CONSTRUCT_EXIT
                                : StackFrame::API_CALLBACK_EXIT)
          .ptr();

  if (DEBUG_BOOL) {
    // These values are not supposed to be looked at.
    values[T::kFrameSPIndex] = kZapValue;
    values[T::kFrameConstantPoolIndex] = kZapValue;
    values[T::kFrameFPIndex] = kZapValue;
    values[T::kFramePCIndex] = kZapValue;
  }

  // Initialize Api arguments part.
  values[T::kTargetIndex] = target.ptr();
  values[T::kIsolateIndex] = reinterpret_cast<Address>(isolate);
  values[T::kReturnValueIndex] = ReadOnlyRoots(isolate).undefined_value().ptr();
  values[T::kContextIndex] = isolate->context().ptr();

  // Make sure the Isolate slot is safe to visit by GC (Isolate pointer
  // is guaranteed to be page aligned).
  DCHECK(HAS_SMI_TAG(values[T::kIsolateIndex]));

  // Initialize JS arguments part.
  values[T::kReceiverIndex] = receiver.ptr();
  for (uint32_t i = 0; i < argc; ++i) {
    if constexpr (std::is_same_v<ArgT, Address>) {
      values[T::kFirstJSArgumentIndex + i] = args[i];
    } else {
      values[T::kFirstJSArgumentIndex + i] = (*args[i]).ptr();
    }
  }
}

FunctionCallbackArguments::~FunctionCallbackArguments() {
  if (DEBUG_BOOL) {
    // Make sure the result handle located inside this structure is not used
    // after this object dies.
    values_.data()[T::kReturnValueIndex] = kZapValue;
  }
}

Tagged<JSAny> FunctionCallbackArguments::CallOrConstruct(
    Isolate* isolate, Tagged<FunctionTemplateInfo> function,
    bool is_construct) {
  RCS_SCOPE(isolate, RuntimeCallCounterId::kFunctionCallback);
  v8::FunctionCallback f =
      reinterpret_cast<v8::FunctionCallback>(function->callback(isolate));
  if (isolate->should_check_side_effects() &&
      !isolate->debug()->PerformSideEffectCheckForCallback(
          handle(function, isolate))) {
    return {};
  }
  // v8::FunctionCallbackInfo structure might start at different positions in
  // values_ array depending on whether it's a construct call or not.
  auto info =
      reinterpret_cast<FunctionCallbackInfo<v8::Value>*>(slot_at(0).location());
  ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f),
                                   is_construct ? ExceptionContext::kConstructor
                                                : ExceptionContext::kOperation,
                                   info);
  f(*info);

  Tagged<Object> result = *slot_at(T::kReturnValueIndex);
  DCHECK(Is<JSAny>(result));
  return Cast<JSAny>(result);
}

PropertyCallbackArguments::PropertyCallbackArguments(Isolate* isolate,
                                                     Tagged<JSObject> holder)
    : Relocatable(isolate)
#ifdef DEBUG
      ,
      is_setter_definer_deleter_(false),
      javascript_execution_counter_(isolate->javascript_execution_counter())
#endif  // DEBUG
{
  Initialize(isolate, holder);
}

PropertyCallbackArguments::PropertyCallbackArguments(
    Isolate* isolate, Tagged<JSObject> holder, Maybe<ShouldThrow> should_throw)
    : Relocatable(isolate)
#ifdef DEBUG
      ,
      is_setter_definer_deleter_(true),
      javascript_execution_counter_(isolate->javascript_execution_counter())
#endif  // DEBUG
{
  Initialize(isolate, holder);

  int value = Internals::kInferShouldThrowMode;
  if (should_throw.IsJust()) {
    value = should_throw.FromJust();
  }
  slot_at(T::kShouldThrowOnErrorIndex).store(Smi::FromInt(value));
}

void PropertyCallbackArguments::Initialize(Isolate* isolate,
                                           Tagged<JSObject> holder) {
  if (DEBUG_BOOL) {
    // Zap these fields to ensure that they are initialized by a subsequent
    // CallXXX(..).
    values_[T::kFrameSPIndex] = kZapValue;
    values_[T::kFrameConstantPoolIndex] = kZapValue;
    values_[T::kFrameTypeIndex] = kZapValue;
    values_[T::kFrameFPIndex] = kZapValue;
    values_[T::kFramePCIndex] = kZapValue;

    values_[T::kPropertyKeyIndex] = kZapValue;
    values_[T::kReturnValueIndex] = kZapValue;
    values_[T::kCallbackInfoIndex] = kZapValue;
    // This field is used only for setter/definer/deleter callbacks.
    values_[T::kShouldThrowOnErrorIndex] = kZapValue;
  }
  values_[T::kIsolateIndex] = reinterpret_cast<Address>(isolate);
  values_[T::kHolderIndex] = holder.ptr();
  DCHECK(!IsJSGlobalObject(holder));

  // Make sure the Isolate slot is safe to visit by GC (Isolate pointer
  // is guaranteed to be page aligned).
  DCHECK(HAS_SMI_TAG(values_[T::kIsolateIndex]));
}

PropertyCallbackArguments::~PropertyCallbackArguments() {
#ifdef DEBUG
  // TODO(chromium:1310062): enable this check.
  // if (javascript_execution_counter_) {
  //   CHECK_WITH_MSG(javascript_execution_counter_ ==
  //                      isolate()->javascript_execution_counter(),
  //                  "Unexpected side effect detected");
  // }
  values_[T::kReturnValueIndex] = kZapValue;
#endif  // DEBUG
}

Maybe<InterceptorResult> PropertyCallbackArguments::GetBooleanReturnValue(
    Isolate* isolate, v8::Intercepted intercepted,
    const char* callback_kind_for_error_message, bool ignore_return_value) {
  if (isolate->has_exception()) {
    // TODO(ishell, 328490288): fix Node.js which has Setter/Definer
    // interceptor callbacks not returning v8::Intercepted::kYes on exceptions.
    if ((false) && DEBUG_BOOL && (intercepted == v8::Intercepted::kNo)) {
      FATAL(
          "Check failed: %s interceptor callback has thrown an "
          "exception but hasn't returned v8::Intercepted::kYes.",
          callback_kind_for_error_message);
    }
    return Nothing<InterceptorResult>();
  }

  if (intercepted == v8::Intercepted::kNo) {
    // Not intercepted, there must be no side effects including exceptions.
    DCHECK(!isolate->has_exception());
    return Just(InterceptorResult::kNotIntercepted);
  }
  DCHECK_EQ(intercepted, v8::Intercepted::kYes);
  AcceptSideEffects();

  if (ignore_return_value) return Just(InterceptorResult::kTrue);

  bool result = IsTrue(*GetReturnValue<Boolean>());
  return Just(result ? InterceptorResult::kTrue : InterceptorResult::kFalse);
}

// -------------------------------------------------------------------------
// Named Interceptor callbacks.

DirectHandle<JSObjectOrUndefined>
PropertyCallbackArguments::CallNamedEnumerator(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor) {
  DCHECK(!is_setter_definer_deleter_);
  DCHECK(interceptor->is_named());
  RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedEnumeratorCallback);
  return CallPropertyEnumerator(isolate, interceptor);
}

// TODO(ishell): return std::optional<PropertyAttributes>.
DirectHandle<Object> PropertyCallbackArguments::CallNamedQuery(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
    DirectHandle<Name> name) {
  DCHECK(!is_setter_definer_deleter_);
  DCHECK_NAME_COMPATIBLE(interceptor, name);
  RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedQueryCallback);
  set_property_key(*name);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  slot_at(kReturnValueIndex).store(Smi::FromInt(v8::None));
  NamedPropertyQueryCallback f = reinterpret_cast<NamedPropertyQueryCallback>(
      interceptor->named_query(isolate));
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Integer, interceptor,
                                    ExceptionContext::kNamedQuery);
  v8::Intercepted intercepted = f(v8::Utils::ToLocal(name), callback_info);
  if (intercepted == v8::Intercepted::kNo) return {};
  return GetReturnValue<Object>();
}

DirectHandle<JSAny> PropertyCallbackArguments::CallNamedGetter(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
    DirectHandle<Name> name) {
  DCHECK(!is_setter_definer_deleter_);
  DCHECK_NAME_COMPATIBLE(interceptor, name);
  RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedGetterCallback);
  set_property_key(*name);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());
  NamedPropertyGetterCallback f = reinterpret_cast<NamedPropertyGetterCallback>(
      interceptor->named_getter(isolate));
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Value, interceptor,
                                    ExceptionContext::kNamedGetter);
  v8::Intercepted intercepted = f(v8::Utils::ToLocal(name), callback_info);
  if (intercepted == v8::Intercepted::kNo) return {};
  return GetReturnValue<JSAny>();
}

Handle<JSAny> PropertyCallbackArguments::CallNamedDescriptor(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
    DirectHandle<Name> name) {
  DCHECK(!is_setter_definer_deleter_);
  DCHECK_NAME_COMPATIBLE(interceptor, name);
  RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedDescriptorCallback);
  set_property_key(*name);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());
  NamedPropertyDescriptorCallback f =
      reinterpret_cast<NamedPropertyDescriptorCallback>(
          interceptor->named_descriptor(isolate));
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Value, interceptor,
                                    ExceptionContext::kNamedDescriptor);
  v8::Intercepted intercepted = f(v8::Utils::ToLocal(name), callback_info);
  if (intercepted == v8::Intercepted::kNo) return {};
  return GetReturnValue<JSAny>();
}

v8::Intercepted PropertyCallbackArguments::CallNamedSetter(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
    DirectHandle<Name> name, DirectHandle<Object> value) {
  DCHECK(is_setter_definer_deleter_);
  DCHECK_NAME_COMPATIBLE(interceptor, name);
  RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedSetterCallback);
  set_property_key(*name);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
  NamedPropertySetterCallbackV2 f =
      reinterpret_cast<NamedPropertySetterCallbackV2>(
          interceptor->named_setter(isolate));
  DirectHandle<InterceptorInfo> has_side_effects;
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Boolean, has_side_effects,
                                    ExceptionContext::kNamedSetter);
  v8::Intercepted intercepted =
      f(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), callback_info);
  return intercepted;
}

v8::Intercepted PropertyCallbackArguments::CallNamedDefiner(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
    DirectHandle<Name> name, const v8::PropertyDescriptor& desc) {
  DCHECK(is_setter_definer_deleter_);
  DCHECK_NAME_COMPATIBLE(interceptor, name);
  RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedDefinerCallback);
  set_property_key(*name);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
  NamedPropertyDefinerCallbackV2 f =
      reinterpret_cast<NamedPropertyDefinerCallbackV2>(
          interceptor->named_definer(isolate));
  DirectHandle<InterceptorInfo> has_side_effects;
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Boolean, has_side_effects,
                                    ExceptionContext::kNamedDefiner);
  v8::Intercepted intercepted =
      f(v8::Utils::ToLocal(name), desc, callback_info);
  return intercepted;
}

v8::Intercepted PropertyCallbackArguments::CallNamedDeleter(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
    DirectHandle<Name> name) {
  DCHECK(is_setter_definer_deleter_);
  DCHECK_NAME_COMPATIBLE(interceptor, name);
  RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedDeleterCallback);
  set_property_key(*name);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
  NamedPropertyDeleterCallback f =
      reinterpret_cast<NamedPropertyDeleterCallback>(
          interceptor->named_deleter(isolate));
  DirectHandle<InterceptorInfo> has_side_effects;
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Boolean, has_side_effects,
                                    ExceptionContext::kNamedDeleter);
  v8::Intercepted intercepted = f(v8::Utils::ToLocal(name), callback_info);
  return intercepted;
}

// -------------------------------------------------------------------------
// Indexed Interceptor callbacks.

DirectHandle<JSObjectOrUndefined>
PropertyCallbackArguments::CallIndexedEnumerator(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor) {
  DCHECK(!is_setter_definer_deleter_);
  DCHECK(!interceptor->is_named());
  RCS_SCOPE(isolate, RuntimeCallCounterId::kIndexedEnumeratorCallback);
  return CallPropertyEnumerator(isolate, interceptor);
}

// TODO(ishell): return std::optional<PropertyAttributes>.
DirectHandle<Object> PropertyCallbackArguments::CallIndexedQuery(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
    uint32_t index) {
  DCHECK(!is_setter_definer_deleter_);
  DCHECK(!interceptor->is_named());
  RCS_SCOPE(isolate, RuntimeCallCounterId::kIndexedQueryCallback);
  set_property_key(index);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  slot_at(kReturnValueIndex).store(Smi::FromInt(v8::None));
  IndexedPropertyQueryCallback f =
      reinterpret_cast<IndexedPropertyQueryCallback>(
          interceptor->indexed_query(isolate));
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Integer, interceptor,
                                    ExceptionContext::kIndexedQuery);
  v8::Intercepted intercepted = f(index, callback_info);
  if (intercepted == v8::Intercepted::kNo) return {};
  return GetReturnValue<Object>();
}

DirectHandle<JSAny> PropertyCallbackArguments::CallIndexedGetter(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
    uint32_t index) {
  DCHECK(!is_setter_definer_deleter_);
  DCHECK(!interceptor->is_named());
  RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedGetterCallback);
  set_property_key(index);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());
  IndexedPropertyGetterCallback f =
      reinterpret_cast<IndexedPropertyGetterCallback>(
          interceptor->indexed_getter(isolate));
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Value, interceptor,
                                    ExceptionContext::kIndexedGetter);
  v8::Intercepted intercepted = f(index, callback_info);
  if (intercepted == v8::Intercepted::kNo) return {};
  return GetReturnValue<JSAny>();
}

Handle<JSAny> PropertyCallbackArguments::CallIndexedDescriptor(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
    uint32_t index) {
  DCHECK(!is_setter_definer_deleter_);
  DCHECK(!interceptor->is_named());
  RCS_SCOPE(isolate, RuntimeCallCounterId::kIndexedDescriptorCallback);
  set_property_key(index);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());
  IndexedPropertyDescriptorCallback f =
      reinterpret_cast<IndexedPropertyDescriptorCallback>(
          interceptor->indexed_descriptor(isolate));
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Value, interceptor,
                                    ExceptionContext::kIndexedDescriptor);
  v8::Intercepted intercepted = f(index, callback_info);
  if (intercepted == v8::Intercepted::kNo) return {};
  return GetReturnValue<JSAny>();
}

v8::Intercepted PropertyCallbackArguments::CallIndexedSetter(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor, uint32_t index,
    DirectHandle<Object> value) {
  DCHECK(is_setter_definer_deleter_);
  DCHECK(!interceptor->is_named());
  RCS_SCOPE(isolate, RuntimeCallCounterId::kIndexedSetterCallback);
  set_property_key(index);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
  IndexedPropertySetterCallback f =
      reinterpret_cast<IndexedPropertySetterCallback>(
          interceptor->indexed_setter(isolate));
  DirectHandle<InterceptorInfo> has_side_effects;
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Boolean, has_side_effects,
                                    ExceptionContext::kIndexedSetter);
  v8::Intercepted intercepted =
      f(index, v8::Utils::ToLocal(value), callback_info);
  return intercepted;
}

v8::Intercepted PropertyCallbackArguments::CallIndexedDefiner(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor, uint32_t index,
    const v8::PropertyDescriptor& desc) {
  DCHECK(is_setter_definer_deleter_);
  DCHECK(!interceptor->is_named());
  RCS_SCOPE(isolate, RuntimeCallCounterId::kIndexedDefinerCallback);
  set_property_key(index);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
  IndexedPropertyDefinerCallback f =
      reinterpret_cast<IndexedPropertyDefinerCallback>(
          interceptor->indexed_definer(isolate));
  DirectHandle<InterceptorInfo> has_side_effects;
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Boolean, has_side_effects,
                                    ExceptionContext::kIndexedDefiner);
  v8::Intercepted intercepted = f(index, desc, callback_info);
  return intercepted;
}

v8::Intercepted PropertyCallbackArguments::CallIndexedDeleter(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
    uint32_t index) {
  DCHECK(is_setter_definer_deleter_);
  DCHECK(!interceptor->is_named());
  RCS_SCOPE(isolate, RuntimeCallCounterId::kIndexedDeleterCallback);
  set_property_key(index);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
  IndexedPropertyDeleterCallback f =
      reinterpret_cast<IndexedPropertyDeleterCallback>(
          interceptor->indexed_deleter(isolate));
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Boolean, interceptor,
                                    ExceptionContext::kIndexedDeleter);
  v8::Intercepted intercepted = f(index, callback_info);
  return intercepted;
}

DirectHandle<JSObjectOrUndefined>
PropertyCallbackArguments::CallPropertyEnumerator(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor) {
  // Named and indexed enumerator callbacks have same signatures.
  static_assert(std::is_same_v<NamedPropertyEnumeratorCallback,
                               IndexedPropertyEnumeratorCallback>);
  DCHECK(!is_setter_definer_deleter_);
  // The actual property key is not relevant for this callback.
  set_property_key(0);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  // Enumerator callback's return value is initialized with undefined even
  // though it's supposed to return v8::Array.
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());
  // TODO(ishell): consider making it return v8::Intercepted to indicate
  // whether the result was set or not.
  IndexedPropertyEnumeratorCallback f;
  if (interceptor->is_named()) {
    f = reinterpret_cast<NamedPropertyEnumeratorCallback>(
        interceptor->named_enumerator(isolate));
  } else {
    f = reinterpret_cast<IndexedPropertyEnumeratorCallback>(
        interceptor->indexed_enumerator(isolate));
  }
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Array, interceptor,
                                    ExceptionContext::kNamedEnumerator);
  f(callback_info);
  DirectHandle<JSAny> result = GetReturnValue<JSAny>();
  DCHECK(IsUndefined(*result) || IsJSObject(*result));
  return Cast<JSObjectOrUndefined>(result);
}

uint32_t PropertyCallbackArguments::CallIndexedIndexOf(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
    DirectHandle<Object> value, uint32_t start_index, uint32_t end_index,
    uint32_t* in_out_length) {
  DCHECK(!is_setter_definer_deleter_);
  // The actual property key is not relevant for this callback.
  set_property_key(0);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  // IndexOf callback doesn't use return value.
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());

  IndexedPropertyIndexOfCallback f =
      reinterpret_cast<IndexedPropertyIndexOfCallback>(
          interceptor->indexed_index_of(isolate));
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, void, interceptor,
                                    ExceptionContext::kUnknown);
  return f(v8::Utils::ToLocal(value), start_index, end_index, in_out_length,
           callback_info);
}

DirectHandle<JSAny> PropertyCallbackArguments::CallIndexedIterableToList(
    Isolate* isolate, DirectHandle<InterceptorInfo> interceptor) {
  DCHECK(!is_setter_definer_deleter_);
  set_property_key(0);
  slot_at(kCallbackInfoIndex).store(*interceptor);
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());

  IndexedPropertyIterableToListCallback f =
      reinterpret_cast<IndexedPropertyIterableToListCallback>(
          interceptor->indexed_iterable_to_list(isolate));
  PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Value, interceptor,
                                    ExceptionContext::kUnknown);
  f(callback_info);
  return GetReturnValue<JSAny>();
}

// -------------------------------------------------------------------------
// Accessors

DirectHandle<JSAny> PropertyCallbackArguments::CallAccessorGetter(
    Isolate* isolate, DirectHandle<AccessorInfo> accessor_info,
    DirectHandle<Name> name) {
  DCHECK(!is_setter_definer_deleter_);
  RCS_SCOPE(isolate, RuntimeCallCounterId::kAccessorGetterCallback);
  // Unlike interceptor callbacks we know that the property exists, so
  // the callback is allowed to have side effects.
  AcceptSideEffects();

  set_property_key(*name);
  slot_at(kCallbackInfoIndex).store(*accessor_info);
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());
  AccessorNameGetterCallback f = reinterpret_cast<AccessorNameGetterCallback>(
      accessor_info->getter(isolate));
  PREPARE_CALLBACK_INFO_ACCESSOR(isolate, f, v8::Value, accessor_info, holder(),
                                 ACCESSOR_GETTER,
                                 ExceptionContext::kAttributeGet);
  f(v8::Utils::ToLocal(name), callback_info);
  return GetReturnValue<JSAny>();
}

bool PropertyCallbackArguments::CallAccessorSetter(
    Isolate* isolate, DirectHandle<AccessorInfo> accessor_info,
    DirectHandle<Name> name, DirectHandle<Object> value) {
  DCHECK(is_setter_definer_deleter_);
  RCS_SCOPE(isolate, RuntimeCallCounterId::kAccessorSetterCallback);
  // Unlike interceptor callbacks we know that the property exists, so
  // the callback is allowed to have side effects.
  AcceptSideEffects();

  set_property_key(*name);
  slot_at(kCallbackInfoIndex).store(*accessor_info);
  slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
  // The actual type of setter callback is either
  // v8::AccessorNameSetterCallback or
  // i::Accessors::AccessorNameBooleanSetterCallback, depending on whether the
  // AccessorInfo was created by the API or internally (see accessors.cc).
  // Here we handle both cases using the AccessorNameSetterCallback signature
  // and checking whether the returned result is set to default value
  // (the undefined value).
  AccessorNameSetterCallbackV2 f =
      reinterpret_cast<AccessorNameSetterCallbackV2>(
          accessor_info->setter(isolate));
  PREPARE_CALLBACK_INFO_ACCESSOR(isolate, f, v8::Boolean, accessor_info,
                                 holder(), ACCESSOR_SETTER,
                                 ExceptionContext::kAttributeSet);
  f(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), callback_info);
  // Historically, in case of v8::AccessorNameSetterCallback it wasn't allowed
  // to set the result and not setting the result was treated as successful
  // execution.
  // During interceptors Api refactoring it was temporarily allowed to call
  // v8::ReturnValue<void>::Set[NonEmpty](Local<S>) and the result was just
  // converted to v8::Boolean which was then treated as a result of [[Set]].
  // In case of AccessorNameBooleanSetterCallback, the result is always
  // set to v8::Boolean or an exception is be thrown (in which case the
  // result is ignored anyway). So, regardless of whether the signature was
  // v8::AccessorNameSetterCallback or AccessorNameBooleanSetterCallback
  // the result is guaranteed to be v8::Boolean value indicating success or
  // failure.
  DirectHandle<Boolean> result = GetReturnValue<Boolean>();
  return IsTrue(*result);
}

#undef PREPARE_CALLBACK_INFO_ACCESSOR
#undef PREPARE_CALLBACK_INFO_INTERCEPTOR

}  // namespace internal
}  // namespace v8

#endif  // V8_API_API_ARGUMENTS_INL_H_