callback.h 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Copyright (c) 2015 GitHub, Inc. All rights reserved.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_CALLBACK_H_
  5. #define ATOM_COMMON_NATIVE_MATE_CONVERTERS_CALLBACK_H_
  6. #include <vector>
  7. #include "atom/common/api/locker.h"
  8. #include "base/bind.h"
  9. #include "base/callback.h"
  10. #include "base/memory/weak_ptr.h"
  11. #include "base/message_loop/message_loop.h"
  12. #include "content/public/browser/browser_thread.h"
  13. #include "native_mate/function_template.h"
  14. #include "native_mate/scoped_persistent.h"
  15. namespace mate {
  16. namespace internal {
  17. template <typename T>
  18. class RefCountedGlobal;
  19. // Manages the V8 function with RAII.
  20. class SafeV8Function {
  21. public:
  22. SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value);
  23. SafeV8Function(const SafeV8Function& other);
  24. ~SafeV8Function();
  25. bool IsAlive() const;
  26. v8::Local<v8::Function> NewHandle(v8::Isolate* isolate) const;
  27. private:
  28. scoped_refptr<RefCountedGlobal<v8::Function>> v8_function_;
  29. };
  30. // Helper to invoke a V8 function with C++ parameters.
  31. template <typename Sig>
  32. struct V8FunctionInvoker {};
  33. template <typename... ArgTypes>
  34. struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> {
  35. static v8::Local<v8::Value> Go(v8::Isolate* isolate,
  36. const SafeV8Function& function,
  37. ArgTypes... raw) {
  38. Locker locker(isolate);
  39. v8::EscapableHandleScope handle_scope(isolate);
  40. if (!function.IsAlive())
  41. return v8::Null(isolate);
  42. v8::MicrotasksScope script_scope(isolate,
  43. v8::MicrotasksScope::kRunMicrotasks);
  44. v8::Local<v8::Function> holder = function.NewHandle(isolate);
  45. v8::Local<v8::Context> context = holder->CreationContext();
  46. v8::Context::Scope context_scope(context);
  47. std::vector<v8::Local<v8::Value>> args{ConvertToV8(isolate, raw)...};
  48. v8::Local<v8::Value> ret(holder->Call(
  49. holder, args.size(), args.empty() ? nullptr : &args.front()));
  50. return handle_scope.Escape(ret);
  51. }
  52. };
  53. template <typename... ArgTypes>
  54. struct V8FunctionInvoker<void(ArgTypes...)> {
  55. static void Go(v8::Isolate* isolate,
  56. const SafeV8Function& function,
  57. ArgTypes... raw) {
  58. Locker locker(isolate);
  59. v8::HandleScope handle_scope(isolate);
  60. if (!function.IsAlive())
  61. return;
  62. v8::MicrotasksScope script_scope(isolate,
  63. v8::MicrotasksScope::kRunMicrotasks);
  64. v8::Local<v8::Function> holder = function.NewHandle(isolate);
  65. v8::Local<v8::Context> context = holder->CreationContext();
  66. v8::Context::Scope context_scope(context);
  67. std::vector<v8::Local<v8::Value>> args{ConvertToV8(isolate, raw)...};
  68. holder->Call(holder, args.size(), args.empty() ? nullptr : &args.front());
  69. }
  70. };
  71. template <typename ReturnType, typename... ArgTypes>
  72. struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
  73. static ReturnType Go(v8::Isolate* isolate,
  74. const SafeV8Function& function,
  75. ArgTypes... raw) {
  76. Locker locker(isolate);
  77. v8::HandleScope handle_scope(isolate);
  78. ReturnType ret = ReturnType();
  79. if (!function.IsAlive())
  80. return ret;
  81. v8::MicrotasksScope script_scope(isolate,
  82. v8::MicrotasksScope::kRunMicrotasks);
  83. v8::Local<v8::Function> holder = function.NewHandle(isolate);
  84. v8::Local<v8::Context> context = holder->CreationContext();
  85. v8::Context::Scope context_scope(context);
  86. std::vector<v8::Local<v8::Value>> args{ConvertToV8(isolate, raw)...};
  87. v8::Local<v8::Value> result;
  88. auto maybe_result = holder->Call(context, holder, args.size(),
  89. args.empty() ? nullptr : &args.front());
  90. if (maybe_result.ToLocal(&result))
  91. Converter<ReturnType>::FromV8(isolate, result, &ret);
  92. return ret;
  93. }
  94. };
  95. // Helper to pass a C++ funtion to JavaScript.
  96. using Translater = base::Callback<void(Arguments* args)>;
  97. v8::Local<v8::Value> CreateFunctionFromTranslater(v8::Isolate* isolate,
  98. const Translater& translater);
  99. v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
  100. v8::Local<v8::Context> context,
  101. v8::Local<v8::Function> func,
  102. v8::Local<v8::Value> arg1,
  103. v8::Local<v8::Value> arg2);
  104. // Calls callback with Arguments.
  105. template <typename Sig>
  106. struct NativeFunctionInvoker {};
  107. template <typename ReturnType, typename... ArgTypes>
  108. struct NativeFunctionInvoker<ReturnType(ArgTypes...)> {
  109. static void Go(base::Callback<ReturnType(ArgTypes...)> val, Arguments* args) {
  110. using Indices = typename IndicesGenerator<sizeof...(ArgTypes)>::type;
  111. Invoker<Indices, ArgTypes...> invoker(args, 0);
  112. if (invoker.IsOK())
  113. invoker.DispatchToCallback(val);
  114. }
  115. };
  116. } // namespace internal
  117. template <typename Sig>
  118. struct Converter<base::OnceCallback<Sig>> {
  119. static bool FromV8(v8::Isolate* isolate,
  120. v8::Local<v8::Value> val,
  121. base::OnceCallback<Sig>* out) {
  122. if (!val->IsFunction())
  123. return false;
  124. *out = base::BindOnce(&internal::V8FunctionInvoker<Sig>::Go, isolate,
  125. internal::SafeV8Function(isolate, val));
  126. return true;
  127. }
  128. };
  129. template <typename Sig>
  130. struct Converter<base::RepeatingCallback<Sig>> {
  131. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  132. const base::RepeatingCallback<Sig>& val) {
  133. // We don't use CreateFunctionTemplate here because it creates a new
  134. // FunctionTemplate everytime, which is cached by V8 and causes leaks.
  135. internal::Translater translater =
  136. base::BindRepeating(&internal::NativeFunctionInvoker<Sig>::Go, val);
  137. return internal::CreateFunctionFromTranslater(isolate, translater);
  138. }
  139. static bool FromV8(v8::Isolate* isolate,
  140. v8::Local<v8::Value> val,
  141. base::RepeatingCallback<Sig>* out) {
  142. if (!val->IsFunction())
  143. return false;
  144. *out = base::BindRepeating(&internal::V8FunctionInvoker<Sig>::Go, isolate,
  145. internal::SafeV8Function(isolate, val));
  146. return true;
  147. }
  148. };
  149. } // namespace mate
  150. #endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_CALLBACK_H_