| Index: gin/modules/module_registry.cc
|
| diff --git a/gin/modules/module_registry.cc b/gin/modules/module_registry.cc
|
| index aad2135b0e1114aa634366d7da39e91831946bfe..1ee8e3cbe8fb92aa36f4852f7d7d92ffe410a63b 100644
|
| --- a/gin/modules/module_registry.cc
|
| +++ b/gin/modules/module_registry.cc
|
| @@ -12,10 +12,20 @@
|
| #include "gin/per_isolate_data.h"
|
| #include "gin/wrapper_info.h"
|
|
|
| +using v8::Context;
|
| using v8::External;
|
| +using v8::Function;
|
| +using v8::FunctionCallbackInfo;
|
| +using v8::FunctionTemplate;
|
| using v8::Handle;
|
| using v8::Isolate;
|
| +using v8::Local;
|
| +using v8::Object;
|
| using v8::ObjectTemplate;
|
| +using v8::Persistent;
|
| +using v8::StackTrace;
|
| +using v8::String;
|
| +using v8::Value;
|
|
|
| namespace gin {
|
|
|
| @@ -25,12 +35,19 @@ struct PendingModule {
|
|
|
| std::string id;
|
| std::vector<std::string> dependencies;
|
| - v8::Persistent<v8::Value> factory;
|
| + Persistent<Value> factory;
|
| };
|
|
|
| +PendingModule::PendingModule() {
|
| +}
|
| +
|
| +PendingModule::~PendingModule() {
|
| + factory.Reset();
|
| +}
|
| +
|
| namespace {
|
|
|
| -void Define(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
| +void Define(const FunctionCallbackInfo<Value>& info) {
|
| Arguments args(info);
|
|
|
| if (!info.Length())
|
| @@ -38,7 +55,7 @@ void Define(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
|
|
| std::string id;
|
| std::vector<std::string> dependencies;
|
| - Handle<v8::Value> factory;
|
| + Handle<Value> factory;
|
|
|
| if (args.PeekNext()->IsString())
|
| args.GetNext(&id);
|
| @@ -47,141 +64,165 @@ void Define(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
| if (!args.GetNext(&factory))
|
| return args.ThrowError();
|
|
|
| - PendingModule* pending = new PendingModule;
|
| + scoped_ptr<PendingModule> pending(new PendingModule);
|
| pending->id = id;
|
| pending->dependencies = dependencies;
|
| pending->factory.Reset(args.isolate(), factory);
|
|
|
| ModuleRegistry* registry =
|
| ModuleRegistry::From(args.isolate()->GetCurrentContext());
|
| - registry->AddPendingModule(args.isolate(), pending);
|
| + registry->AddPendingModule(args.isolate(), pending.Pass());
|
| }
|
|
|
| WrapperInfo g_wrapper_info = {};
|
|
|
| -v8::Local<v8::FunctionTemplate> GetDefineTemplate(v8::Isolate* isolate) {
|
| +Local<FunctionTemplate> GetDefineTemplate(Isolate* isolate) {
|
| PerIsolateData* data = PerIsolateData::From(isolate);
|
| - v8::Local<v8::FunctionTemplate> templ = data->GetFunctionTemplate(
|
| + Local<FunctionTemplate> templ = data->GetFunctionTemplate(
|
| &g_wrapper_info);
|
| if (templ.IsEmpty()) {
|
| - templ = v8::FunctionTemplate::New(Define);
|
| + templ = FunctionTemplate::New(Define);
|
| data->SetFunctionTemplate(&g_wrapper_info, templ);
|
| }
|
| return templ;
|
| }
|
|
|
| -Handle<v8::String> GetHiddenValueKey(v8::Isolate* isolate) {
|
| +Handle<String> GetHiddenValueKey(Isolate* isolate) {
|
| return StringToSymbol(isolate, "::gin::ModuleRegistry");
|
| }
|
|
|
| -} // namespace
|
| -
|
| -
|
| -PendingModule::PendingModule() {
|
| +std::string GetImplicitModuleName(const std::string& explicit_name) {
|
| + if (!explicit_name.empty())
|
| + return explicit_name;
|
| + std::string implicit_name;
|
| + Handle<StackTrace> trace = StackTrace::CurrentStackTrace(1);
|
| + Handle<String> script_name = trace->GetFrame(0)->GetScriptName();
|
| + if (!script_name.IsEmpty())
|
| + ConvertFromV8(script_name, &implicit_name);
|
| + return implicit_name;
|
| }
|
|
|
| -PendingModule::~PendingModule() {
|
| - factory.Reset();
|
| -}
|
| +} // namespace
|
|
|
| -ModuleRegistry::ModuleRegistry(v8::Isolate* isolate)
|
| - : modules_(isolate, v8::Object::New()) {
|
| +ModuleRegistry::ModuleRegistry(Isolate* isolate)
|
| + : modules_(isolate, Object::New()) {
|
| }
|
|
|
| ModuleRegistry::~ModuleRegistry() {
|
| - for (PendingModuleList::iterator it = pending_modules_.begin();
|
| - it != pending_modules_.end(); ++it) {
|
| - delete *it;
|
| - }
|
| modules_.Reset();
|
| }
|
|
|
| -void ModuleRegistry::RegisterGlobals(v8::Isolate* isolate,
|
| - Handle<v8::ObjectTemplate> templ) {
|
| +void ModuleRegistry::RegisterGlobals(Isolate* isolate,
|
| + Handle<ObjectTemplate> templ) {
|
| templ->Set(StringToSymbol(isolate, "define"), GetDefineTemplate(isolate));
|
| }
|
|
|
| -void ModuleRegistry::AddBuiltinModule(Isolate* isolate,
|
| - const std::string& id,
|
| - Handle<ObjectTemplate> templ) {
|
| - DCHECK(!id.empty());
|
| - Handle<v8::Object> modules = v8::Local<v8::Object>::New(isolate, modules_);
|
| - modules->Set(StringToV8(isolate, id), templ->NewInstance());
|
| -}
|
| -
|
| -ModuleRegistry* ModuleRegistry::From(Handle<v8::Context> context) {
|
| - v8::Isolate* isolate = context->GetIsolate();
|
| - Handle<v8::String> key = GetHiddenValueKey(isolate);
|
| - Handle<v8::Value> value = context->Global()->GetHiddenValue(key);
|
| - Handle<v8::External> external;
|
| +ModuleRegistry* ModuleRegistry::From(Handle<Context> context) {
|
| + Isolate* isolate = context->GetIsolate();
|
| + Handle<String> key = GetHiddenValueKey(isolate);
|
| + Handle<Value> value = context->Global()->GetHiddenValue(key);
|
| + Handle<External> external;
|
| if (value.IsEmpty() || !ConvertFromV8(value, &external)) {
|
| PerContextData* data = PerContextData::From(context);
|
| if (!data)
|
| return NULL;
|
| ModuleRegistry* registry = new ModuleRegistry(isolate);
|
| - context->Global()->SetHiddenValue(key, v8::External::New(registry));
|
| + context->Global()->SetHiddenValue(key, External::New(registry));
|
| data->AddSupplement(scoped_ptr<ContextSupplement>(registry));
|
| return registry;
|
| }
|
| return static_cast<ModuleRegistry*>(external->Value());
|
| }
|
|
|
| -void ModuleRegistry::AddPendingModule(v8::Isolate* isolate,
|
| - PendingModule* pending) {
|
| - if (AttemptToLoad(isolate, pending))
|
| - AttemptToLoadPendingModules(isolate);
|
| +void ModuleRegistry::AddBuiltinModule(Isolate* isolate,
|
| + const std::string& id,
|
| + Handle<ObjectTemplate> templ) {
|
| + DCHECK(!id.empty());
|
| + RegisterModule(isolate, id, templ->NewInstance());
|
| }
|
|
|
| -void ModuleRegistry::Detach(Handle<v8::Context> context) {
|
| - context->Global()->SetHiddenValue(GetHiddenValueKey(context->GetIsolate()),
|
| - Handle<v8::Value>());
|
| +void ModuleRegistry::AddPendingModule(Isolate* isolate,
|
| + scoped_ptr<PendingModule> pending) {
|
| + AttemptToLoad(isolate, pending.Pass());
|
| }
|
|
|
| -bool ModuleRegistry::AttemptToLoad(v8::Isolate* isolate,
|
| - PendingModule* pending) {
|
| - Handle<v8::Object> modules = v8::Local<v8::Object>::New(isolate, modules_);
|
| - Handle<v8::String> key = StringToV8(isolate, pending->id);
|
| +void ModuleRegistry::RegisterModule(Isolate* isolate,
|
| + const std::string& id,
|
| + Handle<Value> module) {
|
| + if (id.empty() || module.IsEmpty())
|
| + return;
|
| +
|
| + unsatisfied_dependencies_.erase(id);
|
| + available_modules_.insert(id);
|
| + Handle<Object> modules = Local<Object>::New(isolate, modules_);
|
| + modules->Set(StringToSymbol(isolate, id), module);
|
| +}
|
|
|
| - if (!pending->id.empty() && modules->HasOwnProperty(key)) {
|
| - // We've already loaded a module with this name. Ignore the new one.
|
| - delete pending;
|
| - return true;
|
| +void ModuleRegistry::Detach(Handle<Context> context) {
|
| + context->Global()->SetHiddenValue(GetHiddenValueKey(context->GetIsolate()),
|
| + Handle<Value>());
|
| +}
|
| +
|
| +bool ModuleRegistry::CheckDependencies(PendingModule* pending) {
|
| + size_t num_missing_dependencies = 0;
|
| + size_t len = pending->dependencies.size();
|
| + for (size_t i = 0; i < len; ++i) {
|
| + const std::string& dependency = pending->dependencies[i];
|
| + if (available_modules_.count(dependency))
|
| + continue;
|
| + unsatisfied_dependencies_.insert(dependency);
|
| + num_missing_dependencies++;
|
| }
|
| + return num_missing_dependencies == 0;
|
| +}
|
| +
|
| +void ModuleRegistry::Load(Isolate* isolate, scoped_ptr<PendingModule> pending) {
|
| + if (!pending->id.empty() && available_modules_.count(pending->id))
|
| + return; // We've already loaded this module.
|
|
|
| + Handle<Object> modules = Local<Object>::New(isolate, modules_);
|
| size_t argc = pending->dependencies.size();
|
| - std::vector<Handle<v8::Value> > argv(argc);
|
| + std::vector<Handle<Value> > argv(argc);
|
| for (size_t i = 0; i < argc; ++i) {
|
| - Handle<v8::String> key = StringToV8(isolate, pending->dependencies[i]);
|
| - if (!modules->HasOwnProperty(key)) {
|
| - pending_modules_.push_back(pending);
|
| - return false;
|
| - }
|
| + Handle<String> key = StringToSymbol(isolate, pending->dependencies[i]);
|
| + DCHECK(modules->HasOwnProperty(key));
|
| argv[i] = modules->Get(key);
|
| }
|
|
|
| - Handle<v8::Value> module = v8::Local<v8::Value>::New(
|
| - isolate, pending->factory);
|
| + Handle<Value> module = Local<Value>::New(isolate, pending->factory);
|
|
|
| - Handle<v8::Function> factory;
|
| + Handle<Function> factory;
|
| if (ConvertFromV8(module, &factory)) {
|
| - v8::Handle<v8::Object> global = isolate->GetCurrentContext()->Global();
|
| + Handle<Object> global = isolate->GetCurrentContext()->Global();
|
| module = factory->Call(global, argc, argv.data());
|
| // TODO(abarth): What should we do with exceptions?
|
| }
|
|
|
| - if (!pending->id.empty() && !module.IsEmpty())
|
| - modules->Set(key, module);
|
| + RegisterModule(isolate, GetImplicitModuleName(pending->id), module);
|
| +}
|
|
|
| - delete pending;
|
| +bool ModuleRegistry::AttemptToLoad(Isolate* isolate,
|
| + scoped_ptr<PendingModule> pending) {
|
| + if (!CheckDependencies(pending.get())) {
|
| + pending_modules_.push_back(pending.release());
|
| + return false;
|
| + }
|
| + Load(isolate, pending.Pass());
|
| return true;
|
| }
|
|
|
| -void ModuleRegistry::AttemptToLoadPendingModules(v8::Isolate* isolate) {
|
| - PendingModuleList pending_modules;
|
| - pending_modules.swap(pending_modules_);
|
| - for (PendingModuleList::iterator it = pending_modules.begin();
|
| - it != pending_modules.end(); ++it) {
|
| - AttemptToLoad(isolate, *it);
|
| +void ModuleRegistry::AttemptToLoadMoreModules(Isolate* isolate) {
|
| + bool keep_trying = true;
|
| + while (keep_trying) {
|
| + keep_trying = false;
|
| + PendingModuleVector pending_modules;
|
| + pending_modules.swap(pending_modules_);
|
| + for (size_t i = 0; i < pending_modules.size(); ++i) {
|
| + scoped_ptr<PendingModule> pending(pending_modules[i]);
|
| + pending_modules[i] = NULL;
|
| + if (AttemptToLoad(isolate, pending.Pass()))
|
| + keep_trying = true;
|
| + }
|
| }
|
| }
|
|
|
|
|