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