1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef INCLUDE_V8_FUNCTION_CALLBACK_H_
6#define INCLUDE_V8_FUNCTION_CALLBACK_H_
7
8#include "v8-local-handle.h"  // NOLINT(build/include_directory)
9#include "v8-primitive.h"     // NOLINT(build/include_directory)
10#include "v8config.h"         // NOLINT(build/include_directory)
11
12namespace v8 {
13
14template <typename T>
15class BasicTracedReference;
16template <typename T>
17class Global;
18class Object;
19class Value;
20
21namespace internal {
22class FunctionCallbackArguments;
23class PropertyCallbackArguments;
24}  // namespace internal
25
26namespace debug {
27class ConsoleCallArguments;
28}  // namespace debug
29
30template <typename T>
31class ReturnValue {
32 public:
33  template <class S>
34  V8_INLINE ReturnValue(const ReturnValue<S>& that) : value_(that.value_) {
35    static_assert(std::is_base_of<T, S>::value, "type check");
36  }
37  // Local setters
38  template <typename S>
39  V8_INLINE void Set(const Global<S>& handle);
40  template <typename S>
41  V8_INLINE void Set(const BasicTracedReference<S>& handle);
42  template <typename S>
43  V8_INLINE void Set(const Local<S> handle);
44  // Fast primitive setters
45  V8_INLINE void Set(bool value);
46  V8_INLINE void Set(double i);
47  V8_INLINE void Set(int32_t i);
48  V8_INLINE void Set(uint32_t i);
49  // Fast JS primitive setters
50  V8_INLINE void SetNull();
51  V8_INLINE void SetUndefined();
52  V8_INLINE void SetEmptyString();
53  // Convenience getter for Isolate
54  V8_INLINE Isolate* GetIsolate() const;
55
56  // Pointer setter: Uncompilable to prevent inadvertent misuse.
57  template <typename S>
58  V8_INLINE void Set(S* whatever);
59
60  // Getter. Creates a new Local<> so it comes with a certain performance
61  // hit. If the ReturnValue was not yet set, this will return the undefined
62  // value.
63  V8_INLINE Local<Value> Get() const;
64
65 private:
66  template <class F>
67  friend class ReturnValue;
68  template <class F>
69  friend class FunctionCallbackInfo;
70  template <class F>
71  friend class PropertyCallbackInfo;
72  template <class F, class G, class H>
73  friend class PersistentValueMapBase;
74  V8_INLINE void SetInternal(internal::Address value) { *value_ = value; }
75  V8_INLINE internal::Address GetDefaultValue();
76  V8_INLINE explicit ReturnValue(internal::Address* slot);
77  internal::Address* value_;
78};
79
80/**
81 * The argument information given to function call callbacks.  This
82 * class provides access to information about the context of the call,
83 * including the receiver, the number and values of arguments, and
84 * the holder of the function.
85 */
86template <typename T>
87class FunctionCallbackInfo {
88 public:
89  /** The number of available arguments. */
90  V8_INLINE int Length() const;
91  /**
92   * Accessor for the available arguments. Returns `undefined` if the index
93   * is out of bounds.
94   */
95  V8_INLINE Local<Value> operator[](int i) const;
96  /** Returns the receiver. This corresponds to the "this" value. */
97  V8_INLINE Local<Object> This() const;
98  /**
99   * If the callback was created without a Signature, this is the same
100   * value as This(). If there is a signature, and the signature didn't match
101   * This() but one of its hidden prototypes, this will be the respective
102   * hidden prototype.
103   *
104   * Note that this is not the prototype of This() on which the accessor
105   * referencing this callback was found (which in V8 internally is often
106   * referred to as holder [sic]).
107   */
108  V8_INLINE Local<Object> Holder() const;
109  /** For construct calls, this returns the "new.target" value. */
110  V8_INLINE Local<Value> NewTarget() const;
111  /** Indicates whether this is a regular call or a construct call. */
112  V8_INLINE bool IsConstructCall() const;
113  /** The data argument specified when creating the callback. */
114  V8_INLINE Local<Value> Data() const;
115  /** The current Isolate. */
116  V8_INLINE Isolate* GetIsolate() const;
117  /** The ReturnValue for the call. */
118  V8_INLINE ReturnValue<T> GetReturnValue() const;
119  // This shouldn't be public, but the arm compiler needs it.
120  static const int kArgsLength = 6;
121
122 protected:
123  friend class internal::FunctionCallbackArguments;
124  friend class internal::CustomArguments<FunctionCallbackInfo>;
125  friend class debug::ConsoleCallArguments;
126  static const int kHolderIndex = 0;
127  static const int kIsolateIndex = 1;
128  static const int kReturnValueDefaultValueIndex = 2;
129  static const int kReturnValueIndex = 3;
130  static const int kDataIndex = 4;
131  static const int kNewTargetIndex = 5;
132
133  V8_INLINE FunctionCallbackInfo(internal::Address* implicit_args,
134                                 internal::Address* values, int length);
135  internal::Address* implicit_args_;
136  internal::Address* values_;
137  int length_;
138};
139
140/**
141 * The information passed to a property callback about the context
142 * of the property access.
143 */
144template <typename T>
145class PropertyCallbackInfo {
146 public:
147  /**
148   * \return The isolate of the property access.
149   */
150  V8_INLINE Isolate* GetIsolate() const;
151
152  /**
153   * \return The data set in the configuration, i.e., in
154   * `NamedPropertyHandlerConfiguration` or
155   * `IndexedPropertyHandlerConfiguration.`
156   */
157  V8_INLINE Local<Value> Data() const;
158
159  /**
160   * \return The receiver. In many cases, this is the object on which the
161   * property access was intercepted. When using
162   * `Reflect.get`, `Function.prototype.call`, or similar functions, it is the
163   * object passed in as receiver or thisArg.
164   *
165   * \code
166   *  void GetterCallback(Local<Name> name,
167   *                      const v8::PropertyCallbackInfo<v8::Value>& info) {
168   *     auto context = info.GetIsolate()->GetCurrentContext();
169   *
170   *     v8::Local<v8::Value> a_this =
171   *         info.This()
172   *             ->GetRealNamedProperty(context, v8_str("a"))
173   *             .ToLocalChecked();
174   *     v8::Local<v8::Value> a_holder =
175   *         info.Holder()
176   *             ->GetRealNamedProperty(context, v8_str("a"))
177   *             .ToLocalChecked();
178   *
179   *    CHECK(v8_str("r")->Equals(context, a_this).FromJust());
180   *    CHECK(v8_str("obj")->Equals(context, a_holder).FromJust());
181   *
182   *    info.GetReturnValue().Set(name);
183   *  }
184   *
185   *  v8::Local<v8::FunctionTemplate> templ =
186   *  v8::FunctionTemplate::New(isolate);
187   *  templ->InstanceTemplate()->SetHandler(
188   *      v8::NamedPropertyHandlerConfiguration(GetterCallback));
189   *  LocalContext env;
190   *  env->Global()
191   *      ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
192   *                                           .ToLocalChecked()
193   *                                           ->NewInstance(env.local())
194   *                                           .ToLocalChecked())
195   *      .FromJust();
196   *
197   *  CompileRun("obj.a = 'obj'; var r = {a: 'r'}; Reflect.get(obj, 'x', r)");
198   * \endcode
199   */
200  V8_INLINE Local<Object> This() const;
201
202  /**
203   * \return The object in the prototype chain of the receiver that has the
204   * interceptor. Suppose you have `x` and its prototype is `y`, and `y`
205   * has an interceptor. Then `info.This()` is `x` and `info.Holder()` is `y`.
206   * The Holder() could be a hidden object (the global object, rather
207   * than the global proxy).
208   *
209   * \note For security reasons, do not pass the object back into the runtime.
210   */
211  V8_INLINE Local<Object> Holder() const;
212
213  /**
214   * \return The return value of the callback.
215   * Can be changed by calling Set().
216   * \code
217   * info.GetReturnValue().Set(...)
218   * \endcode
219   *
220   */
221  V8_INLINE ReturnValue<T> GetReturnValue() const;
222
223  /**
224   * \return True if the intercepted function should throw if an error occurs.
225   * Usually, `true` corresponds to `'use strict'`.
226   *
227   * \note Always `false` when intercepting `Reflect.set()`
228   * independent of the language mode.
229   */
230  V8_INLINE bool ShouldThrowOnError() const;
231
232  // This shouldn't be public, but the arm compiler needs it.
233  static const int kArgsLength = 7;
234
235 protected:
236  friend class MacroAssembler;
237  friend class internal::PropertyCallbackArguments;
238  friend class internal::CustomArguments<PropertyCallbackInfo>;
239  static const int kShouldThrowOnErrorIndex = 0;
240  static const int kHolderIndex = 1;
241  static const int kIsolateIndex = 2;
242  static const int kReturnValueDefaultValueIndex = 3;
243  static const int kReturnValueIndex = 4;
244  static const int kDataIndex = 5;
245  static const int kThisIndex = 6;
246
247  V8_INLINE PropertyCallbackInfo(internal::Address* args) : args_(args) {}
248  internal::Address* args_;
249};
250
251using FunctionCallback = void (*)(const FunctionCallbackInfo<Value>& info);
252
253// --- Implementation ---
254
255template <typename T>
256ReturnValue<T>::ReturnValue(internal::Address* slot) : value_(slot) {}
257
258template <typename T>
259template <typename S>
260void ReturnValue<T>::Set(const Global<S>& handle) {
261  static_assert(std::is_base_of<T, S>::value, "type check");
262  if (V8_UNLIKELY(handle.IsEmpty())) {
263    *value_ = GetDefaultValue();
264  } else {
265    *value_ = *reinterpret_cast<internal::Address*>(*handle);
266  }
267}
268
269template <typename T>
270template <typename S>
271void ReturnValue<T>::Set(const BasicTracedReference<S>& handle) {
272  static_assert(std::is_base_of<T, S>::value, "type check");
273  if (V8_UNLIKELY(handle.IsEmpty())) {
274    *value_ = GetDefaultValue();
275  } else {
276    *value_ = *reinterpret_cast<internal::Address*>(handle.val_);
277  }
278}
279
280template <typename T>
281template <typename S>
282void ReturnValue<T>::Set(const Local<S> handle) {
283  static_assert(std::is_void<T>::value || std::is_base_of<T, S>::value,
284                "type check");
285  if (V8_UNLIKELY(handle.IsEmpty())) {
286    *value_ = GetDefaultValue();
287  } else {
288    *value_ = *reinterpret_cast<internal::Address*>(*handle);
289  }
290}
291
292template <typename T>
293void ReturnValue<T>::Set(double i) {
294  static_assert(std::is_base_of<T, Number>::value, "type check");
295  Set(Number::New(GetIsolate(), i));
296}
297
298template <typename T>
299void ReturnValue<T>::Set(int32_t i) {
300  static_assert(std::is_base_of<T, Integer>::value, "type check");
301  using I = internal::Internals;
302  if (V8_LIKELY(I::IsValidSmi(i))) {
303    *value_ = I::IntToSmi(i);
304    return;
305  }
306  Set(Integer::New(GetIsolate(), i));
307}
308
309template <typename T>
310void ReturnValue<T>::Set(uint32_t i) {
311  static_assert(std::is_base_of<T, Integer>::value, "type check");
312  // Can't simply use INT32_MAX here for whatever reason.
313  bool fits_into_int32_t = (i & (1U << 31)) == 0;
314  if (V8_LIKELY(fits_into_int32_t)) {
315    Set(static_cast<int32_t>(i));
316    return;
317  }
318  Set(Integer::NewFromUnsigned(GetIsolate(), i));
319}
320
321template <typename T>
322void ReturnValue<T>::Set(bool value) {
323  static_assert(std::is_base_of<T, Boolean>::value, "type check");
324  using I = internal::Internals;
325  int root_index;
326  if (value) {
327    root_index = I::kTrueValueRootIndex;
328  } else {
329    root_index = I::kFalseValueRootIndex;
330  }
331  *value_ = *I::GetRoot(GetIsolate(), root_index);
332}
333
334template <typename T>
335void ReturnValue<T>::SetNull() {
336  static_assert(std::is_base_of<T, Primitive>::value, "type check");
337  using I = internal::Internals;
338  *value_ = *I::GetRoot(GetIsolate(), I::kNullValueRootIndex);
339}
340
341template <typename T>
342void ReturnValue<T>::SetUndefined() {
343  static_assert(std::is_base_of<T, Primitive>::value, "type check");
344  using I = internal::Internals;
345  *value_ = *I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex);
346}
347
348template <typename T>
349void ReturnValue<T>::SetEmptyString() {
350  static_assert(std::is_base_of<T, String>::value, "type check");
351  using I = internal::Internals;
352  *value_ = *I::GetRoot(GetIsolate(), I::kEmptyStringRootIndex);
353}
354
355template <typename T>
356Isolate* ReturnValue<T>::GetIsolate() const {
357  // Isolate is always the pointer below the default value on the stack.
358  return *reinterpret_cast<Isolate**>(&value_[-2]);
359}
360
361template <typename T>
362Local<Value> ReturnValue<T>::Get() const {
363  using I = internal::Internals;
364  if (*value_ == *I::GetRoot(GetIsolate(), I::kTheHoleValueRootIndex))
365    return Local<Value>(*Undefined(GetIsolate()));
366  return Local<Value>::New(GetIsolate(), reinterpret_cast<Value*>(value_));
367}
368
369template <typename T>
370template <typename S>
371void ReturnValue<T>::Set(S* whatever) {
372  static_assert(sizeof(S) < 0, "incompilable to prevent inadvertent misuse");
373}
374
375template <typename T>
376internal::Address ReturnValue<T>::GetDefaultValue() {
377  // Default value is always the pointer below value_ on the stack.
378  return value_[-1];
379}
380
381template <typename T>
382FunctionCallbackInfo<T>::FunctionCallbackInfo(internal::Address* implicit_args,
383                                              internal::Address* values,
384                                              int length)
385    : implicit_args_(implicit_args), values_(values), length_(length) {}
386
387template <typename T>
388Local<Value> FunctionCallbackInfo<T>::operator[](int i) const {
389  // values_ points to the first argument (not the receiver).
390  if (i < 0 || length_ <= i) return Local<Value>(*Undefined(GetIsolate()));
391  return Local<Value>(reinterpret_cast<Value*>(values_ + i));
392}
393
394template <typename T>
395Local<Object> FunctionCallbackInfo<T>::This() const {
396  // values_ points to the first argument (not the receiver).
397  return Local<Object>(reinterpret_cast<Object*>(values_ - 1));
398}
399
400template <typename T>
401Local<Object> FunctionCallbackInfo<T>::Holder() const {
402  return Local<Object>(
403      reinterpret_cast<Object*>(&implicit_args_[kHolderIndex]));
404}
405
406template <typename T>
407Local<Value> FunctionCallbackInfo<T>::NewTarget() const {
408  return Local<Value>(
409      reinterpret_cast<Value*>(&implicit_args_[kNewTargetIndex]));
410}
411
412template <typename T>
413Local<Value> FunctionCallbackInfo<T>::Data() const {
414  return Local<Value>(reinterpret_cast<Value*>(&implicit_args_[kDataIndex]));
415}
416
417template <typename T>
418Isolate* FunctionCallbackInfo<T>::GetIsolate() const {
419  return *reinterpret_cast<Isolate**>(&implicit_args_[kIsolateIndex]);
420}
421
422template <typename T>
423ReturnValue<T> FunctionCallbackInfo<T>::GetReturnValue() const {
424  return ReturnValue<T>(&implicit_args_[kReturnValueIndex]);
425}
426
427template <typename T>
428bool FunctionCallbackInfo<T>::IsConstructCall() const {
429  return !NewTarget()->IsUndefined();
430}
431
432template <typename T>
433int FunctionCallbackInfo<T>::Length() const {
434  return length_;
435}
436
437template <typename T>
438Isolate* PropertyCallbackInfo<T>::GetIsolate() const {
439  return *reinterpret_cast<Isolate**>(&args_[kIsolateIndex]);
440}
441
442template <typename T>
443Local<Value> PropertyCallbackInfo<T>::Data() const {
444  return Local<Value>(reinterpret_cast<Value*>(&args_[kDataIndex]));
445}
446
447template <typename T>
448Local<Object> PropertyCallbackInfo<T>::This() const {
449  return Local<Object>(reinterpret_cast<Object*>(&args_[kThisIndex]));
450}
451
452template <typename T>
453Local<Object> PropertyCallbackInfo<T>::Holder() const {
454  return Local<Object>(reinterpret_cast<Object*>(&args_[kHolderIndex]));
455}
456
457template <typename T>
458ReturnValue<T> PropertyCallbackInfo<T>::GetReturnValue() const {
459  return ReturnValue<T>(&args_[kReturnValueIndex]);
460}
461
462template <typename T>
463bool PropertyCallbackInfo<T>::ShouldThrowOnError() const {
464  using I = internal::Internals;
465  if (args_[kShouldThrowOnErrorIndex] !=
466      I::IntToSmi(I::kInferShouldThrowMode)) {
467    return args_[kShouldThrowOnErrorIndex] != I::IntToSmi(I::kDontThrow);
468  }
469  return v8::internal::ShouldThrowOnError(
470      reinterpret_cast<v8::internal::Isolate*>(GetIsolate()));
471}
472
473}  // namespace v8
474
475#endif  // INCLUDE_V8_FUNCTION_CALLBACK_H_
476