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