fix: intercept the isolate_holder's new isolate and register it with the node platform before initialization

Chromium Change: 1015020
This commit is contained in:
Samuel Attard 2018-10-03 17:06:40 +10:00 committed by Jeremy Apthorp
parent bacc36dde1
commit 7589c56cea
9 changed files with 139 additions and 129 deletions

View file

@ -10,7 +10,6 @@
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/bridge_task_runner.h"
#include "atom/browser/browser.h"
#include "atom/browser/io_thread.h"
#include "atom/browser/javascript_environment.h"
@ -135,11 +134,9 @@ int AtomBrowserMainParts::PreEarlyInitialization() {
void AtomBrowserMainParts::PostEarlyInitialization() {
brightray::BrowserMainParts::PostEarlyInitialization();
// Temporary set the bridge_task_runner_ as current thread's task runner,
// so we can fool gin::PerIsolateData to use it as its task runner, instead
// of getting current message loop's task runner, which is null for now.
bridge_task_runner_ = new BridgeTaskRunner;
base::ThreadTaskRunnerHandle handle(bridge_task_runner_);
// A workaround was previously needed because there was no ThreadTaskRunner
// set. If this check is failing we may need to re-add that workaround
DCHECK(base::ThreadTaskRunnerHandle::IsSet());
// The ProxyResolverV8 has setup a complete V8 environment, in order to
// avoid conflicts we only initialize our V8 environment after that.
@ -243,8 +240,6 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
brightray::BrowserMainParts::PreMainMessageLoopRun();
bridge_task_runner_->MessageLoopIsReady();
bridge_task_runner_ = nullptr;
#if defined(USE_X11)
libgtkui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess());

View file

@ -108,10 +108,6 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
// A fake BrowserProcess object that used to feed the source code from chrome.
std::unique_ptr<BrowserProcess> fake_browser_process_;
// The gin::PerIsolateData requires a task runner to create, so we feed it
// with a task runner that will post all work to main loop.
scoped_refptr<BridgeTaskRunner> bridge_task_runner_;
// Pointer to exit code.
int* exit_code_ = nullptr;

View file

@ -1,65 +0,0 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/bridge_task_runner.h"
#include <utility>
#include "base/message_loop/message_loop.h"
namespace atom {
BridgeTaskRunner::BridgeTaskRunner() = default;
BridgeTaskRunner::~BridgeTaskRunner() = default;
void BridgeTaskRunner::MessageLoopIsReady() {
auto message_loop = base::MessageLoop::current();
CHECK(message_loop);
for (TaskPair& task : tasks_) {
message_loop->task_runner()->PostDelayedTask(
std::get<0>(task), std::move(std::get<1>(task)), std::get<2>(task));
}
for (TaskPair& task : non_nestable_tasks_) {
message_loop->task_runner()->PostNonNestableDelayedTask(
std::get<0>(task), std::move(std::get<1>(task)), std::get<2>(task));
}
}
bool BridgeTaskRunner::PostDelayedTask(const base::Location& from_here,
base::OnceClosure task,
base::TimeDelta delay) {
auto message_loop = base::MessageLoop::current();
if (!message_loop) {
tasks_.push_back(std::make_tuple(from_here, std::move(task), delay));
return true;
}
return message_loop->task_runner()->PostDelayedTask(from_here,
std::move(task), delay);
}
bool BridgeTaskRunner::RunsTasksInCurrentSequence() const {
auto message_loop = base::MessageLoop::current();
if (!message_loop)
return true;
return message_loop->task_runner()->RunsTasksInCurrentSequence();
}
bool BridgeTaskRunner::PostNonNestableDelayedTask(
const base::Location& from_here,
base::OnceClosure task,
base::TimeDelta delay) {
auto message_loop = base::MessageLoop::current();
if (!message_loop) {
non_nestable_tasks_.push_back(
std::make_tuple(from_here, std::move(task), delay));
return true;
}
return message_loop->task_runner()->PostNonNestableDelayedTask(
from_here, std::move(task), delay);
}
} // namespace atom

View file

@ -1,48 +0,0 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
#define ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
#include <tuple>
#include <vector>
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/tuple.h"
namespace atom {
// Post all tasks to the current message loop's task runner if available,
// otherwise delay the work until message loop is ready.
class BridgeTaskRunner : public base::SingleThreadTaskRunner {
public:
BridgeTaskRunner();
// Called when message loop is ready.
void MessageLoopIsReady();
// base::SingleThreadTaskRunner:
bool PostDelayedTask(const base::Location& from_here,
base::OnceClosure task,
base::TimeDelta delay) override;
bool RunsTasksInCurrentSequence() const override;
bool PostNonNestableDelayedTask(const base::Location& from_here,
base::OnceClosure task,
base::TimeDelta delay) override;
private:
using TaskPair =
std::tuple<base::Location, base::OnceClosure, base::TimeDelta>;
~BridgeTaskRunner() override;
std::vector<TaskPair> tasks_;
std::vector<TaskPair> non_nestable_tasks_;
DISALLOW_COPY_AND_ASSIGN(BridgeTaskRunner);
};
} // namespace atom
#endif // ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_

View file

@ -21,13 +21,19 @@ namespace atom {
JavascriptEnvironment::JavascriptEnvironment()
: initialized_(Initialize()),
isolate_holder_(base::ThreadTaskRunnerHandle::Get()),
isolate_holder_(base::ThreadTaskRunnerHandle::Get(),
new AtomIsolateAllocator(this)),
isolate_(isolate_holder_.isolate()),
isolate_scope_(isolate_),
locker_(isolate_),
handle_scope_(isolate_),
context_(isolate_, v8::Context::New(isolate_)),
context_scope_(v8::Local<v8::Context>::New(isolate_, context_)) {}
context_scope_(v8::Local<v8::Context>::New(isolate_, context_)) {
// The assumption is made here that the isolate_holder_ holds a single isolate
// if this is not the case or changes in the constructor above the logic
// below must be rewritten
node::InitializePrivatePropertiesOnIsolateData(isolate_data_);
}
JavascriptEnvironment::~JavascriptEnvironment() = default;
@ -64,4 +70,16 @@ NodeEnvironment::~NodeEnvironment() {
node::FreeEnvironment(env_);
}
AtomIsolateAllocator::AtomIsolateAllocator(JavascriptEnvironment* env)
: env_(env) {}
v8::Isolate* AtomIsolateAllocator::Allocate() {
v8::Isolate* isolate = v8::Isolate::Allocate();
// This is a cheatsy way to add the Isolate and it's IsolateData to the node
// platform before it is ready
env_->set_isolate_data(node::CreateIsolateData(
isolate, uv_default_loop(), env_->platform(), true /* only_register */));
return isolate;
}
} // namespace atom

View file

@ -11,6 +11,7 @@
namespace node {
class Environment;
class MultiIsolatePlatform;
class IsolateData;
} // namespace node
namespace atom {
@ -29,6 +30,7 @@ class JavascriptEnvironment {
v8::Local<v8::Context> context() const {
return v8::Local<v8::Context>::New(isolate_, context_);
}
void set_isolate_data(node::IsolateData* data) { isolate_data_ = data; }
private:
bool Initialize();
@ -44,6 +46,7 @@ class JavascriptEnvironment {
v8::HandleScope handle_scope_;
v8::UniquePersistent<v8::Context> context_;
v8::Context::Scope context_scope_;
node::IsolateData* isolate_data_;
DISALLOW_COPY_AND_ASSIGN(JavascriptEnvironment);
};
@ -60,6 +63,18 @@ class NodeEnvironment {
DISALLOW_COPY_AND_ASSIGN(NodeEnvironment);
};
class AtomIsolateAllocator : public gin::IsolateAllocater {
public:
explicit AtomIsolateAllocator(JavascriptEnvironment* env);
v8::Isolate* Allocate() override;
private:
JavascriptEnvironment* env_;
DISALLOW_COPY_AND_ASSIGN(AtomIsolateAllocator);
};
} // namespace atom
#endif // ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_