Index: gin/modules/module_registry.cc |
diff --git a/gin/modules/module_registry.cc b/gin/modules/module_registry.cc |
index 78a102c0a6da5186e83987ecef41716181d4c8f0..6ac25590a42228cc6f14ff9ad894251c2621a9f1 100644 |
--- a/gin/modules/module_registry.cc |
+++ b/gin/modules/module_registry.cc |
@@ -4,18 +4,29 @@ |
#include "gin/modules/module_registry.h" |
-#include <assert.h> |
#include <string> |
#include <vector> |
+ |
+#include "base/logging.h" |
#include "gin/arguments.h" |
#include "gin/converter.h" |
#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 +36,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 +56,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 +65,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) { |
- assert(!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)); |
- data->AddSupplement(registry); |
+ context->Global()->SetHiddenValue(key, External::New(isolate, 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()); |
+} |
+ |
+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); |
} |
-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::Detach(Handle<Context> context) { |
+ context->Global()->SetHiddenValue(GetHiddenValueKey(context->GetIsolate()), |
+ Handle<Value>()); |
+} |
- if (!pending->id.empty() && modules->HasOwnProperty(key)) { |
- // We've already loaded a module with this name. Ignore the new one. |
- delete pending; |
- return true; |
+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; |
+ } |
} |
} |