// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_V8_TEMPLATE_H_
#define INCLUDE_V8_TEMPLATE_H_
#include
#include
#include "v8-data.h" // NOLINT(build/include_directory)
#include "v8-function-callback.h" // NOLINT(build/include_directory)
#include "v8-local-handle.h" // NOLINT(build/include_directory)
#include "v8-memory-span.h" // NOLINT(build/include_directory)
#include "v8-object.h" // NOLINT(build/include_directory)
#include "v8config.h" // NOLINT(build/include_directory)
namespace v8 {
class CFunction;
class FunctionTemplate;
class ObjectTemplate;
class Signature;
// --- Templates ---
#define V8_INTRINSICS_LIST(F) \
F(ArrayProto_entries, array_entries_iterator) \
F(ArrayProto_forEach, array_for_each_iterator) \
F(ArrayProto_keys, array_keys_iterator) \
F(ArrayProto_values, array_values_iterator) \
F(ArrayPrototype, initial_array_prototype) \
F(AsyncIteratorPrototype, initial_async_iterator_prototype) \
F(ErrorPrototype, initial_error_prototype) \
F(IteratorPrototype, initial_iterator_prototype) \
F(MapIteratorPrototype, initial_map_iterator_prototype) \
F(ObjProto_valueOf, object_value_of_function) \
F(SetIteratorPrototype, initial_set_iterator_prototype)
enum Intrinsic {
#define V8_DECL_INTRINSIC(name, iname) k##name,
V8_INTRINSICS_LIST(V8_DECL_INTRINSIC)
#undef V8_DECL_INTRINSIC
};
/**
* The superclass of object and function templates.
*/
class V8_EXPORT Template : public Data {
public:
/**
* Adds a property to each instance created by this template.
*
* The property must be defined either as a primitive value, or a template.
*/
void Set(Local name, Local value,
PropertyAttribute attributes = None);
void SetPrivate(Local name, Local value,
PropertyAttribute attributes = None);
V8_INLINE void Set(Isolate* isolate, const char* name, Local value,
PropertyAttribute attributes = None);
void SetAccessorProperty(
Local name,
Local getter = Local(),
Local setter = Local(),
PropertyAttribute attribute = None);
/**
* Whenever the property with the given name is accessed on objects
* created from this Template the getter and setter callbacks
* are called instead of getting and setting the property directly
* on the JavaScript object.
*
* \param name The name of the property for which an accessor is added.
* \param getter The callback to invoke when getting the property.
* \param setter The callback to invoke when setting the property.
* \param data A piece of data that will be passed to the getter and setter
* callbacks whenever they are invoked.
* \param attribute The attributes of the property for which an accessor
* is added.
*/
V8_DEPRECATE_SOON("Use SetNativeDataProperty without AccessControl instead")
void SetNativeDataProperty(
Local name, AccessorGetterCallback getter,
AccessorSetterCallback setter, Local data,
PropertyAttribute attribute, AccessControl settings,
SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect,
SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect);
V8_DEPRECATE_SOON("Use SetNativeDataProperty without AccessControl instead")
void SetNativeDataProperty(
Local name, AccessorNameGetterCallback getter,
AccessorNameSetterCallback setter, Local data,
PropertyAttribute attribute, AccessControl settings,
SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect,
SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect);
V8_DEPRECATE_SOON("Use SetNativeDataProperty with Local instead")
void SetNativeDataProperty(
Local name, AccessorGetterCallback getter,
AccessorSetterCallback setter = nullptr,
Local data = Local(), PropertyAttribute attribute = None,
SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect,
SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect);
void SetNativeDataProperty(
Local name, AccessorNameGetterCallback getter,
AccessorNameSetterCallback setter = nullptr,
Local data = Local(), PropertyAttribute attribute = None,
SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect,
SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect);
/**
* Like SetNativeDataProperty, but V8 will replace the native data property
* with a real data property on first access.
*/
void SetLazyDataProperty(
Local name, AccessorNameGetterCallback getter,
Local data = Local(), PropertyAttribute attribute = None,
SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect,
SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect);
/**
* During template instantiation, sets the value with the intrinsic property
* from the correct context.
*/
void SetIntrinsicDataProperty(Local name, Intrinsic intrinsic,
PropertyAttribute attribute = None);
private:
Template();
friend class ObjectTemplate;
friend class FunctionTemplate;
};
/**
* Interceptor callbacks use this value to indicate whether the request was
* intercepted or not.
*/
enum class Intercepted : uint8_t { kNo = 0, kYes = 1 };
/**
* Interceptor for get requests on an object.
*
* If the interceptor handles the request (i.e. the property should not be
* looked up beyond the interceptor) it should
* - (optionally) use info.GetReturnValue().Set()` to set the return value
* (by default the result is set to v8::Undefined),
* - return `Intercepted::kYes`.
* If the interceptor does not handle the request it must return
* `Intercepted::kNo` and it must not produce side effects.
*
* \param property The name of the property for which the request was
* intercepted.
* \param info Information about the intercepted request, such as
* isolate, receiver, return value, or whether running in `'use strict'` mode.
* See `PropertyCallbackInfo`.
*
* \code
* Intercepted GetterCallback(
* Local name, const v8::PropertyCallbackInfo& info) {
* if (!IsKnownProperty(info.GetIsolate(), name)) return Intercepted::kNo;
* info.GetReturnValue().Set(v8_num(42));
* return Intercepted::kYes;
* }
*
* v8::Local templ =
* v8::FunctionTemplate::New(isolate);
* templ->InstanceTemplate()->SetHandler(
* v8::NamedPropertyHandlerConfiguration(GetterCallback));
* LocalContext env;
* env->Global()
* ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
* .ToLocalChecked()
* ->NewInstance(env.local())
* .ToLocalChecked())
* .FromJust();
* v8::Local result = CompileRun("obj.a = 17; obj.a");
* CHECK(v8_num(42)->Equals(env.local(), result).FromJust());
* \endcode
*
* See also `ObjectTemplate::SetHandler`.
*/
using NamedPropertyGetterCallback = Intercepted (*)(
Local property, const PropertyCallbackInfo& info);
// This variant will be deprecated soon.
//
// Use `info.GetReturnValue().Set()` to set the return value of the
// intercepted get request. If the property does not exist the callback should
// not set the result and must not produce side effects.
using GenericNamedPropertyGetterCallback =
void (*)(Local property, const PropertyCallbackInfo& info);
/**
* Interceptor for set requests on an object.
*
* If the interceptor handles the request (i.e. the property should not be
* looked up beyond the interceptor) it should return `Intercepted::kYes`.
* If the interceptor does not handle the request it must return
* `Intercepted::kNo` and it must not produce side effects.
*
* \param property The name of the property for which the request was
* intercepted.
* \param value The value which the property will have if the request
* is not intercepted.
* \param info Information about the intercepted request, such as
* isolate, receiver, return value, or whether running in `'use strict'` mode.
* See `PropertyCallbackInfo`.
*
* See also `ObjectTemplate::SetHandler.`
*/
using NamedPropertySetterCallback =
Intercepted (*)(Local property, Local value,
const PropertyCallbackInfo& info);
// This variant will be deprecated soon.
//
// Use `info.GetReturnValue()` to indicate whether the request was intercepted
// or not. If the setter successfully intercepts the request, i.e., if the
// request should not be further executed, call
// `info.GetReturnValue().Set(value)`. If the setter did not intercept the
// request, i.e., if the request should be handled as if no interceptor is
// present, do not not call `Set()` and do not produce side effects.
using GenericNamedPropertySetterCallback =
void (*)(Local property, Local value,
const PropertyCallbackInfo& info);
/**
* Intercepts all requests that query the attributes of the
* property, e.g., getOwnPropertyDescriptor(), propertyIsEnumerable(), and
* defineProperty().
*
* If the interceptor handles the request (i.e. the property should not be
* looked up beyond the interceptor) it should
* - use `info.GetReturnValue().Set()` to set to an Integer value encoding
* a `v8::PropertyAttribute` bits,
* - return `Intercepted::kYes`.
* If the interceptor does not handle the request it must return
* `Intercepted::kNo` and it must not produce side effects.
*
* \param property The name of the property for which the request was
* intercepted.
* \param info Information about the intercepted request, such as
* isolate, receiver, return value, or whether running in `'use strict'` mode.
* See `PropertyCallbackInfo`.
*
* \note Some functions query the property attributes internally, even though
* they do not return the attributes. For example, `hasOwnProperty()` can
* trigger this interceptor depending on the state of the object.
*
* See also `ObjectTemplate::SetHandler.`
*/
using NamedPropertyQueryCallback = Intercepted (*)(
Local property, const PropertyCallbackInfo& info);
// This variant will be deprecated soon.
//
// Use `info.GetReturnValue().Set(value)` to set the property attributes. The
// value is an integer encoding a `v8::PropertyAttribute`. If the property does
// not exist the callback should not set the result and must not produce side
// effects.
using GenericNamedPropertyQueryCallback =
void (*)(Local property, const PropertyCallbackInfo& info);
/**
* Interceptor for delete requests on an object.
*
* If the interceptor handles the request (i.e. the property should not be
* looked up beyond the interceptor) it should
* - use `info.GetReturnValue().Set()` to set to a Boolean value indicating
* whether the property deletion was successful or not,
* - return `Intercepted::kYes`.
* If the interceptor does not handle the request it must return
* `Intercepted::kNo` and it must not produce side effects.
*
* \param property The name of the property for which the request was
* intercepted.
* \param info Information about the intercepted request, such as
* isolate, receiver, return value, or whether running in `'use strict'` mode.
* See `PropertyCallbackInfo`.
*
* \note If you need to mimic the behavior of `delete`, i.e., throw in strict
* mode instead of returning false, use `info.ShouldThrowOnError()` to determine
* if you are in strict mode.
*
* See also `ObjectTemplate::SetHandler.`
*/
using NamedPropertyDeleterCallback = Intercepted (*)(
Local property, const PropertyCallbackInfo& info);
// This variant will be deprecated soon.
//
// Use `info.GetReturnValue()` to indicate whether the request was intercepted
// or not. If the deleter successfully intercepts the request, i.e., if the
// request should not be further executed, call
// `info.GetReturnValue().Set(value)` with a boolean `value`. The `value` is
// used as the return value of `delete`. If the deleter does not intercept the
// request then it should not set the result and must not produce side effects.
using GenericNamedPropertyDeleterCallback =
void (*)(Local property, const PropertyCallbackInfo& info);
/**
* Returns an array containing the names of the properties the named
* property getter intercepts.
*
* Note: The values in the array must be of type v8::Name.
*/
using NamedPropertyEnumeratorCallback =
void (*)(const PropertyCallbackInfo& info);
// This variant will be deprecated soon.
// This is just a renaming of the typedef.
using GenericNamedPropertyEnumeratorCallback = NamedPropertyEnumeratorCallback;
/**
* Interceptor for defineProperty requests on an object.
*
* If the interceptor handles the request (i.e. the property should not be
* looked up beyond the interceptor) it should return `Intercepted::kYes`.
* If the interceptor does not handle the request it must return
* `Intercepted::kNo` and it must not produce side effects.
*
* \param property The name of the property for which the request was
* intercepted.
* \param desc The property descriptor which is used to define the
* property if the request is not intercepted.
* \param info Information about the intercepted request, such as
* isolate, receiver, return value, or whether running in `'use strict'` mode.
* See `PropertyCallbackInfo`.
*
* See also `ObjectTemplate::SetHandler`.
*/
using NamedPropertyDefinerCallback =
Intercepted (*)(Local property, const PropertyDescriptor& desc,
const PropertyCallbackInfo& info);
// This variant will be deprecated soon.
//
// Use `info.GetReturnValue()` to indicate whether the request was intercepted
// or not. If the definer successfully intercepts the request, i.e., if the
// request should not be further executed, call
// `info.GetReturnValue().Set(value)`. If the definer did not intercept the
// request, i.e., if the request should be handled as if no interceptor is
// present, do not not call `Set()` and do not produce side effects.
using GenericNamedPropertyDefinerCallback =
void (*)(Local property, const PropertyDescriptor& desc,
const PropertyCallbackInfo& info);
/**
* Interceptor for getOwnPropertyDescriptor requests on an object.
*
* If the interceptor handles the request (i.e. the property should not be
* looked up beyond the interceptor) it should
* - use `info.GetReturnValue().Set()` to set the return value which must be
* object that can be converted to a PropertyDescriptor (for example,
* a value returned by `v8::Object::getOwnPropertyDescriptor`),
* - return `Intercepted::kYes`.
* If the interceptor does not handle the request it must return
* `Intercepted::kNo` and it must not produce side effects.
*
* \param property The name of the property for which the request was
* intercepted.
* \info Information about the intercepted request, such as
* isolate, receiver, return value, or whether running in `'use strict'` mode.
* See `PropertyCallbackInfo`.
*
* \note If GetOwnPropertyDescriptor is intercepted, it will
* always return true, i.e., indicate that the property was found.
*
* See also `ObjectTemplate::SetHandler`.
*/
using NamedPropertyDescriptorCallback = Intercepted (*)(
Local property, const PropertyCallbackInfo& info);
// This variant will be deprecated soon.
//
// Use `info.GetReturnValue().Set()` to set the return value of the
// intercepted request. The return value must be an object that
// can be converted to a PropertyDescriptor, e.g., a `v8::Value` returned from
// `v8::Object::getOwnPropertyDescriptor`.
using GenericNamedPropertyDescriptorCallback =
void (*)(Local property, const PropertyCallbackInfo& info);
// TODO(ishell): Rename IndexedPropertyXxxCallbackV2 back to
// IndexedPropertyXxxCallback once the old IndexedPropertyXxxCallback is
// removed.
/**
* See `v8::GenericNamedPropertyGetterCallback`.
*/
using IndexedPropertyGetterCallbackV2 =
Intercepted (*)(uint32_t index, const PropertyCallbackInfo& info);
// This variant will be deprecated soon.
using IndexedPropertyGetterCallback =
void (*)(uint32_t index, const PropertyCallbackInfo& info);
/**
* See `v8::GenericNamedPropertySetterCallback`.
*/
using IndexedPropertySetterCallbackV2 = Intercepted (*)(
uint32_t index, Local value, const PropertyCallbackInfo& info);
// This variant will be deprecated soon.
using IndexedPropertySetterCallback =
void (*)(uint32_t index, Local value,
const PropertyCallbackInfo& info);
/**
* See `v8::GenericNamedPropertyQueryCallback`.
*/
using IndexedPropertyQueryCallbackV2 =
Intercepted (*)(uint32_t index, const PropertyCallbackInfo& info);
// This variant will be deprecated soon.
using IndexedPropertyQueryCallback =
void (*)(uint32_t index, const PropertyCallbackInfo& info);
/**
* See `v8::GenericNamedPropertyDeleterCallback`.
*/
using IndexedPropertyDeleterCallbackV2 =
Intercepted (*)(uint32_t index, const PropertyCallbackInfo& info);
// This variant will be deprecated soon.
using IndexedPropertyDeleterCallback =
void (*)(uint32_t index, const PropertyCallbackInfo& info);
/**
* Returns an array containing the indices of the properties the indexed
* property getter intercepts.
*
* Note: The values in the array must be uint32_t.
*/
using IndexedPropertyEnumeratorCallback =
void (*)(const PropertyCallbackInfo& info);
/**
* See `v8::GenericNamedPropertyDefinerCallback`.
*/
using IndexedPropertyDefinerCallbackV2 =
Intercepted (*)(uint32_t index, const PropertyDescriptor& desc,
const PropertyCallbackInfo& info);
// This variant will be deprecated soon.
using IndexedPropertyDefinerCallback =
void (*)(uint32_t index, const PropertyDescriptor& desc,
const PropertyCallbackInfo& info);
/**
* See `v8::GenericNamedPropertyDescriptorCallback`.
*/
using IndexedPropertyDescriptorCallbackV2 =
Intercepted (*)(uint32_t index, const PropertyCallbackInfo& info);
// This variant will be deprecated soon.
using IndexedPropertyDescriptorCallback =
void (*)(uint32_t index, const PropertyCallbackInfo& info);
/**
* Returns true if the given context should be allowed to access the given
* object.
*/
using AccessCheckCallback = bool (*)(Local accessing_context,
Local