Chromium Code Reviews| 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; |
|
jochen (gone - plz use gerrit)
2013/11/18 12:46:05
is there a reason why you use all those names? I f
abarth-chromium
2013/11/18 15:33:06
If we don't do this, there are a bunch of lines th
|
| 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)); |
|
jochen (gone - plz use gerrit)
2013/11/18 12:46:05
I just changed this API to require isolate as firs
abarth-chromium
2013/11/18 15:33:06
Nice! It was odd that it didn't before. Fixed.
|
| 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; |
| + } |
| } |
| } |