From 656e403f0102c59428261c1eaad22912d2bbd3c5 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 23 Jul 2015 14:58:03 +0800 Subject: [PATCH] Use C++11 version of CreateFunctionTemplate --- native_mate/function_template.h | 606 ++++++--------------------- native_mate/function_template.h.pump | 250 ----------- 2 files changed, 122 insertions(+), 734 deletions(-) delete mode 100644 native_mate/function_template.h.pump diff --git a/native_mate/function_template.h b/native_mate/function_template.h index 59a999627da5..0761dca58b57 100644 --- a/native_mate/function_template.h +++ b/native_mate/function_template.h @@ -1,7 +1,3 @@ -// This file was GENERATED by command: -// pump.py function_template.h.pump -// DO NOT EDIT BY HAND!!! - // Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE.chromium file. @@ -17,8 +13,6 @@ namespace mate { -class PerIsolateData; - enum CreateFunctionTemplateFlags { HolderIsFirstArgument = 1 << 0, SafeAfterDestroyed = 1 << 1, @@ -96,221 +90,6 @@ class CallbackHolder : public CallbackHolderBase { DISALLOW_COPY_AND_ASSIGN(CallbackHolder); }; - -// This set of templates invokes a base::Callback, converts the return type to a -// JavaScript value, and returns that value to script via the provided -// mate::Arguments object. -// -// In C++, you can declare the function foo(void), but you can't pass a void -// expression to foo. As a result, we must specialize the case of Callbacks that -// have the void return type. -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4, - const P5& a5, - const P6& a6, - const P7& a7) { - MATE_METHOD_RETURN(callback.Run(a1, a2, a3, a4, a5, a6, a7)); - } -}; -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4, - const P5& a5, - const P6& a6, - const P7& a7) { - callback.Run(a1, a2, a3, a4, a5, a6, a7); - MATE_METHOD_RETURN_UNDEFINED(); - } -}; - -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4, - const P5& a5, - const P6& a6) { - MATE_METHOD_RETURN(callback.Run(a1, a2, a3, a4, a5, a6)); - } -}; -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4, - const P5& a5, - const P6& a6) { - callback.Run(a1, a2, a3, a4, a5, a6); - MATE_METHOD_RETURN_UNDEFINED(); - } -}; - -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4, - const P5& a5) { - MATE_METHOD_RETURN(callback.Run(a1, a2, a3, a4, a5)); - } -}; -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4, - const P5& a5) { - callback.Run(a1, a2, a3, a4, a5); - MATE_METHOD_RETURN_UNDEFINED(); - } -}; - -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4) { - MATE_METHOD_RETURN(callback.Run(a1, a2, a3, a4)); - } -}; -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3, - const P4& a4) { - callback.Run(a1, a2, a3, a4); - MATE_METHOD_RETURN_UNDEFINED(); - } -}; - -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3) { - MATE_METHOD_RETURN(callback.Run(a1, a2, a3)); - } -}; -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1, - const P2& a2, - const P3& a3) { - callback.Run(a1, a2, a3); - MATE_METHOD_RETURN_UNDEFINED(); - } -}; - -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1, - const P2& a2) { - MATE_METHOD_RETURN(callback.Run(a1, a2)); - } -}; -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1, - const P2& a2) { - callback.Run(a1, a2); - MATE_METHOD_RETURN_UNDEFINED(); - } -}; - -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1) { - MATE_METHOD_RETURN(callback.Run(a1)); - } -}; -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback, - const P1& a1) { - callback.Run(a1); - MATE_METHOD_RETURN_UNDEFINED(); - } -}; - -template -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback) { - MATE_METHOD_RETURN(callback.Run()); - } -}; -template<> -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback) { - callback.Run(); - MATE_METHOD_RETURN_UNDEFINED(); - } -}; - - template bool GetNextArgument(Arguments* args, int create_flags, bool is_first, T* result) { @@ -341,278 +120,120 @@ inline bool GetNextArgument(Arguments* args, int create_flags, return true; } +// Classes for generating and storing an argument pack of integer indices +// (based on well-known "indices trick", see: http://goo.gl/bKKojn): +template +struct IndicesHolder {}; + +template +struct IndicesGenerator { + using type = typename IndicesGenerator::type; +}; +template +struct IndicesGenerator<0, indices...> { + using type = IndicesHolder; +}; + +// Class template for extracting and storing single argument for callback +// at position |index|. +template +struct ArgumentHolder { + using ArgLocalType = typename CallbackParamTraits::LocalType; + + ArgLocalType value; + bool ok; + + ArgumentHolder(Arguments* args, int create_flags) + : ok(false) { + if (index == 0 && + (create_flags & HolderIsFirstArgument) && + !(create_flags & SafeAfterDestroyed) && + DestroyedChecker::IsDestroyed(args)) { + args->ThrowError("Object has been destroyed"); + return; + } + ok = GetNextArgument(args, create_flags, index == 0, &value); + if (!ok) { + // Ideally we would include the expected c++ type in the error + // message which we can access via typeid(ArgType).name() + // however we compile with no-rtti, which disables typeid. + args->ThrowError(); + } + } +}; + +// Class template for converting arguments from JavaScript to C++ and running +// the callback with them. +template +class Invoker {}; + +template +class Invoker, ArgTypes...> + : public ArgumentHolder... { + public: + // Invoker<> inherits from ArgumentHolder<> for each argument. + // C++ has always been strict about the class initialization order, + // so it is guaranteed ArgumentHolders will be initialized (and thus, will + // extract arguments from Arguments) in the right order. + Invoker(Arguments* args, int create_flags) + : ArgumentHolder(args, create_flags)..., args_(args) { + // GCC thinks that create_flags is going unused, even though the + // expansion above clearly makes use of it. Per jyasskin@, casting + // to void is the commonly accepted way to convince the compiler + // that you're actually using a parameter/varible. + (void)create_flags; + } + + bool IsOK() { + return And(ArgumentHolder::ok...); + } + + template + void DispatchToCallback(base::Callback callback) { + args_->Return(callback.Run(ArgumentHolder::value...)); + } + + // In C++, you can declare the function foo(void), but you can't pass a void + // expression to foo. As a result, we must specialize the case of Callbacks + // that have the void return type. + void DispatchToCallback(base::Callback callback) { + callback.Run(ArgumentHolder::value...); + } + + private: + static bool And() { return true; } + template + static bool And(bool arg1, T... args) { + return arg1 && And(args...); + } + + Arguments* args_; +}; // DispatchToCallback converts all the JavaScript arguments to C++ types and // invokes the base::Callback. -template -struct Dispatcher { -}; +template +struct Dispatcher {}; -template -struct Dispatcher { - static MATE_METHOD(DispatchToCallback) { +template +struct Dispatcher { + static void DispatchToCallback( + const v8::FunctionCallbackInfo& info) { Arguments args(info); v8::Local v8_holder; CHECK(args.GetData(&v8_holder)); CallbackHolderBase* holder_base = reinterpret_cast( v8_holder->Value()); - typedef CallbackHolder HolderT; + typedef CallbackHolder HolderT; HolderT* holder = static_cast(holder_base); - return Invoker::Go(args, holder->callback); - } -}; - -template -struct Dispatcher { - static MATE_METHOD(DispatchToCallback) { - Arguments args(info); - v8::Local v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - - typename CallbackParamTraits::LocalType a1; - if ((holder->flags & HolderIsFirstArgument) && - !(holder->flags & SafeAfterDestroyed) && - DestroyedChecker::LocalType>::IsDestroyed(&args)) { - args.ThrowError("Object has been destroyed"); - MATE_METHOD_RETURN_UNDEFINED(); - } - if (!GetNextArgument(&args, holder->flags, true, &a1)) { - args.ThrowError(); - MATE_METHOD_RETURN_UNDEFINED(); - } - - return Invoker::Go(args, holder->callback, a1); - } -}; - -template -struct Dispatcher { - static MATE_METHOD(DispatchToCallback) { - Arguments args(info); - v8::Local v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - - typename CallbackParamTraits::LocalType a1; - typename CallbackParamTraits::LocalType a2; - if ((holder->flags & HolderIsFirstArgument) && - !(holder->flags & SafeAfterDestroyed) && - DestroyedChecker::LocalType>::IsDestroyed(&args)) { - args.ThrowError("Object has been destroyed"); - MATE_METHOD_RETURN_UNDEFINED(); - } - if (!GetNextArgument(&args, holder->flags, true, &a1) || - !GetNextArgument(&args, holder->flags, false, &a2)) { - args.ThrowError(); - MATE_METHOD_RETURN_UNDEFINED(); - } - - return Invoker::Go(args, holder->callback, a1, a2); - } -}; - -template -struct Dispatcher { - static MATE_METHOD(DispatchToCallback) { - Arguments args(info); - v8::Local v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - - typename CallbackParamTraits::LocalType a1; - typename CallbackParamTraits::LocalType a2; - typename CallbackParamTraits::LocalType a3; - if ((holder->flags & HolderIsFirstArgument) && - !(holder->flags & SafeAfterDestroyed) && - DestroyedChecker::LocalType>::IsDestroyed(&args)) { - args.ThrowError("Object has been destroyed"); - MATE_METHOD_RETURN_UNDEFINED(); - } - if (!GetNextArgument(&args, holder->flags, true, &a1) || - !GetNextArgument(&args, holder->flags, false, &a2) || - !GetNextArgument(&args, holder->flags, false, &a3)) { - args.ThrowError(); - MATE_METHOD_RETURN_UNDEFINED(); - } - - return Invoker::Go(args, holder->callback, a1, a2, a3); - } -}; - -template -struct Dispatcher { - static MATE_METHOD(DispatchToCallback) { - Arguments args(info); - v8::Local v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - - typename CallbackParamTraits::LocalType a1; - typename CallbackParamTraits::LocalType a2; - typename CallbackParamTraits::LocalType a3; - typename CallbackParamTraits::LocalType a4; - if ((holder->flags & HolderIsFirstArgument) && - !(holder->flags & SafeAfterDestroyed) && - DestroyedChecker::LocalType>::IsDestroyed(&args)) { - args.ThrowError("Object has been destroyed"); - MATE_METHOD_RETURN_UNDEFINED(); - } - if (!GetNextArgument(&args, holder->flags, true, &a1) || - !GetNextArgument(&args, holder->flags, false, &a2) || - !GetNextArgument(&args, holder->flags, false, &a3) || - !GetNextArgument(&args, holder->flags, false, &a4)) { - args.ThrowError(); - MATE_METHOD_RETURN_UNDEFINED(); - } - - return Invoker::Go(args, holder->callback, a1, a2, a3, - a4); - } -}; - -template -struct Dispatcher { - static MATE_METHOD(DispatchToCallback) { - Arguments args(info); - v8::Local v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - - typename CallbackParamTraits::LocalType a1; - typename CallbackParamTraits::LocalType a2; - typename CallbackParamTraits::LocalType a3; - typename CallbackParamTraits::LocalType a4; - typename CallbackParamTraits::LocalType a5; - if ((holder->flags & HolderIsFirstArgument) && - !(holder->flags & SafeAfterDestroyed) && - DestroyedChecker::LocalType>::IsDestroyed(&args)) { - args.ThrowError("Object has been destroyed"); - MATE_METHOD_RETURN_UNDEFINED(); - } - if (!GetNextArgument(&args, holder->flags, true, &a1) || - !GetNextArgument(&args, holder->flags, false, &a2) || - !GetNextArgument(&args, holder->flags, false, &a3) || - !GetNextArgument(&args, holder->flags, false, &a4) || - !GetNextArgument(&args, holder->flags, false, &a5)) { - args.ThrowError(); - MATE_METHOD_RETURN_UNDEFINED(); - } - - return Invoker::Go(args, holder->callback, a1, a2, - a3, a4, a5); - } -}; - -template -struct Dispatcher { - static MATE_METHOD(DispatchToCallback) { - Arguments args(info); - v8::Local v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - - typename CallbackParamTraits::LocalType a1; - typename CallbackParamTraits::LocalType a2; - typename CallbackParamTraits::LocalType a3; - typename CallbackParamTraits::LocalType a4; - typename CallbackParamTraits::LocalType a5; - typename CallbackParamTraits::LocalType a6; - if ((holder->flags & HolderIsFirstArgument) && - !(holder->flags & SafeAfterDestroyed) && - DestroyedChecker::LocalType>::IsDestroyed(&args)) { - args.ThrowError("Object has been destroyed"); - MATE_METHOD_RETURN_UNDEFINED(); - } - if (!GetNextArgument(&args, holder->flags, true, &a1) || - !GetNextArgument(&args, holder->flags, false, &a2) || - !GetNextArgument(&args, holder->flags, false, &a3) || - !GetNextArgument(&args, holder->flags, false, &a4) || - !GetNextArgument(&args, holder->flags, false, &a5) || - !GetNextArgument(&args, holder->flags, false, &a6)) { - args.ThrowError(); - MATE_METHOD_RETURN_UNDEFINED(); - } - - return Invoker::Go(args, holder->callback, a1, - a2, a3, a4, a5, a6); - } -}; - -template -struct Dispatcher { - static MATE_METHOD(DispatchToCallback) { - Arguments args(info); - v8::Local v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - - typename CallbackParamTraits::LocalType a1; - typename CallbackParamTraits::LocalType a2; - typename CallbackParamTraits::LocalType a3; - typename CallbackParamTraits::LocalType a4; - typename CallbackParamTraits::LocalType a5; - typename CallbackParamTraits::LocalType a6; - typename CallbackParamTraits::LocalType a7; - if ((holder->flags & HolderIsFirstArgument) && - !(holder->flags & SafeAfterDestroyed) && - DestroyedChecker::LocalType>::IsDestroyed(&args)) { - args.ThrowError("Object has been destroyed"); - MATE_METHOD_RETURN_UNDEFINED(); - } - if (!GetNextArgument(&args, holder->flags, true, &a1) || - !GetNextArgument(&args, holder->flags, false, &a2) || - !GetNextArgument(&args, holder->flags, false, &a3) || - !GetNextArgument(&args, holder->flags, false, &a4) || - !GetNextArgument(&args, holder->flags, false, &a5) || - !GetNextArgument(&args, holder->flags, false, &a6) || - !GetNextArgument(&args, holder->flags, false, &a7)) { - args.ThrowError(); - MATE_METHOD_RETURN_UNDEFINED(); - } - - return Invoker::Go(args, holder->callback, - a1, a2, a3, a4, a5, a6, a7); + using Indices = typename IndicesGenerator::type; + Invoker invoker(&args, holder->flags); + if (invoker.IsOK()) + invoker.DispatchToCallback(holder->callback); } }; @@ -621,8 +242,13 @@ struct Dispatcher { // CreateFunctionTemplate creates a v8::FunctionTemplate that will create // JavaScript functions that execute a provided C++ function or base::Callback. -// JavaScript arguments are automatically converted via mate::Converter, as is +// JavaScript arguments are automatically converted via gin::Converter, as is // the return value of the C++ function, if any. +// +// 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. template v8::Local CreateFunctionTemplate( v8::Isolate* isolate, const base::Callback callback, @@ -631,14 +257,26 @@ v8::Local CreateFunctionTemplate( HolderT* holder = new HolderT(isolate, callback, callback_flags); return v8::FunctionTemplate::New( -#if NODE_VERSION_AT_LEAST(0, 11, 11) isolate, -#endif &internal::Dispatcher::DispatchToCallback, ConvertToV8 >(isolate, holder->GetHandle(isolate))); } +// CreateFunctionHandler installs a CallAsFunction handler on the given +// object template that forwards to a provided C++ function or base::Callback. +template +void CreateFunctionHandler(v8::Isolate* isolate, + v8::Local tmpl, + const base::Callback callback, + int callback_flags = 0) { + typedef internal::CallbackHolder HolderT; + HolderT* holder = new HolderT(isolate, callback, callback_flags); + tmpl->SetCallAsFunctionHandler(&internal::Dispatcher::DispatchToCallback, + ConvertToV8 >( + isolate, holder->GetHandle(isolate))); +} + } // namespace mate #endif // NATIVE_MATE_FUNCTION_TEMPLATE_H_ diff --git a/native_mate/function_template.h.pump b/native_mate/function_template.h.pump deleted file mode 100644 index 10e64751fb14..000000000000 --- a/native_mate/function_template.h.pump +++ /dev/null @@ -1,250 +0,0 @@ -$$ This is a pump file for generating file templates. Pump is a python -$$ script that is part of the Google Test suite of utilities. Description -$$ can be found here: -$$ -$$ http://code.google.com/p/googletest/wiki/PumpManual -$$ -$var MAX_ARITY = 7 -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE.chromium file. - -#ifndef NATIVE_MATE_FUNCTION_TEMPLATE_H_ -#define NATIVE_MATE_FUNCTION_TEMPLATE_H_ - -#include "base/callback.h" -#include "base/logging.h" -#include "native_mate/arguments.h" -#include "native_mate/wrappable.h" -#include "v8/include/v8.h" - -namespace mate { - -class PerIsolateData; - -enum CreateFunctionTemplateFlags { - HolderIsFirstArgument = 1 << 0, - SafeAfterDestroyed = 1 << 1, -}; - -namespace internal { - -// Check if the class has been destroyed. -template -struct DestroyedChecker { - static bool IsDestroyed(Arguments* args) { - return false; - } -}; -template -struct DestroyedChecker::value>::type> { - static bool IsDestroyed(Arguments* args) { - T* object; - if (args->GetHolder(&object)) - return static_cast(object)->IsDestroyed(); - else - return false; - } -}; - -template -struct CallbackParamTraits { - typedef T LocalType; -}; -template -struct CallbackParamTraits { - typedef T LocalType; -}; -template -struct CallbackParamTraits { - typedef T* LocalType; -}; - - -// CallbackHolder and CallbackHolderBase are used to pass a base::Callback from -// CreateFunctionTemplate through v8 (via v8::FunctionTemplate) to -// DispatchToCallback, where it is invoked. - -// This simple base class is used so that we can share a single object template -// among every CallbackHolder instance. -class CallbackHolderBase { - public: - v8::Local GetHandle(v8::Isolate* isolate); - - protected: - explicit CallbackHolderBase(v8::Isolate* isolate); - virtual ~CallbackHolderBase(); - - private: - static MATE_WEAK_CALLBACK(WeakCallback, v8::External, CallbackHolderBase); - - v8::UniquePersistent v8_ref_; - - DISALLOW_COPY_AND_ASSIGN(CallbackHolderBase); -}; - -template -class CallbackHolder : public CallbackHolderBase { - public: - CallbackHolder(v8::Isolate* isolate, - const base::Callback& callback, - int flags) - : CallbackHolderBase(isolate), callback(callback), flags(flags) {} - base::Callback callback; - int flags; - private: - virtual ~CallbackHolder() {} - - DISALLOW_COPY_AND_ASSIGN(CallbackHolder); -}; - - -// This set of templates invokes a base::Callback, converts the return type to a -// JavaScript value, and returns that value to script via the provided -// mate::Arguments object. -// -// In C++, you can declare the function foo(void), but you can't pass a void -// expression to foo. As a result, we must specialize the case of Callbacks that -// have the void return type. - -$range ARITY 0..MAX_ARITY -$for ARITY [[ -$var INV_ARITY = MAX_ARITY - ARITY -$range ARG 1..INV_ARITY -$range VOID INV_ARITY+1..MAX_ARITY - -$if ARITY == 0 [[ -template -struct Invoker { -]] $else [[ -template -struct Invoker { -]] - - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback$for ARG [[, - const P$(ARG)& a$(ARG)]]) { - MATE_METHOD_RETURN(callback.Run($for ARG, [[a$(ARG)]])); - } -}; -template<$for ARG , [[typename P$(ARG)]]> -struct Invoker { - inline static MATE_METHOD_RETURN_TYPE Go( - Arguments& args, - const base::Callback& callback$for ARG [[, - const P$(ARG)& a$(ARG)]]) { - callback.Run($for ARG, [[a$(ARG)]]); - MATE_METHOD_RETURN_UNDEFINED(); - } -}; - - -]] - -template -bool GetNextArgument(Arguments* args, int create_flags, bool is_first, - T* result) { - if (is_first && (create_flags & HolderIsFirstArgument) != 0) { - return args->GetHolder(result); - } else { - return args->GetNext(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, int create_flags, bool is_first, - Arguments* result) { - *result = *args; - return true; -} -inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first, - Arguments** result) { - *result = args; - return true; -} - -// It's common for clients to just need the isolate, so we make that easy. -inline bool GetNextArgument(Arguments* args, int create_flags, - bool is_first, v8::Isolate** result) { - *result = args->isolate(); - return true; -} - - -// DispatchToCallback converts all the JavaScript arguments to C++ types and -// invokes the base::Callback. -template -struct Dispatcher { -}; - -$range ARITY 0..MAX_ARITY -$for ARITY [[ -$range ARG 1..ARITY - -template -struct Dispatcher { - static MATE_METHOD(DispatchToCallback) { - Arguments args(info); - v8::Local v8_holder; - CHECK(args.GetData(&v8_holder)); - CallbackHolderBase* holder_base = reinterpret_cast( - v8_holder->Value()); - - typedef CallbackHolder HolderT; - HolderT* holder = static_cast(holder_base); - -$if ARITY != 0 [[ - - -$for ARG [[ typename CallbackParamTraits::LocalType a$(ARG); - -]] - if ((holder->flags & HolderIsFirstArgument) && - !(holder->flags & SafeAfterDestroyed) && - DestroyedChecker::LocalType>::IsDestroyed(&args)) { - args.ThrowError("Object has been destroyed"); - MATE_METHOD_RETURN_UNDEFINED(); - } - if ($for ARG || - [[!GetNextArgument(&args, holder->flags, $if ARG == 1 [[true]] $else [[false]], &a$(ARG))]]) { - args.ThrowError(); - MATE_METHOD_RETURN_UNDEFINED(); - } - -]] - - return Invoker::Go(args, holder->callback$for ARG [[, a$(ARG)]]); - } -}; - -]] - -} // namespace internal - - -// CreateFunctionTemplate creates a v8::FunctionTemplate that will create -// JavaScript functions that execute a provided C++ function or base::Callback. -// JavaScript arguments are automatically converted via mate::Converter, as is -// the return value of the C++ function, if any. -template -v8::Local CreateFunctionTemplate( - v8::Isolate* isolate, const base::Callback callback, - int callback_flags = 0) { - typedef internal::CallbackHolder HolderT; - HolderT* holder = new HolderT(isolate, callback, callback_flags); - - return v8::FunctionTemplate::New( -#if NODE_VERSION_AT_LEAST(0, 11, 11) - isolate, -#endif - &internal::Dispatcher::DispatchToCallback, - ConvertToV8 >(isolate, - holder->GetHandle(isolate))); -} - -} // namespace mate - -#endif // NATIVE_MATE_FUNCTION_TEMPLATE_H_