// Copyright (c) 2018 GitHub, Inc. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. #ifndef SHELL_COMMON_GIN_HELPER_CONSTRUCTOR_H_ #define SHELL_COMMON_GIN_HELPER_CONSTRUCTOR_H_ #include "shell/common/gin_helper/function_template.h" #include "shell/common/gin_helper/wrappable_base.h" namespace gin_helper { namespace internal { // This set of templates invokes a base::Callback by converting the Arguments // into native types. It relies on the function_template.h to provide helper // templates. inline WrappableBase* InvokeFactory( gin::Arguments* args, const base::Callback& callback) { return callback.Run(); } template inline WrappableBase* InvokeFactory( gin::Arguments* args, const base::Callback& callback) { typename CallbackParamTraits::LocalType a1; if (!gin_helper::GetNextArgument(args, 0, true, &a1)) return nullptr; return callback.Run(a1); } template inline WrappableBase* InvokeFactory( gin::Arguments* args, const base::Callback& callback) { typename CallbackParamTraits::LocalType a1; typename CallbackParamTraits::LocalType a2; if (!gin_helper::GetNextArgument(args, 0, true, &a1) || !gin_helper::GetNextArgument(args, 0, false, &a2)) return nullptr; return callback.Run(a1, a2); } template inline WrappableBase* InvokeFactory( gin::Arguments* args, const base::Callback& callback) { typename CallbackParamTraits::LocalType a1; typename CallbackParamTraits::LocalType a2; typename CallbackParamTraits::LocalType a3; if (!gin_helper::GetNextArgument(args, 0, true, &a1) || !gin_helper::GetNextArgument(args, 0, false, &a2) || !gin_helper::GetNextArgument(args, 0, false, &a3)) return nullptr; return callback.Run(a1, a2, a3); } template inline WrappableBase* InvokeFactory( gin::Arguments* args, const base::Callback& callback) { typename CallbackParamTraits::LocalType a1; typename CallbackParamTraits::LocalType a2; typename CallbackParamTraits::LocalType a3; typename CallbackParamTraits::LocalType a4; if (!gin_helper::GetNextArgument(args, 0, true, &a1) || !gin_helper::GetNextArgument(args, 0, false, &a2) || !gin_helper::GetNextArgument(args, 0, false, &a3) || !gin_helper::GetNextArgument(args, 0, false, &a4)) return nullptr; return callback.Run(a1, a2, a3, a4); } template inline WrappableBase* InvokeFactory( gin::Arguments* args, const base::Callback& callback) { typename CallbackParamTraits::LocalType a1; typename CallbackParamTraits::LocalType a2; typename CallbackParamTraits::LocalType a3; typename CallbackParamTraits::LocalType a4; typename CallbackParamTraits::LocalType a5; if (!gin_helper::GetNextArgument(args, 0, true, &a1) || !gin_helper::GetNextArgument(args, 0, false, &a2) || !gin_helper::GetNextArgument(args, 0, false, &a3) || !gin_helper::GetNextArgument(args, 0, false, &a4) || !gin_helper::GetNextArgument(args, 0, false, &a5)) return nullptr; return callback.Run(a1, a2, a3, a4, a5); } template inline WrappableBase* InvokeFactory( gin::Arguments* args, const base::Callback& callback) { 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 (!gin_helper::GetNextArgument(args, 0, true, &a1) || !gin_helper::GetNextArgument(args, 0, false, &a2) || !gin_helper::GetNextArgument(args, 0, false, &a3) || !gin_helper::GetNextArgument(args, 0, false, &a4) || !gin_helper::GetNextArgument(args, 0, false, &a5) || !gin_helper::GetNextArgument(args, 0, false, &a6)) return nullptr; return callback.Run(a1, a2, a3, a4, a5, a6); } template void InvokeNew(const base::Callback& factory, v8::Isolate* isolate, gin_helper::Arguments* args) { if (!args->IsConstructCall()) { args->ThrowError("Requires constructor call"); return; } WrappableBase* object; { // Don't continue if the constructor throws an exception. v8::TryCatch try_catch(isolate); object = internal::InvokeFactory(args, factory); if (try_catch.HasCaught()) { try_catch.ReThrow(); return; } } if (!object) args->ThrowError(); return; } } // namespace internal // Create a FunctionTemplate that can be "new"ed in JavaScript. // It is user's responsibility to ensure this function is called for one type // only ONCE in the program's whole lifetime, otherwise we would have memory // leak. template v8::Local CreateConstructor( v8::Isolate* isolate, const base::RepeatingCallback& func) { #ifndef NDEBUG static bool called = false; CHECK(!called) << "CreateConstructor can only be called for one type once"; called = true; #endif v8::Local templ = CreateFunctionTemplate( isolate, base::BindRepeating(&internal::InvokeNew, func)); templ->InstanceTemplate()->SetInternalFieldCount(1); T::BuildPrototype(isolate, templ); return templ->GetFunction(isolate->GetCurrentContext()).ToLocalChecked(); } } // namespace gin_helper #endif // SHELL_COMMON_GIN_HELPER_CONSTRUCTOR_H_