// 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_ARGUMENTS_H_
#define V8_API_ARGUMENTS_H_

#include "src/api.h"
#include "src/debug/debug.h"
#include "src/isolate.h"
#include "src/objects/slots.h"
#include "src/visitors.h"

namespace v8 {
namespace internal {

// Custom arguments replicate a small segment of stack that can be
// accessed through an Arguments object the same way the actual stack
// can.
class CustomArgumentsBase : public Relocatable {
 protected:
  explicit inline CustomArgumentsBase(Isolate* isolate);
};

template <typename T>
class CustomArguments : public CustomArgumentsBase {
 public:
  static const int kReturnValueOffset = T::kReturnValueIndex;

  ~CustomArguments() override;

  inline void IterateInstance(RootVisitor* v) override {
    v->VisitRootPointers(Root::kRelocatable, nullptr, slot_at(0),
                         slot_at(T::kArgsLength));
  }

 protected:
  explicit inline CustomArguments(Isolate* isolate)
      : CustomArgumentsBase(isolate) {}

  template <typename V>
  Handle<V> GetReturnValue(Isolate* isolate);

  inline Isolate* isolate() {
    return reinterpret_cast<Isolate*>((*slot_at(T::kIsolateIndex)).ptr());
  }

  inline FullObjectSlot slot_at(int index) {
    // This allows index == T::kArgsLength so "one past the end" slots
    // can be retrieved for iterating purposes.
    DCHECK_LE(static_cast<unsigned>(index),
              static_cast<unsigned>(T::kArgsLength));
    return FullObjectSlot(values_ + index);
  }
  Address values_[T::kArgsLength];
};

// Note: Calling args.Call() sets the return value on args. For multiple
// Call()'s, a new args should be used every time.
class PropertyCallbackArguments
    : public CustomArguments<PropertyCallbackInfo<Value> > {
 public:
  typedef PropertyCallbackInfo<Value> T;
  typedef CustomArguments<T> Super;
  static const int kArgsLength = T::kArgsLength;
  static const int kThisIndex = T::kThisIndex;
  static const int kHolderIndex = T::kHolderIndex;
  static const int kDataIndex = T::kDataIndex;
  static const int kReturnValueDefaultValueIndex =
      T::kReturnValueDefaultValueIndex;
  static const int kIsolateIndex = T::kIsolateIndex;
  static const int kShouldThrowOnErrorIndex = T::kShouldThrowOnErrorIndex;

  PropertyCallbackArguments(Isolate* isolate, Object data, Object self,
                            JSObject holder, ShouldThrow should_throw);

  // -------------------------------------------------------------------------
  // Accessor Callbacks
  // Also used for AccessorSetterCallback.
  inline Handle<Object> CallAccessorSetter(Handle<AccessorInfo> info,
                                           Handle<Name> name,
                                           Handle<Object> value);
  // Also used for AccessorGetterCallback, AccessorNameGetterCallback.
  inline Handle<Object> CallAccessorGetter(Handle<AccessorInfo> info,
                                           Handle<Name> name);

  // -------------------------------------------------------------------------
  // Named Interceptor Callbacks
  inline Handle<Object> CallNamedQuery(Handle<InterceptorInfo> interceptor,
                                       Handle<Name> name);
  inline Handle<Object> CallNamedGetter(Handle<InterceptorInfo> interceptor,
                                        Handle<Name> name);
  inline Handle<Object> CallNamedSetter(Handle<InterceptorInfo> interceptor,
                                        Handle<Name> name,
                                        Handle<Object> value);
  inline Handle<Object> CallNamedDefiner(Handle<InterceptorInfo> interceptor,
                                         Handle<Name> name,
                                         const v8::PropertyDescriptor& desc);
  inline Handle<Object> CallNamedDeleter(Handle<InterceptorInfo> interceptor,
                                         Handle<Name> name);
  inline Handle<Object> CallNamedDescriptor(Handle<InterceptorInfo> interceptor,
                                            Handle<Name> name);
  inline Handle<JSObject> CallNamedEnumerator(
      Handle<InterceptorInfo> interceptor);

  // -------------------------------------------------------------------------
  // Indexed Interceptor Callbacks
  inline Handle<Object> CallIndexedQuery(Handle<InterceptorInfo> interceptor,
                                         uint32_t index);
  inline Handle<Object> CallIndexedGetter(Handle<InterceptorInfo> interceptor,
                                          uint32_t index);
  inline Handle<Object> CallIndexedSetter(Handle<InterceptorInfo> interceptor,
                                          uint32_t index, Handle<Object> value);
  inline Handle<Object> CallIndexedDefiner(Handle<InterceptorInfo> interceptor,
                                           uint32_t index,
                                           const v8::PropertyDescriptor& desc);
  inline Handle<Object> CallIndexedDeleter(Handle<InterceptorInfo> interceptor,
                                           uint32_t index);
  inline Handle<Object> CallIndexedDescriptor(
      Handle<InterceptorInfo> interceptor, uint32_t index);
  inline Handle<JSObject> CallIndexedEnumerator(
      Handle<InterceptorInfo> interceptor);

 private:
  /*
   * The following Call functions wrap the calling of all callbacks to handle
   * calling either the old or the new style callbacks depending on which one
   * has been registered.
   * For old callbacks which return an empty handle, the ReturnValue is checked
   * and used if it's been set to anything inside the callback.
   * New style callbacks always use the return value.
   */
  inline Handle<JSObject> CallPropertyEnumerator(
      Handle<InterceptorInfo> interceptor);

  inline Handle<Object> BasicCallIndexedGetterCallback(
      IndexedPropertyGetterCallback f, uint32_t index, Handle<Object> info);
  inline Handle<Object> BasicCallNamedGetterCallback(
      GenericNamedPropertyGetterCallback f, Handle<Name> name,
      Handle<Object> info, Handle<Object> receiver = Handle<Object>());

  inline JSObject holder();
  inline Object receiver();

  // Don't copy PropertyCallbackArguments, because they would both have the
  // same prev_ pointer.
  DISALLOW_COPY_AND_ASSIGN(PropertyCallbackArguments);
};

class FunctionCallbackArguments
    : public CustomArguments<FunctionCallbackInfo<Value> > {
 public:
  typedef FunctionCallbackInfo<Value> T;
  typedef CustomArguments<T> Super;
  static const int kArgsLength = T::kArgsLength;
  static const int kHolderIndex = T::kHolderIndex;
  static const int kDataIndex = T::kDataIndex;
  static const int kReturnValueDefaultValueIndex =
      T::kReturnValueDefaultValueIndex;
  static const int kIsolateIndex = T::kIsolateIndex;
  static const int kNewTargetIndex = T::kNewTargetIndex;

  FunctionCallbackArguments(internal::Isolate* isolate, internal::Object data,
                            internal::HeapObject callee,
                            internal::Object holder,
                            internal::HeapObject new_target,
                            internal::Address* argv, int argc);

  /*
   * The following Call function wraps the calling of all callbacks to handle
   * calling either the old or the new style callbacks depending on which one
   * has been registered.
   * For old callbacks which return an empty handle, the ReturnValue is checked
   * and used if it's been set to anything inside the callback.
   * New style callbacks always use the return value.
   */
  inline Handle<Object> Call(CallHandlerInfo handler);

 private:
  inline JSObject holder();

  internal::Address* argv_;
  int argc_;
};

}  // namespace internal
}  // namespace v8

#endif  // V8_API_ARGUMENTS_H_
