// Copyright 2014 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef GIN_FUNCTION_TEMPLATE_H_ #define GIN_FUNCTION_TEMPLATE_H_ #include <stddef.h> #include <type_traits> #include <utility> #include "base/check.h" #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "base/observer_list.h" #include "base/strings/strcat.h" #include "gin/arguments.h" #include "gin/converter.h" #include "gin/gin_export.h" #include "gin/per_isolate_data.h" #include "v8/include/v8-external.h" #include "v8/include/v8-forward.h" #include "v8/include/v8-persistent-handle.h" #include "v8/include/v8-template.h" namespace gin { struct InvokerOptions { … }; namespace internal { template<typename T> struct CallbackParamTraits { … }; CallbackParamTraits<const T &>; CallbackParamTraits<const T *>; // CallbackHolder and CallbackHolderBase are used to pass a // base::RepeatingCallback from CreateFunctionTemplate through v8 (via // v8::FunctionTemplate) to DispatchToCallback, where it is invoked. // CallbackHolder will clean up the callback in two different scenarios: // - If the garbage collector finds that it's garbage and collects it. (But note // that even _if_ we become garbage, we might never get collected!) // - If the isolate gets disposed. // // TODO(crbug.com/40210365): When gin::Wrappable gets migrated over to using // cppgc, this class should also be considered for migration. // This simple base class is used so that we can share a single object template // among every CallbackHolder instance. class GIN_EXPORT CallbackHolderBase { … }; template<typename Sig> class CallbackHolder : public CallbackHolderBase { … }; template <typename T> bool GetNextArgument(Arguments* args, const InvokerOptions& invoker_options, bool is_first, T* result) { … } // For advanced use cases, we allow callers to request the unparsed Arguments // object and poke around in it directly. inline bool GetNextArgument(Arguments* args, const InvokerOptions& invoker_options, bool is_first, Arguments* result) { … } inline bool GetNextArgument(Arguments* args, const InvokerOptions& invoker_options, bool is_first, Arguments** result) { … } // It's common for clients to just need the isolate, so we make that easy. inline bool GetNextArgument(Arguments* args, const InvokerOptions& invoker_options, bool is_first, v8::Isolate** result) { … } // Throws an error indicating conversion failure. GIN_EXPORT void ThrowConversionError(Arguments* args, const InvokerOptions& invoker_options, size_t index); // Class template for extracting and storing single argument for callback // at position |index|. template <size_t index, typename ArgType, typename = void> struct ArgumentHolder { … }; // This is required for types such as v8::LocalVector<T>, which don't have // a default constructor. To create an element of such a type, the isolate // has to be provided. ArgumentHolder<index, ArgType, std::enable_if_t<!std::is_default_constructible_v<typename CallbackParamTraits<ArgType>::LocalType> && std::is_constructible_v<typename CallbackParamTraits<ArgType>::LocalType, v8::Isolate *>>>; // Class template for converting arguments from JavaScript to C++ and running // the callback with them. template <typename IndicesType, typename... ArgTypes> class Invoker; Invoker<std::index_sequence<indices...>, ArgTypes...>; // DispatchToCallback converts all the JavaScript arguments to C++ types and // invokes the base::RepeatingCallback. template <typename Sig> struct Dispatcher { … }; Dispatcher<ReturnType (ArgTypes...)>; } // namespace internal // CreateFunctionTemplate creates a v8::FunctionTemplate that will create // JavaScript functions that execute a provided C++ function or // base::RepeatingCallback. JavaScript arguments are automatically converted via // gin::Converter, as is the return value of the C++ function, if any. // |invoker_options| contains additional parameters. If it contains a // holder_type, it will be used to provide a useful conversion error if the // holder is the first argument. If not provided, a generic invocation error // will be used. // // NOTE: V8 caches FunctionTemplates for a lifetime of a web page for its own // internal reasons, thus it is generally a good idea to cache the template // returned by this function. Otherwise, repeated method invocations from JS // will create substantial memory leaks. See http://crbug.com/463487. // // The callback will be destroyed if either the function template gets garbage // collected or _after_ the isolate is disposed. Garbage collection can never be // relied upon. As such, any destructors for objects bound to the callback must // not depend on the isolate being alive at the point they are called. The order // in which callbacks are destroyed is not guaranteed. template <typename Sig> v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( v8::Isolate* isolate, base::RepeatingCallback<Sig> callback, InvokerOptions invoker_options = { … } // CreateDataPropertyCallback creates a v8::AccessorNameGetterCallback and // corresponding data value that will hold and execute the provided // base::RepeatingCallback, using automatic conversions similar to // |CreateFunctionTemplate|. // // It is expected that these will be passed to v8::Template::SetLazyDataProperty // or another similar function. template <typename Sig> std::pair<v8::AccessorNameGetterCallback, v8::Local<v8::Value>> CreateDataPropertyCallback(v8::Isolate* isolate, base::RepeatingCallback<Sig> callback, InvokerOptions invoker_options = { … } } // namespace gin #endif // GIN_FUNCTION_TEMPLATE_H_