Commit 929aa683 authored by eroman's avatar eroman Committed by Commit bot

Lazily initialize the v8::Isolate used by ProxyResolverV8 (in the browser process).

Also removes the limitation of ProxyResolverV8 not being available in single-process mode which no longer applies.

BUG=454983

Review URL: https://codereview.chromium.org/957933002

Cr-Commit-Position: refs/heads/master@{#318277}
parent 44b0fe09
...@@ -104,12 +104,6 @@ net::ProxyService* ProxyServiceFactory::CreateProxyService( ...@@ -104,12 +104,6 @@ net::ProxyService* ProxyServiceFactory::CreateProxyService(
bool use_v8 = false; bool use_v8 = false;
#else #else
bool use_v8 = !command_line.HasSwitch(switches::kWinHttpProxyResolver); bool use_v8 = !command_line.HasSwitch(switches::kWinHttpProxyResolver);
if (use_v8 && command_line.HasSwitch(switches::kSingleProcess)) {
// See the note about V8 multithreading in net/proxy/proxy_resolver_v8.h
// to understand why we have this limitation.
LOG(ERROR) << "Cannot use V8 Proxy resolver in single process mode.";
use_v8 = false; // Fallback to non-v8 implementation.
}
#endif // defined(OS_IOS) #endif // defined(OS_IOS)
size_t num_pac_threads = 0u; // Use default number of threads. size_t num_pac_threads = 0u; // Use default number of threads.
...@@ -133,8 +127,6 @@ net::ProxyService* ProxyServiceFactory::CreateProxyService( ...@@ -133,8 +127,6 @@ net::ProxyService* ProxyServiceFactory::CreateProxyService(
#if defined(OS_IOS) #if defined(OS_IOS)
NOTREACHED(); NOTREACHED();
#else #else
net::ProxyResolverV8::EnsureIsolateCreated();
net::DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher; net::DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher;
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
dhcp_proxy_script_fetcher = dhcp_proxy_script_fetcher =
......
...@@ -15,7 +15,6 @@ namespace { ...@@ -15,7 +15,6 @@ namespace {
scoped_ptr<ProxyResolver> CreateDefaultProxyResolver( scoped_ptr<ProxyResolver> CreateDefaultProxyResolver(
HostResolver* host_resolver) { HostResolver* host_resolver) {
ProxyResolverV8::EnsureIsolateCreated();
return make_scoped_ptr( return make_scoped_ptr(
new ProxyResolverV8Tracing(host_resolver, nullptr, nullptr)); new ProxyResolverV8Tracing(host_resolver, nullptr, nullptr));
} }
......
...@@ -215,8 +215,6 @@ class MockJSBindings : public net::ProxyResolverV8::JSBindings { ...@@ -215,8 +215,6 @@ class MockJSBindings : public net::ProxyResolverV8::JSBindings {
}; };
TEST(ProxyResolverPerfTest, ProxyResolverV8) { TEST(ProxyResolverPerfTest, ProxyResolverV8) {
net::ProxyResolverV8::EnsureIsolateCreated();
MockJSBindings js_bindings; MockJSBindings js_bindings;
net::ProxyResolverV8 resolver; net::ProxyResolverV8 resolver;
resolver.set_js_bindings(&js_bindings); resolver.set_js_bindings(&js_bindings);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/debug/leak_annotations.h" #include "base/debug/leak_annotations.h"
#include "base/lazy_instance.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string_tokenizer.h" #include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
...@@ -345,6 +346,57 @@ bool IsPlainHostName(const std::string& hostname_utf8) { ...@@ -345,6 +346,57 @@ bool IsPlainHostName(const std::string& hostname_utf8) {
return !ParseIPLiteralToNumber(hostname_utf8, &unused); return !ParseIPLiteralToNumber(hostname_utf8, &unused);
} }
// All instances of ProxyResolverV8 share the same v8::Isolate. This isolate is
// created lazily the first time it is needed and lives until process shutdown.
// This creation might happen from any thread, as ProxyResolverV8 is typically
// run in a threadpool.
//
// TODO(eroman): The lazily created isolate is never freed. Instead it should be
// disposed once there are no longer any ProxyResolverV8 referencing it.
class SharedIsolateFactory {
public:
SharedIsolateFactory() : has_initialized_v8_(false) {}
// Lazily creates a v8::Isolate, or returns the already created instance.
v8::Isolate* GetSharedIsolate() {
base::AutoLock l(lock_);
if (!holder_) {
// Do one-time initialization for V8.
if (!has_initialized_v8_) {
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
gin::IsolateHolder::LoadV8Snapshot();
#endif
gin::IsolateHolder::Initialize(
gin::IsolateHolder::kNonStrictMode,
gin::ArrayBufferAllocator::SharedInstance());
has_initialized_v8_ = true;
}
holder_.reset(new gin::IsolateHolder);
}
return holder_->isolate();
}
v8::Isolate* GetSharedIsolateWithoutCreating() {
base::AutoLock l(lock_);
return holder_ ? holder_->isolate() : NULL;
}
private:
base::Lock lock_;
scoped_ptr<gin::IsolateHolder> holder_;
bool has_initialized_v8_;
DISALLOW_COPY_AND_ASSIGN(SharedIsolateFactory);
};
base::LazyInstance<SharedIsolateFactory>::Leaky g_isolate_factory =
LAZY_INSTANCE_INITIALIZER;
} // namespace } // namespace
// ProxyResolverV8::Context --------------------------------------------------- // ProxyResolverV8::Context ---------------------------------------------------
...@@ -789,53 +841,39 @@ int ProxyResolverV8::SetPacScript( ...@@ -789,53 +841,39 @@ int ProxyResolverV8::SetPacScript(
return ERR_PAC_SCRIPT_FAILED; return ERR_PAC_SCRIPT_FAILED;
// Try parsing the PAC script. // Try parsing the PAC script.
scoped_ptr<Context> context(new Context(this, GetDefaultIsolate())); scoped_ptr<Context> context(
new Context(this, g_isolate_factory.Get().GetSharedIsolate()));
int rv = context->InitV8(script_data); int rv = context->InitV8(script_data);
if (rv == OK) if (rv == OK)
context_.reset(context.release()); context_.reset(context.release());
return rv; return rv;
} }
// static
void ProxyResolverV8::EnsureIsolateCreated() {
if (g_proxy_resolver_isolate_)
return;
gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
gin::ArrayBufferAllocator::SharedInstance());
g_proxy_resolver_isolate_ = new gin::IsolateHolder;
ANNOTATE_LEAKING_OBJECT_PTR(g_proxy_resolver_isolate_);
}
// static
v8::Isolate* ProxyResolverV8::GetDefaultIsolate() {
DCHECK(g_proxy_resolver_isolate_)
<< "Must call ProxyResolverV8::EnsureIsolateCreated() first";
return g_proxy_resolver_isolate_->isolate();
}
gin::IsolateHolder* ProxyResolverV8::g_proxy_resolver_isolate_ = NULL;
// static // static
size_t ProxyResolverV8::GetTotalHeapSize() { size_t ProxyResolverV8::GetTotalHeapSize() {
if (!g_proxy_resolver_isolate_) v8::Isolate* isolate =
g_isolate_factory.Get().GetSharedIsolateWithoutCreating();
if (!isolate)
return 0; return 0;
v8::Locker locked(g_proxy_resolver_isolate_->isolate()); v8::Locker locked(isolate);
v8::Isolate::Scope isolate_scope(g_proxy_resolver_isolate_->isolate()); v8::Isolate::Scope isolate_scope(isolate);
v8::HeapStatistics heap_statistics; v8::HeapStatistics heap_statistics;
g_proxy_resolver_isolate_->isolate()->GetHeapStatistics(&heap_statistics); isolate->GetHeapStatistics(&heap_statistics);
return heap_statistics.total_heap_size(); return heap_statistics.total_heap_size();
} }
// static // static
size_t ProxyResolverV8::GetUsedHeapSize() { size_t ProxyResolverV8::GetUsedHeapSize() {
if (!g_proxy_resolver_isolate_) v8::Isolate* isolate =
g_isolate_factory.Get().GetSharedIsolateWithoutCreating();
if (!isolate)
return 0; return 0;
v8::Locker locked(g_proxy_resolver_isolate_->isolate()); v8::Locker locked(isolate);
v8::Isolate::Scope isolate_scope(g_proxy_resolver_isolate_->isolate()); v8::Isolate::Scope isolate_scope(isolate);
v8::HeapStatistics heap_statistics; v8::HeapStatistics heap_statistics;
g_proxy_resolver_isolate_->isolate()->GetHeapStatistics(&heap_statistics); isolate->GetHeapStatistics(&heap_statistics);
return heap_statistics.used_heap_size(); return heap_statistics.used_heap_size();
} }
......
...@@ -10,35 +10,9 @@ ...@@ -10,35 +10,9 @@
#include "net/base/net_export.h" #include "net/base/net_export.h"
#include "net/proxy/proxy_resolver.h" #include "net/proxy/proxy_resolver.h"
namespace gin {
class IsolateHolder;
} // namespace gin
namespace v8 {
class HeapStatistics;
class Isolate;
} // namespace v8
namespace net { namespace net {
// Implementation of ProxyResolver that uses V8 to evaluate PAC scripts. // Implementation of ProxyResolver that uses V8 to evaluate PAC scripts.
//
// ----------------------------------------------------------------------------
// !!! Important note on threading model:
// ----------------------------------------------------------------------------
// There can be only one instance of V8 running at a time. To enforce this
// constraint, ProxyResolverV8 holds a v8::Locker during execution. Therefore
// it is OK to run multiple instances of ProxyResolverV8 on different threads,
// since only one will be running inside V8 at a time.
//
// It is important that *ALL* instances of V8 in the process be using
// v8::Locker. If not there can be race conditions between the non-locked V8
// instances and the locked V8 instances used by ProxyResolverV8 (assuming they
// run on different threads).
//
// This is the case with the V8 instance used by chromium's renderer -- it runs
// on a different thread from ProxyResolver (renderer thread vs PAC thread),
// and does not use locking since it expects to be alone.
class NET_EXPORT_PRIVATE ProxyResolverV8 : public ProxyResolver { class NET_EXPORT_PRIVATE ProxyResolverV8 : public ProxyResolver {
public: public:
// Interface for the javascript bindings. // Interface for the javascript bindings.
...@@ -93,21 +67,12 @@ class NET_EXPORT_PRIVATE ProxyResolverV8 : public ProxyResolver { ...@@ -93,21 +67,12 @@ class NET_EXPORT_PRIVATE ProxyResolverV8 : public ProxyResolver {
int SetPacScript(const scoped_refptr<ProxyResolverScriptData>& script_data, int SetPacScript(const scoped_refptr<ProxyResolverScriptData>& script_data,
const net::CompletionCallback& /*callback*/) override; const net::CompletionCallback& /*callback*/) override;
// Create an isolate to use for the proxy resolver. If the embedder invokes
// this method multiple times, it must be invoked in a thread safe manner,
// e.g. always from the same thread.
static void EnsureIsolateCreated();
static v8::Isolate* GetDefaultIsolate();
// Get total/ued heap memory usage of all v8 instances used by the proxy // Get total/ued heap memory usage of all v8 instances used by the proxy
// resolver. // resolver.
static size_t GetTotalHeapSize(); static size_t GetTotalHeapSize();
static size_t GetUsedHeapSize(); static size_t GetUsedHeapSize();
private: private:
static gin::IsolateHolder* g_proxy_resolver_isolate_;
// Context holds the Javascript state for the most recently loaded PAC // Context holds the Javascript state for the most recently loaded PAC
// script. It corresponds with the data from the last call to // script. It corresponds with the data from the last call to
// SetPacScript(). // SetPacScript().
......
...@@ -19,14 +19,6 @@ ...@@ -19,14 +19,6 @@
#include "url/android/url_jni_registrar.h" #include "url/android/url_jni_registrar.h"
#endif #endif
#if !defined(OS_IOS)
#include "net/proxy/proxy_resolver_v8.h"
#endif
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
#include "gin/public/isolate_holder.h"
#endif
#if !defined(OS_ANDROID) && !defined(OS_IOS) #if !defined(OS_ANDROID) && !defined(OS_IOS)
#include "third_party/mojo/src/mojo/edk/embedder/test_embedder.h" #include "third_party/mojo/src/mojo/edk/embedder/test_embedder.h"
#endif #endif
...@@ -65,14 +57,6 @@ int main(int argc, char** argv) { ...@@ -65,14 +57,6 @@ int main(int argc, char** argv) {
// single-threaded. // single-threaded.
net::EnableSSLServerSockets(); net::EnableSSLServerSockets();
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
gin::IsolateHolder::LoadV8Snapshot();
#endif
#if !defined(OS_IOS)
net::ProxyResolverV8::EnsureIsolateCreated();
#endif
#if !defined(OS_ANDROID) && !defined(OS_IOS) #if !defined(OS_ANDROID) && !defined(OS_IOS)
mojo::embedder::test::InitWithSimplePlatformSupport(); mojo::embedder::test::InitWithSimplePlatformSupport();
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment