blob: 46fddf5d5710378a895a82695d6708fe31566701 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "tonic/dart_script_loader_sync.h"
#include "base/callback.h"
#include "base/run_loop.h"
#include "base/trace_event/trace_event.h"
#include "mojo/message_pump/message_pump_mojo.h"
#include "tonic/dart_api_scope.h"
#include "tonic/dart_converter.h"
#include "tonic/dart_dependency_catcher.h"
#include "tonic/dart_error.h"
#include "tonic/dart_isolate_scope.h"
#include "tonic/dart_library_loader.h"
#include "tonic/dart_library_provider.h"
#include "tonic/dart_state.h"
namespace tonic {
static void BlockWaitingForDependencies(
tonic::DartLibraryLoader* loader,
const std::unordered_set<tonic::DartDependency*>& dependencies) {
{
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
base::MessageLoop::current()->task_runner();
base::RunLoop run_loop;
task_runner->PostTask(
FROM_HERE,
base::Bind(
&tonic::DartLibraryLoader::WaitForDependencies,
base::Unretained(loader),
dependencies,
base::Bind(
base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask),
task_runner.get(), FROM_HERE,
run_loop.QuitClosure())));
run_loop.Run();
}
}
static void InnerLoadScript(
const std::string& script_uri,
tonic::DartLibraryProvider* library_provider) {
// When spawning isolates, Dart expects the script loading to be completed
// before returning from the isolate creation callback. The mojo dart
// controller also expects the isolate to be finished loading a script
// before the isolate creation callback returns.
// We block here by creating a nested message pump and waiting for the load
// to complete.
DCHECK(base::MessageLoop::current() != nullptr);
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
// Initiate the load.
auto dart_state = tonic::DartState::Current();
DCHECK(library_provider != nullptr);
tonic::DartLibraryLoader& loader = dart_state->library_loader();
loader.set_library_provider(library_provider);
std::unordered_set<tonic::DartDependency*> dependencies;
{
tonic::DartDependencyCatcher dependency_catcher(loader);
loader.LoadScript(script_uri);
// Copy dependencies before dependency_catcher goes out of scope.
dependencies = std::unordered_set<tonic::DartDependency*>(
dependency_catcher.dependencies());
}
// Run inner message loop.
BlockWaitingForDependencies(&loader, dependencies);
// Finalize loading.
tonic::LogIfError(Dart_FinalizeLoading(true));
}
void DartScriptLoaderSync::LoadScript(
const std::string& script_uri,
DartLibraryProvider* library_provider) {
if (base::MessageLoop::current() == nullptr) {
// Threads running on the Dart thread pool may not have a message loop,
// we rely on a message loop during loading. Create a temporary one
// here.
base::MessageLoop message_loop(mojo::common::MessagePumpMojo::Create());
InnerLoadScript(script_uri, library_provider);
} else {
// Thread has a message loop, use it.
InnerLoadScript(script_uri, library_provider);
}
}
} // namespace tonic