diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index e386e678a47c..4031fb27cf30 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -132,6 +132,7 @@ void AtomBrowserMainParts::PostEarlyInitialization() { // Create the global environment. node::Environment* env = node_bindings_->CreateEnvironment(js_env_->context()); + node_env_.reset(new NodeEnvironment(env)); // Make sure node can get correct environment when debugging. if (node_debugger_->IsRunning()) diff --git a/atom/browser/atom_browser_main_parts.h b/atom/browser/atom_browser_main_parts.h index 0d8619f6865a..71adc43d5e65 100644 --- a/atom/browser/atom_browser_main_parts.h +++ b/atom/browser/atom_browser_main_parts.h @@ -22,6 +22,7 @@ class Browser; class JavascriptEnvironment; class NodeBindings; class NodeDebugger; +class NodeEnvironment; class BridgeTaskRunner; class AtomBrowserMainParts : public brightray::BrowserMainParts { @@ -79,6 +80,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts { std::unique_ptr browser_; std::unique_ptr js_env_; + std::unique_ptr node_env_; std::unique_ptr node_bindings_; std::unique_ptr atom_bindings_; std::unique_ptr node_debugger_; diff --git a/atom/browser/javascript_environment.cc b/atom/browser/javascript_environment.cc index 3cdd2c771ee6..b3e01c1c3009 100644 --- a/atom/browser/javascript_environment.cc +++ b/atom/browser/javascript_environment.cc @@ -12,6 +12,8 @@ #include "gin/array_buffer.h" #include "gin/v8_initializer.h" +#include "atom/common/node_includes.h" + namespace atom { JavascriptEnvironment::JavascriptEnvironment() @@ -46,4 +48,11 @@ bool JavascriptEnvironment::Initialize() { return true; } +NodeEnvironment::NodeEnvironment(node::Environment* env) : env_(env) { +} + +NodeEnvironment::~NodeEnvironment() { + node::FreeEnvironment(env_); +} + } // namespace atom diff --git a/atom/browser/javascript_environment.h b/atom/browser/javascript_environment.h index 1f4d2f453478..43a7295f9026 100644 --- a/atom/browser/javascript_environment.h +++ b/atom/browser/javascript_environment.h @@ -8,8 +8,13 @@ #include "base/macros.h" #include "gin/public/isolate_holder.h" +namespace node { +class Environment; +} + namespace atom { +// Manage the V8 isolate and context automatically. class JavascriptEnvironment { public: JavascriptEnvironment(); @@ -37,6 +42,18 @@ class JavascriptEnvironment { DISALLOW_COPY_AND_ASSIGN(JavascriptEnvironment); }; +// Manage the Node Environment automatically. +class NodeEnvironment { + public: + explicit NodeEnvironment(node::Environment* env); + ~NodeEnvironment(); + + private: + node::Environment* env_; + + DISALLOW_COPY_AND_ASSIGN(NodeEnvironment); +}; + } // namespace atom #endif // ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_ diff --git a/atom/common/api/atom_bindings.cc b/atom/common/api/atom_bindings.cc index 2b4bec6328d9..f1b56c675936 100644 --- a/atom/common/api/atom_bindings.cc +++ b/atom/common/api/atom_bindings.cc @@ -84,6 +84,7 @@ AtomBindings::AtomBindings() { } AtomBindings::~AtomBindings() { + uv_close(reinterpret_cast(&call_next_tick_async_), nullptr); } void AtomBindings::BindTo(v8::Isolate* isolate, @@ -117,6 +118,13 @@ void AtomBindings::BindTo(v8::Isolate* isolate, } } +void AtomBindings::EnvironmentDestroyed(node::Environment* env) { + auto it = std::find(pending_next_ticks_.begin(), pending_next_ticks_.end(), + env); + if (it != pending_next_ticks_.end()) + pending_next_ticks_.erase(it); +} + void AtomBindings::ActivateUVLoop(v8::Isolate* isolate) { node::Environment* env = node::Environment::GetCurrent(isolate); if (std::find(pending_next_ticks_.begin(), pending_next_ticks_.end(), env) != diff --git a/atom/common/api/atom_bindings.h b/atom/common/api/atom_bindings.h index 58c2336c0e8b..3fd43cc8a145 100644 --- a/atom/common/api/atom_bindings.h +++ b/atom/common/api/atom_bindings.h @@ -27,6 +27,9 @@ class AtomBindings { // load native code from Electron instead. void BindTo(v8::Isolate* isolate, v8::Local process); + // Should be called when a node::Environment has been destroyed. + void EnvironmentDestroyed(node::Environment* env); + static void Log(const base::string16& message); static void Crash(); diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 0737314d07f1..4cf2ba56e4c8 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -117,6 +117,7 @@ NodeBindings::~NodeBindings() { // Clear uv. uv_sem_destroy(&embed_sem_); + uv_close(reinterpret_cast(&dummy_uv_handle_), nullptr); } void NodeBindings::Initialize() { diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 9f91c901965f..078bcf743cfc 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -213,7 +213,8 @@ std::vector ParseSchemesCLISwitch(const char* switch_name) { } // namespace AtomRendererClient::AtomRendererClient() - : node_bindings_(NodeBindings::Create(false)), + : node_integration_initialized_(false), + node_bindings_(NodeBindings::Create(false)), atom_bindings_(new AtomBindings) { isolated_world_ = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kContextIsolation); @@ -349,11 +350,9 @@ void AtomRendererClient::DidCreateScriptContext( if (!render_frame->IsMainFrame() && !IsDevToolsExtension(render_frame)) return; - // Whether the node binding has been initialized. - bool first_time = node_bindings_->uv_env() == nullptr; - // Prepare the node bindings. - if (first_time) { + if (!node_integration_initialized_) { + node_integration_initialized_ = true; node_bindings_->Initialize(); node_bindings_->PrepareMessageLoop(); } @@ -369,7 +368,7 @@ void AtomRendererClient::DidCreateScriptContext( // Load everything. node_bindings_->LoadEnvironment(env); - if (first_time) { + if (node_bindings_->uv_env() == nullptr) { // Make uv loop being wrapped by window context. node_bindings_->set_uv_env(env); @@ -388,6 +387,14 @@ void AtomRendererClient::WillReleaseScriptContext( node::Environment* env = node::Environment::GetCurrent(context); if (env) mate::EmitEvent(env->isolate(), env->process_object(), "exit"); + + // The main frame may be replaced. + if (env == node_bindings_->uv_env()) + node_bindings_->set_uv_env(nullptr); + + // Destroy the node environment. + node::FreeEnvironment(env); + atom_bindings_->EnvironmentDestroyed(env); } bool AtomRendererClient::ShouldFork(blink::WebLocalFrame* frame, diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index a693262fed1b..c1d86cddf5e3 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -66,6 +66,9 @@ class AtomRendererClient : public content::ContentRendererClient { std::vector>* key_systems) override; + // Whether the node integration has been initialized. + bool node_integration_initialized_; + std::unique_ptr node_bindings_; std::unique_ptr atom_bindings_; std::unique_ptr preferences_manager_;