callback.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright (c) 2019 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 SHELL_COMMON_GIN_HELPER_CALLBACK_H_
  5. #define SHELL_COMMON_GIN_HELPER_CALLBACK_H_
  6. #include <utility>
  7. #include <vector>
  8. #include "base/bind.h"
  9. #include "gin/dictionary.h"
  10. #include "shell/common/gin_converters/std_converter.h"
  11. #include "shell/common/gin_helper/function_template.h"
  12. #include "shell/common/gin_helper/locker.h"
  13. #include "shell/common/gin_helper/microtasks_scope.h"
  14. // Implements safe conversions between JS functions and base::RepeatingCallback.
  15. namespace gin_helper {
  16. template <typename T>
  17. class RefCountedGlobal;
  18. // Manages the V8 function with RAII.
  19. class SafeV8Function {
  20. public:
  21. SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value);
  22. SafeV8Function(const SafeV8Function& other);
  23. ~SafeV8Function();
  24. bool IsAlive() const;
  25. v8::Local<v8::Function> NewHandle(v8::Isolate* isolate) const;
  26. private:
  27. scoped_refptr<RefCountedGlobal<v8::Function>> v8_function_;
  28. };
  29. // Helper to invoke a V8 function with C++ parameters.
  30. template <typename Sig>
  31. struct V8FunctionInvoker {};
  32. template <typename... ArgTypes>
  33. struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> {
  34. static v8::Local<v8::Value> Go(v8::Isolate* isolate,
  35. const SafeV8Function& function,
  36. ArgTypes... raw) {
  37. gin_helper::Locker locker(isolate);
  38. v8::EscapableHandleScope handle_scope(isolate);
  39. if (!function.IsAlive())
  40. return v8::Null(isolate);
  41. gin_helper::MicrotasksScope microtasks_scope(isolate, true);
  42. v8::Local<v8::Function> holder = function.NewHandle(isolate);
  43. v8::Local<v8::Context> context = holder->CreationContext();
  44. v8::Context::Scope context_scope(context);
  45. std::vector<v8::Local<v8::Value>> args{
  46. gin::ConvertToV8(isolate, std::forward<ArgTypes>(raw))...};
  47. v8::MaybeLocal<v8::Value> ret = holder->Call(
  48. context, holder, args.size(), args.empty() ? nullptr : &args.front());
  49. if (ret.IsEmpty())
  50. return v8::Undefined(isolate);
  51. else
  52. return handle_scope.Escape(ret.ToLocalChecked());
  53. }
  54. };
  55. template <typename... ArgTypes>
  56. struct V8FunctionInvoker<void(ArgTypes...)> {
  57. static void Go(v8::Isolate* isolate,
  58. const SafeV8Function& function,
  59. ArgTypes... raw) {
  60. gin_helper::Locker locker(isolate);
  61. v8::HandleScope handle_scope(isolate);
  62. if (!function.IsAlive())
  63. return;
  64. gin_helper::MicrotasksScope microtasks_scope(isolate, true);
  65. v8::Local<v8::Function> holder = function.NewHandle(isolate);
  66. v8::Local<v8::Context> context = holder->CreationContext();
  67. v8::Context::Scope context_scope(context);
  68. std::vector<v8::Local<v8::Value>> args{
  69. gin::ConvertToV8(isolate, std::forward<ArgTypes>(raw))...};
  70. holder
  71. ->Call(context, holder, args.size(),
  72. args.empty() ? nullptr : &args.front())
  73. .IsEmpty();
  74. }
  75. };
  76. template <typename ReturnType, typename... ArgTypes>
  77. struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
  78. static ReturnType Go(v8::Isolate* isolate,
  79. const SafeV8Function& function,
  80. ArgTypes... raw) {
  81. gin_helper::Locker locker(isolate);
  82. v8::HandleScope handle_scope(isolate);
  83. ReturnType ret = ReturnType();
  84. if (!function.IsAlive())
  85. return ret;
  86. gin_helper::MicrotasksScope microtasks_scope(isolate, true);
  87. v8::Local<v8::Function> holder = function.NewHandle(isolate);
  88. v8::Local<v8::Context> context = holder->CreationContext();
  89. v8::Context::Scope context_scope(context);
  90. std::vector<v8::Local<v8::Value>> args{
  91. gin::ConvertToV8(isolate, std::forward<ArgTypes>(raw))...};
  92. v8::Local<v8::Value> result;
  93. auto maybe_result = holder->Call(context, holder, args.size(),
  94. args.empty() ? nullptr : &args.front());
  95. if (maybe_result.ToLocal(&result))
  96. gin::Converter<ReturnType>::FromV8(isolate, result, &ret);
  97. return ret;
  98. }
  99. };
  100. // Helper to pass a C++ function to JavaScript.
  101. using Translater = base::RepeatingCallback<void(gin::Arguments* args)>;
  102. v8::Local<v8::Value> CreateFunctionFromTranslater(v8::Isolate* isolate,
  103. const Translater& translater,
  104. bool one_time);
  105. v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
  106. v8::Local<v8::Context> context,
  107. v8::Local<v8::Function> func,
  108. v8::Local<v8::Value> arg1,
  109. v8::Local<v8::Value> arg2);
  110. // Calls callback with Arguments.
  111. template <typename Sig>
  112. struct NativeFunctionInvoker {};
  113. template <typename ReturnType, typename... ArgTypes>
  114. struct NativeFunctionInvoker<ReturnType(ArgTypes...)> {
  115. static void Go(base::RepeatingCallback<ReturnType(ArgTypes...)> val,
  116. gin::Arguments* args) {
  117. using Indices = typename IndicesGenerator<sizeof...(ArgTypes)>::type;
  118. Invoker<Indices, ArgTypes...> invoker(args, 0);
  119. if (invoker.IsOK())
  120. invoker.DispatchToCallback(val);
  121. }
  122. };
  123. // Convert a callback to V8 without the call number limitation, this can easily
  124. // cause memory leaks so use it with caution.
  125. template <typename Sig>
  126. v8::Local<v8::Value> CallbackToV8Leaked(
  127. v8::Isolate* isolate,
  128. const base::RepeatingCallback<Sig>& val) {
  129. Translater translater =
  130. base::BindRepeating(&NativeFunctionInvoker<Sig>::Go, val);
  131. return CreateFunctionFromTranslater(isolate, translater, false);
  132. }
  133. } // namespace gin_helper
  134. #endif // SHELL_COMMON_GIN_HELPER_CALLBACK_H_