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