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