Make sure handles of callbacks are releases on exit
Some callbacks are stored in native resources that not managed by JavaScript, so when those resources are destroyed the JavaScript context may already be destroyed, and releasing callbacks then would result in crash.
This commit is contained in:
parent
acf4372cf7
commit
d70706f876
2 changed files with 66 additions and 11 deletions
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
namespace internal {
|
||||
|
@ -54,6 +56,33 @@ v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
|
|||
|
||||
} // namespace
|
||||
|
||||
SafeV8Function::SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value)
|
||||
: v8_function_(new RefCountedPersistent<v8::Function>(isolate, value)),
|
||||
weak_factory_(this) {
|
||||
Init();
|
||||
}
|
||||
|
||||
SafeV8Function::SafeV8Function(const SafeV8Function& other)
|
||||
: v8_function_(other.v8_function_),
|
||||
weak_factory_(this) {
|
||||
Init();
|
||||
}
|
||||
|
||||
v8::Local<v8::Function> SafeV8Function::NewHandle() const {
|
||||
return v8_function_->NewHandle();
|
||||
}
|
||||
|
||||
void SafeV8Function::Init() {
|
||||
if (Locker::IsBrowserProcess() && atom::AtomBrowserMainParts::Get())
|
||||
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
|
||||
base::Bind(&SafeV8Function::FreeHandle, weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void SafeV8Function::FreeHandle() {
|
||||
Locker locker(v8_function_->isolate());
|
||||
v8_function_ = nullptr;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> CreateFunctionFromTranslater(
|
||||
v8::Isolate* isolate, const Translater& translater) {
|
||||
// The FunctionTemplate is cached.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "atom/common/api/locker.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "native_mate/function_template.h"
|
||||
#include "native_mate/scoped_persistent.h"
|
||||
#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
|
||||
|
@ -18,7 +19,24 @@ namespace mate {
|
|||
|
||||
namespace internal {
|
||||
|
||||
typedef scoped_refptr<RefCountedPersistent<v8::Function> > SafeV8Function;
|
||||
// Manages the V8 function with RAII, and automatically cleans the handle when
|
||||
// JavaScript context is destroyed, even when the class is not destroyed.
|
||||
class SafeV8Function {
|
||||
public:
|
||||
SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value);
|
||||
SafeV8Function(const SafeV8Function& other);
|
||||
|
||||
bool is_alive() const { return v8_function_.get(); }
|
||||
|
||||
v8::Local<v8::Function> NewHandle() const;
|
||||
|
||||
private:
|
||||
void Init();
|
||||
void FreeHandle();
|
||||
|
||||
scoped_refptr<RefCountedPersistent<v8::Function>> v8_function_;
|
||||
base::WeakPtrFactory<SafeV8Function> weak_factory_;
|
||||
};
|
||||
|
||||
// Helper to invoke a V8 function with C++ parameters.
|
||||
template <typename Sig>
|
||||
|
@ -26,14 +44,17 @@ struct V8FunctionInvoker {};
|
|||
|
||||
template <typename... ArgTypes>
|
||||
struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> {
|
||||
static v8::Local<v8::Value> Go(v8::Isolate* isolate, SafeV8Function function,
|
||||
static v8::Local<v8::Value> Go(v8::Isolate* isolate,
|
||||
const SafeV8Function& function,
|
||||
ArgTypes... raw) {
|
||||
Locker locker(isolate);
|
||||
v8::EscapableHandleScope handle_scope(isolate);
|
||||
if (!function.is_alive())
|
||||
return v8::Null(isolate);
|
||||
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
|
||||
Locker::IsBrowserProcess() ?
|
||||
nullptr : new blink::WebScopedRunV8Script(isolate));
|
||||
v8::Local<v8::Function> holder = function->NewHandle();
|
||||
v8::Local<v8::Function> holder = function.NewHandle();
|
||||
v8::Local<v8::Context> context = holder->CreationContext();
|
||||
v8::Context::Scope context_scope(context);
|
||||
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
|
||||
|
@ -44,14 +65,17 @@ struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> {
|
|||
|
||||
template <typename... ArgTypes>
|
||||
struct V8FunctionInvoker<void(ArgTypes...)> {
|
||||
static void Go(v8::Isolate* isolate, SafeV8Function function,
|
||||
static void Go(v8::Isolate* isolate,
|
||||
const SafeV8Function& function,
|
||||
ArgTypes... raw) {
|
||||
Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
if (!function.is_alive())
|
||||
return;
|
||||
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
|
||||
Locker::IsBrowserProcess() ?
|
||||
nullptr : new blink::WebScopedRunV8Script(isolate));
|
||||
v8::Local<v8::Function> holder = function->NewHandle();
|
||||
v8::Local<v8::Function> holder = function.NewHandle();
|
||||
v8::Local<v8::Context> context = holder->CreationContext();
|
||||
v8::Context::Scope context_scope(context);
|
||||
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
|
||||
|
@ -61,17 +85,20 @@ struct V8FunctionInvoker<void(ArgTypes...)> {
|
|||
|
||||
template <typename ReturnType, typename... ArgTypes>
|
||||
struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
|
||||
static ReturnType Go(v8::Isolate* isolate, SafeV8Function function,
|
||||
static ReturnType Go(v8::Isolate* isolate,
|
||||
const SafeV8Function& function,
|
||||
ArgTypes... raw) {
|
||||
Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
ReturnType ret = ReturnType();
|
||||
if (!function.is_alive())
|
||||
return ret;
|
||||
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
|
||||
Locker::IsBrowserProcess() ?
|
||||
nullptr : new blink::WebScopedRunV8Script(isolate));
|
||||
v8::Local<v8::Function> holder = function->NewHandle();
|
||||
v8::Local<v8::Function> holder = function.NewHandle();
|
||||
v8::Local<v8::Context> context = holder->CreationContext();
|
||||
v8::Context::Scope context_scope(context);
|
||||
ReturnType ret = ReturnType();
|
||||
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
|
||||
v8::Local<v8::Value> result;
|
||||
auto maybe_result =
|
||||
|
@ -119,9 +146,8 @@ struct Converter<base::Callback<Sig>> {
|
|||
if (!val->IsFunction())
|
||||
return false;
|
||||
|
||||
internal::SafeV8Function function(
|
||||
new RefCountedPersistent<v8::Function>(isolate, val));
|
||||
*out = base::Bind(&internal::V8FunctionInvoker<Sig>::Go, isolate, function);
|
||||
*out = base::Bind(&internal::V8FunctionInvoker<Sig>::Go,
|
||||
isolate, internal::SafeV8Function(isolate, val));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue