diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-26 21:02:51 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-26 21:02:51 +0000 |
commit | 81f8b91b2f2213ad40d5bd4ecbe096550a2eedd6 (patch) | |
tree | 8527f82a4bb22c71187c73e4bca60c8c414957e3 /gin | |
parent | 615bca519a93ba2d550455189802584cae4fafb5 (diff) | |
download | chromium_src-81f8b91b2f2213ad40d5bd4ecbe096550a2eedd6.zip chromium_src-81f8b91b2f2213ad40d5bd4ecbe096550a2eedd6.tar.gz chromium_src-81f8b91b2f2213ad40d5bd4ecbe096550a2eedd6.tar.bz2 |
Implement support in function_template.h for return types.
Review URL: https://codereview.chromium.org/86783002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@237408 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gin')
-rw-r--r-- | gin/function_template.cc | 21 | ||||
-rw-r--r-- | gin/function_template.h | 220 | ||||
-rw-r--r-- | gin/function_template.h.pump | 87 | ||||
-rw-r--r-- | gin/isolate_holder.cc | 2 | ||||
-rw-r--r-- | gin/test/gtest.cc | 6 |
5 files changed, 250 insertions, 86 deletions
diff --git a/gin/function_template.cc b/gin/function_template.cc index 9815b67..e8878e0 100644 --- a/gin/function_template.cc +++ b/gin/function_template.cc @@ -8,19 +8,22 @@ namespace gin { -WrapperInfo CallbackHolderBase::kWrapperInfo = { kEmbedderNativeGin }; +WrapperInfo internal::CallbackHolderBase::kWrapperInfo = { kEmbedderNativeGin }; -// static -void CallbackHolderBase::EnsureRegistered(PerIsolateData* isolate_data) { - if (!isolate_data->GetObjectTemplate(&kWrapperInfo).IsEmpty()) +WrapperInfo* internal::CallbackHolderBase::GetWrapperInfo() { + return &kWrapperInfo; +} + +void InitFunctionTemplates(PerIsolateData* isolate_data) { + if (!isolate_data->GetObjectTemplate( + &internal::CallbackHolderBase::kWrapperInfo).IsEmpty()) { return; + } + v8::Handle<v8::ObjectTemplate> templ(v8::ObjectTemplate::New()); templ->SetInternalFieldCount(kNumberOfInternalFields); - isolate_data->SetObjectTemplate(&kWrapperInfo, templ); -} - -WrapperInfo* CallbackHolderBase::GetWrapperInfo() { - return &kWrapperInfo; + isolate_data->SetObjectTemplate(&internal::CallbackHolderBase::kWrapperInfo, + templ); } } // namespace gin diff --git a/gin/function_template.h b/gin/function_template.h index 7cf84f8..0685c1b 100644 --- a/gin/function_template.h +++ b/gin/function_template.h @@ -33,12 +33,10 @@ struct RemoveConstRef<const T&> { typedef T Type; }; -} // namespace internal - // CallbackHolder and CallbackHolderBase are used to pass a base::Callback from // CreateFunctionTemplate through v8 (via v8::FunctionTemplate) to -// DispatchCallback, where it is invoked. +// DispatchToCallback, where it is invoked. // // v8::FunctionTemplate only supports passing void* as data so how do we know // when to delete the base::Callback? That's where CallbackHolderBase comes in. @@ -47,17 +45,12 @@ struct RemoveConstRef<const T&> { // JavaScript references in V8. class CallbackHolderBase : public Wrappable { public: - static void EnsureRegistered(PerIsolateData* isolate_data); virtual WrapperInfo* GetWrapperInfo() OVERRIDE; static WrapperInfo kWrapperInfo; protected: virtual ~CallbackHolderBase() {} }; -template<> -struct Converter<CallbackHolderBase*> - : public WrappableConverter<CallbackHolderBase> {}; - template<typename Sig> class CallbackHolder : public CallbackHolderBase { public: @@ -68,6 +61,97 @@ class CallbackHolder : public CallbackHolderBase { virtual ~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 +// gin::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<typename R, typename P1 = void, typename P2 = void, typename P3 = void> +struct Invoker { + inline static void Go( + Arguments* args, + const base::Callback<R(P1, P2, P3)>& callback, + const P1& a1, + const P2& a2, + const P3& a3) { + args->Return(callback.Run(a1, a2, a3)); + } +}; +template<typename P1, typename P2, typename P3> +struct Invoker<void, P1, P2, P3> { + inline static void Go( + Arguments* args, + const base::Callback<void(P1, P2, P3)>& callback, + const P1& a1, + const P2& a2, + const P3& a3) { + callback.Run(a1, a2, a3); + } +}; + +template<typename R, typename P1, typename P2> +struct Invoker<R, P1, P2, void> { + inline static void Go( + Arguments* args, + const base::Callback<R(P1, P2)>& callback, + const P1& a1, + const P2& a2) { + args->Return(callback.Run(a1, a2)); + } +}; +template<typename P1, typename P2> +struct Invoker<void, P1, P2, void> { + inline static void Go( + Arguments* args, + const base::Callback<void(P1, P2)>& callback, + const P1& a1, + const P2& a2) { + callback.Run(a1, a2); + } +}; + +template<typename R, typename P1> +struct Invoker<R, P1, void, void> { + inline static void Go( + Arguments* args, + const base::Callback<R(P1)>& callback, + const P1& a1) { + args->Return(callback.Run(a1)); + } +}; +template<typename P1> +struct Invoker<void, P1, void, void> { + inline static void Go( + Arguments* args, + const base::Callback<void(P1)>& callback, + const P1& a1) { + callback.Run(a1); + } +}; + +template<typename R> +struct Invoker<R, void, void, void> { + inline static void Go( + Arguments* args, + const base::Callback<R()>& callback) { + args->Return(callback.Run()); + } +}; +template<> +struct Invoker<void, void, void, void> { + inline static void Go( + Arguments* args, + const base::Callback<void()>& callback) { + callback.Run(); + } +}; + + +// DispatchToCallback converts all the JavaScript arguments to C++ types and +// invokes the base::Callback. template<typename R> static void DispatchToCallback( const v8::FunctionCallbackInfo<v8::Value>& info) { @@ -75,21 +159,10 @@ static void DispatchToCallback( CallbackHolderBase* holder_base = NULL; CHECK(args.GetData(&holder_base)); - typedef CallbackHolder<void()> HolderT; + typedef CallbackHolder<R()> HolderT; HolderT* holder = static_cast<HolderT*>(holder_base); - holder->callback.Run(); -} - -template<typename R> -v8::Local<v8::FunctionTemplate> CreateFunctionTempate( - v8::Isolate* isolate, - const base::Callback<R()> callback) { - typedef CallbackHolder<void()> HolderT; - scoped_refptr<HolderT> holder(new HolderT(callback)); - return v8::FunctionTemplate::New( - &DispatchToCallback<R>, - ConvertToV8<CallbackHolderBase*>(isolate, holder.get())); + Invoker<R>::Go(&args, holder->callback); } template<typename R, typename P1> @@ -99,27 +172,16 @@ static void DispatchToCallback( CallbackHolderBase* holder_base = NULL; CHECK(args.GetData(&holder_base)); - typedef CallbackHolder<void(P1)> HolderT; + typedef CallbackHolder<R(P1)> HolderT; HolderT* holder = static_cast<HolderT*>(holder_base); - typename internal::RemoveConstRef<P1>::Type a1; + typename RemoveConstRef<P1>::Type a1; if (!args.GetNext(&a1)) { args.ThrowError(); return; } - holder->callback.Run(a1); -} - -template<typename R, typename P1> -v8::Local<v8::FunctionTemplate> CreateFunctionTempate( - v8::Isolate* isolate, - const base::Callback<R(P1)> callback) { - typedef CallbackHolder<void(P1)> HolderT; - scoped_refptr<HolderT> holder(new HolderT(callback)); - return v8::FunctionTemplate::New( - &DispatchToCallback<R, P1>, - ConvertToV8<CallbackHolderBase*>(isolate, holder.get())); + Invoker<R, P1>::Go(&args, holder->callback, a1); } template<typename R, typename P1, typename P2> @@ -129,29 +191,18 @@ static void DispatchToCallback( CallbackHolderBase* holder_base = NULL; CHECK(args.GetData(&holder_base)); - typedef CallbackHolder<void(P1, P2)> HolderT; + typedef CallbackHolder<R(P1, P2)> HolderT; HolderT* holder = static_cast<HolderT*>(holder_base); - typename internal::RemoveConstRef<P1>::Type a1; - typename internal::RemoveConstRef<P2>::Type a2; + typename RemoveConstRef<P1>::Type a1; + typename RemoveConstRef<P2>::Type a2; if (!args.GetNext(&a1) || !args.GetNext(&a2)) { args.ThrowError(); return; } - holder->callback.Run(a1, a2); -} - -template<typename R, typename P1, typename P2> -v8::Local<v8::FunctionTemplate> CreateFunctionTempate( - v8::Isolate* isolate, - const base::Callback<R(P1, P2)> callback) { - typedef CallbackHolder<void(P1, P2)> HolderT; - scoped_refptr<HolderT> holder(new HolderT(callback)); - return v8::FunctionTemplate::New( - &DispatchToCallback<R, P1, P2>, - ConvertToV8<CallbackHolderBase*>(isolate, holder.get())); + Invoker<R, P1, P2>::Go(&args, holder->callback, a1, a2); } template<typename R, typename P1, typename P2, typename P3> @@ -161,12 +212,12 @@ static void DispatchToCallback( CallbackHolderBase* holder_base = NULL; CHECK(args.GetData(&holder_base)); - typedef CallbackHolder<void(P1, P2, P3)> HolderT; + typedef CallbackHolder<R(P1, P2, P3)> HolderT; HolderT* holder = static_cast<HolderT*>(holder_base); - typename internal::RemoveConstRef<P1>::Type a1; - typename internal::RemoveConstRef<P2>::Type a2; - typename internal::RemoveConstRef<P3>::Type a3; + typename RemoveConstRef<P1>::Type a1; + typename RemoveConstRef<P2>::Type a2; + typename RemoveConstRef<P3>::Type a3; if (!args.GetNext(&a1) || !args.GetNext(&a2) || !args.GetNext(&a3)) { @@ -174,18 +225,69 @@ static void DispatchToCallback( return; } - holder->callback.Run(a1, a2, a3); + Invoker<R, P1, P2, P3>::Go(&args, holder->callback, a1, a2, a3); +} + +} // namespace internal + + +// This should be called once per-isolate to initialize the function template +// system. +void InitFunctionTemplates(PerIsolateData* isolate_data); + +// This has to be outside the internal namespace because template +// specializations must be declared in the same namespace as the original +// template. +template<> +struct Converter<internal::CallbackHolderBase*> + : public WrappableConverter<internal::CallbackHolderBase> {}; + + +// Creates a v8::FunctionTemplate that will run the provided base::Callback each +// time it is called. JavaScript arguments and return values are converted via +// gin::Converter. +template<typename R> +v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( + v8::Isolate* isolate, + const base::Callback<R()> callback) { + typedef internal::CallbackHolder<R()> HolderT; + scoped_refptr<HolderT> holder(new HolderT(callback)); + return v8::FunctionTemplate::New( + &internal::DispatchToCallback<R>, + ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); +} + +template<typename R, typename P1> +v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( + v8::Isolate* isolate, + const base::Callback<R(P1)> callback) { + typedef internal::CallbackHolder<R(P1)> HolderT; + scoped_refptr<HolderT> holder(new HolderT(callback)); + return v8::FunctionTemplate::New( + &internal::DispatchToCallback<R, P1>, + ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); +} + +template<typename R, typename P1, typename P2> +v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( + v8::Isolate* isolate, + const base::Callback<R(P1, P2)> callback) { + typedef internal::CallbackHolder<R(P1, P2)> HolderT; + scoped_refptr<HolderT> holder(new HolderT(callback)); + return v8::FunctionTemplate::New( + &internal::DispatchToCallback<R, P1, P2>, + ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); } template<typename R, typename P1, typename P2, typename P3> -v8::Local<v8::FunctionTemplate> CreateFunctionTempate( +v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( v8::Isolate* isolate, const base::Callback<R(P1, P2, P3)> callback) { - typedef CallbackHolder<void(P1, P2, P3)> HolderT; + typedef internal::CallbackHolder<R(P1, P2, P3)> HolderT; scoped_refptr<HolderT> holder(new HolderT(callback)); return v8::FunctionTemplate::New( - &DispatchToCallback<R, P1, P2, P3>, - ConvertToV8<CallbackHolderBase*>(isolate, holder.get())); + &internal::DispatchToCallback<R, P1, P2, P3>, + ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); } } // namespace gin diff --git a/gin/function_template.h.pump b/gin/function_template.h.pump index 802e048b..7e90324 100644 --- a/gin/function_template.h.pump +++ b/gin/function_template.h.pump @@ -36,12 +36,10 @@ struct RemoveConstRef<const T&> { typedef T Type; }; -} // namespace internal - // CallbackHolder and CallbackHolderBase are used to pass a base::Callback from // CreateFunctionTemplate through v8 (via v8::FunctionTemplate) to -// DispatchCallback, where it is invoked. +// DispatchToCallback, where it is invoked. // // v8::FunctionTemplate only supports passing void* as data so how do we know // when to delete the base::Callback? That's where CallbackHolderBase comes in. @@ -57,10 +55,6 @@ class CallbackHolderBase : public Wrappable { virtual ~CallbackHolderBase() {} }; -template<> -struct Converter<CallbackHolderBase*> - : public WrappableConverter<CallbackHolderBase> {}; - template<typename Sig> class CallbackHolder : public CallbackHolderBase { public: @@ -71,6 +65,51 @@ class CallbackHolder : public CallbackHolderBase { virtual ~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 +// gin::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<typename R$for ARG [[, typename P$(ARG) = void]]> +struct Invoker { +]] $else [[ +template<typename R$for ARG [[, typename P$(ARG)]]> +struct Invoker<R$for ARG [[, P$(ARG)]]$for VOID [[, void]]> { +]] + + inline static void Go( + Arguments* args, + const base::Callback<R($for ARG , [[P$(ARG)]])>& callback$for ARG [[, + const P$(ARG)& a$(ARG)]]) { + args->Return(callback.Run($for ARG, [[a$(ARG)]])); + } +}; +template<$for ARG , [[typename P$(ARG)]]> +struct Invoker<void$for ARG [[, P$(ARG)]]$for VOID [[, void]]> { + inline static void Go( + Arguments* args, + const base::Callback<void($for ARG , [[P$(ARG)]])>& callback$for ARG [[, + const P$(ARG)& a$(ARG)]]) { + callback.Run($for ARG, [[a$(ARG)]]); + } +}; + + +]] + +// DispatchToCallback converts all the JavaScript arguments to C++ types and +// invokes the base::Callback. $range ARITY 0..MAX_ARITY $for ARITY [[ $range ARG 1..ARITY @@ -82,13 +121,13 @@ static void DispatchToCallback( CallbackHolderBase* holder_base = NULL; CHECK(args.GetData(&holder_base)); - typedef CallbackHolder<void($for ARG , [[P$(ARG)]])> HolderT; + typedef CallbackHolder<R($for ARG , [[P$(ARG)]])> HolderT; HolderT* holder = static_cast<HolderT*>(holder_base); $if ARITY != 0 [[ -$for ARG [[ typename internal::RemoveConstRef<P$(ARG)>::Type a$(ARG); +$for ARG [[ typename RemoveConstRef<P$(ARG)>::Type a$(ARG); ]] if ( @@ -100,18 +139,38 @@ $for ARG || ]] - holder->callback.Run($for ARG , [[a$(ARG)]]); + Invoker<R$for ARG [[, P$(ARG)]]>::Go(&args, holder->callback$for ARG [[, a$(ARG)]]); } +]] + +} // namespace internal + + +// This has to be outside the internal namespace because template +// specializations must be declared in the same namespace as the original +// template. +template<> +struct Converter<internal::CallbackHolderBase*> + : public WrappableConverter<internal::CallbackHolderBase> {}; + + +// Creates a v8::FunctionTemplate that will run the provided base::Callback each +// time it is called. JavaScript arguments and return values are converted via +// gin::Converter. +$range ARITY 0..MAX_ARITY +$for ARITY [[ +$range ARG 1..ARITY + template<typename R$for ARG [[, typename P$(ARG)]]> -v8::Local<v8::FunctionTemplate> CreateFunctionTempate( +v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( v8::Isolate* isolate, const base::Callback<R($for ARG , [[P$(ARG)]])> callback) { - typedef CallbackHolder<void($for ARG , [[P$(ARG)]])> HolderT; + typedef internal::CallbackHolder<R($for ARG , [[P$(ARG)]])> HolderT; scoped_refptr<HolderT> holder(new HolderT(callback)); return v8::FunctionTemplate::New( - &DispatchToCallback<R$for ARG [[, P$(ARG)]]>, - ConvertToV8<CallbackHolderBase*>(isolate, holder.get())); + &internal::DispatchToCallback<R$for ARG [[, P$(ARG)]]>, + ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); } ]] diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc index 9e3109d..b5501b6 100644 --- a/gin/isolate_holder.cc +++ b/gin/isolate_holder.cc @@ -53,7 +53,7 @@ IsolateHolder::IsolateHolder() v8::Isolate::Scope isolate_scope(isolate_); v8::HandleScope handle_scope(isolate_); isolate_data_.reset(new PerIsolateData(isolate_)); - CallbackHolderBase::EnsureRegistered(isolate_data_.get()); + InitFunctionTemplates(isolate_data_.get()); } IsolateHolder::IsolateHolder(v8::Isolate* isolate) diff --git a/gin/test/gtest.cc b/gin/test/gtest.cc index eafff4d..a0cf70c 100644 --- a/gin/test/gtest.cc +++ b/gin/test/gtest.cc @@ -57,11 +57,11 @@ v8::Local<v8::ObjectTemplate> GTest::GetTemplate(v8::Isolate* isolate) { templ->Set(StringToSymbol(isolate, "fail"), v8::FunctionTemplate::New(Fail)); templ->Set(StringToSymbol(isolate, "expectTrue"), - CreateFunctionTempate(isolate, base::Bind(ExpectTrue))); + CreateFunctionTemplate(isolate, base::Bind(ExpectTrue))); templ->Set(StringToSymbol(isolate, "expectFalse"), - CreateFunctionTempate(isolate, base::Bind(ExpectFalse))); + CreateFunctionTemplate(isolate, base::Bind(ExpectFalse))); templ->Set(StringToSymbol(isolate, "expectEqual"), - CreateFunctionTempate(isolate, base::Bind(ExpectEqual))); + CreateFunctionTemplate(isolate, base::Bind(ExpectEqual))); data->SetObjectTemplate(&g_wrapper_info, templ); } return templ; |