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