1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "gin/modules/module_registry.h"
10 #include "base/logging.h"
11 #include "gin/arguments.h"
12 #include "gin/converter.h"
13 #include "gin/modules/module_registry_observer.h"
14 #include "gin/per_context_data.h"
15 #include "gin/per_isolate_data.h"
16 #include "gin/public/wrapper_info.h"
17 #include "gin/runner.h"
22 using v8::FunctionTemplate
;
26 using v8::ObjectTemplate
;
34 struct PendingModule
{
39 std::vector
<std::string
> dependencies
;
40 Persistent
<Value
> factory
;
43 PendingModule::PendingModule() {
46 PendingModule::~PendingModule() {
52 // Key for base::SupportsUserData::Data.
53 const char kModuleRegistryKey
[] = "ModuleRegistry";
55 struct ModuleRegistryData
: public base::SupportsUserData::Data
{
56 scoped_ptr
<ModuleRegistry
> registry
;
59 void Define(const v8::FunctionCallbackInfo
<Value
>& info
) {
63 return args
.ThrowTypeError("At least one argument is required.");
66 std::vector
<std::string
> dependencies
;
67 v8::Handle
<Value
> factory
;
69 if (args
.PeekNext()->IsString())
71 if (args
.PeekNext()->IsArray())
72 args
.GetNext(&dependencies
);
73 if (!args
.GetNext(&factory
))
74 return args
.ThrowError();
76 scoped_ptr
<PendingModule
> pending(new PendingModule
);
78 pending
->dependencies
= dependencies
;
79 pending
->factory
.Reset(args
.isolate(), factory
);
81 ModuleRegistry
* registry
=
82 ModuleRegistry::From(args
.isolate()->GetCurrentContext());
83 registry
->AddPendingModule(args
.isolate(), pending
.Pass());
86 WrapperInfo g_wrapper_info
= { kEmbedderNativeGin
};
88 Local
<FunctionTemplate
> GetDefineTemplate(Isolate
* isolate
) {
89 PerIsolateData
* data
= PerIsolateData::From(isolate
);
90 Local
<FunctionTemplate
> templ
= data
->GetFunctionTemplate(
92 if (templ
.IsEmpty()) {
93 templ
= FunctionTemplate::New(isolate
, Define
);
94 data
->SetFunctionTemplate(&g_wrapper_info
, templ
);
101 ModuleRegistry::ModuleRegistry(Isolate
* isolate
)
102 : modules_(isolate
, Object::New(isolate
)) {
105 ModuleRegistry::~ModuleRegistry() {
110 void ModuleRegistry::RegisterGlobals(Isolate
* isolate
,
111 v8::Handle
<ObjectTemplate
> templ
) {
112 templ
->Set(StringToSymbol(isolate
, "define"), GetDefineTemplate(isolate
));
116 void ModuleRegistry::InstallGlobals(v8::Isolate
* isolate
,
117 v8::Handle
<v8::Object
> obj
) {
118 obj
->Set(StringToSymbol(isolate
, "define"),
119 GetDefineTemplate(isolate
)->GetFunction());
123 ModuleRegistry
* ModuleRegistry::From(v8::Handle
<Context
> context
) {
124 PerContextData
* data
= PerContextData::From(context
);
128 ModuleRegistryData
* registry_data
= static_cast<ModuleRegistryData
*>(
129 data
->GetUserData(kModuleRegistryKey
));
130 if (!registry_data
) {
131 // PerContextData takes ownership of ModuleRegistryData.
132 registry_data
= new ModuleRegistryData
;
133 registry_data
->registry
.reset(new ModuleRegistry(context
->GetIsolate()));
134 data
->SetUserData(kModuleRegistryKey
, registry_data
);
136 return registry_data
->registry
.get();
139 void ModuleRegistry::AddObserver(ModuleRegistryObserver
* observer
) {
140 observer_list_
.AddObserver(observer
);
143 void ModuleRegistry::RemoveObserver(ModuleRegistryObserver
* observer
) {
144 observer_list_
.RemoveObserver(observer
);
147 void ModuleRegistry::AddBuiltinModule(Isolate
* isolate
, const std::string
& id
,
148 v8::Handle
<Value
> module
) {
150 RegisterModule(isolate
, id
, module
);
153 void ModuleRegistry::AddPendingModule(Isolate
* isolate
,
154 scoped_ptr
<PendingModule
> pending
) {
155 const std::string pending_id
= pending
->id
;
156 const std::vector
<std::string
> pending_dependencies
= pending
->dependencies
;
157 AttemptToLoad(isolate
, pending
.Pass());
158 FOR_EACH_OBSERVER(ModuleRegistryObserver
, observer_list_
,
159 OnDidAddPendingModule(pending_id
, pending_dependencies
));
162 void ModuleRegistry::LoadModule(Isolate
* isolate
,
163 const std::string
& id
,
164 LoadModuleCallback callback
) {
165 if (available_modules_
.find(id
) != available_modules_
.end()) {
166 // Should we call the callback asynchronously?
167 callback
.Run(GetModule(isolate
, id
));
170 waiting_callbacks_
.insert(std::make_pair(id
, callback
));
172 for (size_t i
= 0; i
< pending_modules_
.size(); ++i
) {
173 if (pending_modules_
[i
]->id
== id
)
177 unsatisfied_dependencies_
.insert(id
);
180 void ModuleRegistry::RegisterModule(Isolate
* isolate
,
181 const std::string
& id
,
182 v8::Handle
<Value
> module
) {
183 if (id
.empty() || module
.IsEmpty())
186 unsatisfied_dependencies_
.erase(id
);
187 available_modules_
.insert(id
);
188 v8::Handle
<Object
> modules
= Local
<Object
>::New(isolate
, modules_
);
189 modules
->Set(StringToSymbol(isolate
, id
), module
);
191 std::pair
<LoadModuleCallbackMap::iterator
, LoadModuleCallbackMap::iterator
>
192 range
= waiting_callbacks_
.equal_range(id
);
193 std::vector
<LoadModuleCallback
> callbacks
;
194 callbacks
.reserve(waiting_callbacks_
.count(id
));
195 for (LoadModuleCallbackMap::iterator it
= range
.first
; it
!= range
.second
;
197 callbacks
.push_back(it
->second
);
199 waiting_callbacks_
.erase(range
.first
, range
.second
);
200 for (std::vector
<LoadModuleCallback
>::iterator it
= callbacks
.begin();
201 it
!= callbacks
.end();
203 // Should we call the callback asynchronously?
208 bool ModuleRegistry::CheckDependencies(PendingModule
* pending
) {
209 size_t num_missing_dependencies
= 0;
210 size_t len
= pending
->dependencies
.size();
211 for (size_t i
= 0; i
< len
; ++i
) {
212 const std::string
& dependency
= pending
->dependencies
[i
];
213 if (available_modules_
.count(dependency
))
215 unsatisfied_dependencies_
.insert(dependency
);
216 num_missing_dependencies
++;
218 return num_missing_dependencies
== 0;
221 void ModuleRegistry::Load(Isolate
* isolate
, scoped_ptr
<PendingModule
> pending
) {
222 if (!pending
->id
.empty() && available_modules_
.count(pending
->id
))
223 return; // We've already loaded this module.
225 uint32_t argc
= static_cast<uint32_t>(pending
->dependencies
.size());
226 std::vector
<v8::Handle
<Value
> > argv(argc
);
227 for (uint32_t i
= 0; i
< argc
; ++i
)
228 argv
[i
] = GetModule(isolate
, pending
->dependencies
[i
]);
230 v8::Handle
<Value
> module
= Local
<Value
>::New(isolate
, pending
->factory
);
232 v8::Handle
<Function
> factory
;
233 if (ConvertFromV8(isolate
, module
, &factory
)) {
234 PerContextData
* data
= PerContextData::From(isolate
->GetCurrentContext());
235 Runner
* runner
= data
->runner();
236 module
= runner
->Call(factory
, runner
->global(), argc
,
237 argv
.empty() ? NULL
: &argv
.front());
238 if (pending
->id
.empty())
239 ConvertFromV8(isolate
, factory
->GetScriptOrigin().ResourceName(),
243 RegisterModule(isolate
, pending
->id
, module
);
246 bool ModuleRegistry::AttemptToLoad(Isolate
* isolate
,
247 scoped_ptr
<PendingModule
> pending
) {
248 if (!CheckDependencies(pending
.get())) {
249 pending_modules_
.push_back(pending
.release());
252 Load(isolate
, pending
.Pass());
256 v8::Handle
<v8::Value
> ModuleRegistry::GetModule(v8::Isolate
* isolate
,
257 const std::string
& id
) {
258 v8::Handle
<Object
> modules
= Local
<Object
>::New(isolate
, modules_
);
259 v8::Handle
<String
> key
= StringToSymbol(isolate
, id
);
260 DCHECK(modules
->HasOwnProperty(key
));
261 return modules
->Get(key
);
264 void ModuleRegistry::AttemptToLoadMoreModules(Isolate
* isolate
) {
265 bool keep_trying
= true;
266 while (keep_trying
) {
268 PendingModuleVector pending_modules
;
269 pending_modules
.swap(pending_modules_
);
270 for (size_t i
= 0; i
< pending_modules
.size(); ++i
) {
271 scoped_ptr
<PendingModule
> pending(pending_modules
[i
]);
272 pending_modules
[i
] = NULL
;
273 if (AttemptToLoad(isolate
, pending
.Pass()))