Avi Drissman | 468e51b6 | 2022-09-13 20:47:01 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
aa@chromium.org | 37dacfa | 2013-11-26 03:31:04 | [diff] [blame] | 4 | |
aa@chromium.org | b520e13 | 2013-11-29 03:21:48 | [diff] [blame] | 5 | #ifndef GIN_FUNCTION_TEMPLATE_H_ |
| 6 | #define GIN_FUNCTION_TEMPLATE_H_ |
| 7 | |
avi | 90e658dd | 2015-12-21 07:16:19 | [diff] [blame] | 8 | #include <stddef.h> |
Nikolaos Papaspyrou | 5ce2a2f | 2023-10-19 09:09:00 | [diff] [blame] | 9 | #include <type_traits> |
Jeremy Roman | 6a1242b | 2019-02-04 17:51:57 | [diff] [blame] | 10 | #include <utility> |
avi | 90e658dd | 2015-12-21 07:16:19 | [diff] [blame] | 11 | |
Hans Wennborg | c8b134b | 2020-06-19 21:15:39 | [diff] [blame] | 12 | #include "base/check.h" |
Avi Drissman | 93a273dd | 2023-01-11 00:38:27 | [diff] [blame] | 13 | #include "base/functional/callback.h" |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 14 | #include "base/memory/raw_ptr.h" |
Ashley Newson | deda181 | 2024-01-09 12:04:18 | [diff] [blame] | 15 | #include "base/observer_list.h" |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 16 | #include "base/strings/strcat.h" |
aa@chromium.org | 314cde1 | 2013-11-23 20:26:51 | [diff] [blame] | 17 | #include "gin/arguments.h" |
| 18 | #include "gin/converter.h" |
jochen@chromium.org | 48c2163 | 2013-12-12 21:32:34 | [diff] [blame] | 19 | #include "gin/gin_export.h" |
Ashley Newson | deda181 | 2024-01-09 12:04:18 | [diff] [blame] | 20 | #include "gin/per_isolate_data.h" |
Dan Elphick | 05acd60 | 2021-08-30 15:22:07 | [diff] [blame] | 21 | #include "v8/include/v8-external.h" |
| 22 | #include "v8/include/v8-forward.h" |
| 23 | #include "v8/include/v8-persistent-handle.h" |
| 24 | #include "v8/include/v8-template.h" |
aa@chromium.org | 314cde1 | 2013-11-23 20:26:51 | [diff] [blame] | 25 | |
| 26 | namespace gin { |
| 27 | |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 28 | struct InvokerOptions { |
| 29 | bool holder_is_first_argument = false; |
| 30 | const char* holder_type = nullptr; // Null if unknown or not applicable. |
aa@chromium.org | bf3dd3c | 2013-12-06 06:55:25 | [diff] [blame] | 31 | }; |
| 32 | |
aa@chromium.org | 37dacfa | 2013-11-26 03:31:04 | [diff] [blame] | 33 | namespace internal { |
| 34 | |
aa@chromium.org | 314cde1 | 2013-11-23 20:26:51 | [diff] [blame] | 35 | template<typename T> |
aa@chromium.org | bf3dd3c | 2013-12-06 06:55:25 | [diff] [blame] | 36 | struct CallbackParamTraits { |
| 37 | typedef T LocalType; |
aa@chromium.org | 314cde1 | 2013-11-23 20:26:51 | [diff] [blame] | 38 | }; |
| 39 | template<typename T> |
aa@chromium.org | bf3dd3c | 2013-12-06 06:55:25 | [diff] [blame] | 40 | struct CallbackParamTraits<const T&> { |
| 41 | typedef T LocalType; |
| 42 | }; |
| 43 | template<typename T> |
| 44 | struct CallbackParamTraits<const T*> { |
| 45 | typedef T* LocalType; |
aa@chromium.org | 314cde1 | 2013-11-23 20:26:51 | [diff] [blame] | 46 | }; |
| 47 | |
Colin Blundell | ea615d42 | 2021-05-12 09:35:41 | [diff] [blame] | 48 | // CallbackHolder and CallbackHolderBase are used to pass a |
| 49 | // base::RepeatingCallback from CreateFunctionTemplate through v8 (via |
| 50 | // v8::FunctionTemplate) to DispatchToCallback, where it is invoked. |
aa@chromium.org | 6fe5610 | 2013-12-08 07:10:58 | [diff] [blame] | 51 | |
Ashley Newson | deda181 | 2024-01-09 12:04:18 | [diff] [blame] | 52 | // CallbackHolder will clean up the callback in two different scenarios: |
| 53 | // - If the garbage collector finds that it's garbage and collects it. (But note |
| 54 | // that even _if_ we become garbage, we might never get collected!) |
| 55 | // - If the isolate gets disposed. |
| 56 | // |
| 57 | // TODO(crbug.com/1285119): When gin::Wrappable gets migrated over to using |
| 58 | // cppgc, this class should also be considered for migration. |
| 59 | |
aa@chromium.org | 6fe5610 | 2013-12-08 07:10:58 | [diff] [blame] | 60 | // This simple base class is used so that we can share a single object template |
| 61 | // among every CallbackHolder instance. |
jochen@chromium.org | bf014290 | 2014-02-11 15:06:12 | [diff] [blame] | 62 | class GIN_EXPORT CallbackHolderBase { |
jochen@chromium.org | b4acaf8 | 2013-12-12 09:40:50 | [diff] [blame] | 63 | public: |
Daniel Hosseinian | 68c0798d | 2021-04-16 08:16:07 | [diff] [blame] | 64 | CallbackHolderBase(const CallbackHolderBase&) = delete; |
| 65 | CallbackHolderBase& operator=(const CallbackHolderBase&) = delete; |
| 66 | |
deepak.s | faaa1b6 | 2015-04-30 07:30:48 | [diff] [blame] | 67 | v8::Local<v8::External> GetHandle(v8::Isolate* isolate); |
jochen@chromium.org | bf014290 | 2014-02-11 15:06:12 | [diff] [blame] | 68 | |
aa@chromium.org | 314cde1 | 2013-11-23 20:26:51 | [diff] [blame] | 69 | protected: |
jochen@chromium.org | bf014290 | 2014-02-11 15:06:12 | [diff] [blame] | 70 | explicit CallbackHolderBase(v8::Isolate* isolate); |
| 71 | virtual ~CallbackHolderBase(); |
| 72 | |
| 73 | private: |
Ashley Newson | deda181 | 2024-01-09 12:04:18 | [diff] [blame] | 74 | class DisposeObserver : gin::PerIsolateData::DisposeObserver { |
| 75 | public: |
| 76 | DisposeObserver(gin::PerIsolateData* per_isolate_data, |
| 77 | CallbackHolderBase* holder); |
| 78 | ~DisposeObserver() override; |
| 79 | void OnBeforeDispose(v8::Isolate* isolate) override; |
| 80 | void OnDisposed() override; |
| 81 | |
| 82 | private: |
| 83 | const raw_ref<gin::PerIsolateData> per_isolate_data_; |
| 84 | const raw_ref<CallbackHolderBase> holder_; |
| 85 | }; |
| 86 | |
dcarney | 99ade908 | 2015-04-22 09:55:42 | [diff] [blame] | 87 | static void FirstWeakCallback( |
| 88 | const v8::WeakCallbackInfo<CallbackHolderBase>& data); |
| 89 | static void SecondWeakCallback( |
| 90 | const v8::WeakCallbackInfo<CallbackHolderBase>& data); |
jochen@chromium.org | bf014290 | 2014-02-11 15:06:12 | [diff] [blame] | 91 | |
dcarney | 99ade908 | 2015-04-22 09:55:42 | [diff] [blame] | 92 | v8::Global<v8::External> v8_ref_; |
Ashley Newson | deda181 | 2024-01-09 12:04:18 | [diff] [blame] | 93 | DisposeObserver dispose_observer_; |
aa@chromium.org | 314cde1 | 2013-11-23 20:26:51 | [diff] [blame] | 94 | }; |
| 95 | |
aa@chromium.org | 314cde1 | 2013-11-23 20:26:51 | [diff] [blame] | 96 | template<typename Sig> |
| 97 | class CallbackHolder : public CallbackHolderBase { |
| 98 | public: |
jochen@chromium.org | bf014290 | 2014-02-11 15:06:12 | [diff] [blame] | 99 | CallbackHolder(v8::Isolate* isolate, |
tzik | c21a0dc | 2017-11-14 08:23:44 | [diff] [blame] | 100 | base::RepeatingCallback<Sig> callback, |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 101 | InvokerOptions invoker_options) |
tzik | c21a0dc | 2017-11-14 08:23:44 | [diff] [blame] | 102 | : CallbackHolderBase(isolate), |
| 103 | callback(std::move(callback)), |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 104 | invoker_options(std::move(invoker_options)) {} |
Daniel Hosseinian | 68c0798d | 2021-04-16 08:16:07 | [diff] [blame] | 105 | CallbackHolder(const CallbackHolder&) = delete; |
| 106 | CallbackHolder& operator=(const CallbackHolder&) = delete; |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 107 | |
tzik | c21a0dc | 2017-11-14 08:23:44 | [diff] [blame] | 108 | base::RepeatingCallback<Sig> callback; |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 109 | InvokerOptions invoker_options; |
| 110 | |
aa@chromium.org | 314cde1 | 2013-11-23 20:26:51 | [diff] [blame] | 111 | private: |
Daniel Hosseinian | 68c0798d | 2021-04-16 08:16:07 | [diff] [blame] | 112 | ~CallbackHolder() override = default; |
aa@chromium.org | 314cde1 | 2013-11-23 20:26:51 | [diff] [blame] | 113 | }; |
| 114 | |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 115 | template <typename T> |
| 116 | bool GetNextArgument(Arguments* args, |
| 117 | const InvokerOptions& invoker_options, |
| 118 | bool is_first, |
aa@chromium.org | bf3dd3c | 2013-12-06 06:55:25 | [diff] [blame] | 119 | T* result) { |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 120 | if (is_first && invoker_options.holder_is_first_argument) { |
aa@chromium.org | bf3dd3c | 2013-12-06 06:55:25 | [diff] [blame] | 121 | return args->GetHolder(result); |
| 122 | } else { |
| 123 | return args->GetNext(result); |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | // For advanced use cases, we allow callers to request the unparsed Arguments |
| 128 | // object and poke around in it directly. |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 129 | inline bool GetNextArgument(Arguments* args, |
| 130 | const InvokerOptions& invoker_options, |
| 131 | bool is_first, |
aa@chromium.org | bf3dd3c | 2013-12-06 06:55:25 | [diff] [blame] | 132 | Arguments* result) { |
| 133 | *result = *args; |
| 134 | return true; |
| 135 | } |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 136 | inline bool GetNextArgument(Arguments* args, |
| 137 | const InvokerOptions& invoker_options, |
| 138 | bool is_first, |
aa@chromium.org | 5b971af | 2014-01-06 22:20:54 | [diff] [blame] | 139 | Arguments** result) { |
| 140 | *result = args; |
| 141 | return true; |
| 142 | } |
aa@chromium.org | bf3dd3c | 2013-12-06 06:55:25 | [diff] [blame] | 143 | |
aa@chromium.org | 2491f14 | 2013-12-21 17:54:37 | [diff] [blame] | 144 | // It's common for clients to just need the isolate, so we make that easy. |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 145 | inline bool GetNextArgument(Arguments* args, |
| 146 | const InvokerOptions& invoker_options, |
| 147 | bool is_first, |
| 148 | v8::Isolate** result) { |
aa@chromium.org | 2491f14 | 2013-12-21 17:54:37 | [diff] [blame] | 149 | *result = args->isolate(); |
| 150 | return true; |
| 151 | } |
| 152 | |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 153 | // Throws an error indicating conversion failure. |
| 154 | GIN_EXPORT void ThrowConversionError(Arguments* args, |
| 155 | const InvokerOptions& invoker_options, |
| 156 | size_t index); |
| 157 | |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 158 | // Class template for extracting and storing single argument for callback |
| 159 | // at position |index|. |
Nikolaos Papaspyrou | 5ce2a2f | 2023-10-19 09:09:00 | [diff] [blame] | 160 | template <size_t index, typename ArgType, typename = void> |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 161 | struct ArgumentHolder { |
| 162 | using ArgLocalType = typename CallbackParamTraits<ArgType>::LocalType; |
| 163 | |
| 164 | ArgLocalType value; |
| 165 | bool ok; |
| 166 | |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 167 | ArgumentHolder(Arguments* args, const InvokerOptions& invoker_options) |
| 168 | : ok(GetNextArgument(args, invoker_options, index == 0, &value)) { |
| 169 | if (!ok) |
| 170 | ThrowConversionError(args, invoker_options, index); |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 171 | } |
| 172 | }; |
| 173 | |
Nikolaos Papaspyrou | 5ce2a2f | 2023-10-19 09:09:00 | [diff] [blame] | 174 | // This is required for types such as v8::LocalVector<T>, which don't have |
| 175 | // a default constructor. To create an element of such a type, the isolate |
| 176 | // has to be provided. |
| 177 | template <size_t index, typename ArgType> |
| 178 | struct ArgumentHolder< |
| 179 | index, |
| 180 | ArgType, |
| 181 | std::enable_if_t<!std::is_default_constructible_v< |
| 182 | typename CallbackParamTraits<ArgType>::LocalType> && |
| 183 | std::is_constructible_v< |
| 184 | typename CallbackParamTraits<ArgType>::LocalType, |
| 185 | v8::Isolate*>>> { |
| 186 | using ArgLocalType = typename CallbackParamTraits<ArgType>::LocalType; |
| 187 | |
| 188 | ArgLocalType value; |
| 189 | bool ok; |
| 190 | |
| 191 | ArgumentHolder(Arguments* args, const InvokerOptions& invoker_options) |
| 192 | : value(args->isolate()), |
| 193 | ok(GetNextArgument(args, invoker_options, index == 0, &value)) { |
| 194 | if (!ok) { |
| 195 | ThrowConversionError(args, invoker_options, index); |
| 196 | } |
| 197 | } |
| 198 | }; |
| 199 | |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 200 | // Class template for converting arguments from JavaScript to C++ and running |
| 201 | // the callback with them. |
| 202 | template <typename IndicesType, typename... ArgTypes> |
tzik | c21a0dc | 2017-11-14 08:23:44 | [diff] [blame] | 203 | class Invoker; |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 204 | |
| 205 | template <size_t... indices, typename... ArgTypes> |
tzik | c21a0dc | 2017-11-14 08:23:44 | [diff] [blame] | 206 | class Invoker<std::index_sequence<indices...>, ArgTypes...> |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 207 | : public ArgumentHolder<indices, ArgTypes>... { |
| 208 | public: |
| 209 | // Invoker<> inherits from ArgumentHolder<> for each argument. |
| 210 | // C++ has always been strict about the class initialization order, |
| 211 | // so it is guaranteed ArgumentHolders will be initialized (and thus, will |
| 212 | // extract arguments from Arguments) in the right order. |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 213 | Invoker(Arguments* args, const InvokerOptions& invoker_options) |
| 214 | : ArgumentHolder<indices, ArgTypes>(args, invoker_options)..., |
| 215 | args_(args) {} |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 216 | |
| 217 | bool IsOK() { |
| 218 | return And(ArgumentHolder<indices, ArgTypes>::ok...); |
| 219 | } |
| 220 | |
| 221 | template <typename ReturnType> |
tzik | c21a0dc | 2017-11-14 08:23:44 | [diff] [blame] | 222 | void DispatchToCallback( |
| 223 | base::RepeatingCallback<ReturnType(ArgTypes...)> callback) { |
Jeremy Apthorp | 789ac3b | 2020-04-01 01:06:45 | [diff] [blame] | 224 | args_->Return( |
| 225 | callback.Run(std::move(ArgumentHolder<indices, ArgTypes>::value)...)); |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 226 | } |
| 227 | |
| 228 | // In C++, you can declare the function foo(void), but you can't pass a void |
| 229 | // expression to foo. As a result, we must specialize the case of Callbacks |
| 230 | // that have the void return type. |
tzik | c21a0dc | 2017-11-14 08:23:44 | [diff] [blame] | 231 | void DispatchToCallback(base::RepeatingCallback<void(ArgTypes...)> callback) { |
Jeremy Apthorp | 789ac3b | 2020-04-01 01:06:45 | [diff] [blame] | 232 | callback.Run(std::move(ArgumentHolder<indices, ArgTypes>::value)...); |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 233 | } |
| 234 | |
| 235 | private: |
| 236 | static bool And() { return true; } |
| 237 | template <typename... T> |
| 238 | static bool And(bool arg1, T... args) { |
| 239 | return arg1 && And(args...); |
| 240 | } |
| 241 | |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 242 | raw_ptr<Arguments> args_; |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 243 | }; |
aa@chromium.org | bf3dd3c | 2013-12-06 06:55:25 | [diff] [blame] | 244 | |
aa@chromium.org | 81f8b91b | 2013-11-26 21:02:51 | [diff] [blame] | 245 | // DispatchToCallback converts all the JavaScript arguments to C++ types and |
Colin Blundell | ea615d42 | 2021-05-12 09:35:41 | [diff] [blame] | 246 | // invokes the base::RepeatingCallback. |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 247 | template <typename Sig> |
| 248 | struct Dispatcher {}; |
aa@chromium.org | bf3dd3c | 2013-12-06 06:55:25 | [diff] [blame] | 249 | |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 250 | template <typename ReturnType, typename... ArgTypes> |
| 251 | struct Dispatcher<ReturnType(ArgTypes...)> { |
Jeremy Roman | 6a1242b | 2019-02-04 17:51:57 | [diff] [blame] | 252 | static void DispatchToCallbackImpl(Arguments* args) { |
deepak.s | faaa1b6 | 2015-04-30 07:30:48 | [diff] [blame] | 253 | v8::Local<v8::External> v8_holder; |
Jeremy Roman | 6a1242b | 2019-02-04 17:51:57 | [diff] [blame] | 254 | CHECK(args->GetData(&v8_holder)); |
jochen@chromium.org | bf014290 | 2014-02-11 15:06:12 | [diff] [blame] | 255 | CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>( |
| 256 | v8_holder->Value()); |
aa@chromium.org | 314cde1 | 2013-11-23 20:26:51 | [diff] [blame] | 257 | |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 258 | typedef CallbackHolder<ReturnType(ArgTypes...)> HolderT; |
aa@chromium.org | bf3dd3c | 2013-12-06 06:55:25 | [diff] [blame] | 259 | HolderT* holder = static_cast<HolderT*>(holder_base); |
aa@chromium.org | 37dacfa | 2013-11-26 03:31:04 | [diff] [blame] | 260 | |
tzik | c21a0dc | 2017-11-14 08:23:44 | [diff] [blame] | 261 | using Indices = std::index_sequence_for<ArgTypes...>; |
Jeremy Roman | 6a1242b | 2019-02-04 17:51:57 | [diff] [blame] | 262 | Invoker<Indices, ArgTypes...> invoker(args, holder->invoker_options); |
kolczyk | 735c49b6 | 2014-10-24 13:06:04 | [diff] [blame] | 263 | if (invoker.IsOK()) |
| 264 | invoker.DispatchToCallback(holder->callback); |
aa@chromium.org | d73341d1 | 2013-12-21 00:48:46 | [diff] [blame] | 265 | } |
Jeremy Roman | 6a1242b | 2019-02-04 17:51:57 | [diff] [blame] | 266 | |
| 267 | static void DispatchToCallback( |
| 268 | const v8::FunctionCallbackInfo<v8::Value>& info) { |
| 269 | Arguments args(info); |
| 270 | DispatchToCallbackImpl(&args); |
| 271 | } |
| 272 | |
| 273 | static void DispatchToCallbackForProperty( |
| 274 | v8::Local<v8::Name>, |
| 275 | const v8::PropertyCallbackInfo<v8::Value>& info) { |
| 276 | Arguments args(info); |
| 277 | DispatchToCallbackImpl(&args); |
| 278 | } |
aa@chromium.org | d73341d1 | 2013-12-21 00:48:46 | [diff] [blame] | 279 | }; |
| 280 | |
aa@chromium.org | 81f8b91b | 2013-11-26 21:02:51 | [diff] [blame] | 281 | } // namespace internal |
| 282 | |
aa@chromium.org | bf3dd3c | 2013-12-06 06:55:25 | [diff] [blame] | 283 | // CreateFunctionTemplate creates a v8::FunctionTemplate that will create |
Colin Blundell | ea615d42 | 2021-05-12 09:35:41 | [diff] [blame] | 284 | // JavaScript functions that execute a provided C++ function or |
| 285 | // base::RepeatingCallback. JavaScript arguments are automatically converted via |
| 286 | // gin::Converter, as is the return value of the C++ function, if any. |
| 287 | // |invoker_options| contains additional parameters. If it contains a |
| 288 | // holder_type, it will be used to provide a useful conversion error if the |
| 289 | // holder is the first argument. If not provided, a generic invocation error |
| 290 | // will be used. |
mnaganov | 098ba6f | 2015-03-03 16:34:48 | [diff] [blame] | 291 | // |
| 292 | // NOTE: V8 caches FunctionTemplates for a lifetime of a web page for its own |
| 293 | // internal reasons, thus it is generally a good idea to cache the template |
| 294 | // returned by this function. Otherwise, repeated method invocations from JS |
| 295 | // will create substantial memory leaks. See http://crbug.com/463487. |
Ashley Newson | deda181 | 2024-01-09 12:04:18 | [diff] [blame] | 296 | // |
| 297 | // The callback will be destroyed if either the function template gets garbage |
| 298 | // collected or _after_ the isolate is disposed. Garbage collection can never be |
| 299 | // relied upon. As such, any destructors for objects bound to the callback must |
| 300 | // not depend on the isolate being alive at the point they are called. The order |
| 301 | // in which callbacks are destroyed is not guaranteed. |
tzik | c21a0dc | 2017-11-14 08:23:44 | [diff] [blame] | 302 | template <typename Sig> |
aa@chromium.org | 81f8b91b | 2013-11-26 21:02:51 | [diff] [blame] | 303 | v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( |
tzik | c21a0dc | 2017-11-14 08:23:44 | [diff] [blame] | 304 | v8::Isolate* isolate, |
| 305 | base::RepeatingCallback<Sig> callback, |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 306 | InvokerOptions invoker_options = {}) { |
aa@chromium.org | bf3dd3c | 2013-12-06 06:55:25 | [diff] [blame] | 307 | typedef internal::CallbackHolder<Sig> HolderT; |
Devlin Cronin | e9db984 | 2018-04-09 17:51:05 | [diff] [blame] | 308 | HolderT* holder = |
| 309 | new HolderT(isolate, std::move(callback), std::move(invoker_options)); |
jochen@chromium.org | bf014290 | 2014-02-11 15:06:12 | [diff] [blame] | 310 | |
jochen | 596fd5e | 2016-07-06 12:29:50 | [diff] [blame] | 311 | v8::Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New( |
| 312 | isolate, &internal::Dispatcher<Sig>::DispatchToCallback, |
Sathya Gunasekaran | 77d2ce8 | 2021-01-08 16:41:13 | [diff] [blame] | 313 | ConvertToV8<v8::Local<v8::External>>(isolate, holder->GetHandle(isolate)), |
| 314 | v8::Local<v8::Signature>(), 0, v8::ConstructorBehavior::kThrow); |
jochen | 596fd5e | 2016-07-06 12:29:50 | [diff] [blame] | 315 | return tmpl; |
aa@chromium.org | 7618ebbb | 2013-11-27 03:38:26 | [diff] [blame] | 316 | } |
| 317 | |
Jeremy Roman | 6a1242b | 2019-02-04 17:51:57 | [diff] [blame] | 318 | // CreateDataPropertyCallback creates a v8::AccessorNameGetterCallback and |
| 319 | // corresponding data value that will hold and execute the provided |
| 320 | // base::RepeatingCallback, using automatic conversions similar to |
| 321 | // |CreateFunctionTemplate|. |
| 322 | // |
| 323 | // It is expected that these will be passed to v8::Template::SetLazyDataProperty |
| 324 | // or another similar function. |
| 325 | template <typename Sig> |
| 326 | std::pair<v8::AccessorNameGetterCallback, v8::Local<v8::Value>> |
| 327 | CreateDataPropertyCallback(v8::Isolate* isolate, |
| 328 | base::RepeatingCallback<Sig> callback, |
| 329 | InvokerOptions invoker_options = {}) { |
| 330 | typedef internal::CallbackHolder<Sig> HolderT; |
| 331 | HolderT* holder = |
| 332 | new HolderT(isolate, std::move(callback), std::move(invoker_options)); |
| 333 | return {&internal::Dispatcher<Sig>::DispatchToCallbackForProperty, |
| 334 | ConvertToV8<v8::Local<v8::External>>(isolate, |
| 335 | holder->GetHandle(isolate))}; |
| 336 | } |
| 337 | |
aa@chromium.org | 314cde1 | 2013-11-23 20:26:51 | [diff] [blame] | 338 | } // namespace gin |
aa@chromium.org | b520e13 | 2013-11-29 03:21:48 | [diff] [blame] | 339 | |
| 340 | #endif // GIN_FUNCTION_TEMPLATE_H_ |