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 
12 namespace v8 {
13 
14 template <typename T>
15 class BasicTracedReference;
16 template <typename T>
17 class Global;
18 class Object;
19 class Value;
20 
21 namespace internal {
22 class FunctionCallbackArguments;
23 class PropertyCallbackArguments;
24 class Builtins;
25 }  // namespace internal
26 
27 namespace debug {
28 class ConsoleCallArguments;
29 }  // namespace debug
30 
31 template <typename T>
32 class ReturnValue {
33  public:
34   template <class S>
ReturnValue(const ReturnValue<S>& that)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;
SetInternal(internal::Address value)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  */
91 template <typename T>
92 class 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  */
164 template <typename T>
165 class 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 
PropertyCallbackInfo(internal::Address* args)267   V8_INLINE explicit PropertyCallbackInfo(internal::Address* args)
268       : args_(args) {}
269 
270   internal::Address* args_;
271 };
272 
273 using FunctionCallback = void (*)(const FunctionCallbackInfo<Value>& info);
274 
275 // --- Implementation ---
276 
277 template <typename T>
ReturnValue(internal::Address* slot)278 ReturnValue<T>::ReturnValue(internal::Address* slot) : value_(slot) {}
279 
280 template <typename T>
281 template <typename S>
Set(const Global<S>& handle)282 void 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 
291 template <typename T>
292 template <typename S>
Set(const BasicTracedReference<S>& handle)293 void 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 
302 template <typename T>
303 template <typename S>
Set(const Local<S> handle)304 void 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 
314 template <typename T>
Set(double i)315 void 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 
320 template <typename T>
Set(int32_t i)321 void 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 
331 template <typename T>
Set(uint32_t i)332 void 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 
343 template <typename T>
Set(bool value)344 void 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 
356 template <typename T>
SetNull()357 void 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 
363 template <typename T>
SetUndefined()364 void 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 
370 template <typename T>
SetEmptyString()371 void 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 
377 template <typename T>
GetIsolate() const378 Isolate* ReturnValue<T>::GetIsolate() const {
379   return *reinterpret_cast<Isolate**>(&value_[kIsolateValueIndex]);
380 }
381 
382 template <typename T>
Get() const383 Local<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 
395 template <typename T>
396 template <typename S>
397 void ReturnValue<T>::Set(S* whatever) {
398   static_assert(sizeof(S) < 0, "incompilable to prevent inadvertent misuse");
399 }
400 
401 template <typename T>
402 internal::Address ReturnValue<T>::GetDefaultValue() {
403   using I = internal::Internals;
404   return I::GetRoot(GetIsolate(), I::kTheHoleValueRootIndex);
405 }
406 
407 template <typename T>
408 FunctionCallbackInfo<T>::FunctionCallbackInfo(internal::Address* implicit_args,
409                                               internal::Address* values,
410                                               int length)
411     : implicit_args_(implicit_args), values_(values), length_(length) {}
412 
413 template <typename T>
414 Local<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 
420 template <typename T>
421 Local<Object> FunctionCallbackInfo<T>::This() const {
422   // values_ points to the first argument (not the receiver).
423   return Local<Object>::FromSlot(values_ + kThisValuesIndex);
424 }
425 
426 template <typename T>
427 Local<Object> FunctionCallbackInfo<T>::Holder() const {
428   return Local<Object>::FromSlot(&implicit_args_[kHolderIndex]);
429 }
430 
431 template <typename T>
432 Local<Value> FunctionCallbackInfo<T>::NewTarget() const {
433   return Local<Value>::FromSlot(&implicit_args_[kNewTargetIndex]);
434 }
435 
436 template <typename T>
437 Local<Value> FunctionCallbackInfo<T>::Data() const {
438   return Local<Value>::FromSlot(&implicit_args_[kDataIndex]);
439 }
440 
441 template <typename T>
442 Isolate* FunctionCallbackInfo<T>::GetIsolate() const {
443   return *reinterpret_cast<Isolate**>(&implicit_args_[kIsolateIndex]);
444 }
445 
446 template <typename T>
447 ReturnValue<T> FunctionCallbackInfo<T>::GetReturnValue() const {
448   return ReturnValue<T>(&implicit_args_[kReturnValueIndex]);
449 }
450 
451 template <typename T>
452 bool FunctionCallbackInfo<T>::IsConstructCall() const {
453   return !NewTarget()->IsUndefined();
454 }
455 
456 template <typename T>
457 int FunctionCallbackInfo<T>::Length() const {
458   return length_;
459 }
460 
461 template <typename T>
462 Isolate* PropertyCallbackInfo<T>::GetIsolate() const {
463   return *reinterpret_cast<Isolate**>(&args_[kIsolateIndex]);
464 }
465 
466 template <typename T>
467 Local<Value> PropertyCallbackInfo<T>::Data() const {
468   return Local<Value>::FromSlot(&args_[kDataIndex]);
469 }
470 
471 template <typename T>
472 Local<Object> PropertyCallbackInfo<T>::This() const {
473   return Local<Object>::FromSlot(&args_[kThisIndex]);
474 }
475 
476 template <typename T>
477 Local<Object> PropertyCallbackInfo<T>::Holder() const {
478   return Local<Object>::FromSlot(&args_[kHolderIndex]);
479 }
480 
481 template <typename T>
482 ReturnValue<T> PropertyCallbackInfo<T>::GetReturnValue() const {
483   return ReturnValue<T>(&args_[kReturnValueIndex]);
484 }
485 
486 template <typename T>
487 bool 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