• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }  // namespace internal
25 
26 namespace debug {
27 class ConsoleCallArguments;
28 }  // namespace debug
29 
30 template <typename T>
31 class ReturnValue {
32  public:
33   template <class S>
ReturnValue(const ReturnValue<S> & that)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;
SetInternal(internal::Address value)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  */
86 template <typename T>
87 class 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  */
144 template <typename T>
145 class 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 
PropertyCallbackInfo(internal::Address * args)247   V8_INLINE PropertyCallbackInfo(internal::Address* args) : args_(args) {}
248   internal::Address* args_;
249 };
250 
251 using FunctionCallback = void (*)(const FunctionCallbackInfo<Value>& info);
252 
253 // --- Implementation ---
254 
255 template <typename T>
ReturnValue(internal::Address * slot)256 ReturnValue<T>::ReturnValue(internal::Address* slot) : value_(slot) {}
257 
258 template <typename T>
259 template <typename S>
Set(const Global<S> & handle)260 void 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 
269 template <typename T>
270 template <typename S>
Set(const BasicTracedReference<S> & handle)271 void 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 
280 template <typename T>
281 template <typename S>
Set(const Local<S> handle)282 void 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 
292 template <typename T>
Set(double i)293 void 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 
298 template <typename T>
Set(int32_t i)299 void 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 
309 template <typename T>
Set(uint32_t i)310 void 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 
321 template <typename T>
Set(bool value)322 void 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 
334 template <typename T>
SetNull()335 void 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 
341 template <typename T>
SetUndefined()342 void 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 
348 template <typename T>
SetEmptyString()349 void 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 
355 template <typename T>
GetIsolate()356 Isolate* 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 
361 template <typename T>
Get()362 Local<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 
369 template <typename T>
370 template <typename S>
Set(S * whatever)371 void ReturnValue<T>::Set(S* whatever) {
372   static_assert(sizeof(S) < 0, "incompilable to prevent inadvertent misuse");
373 }
374 
375 template <typename T>
GetDefaultValue()376 internal::Address ReturnValue<T>::GetDefaultValue() {
377   // Default value is always the pointer below value_ on the stack.
378   return value_[-1];
379 }
380 
381 template <typename T>
FunctionCallbackInfo(internal::Address * implicit_args,internal::Address * values,int length)382 FunctionCallbackInfo<T>::FunctionCallbackInfo(internal::Address* implicit_args,
383                                               internal::Address* values,
384                                               int length)
385     : implicit_args_(implicit_args), values_(values), length_(length) {}
386 
387 template <typename T>
388 Local<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 
394 template <typename T>
This()395 Local<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 
400 template <typename T>
Holder()401 Local<Object> FunctionCallbackInfo<T>::Holder() const {
402   return Local<Object>(
403       reinterpret_cast<Object*>(&implicit_args_[kHolderIndex]));
404 }
405 
406 template <typename T>
NewTarget()407 Local<Value> FunctionCallbackInfo<T>::NewTarget() const {
408   return Local<Value>(
409       reinterpret_cast<Value*>(&implicit_args_[kNewTargetIndex]));
410 }
411 
412 template <typename T>
Data()413 Local<Value> FunctionCallbackInfo<T>::Data() const {
414   return Local<Value>(reinterpret_cast<Value*>(&implicit_args_[kDataIndex]));
415 }
416 
417 template <typename T>
GetIsolate()418 Isolate* FunctionCallbackInfo<T>::GetIsolate() const {
419   return *reinterpret_cast<Isolate**>(&implicit_args_[kIsolateIndex]);
420 }
421 
422 template <typename T>
GetReturnValue()423 ReturnValue<T> FunctionCallbackInfo<T>::GetReturnValue() const {
424   return ReturnValue<T>(&implicit_args_[kReturnValueIndex]);
425 }
426 
427 template <typename T>
IsConstructCall()428 bool FunctionCallbackInfo<T>::IsConstructCall() const {
429   return !NewTarget()->IsUndefined();
430 }
431 
432 template <typename T>
Length()433 int FunctionCallbackInfo<T>::Length() const {
434   return length_;
435 }
436 
437 template <typename T>
GetIsolate()438 Isolate* PropertyCallbackInfo<T>::GetIsolate() const {
439   return *reinterpret_cast<Isolate**>(&args_[kIsolateIndex]);
440 }
441 
442 template <typename T>
Data()443 Local<Value> PropertyCallbackInfo<T>::Data() const {
444   return Local<Value>(reinterpret_cast<Value*>(&args_[kDataIndex]));
445 }
446 
447 template <typename T>
This()448 Local<Object> PropertyCallbackInfo<T>::This() const {
449   return Local<Object>(reinterpret_cast<Object*>(&args_[kThisIndex]));
450 }
451 
452 template <typename T>
Holder()453 Local<Object> PropertyCallbackInfo<T>::Holder() const {
454   return Local<Object>(reinterpret_cast<Object*>(&args_[kHolderIndex]));
455 }
456 
457 template <typename T>
GetReturnValue()458 ReturnValue<T> PropertyCallbackInfo<T>::GetReturnValue() const {
459   return ReturnValue<T>(&args_[kReturnValueIndex]);
460 }
461 
462 template <typename T>
ShouldThrowOnError()463 bool 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