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/per_isolate_data.h"
14 #include "gin/public/wrapper_info.h"
15 #include "gin/runner.h"
20 using v8::FunctionTemplate
;
24 using v8::ObjectTemplate
;
32 struct PendingModule
{
37 std::vector
<std::string
> dependencies
;
38 Persistent
<Value
> factory
;
41 PendingModule::PendingModule() {
44 PendingModule::~PendingModule() {
50 void Define(const v8::FunctionCallbackInfo
<Value
>& info
) {
54 return args
.ThrowTypeError("At least one argument is required.");
57 std::vector
<std::string
> dependencies
;
58 v8::Handle
<Value
> factory
;
60 if (args
.PeekNext()->IsString())
62 if (args
.PeekNext()->IsArray())
63 args
.GetNext(&dependencies
);
64 if (!args
.GetNext(&factory
))
65 return args
.ThrowError();
67 scoped_ptr
<PendingModule
> pending(new PendingModule
);
69 pending
->dependencies
= dependencies
;
70 pending
->factory
.Reset(args
.isolate(), factory
);
72 ModuleRegistry
* registry
=
73 ModuleRegistry::From(args
.isolate()->GetCurrentContext());
74 registry
->AddPendingModule(args
.isolate(), pending
.Pass());
77 WrapperInfo g_wrapper_info
= { kEmbedderNativeGin
};
79 Local
<FunctionTemplate
> GetDefineTemplate(Isolate
* isolate
) {
80 PerIsolateData
* data
= PerIsolateData::From(isolate
);
81 Local
<FunctionTemplate
> templ
= data
->GetFunctionTemplate(
83 if (templ
.IsEmpty()) {
84 templ
= FunctionTemplate::New(Define
);
85 data
->SetFunctionTemplate(&g_wrapper_info
, templ
);
90 v8::Handle
<String
> GetHiddenValueKey(Isolate
* isolate
) {
91 return StringToSymbol(isolate
, "::gin::ModuleRegistry");
96 ModuleRegistry::ModuleRegistry(Isolate
* isolate
)
97 : modules_(isolate
, Object::New()) {
100 ModuleRegistry::~ModuleRegistry() {
104 void ModuleRegistry::RegisterGlobals(Isolate
* isolate
,
105 v8::Handle
<ObjectTemplate
> templ
) {
106 templ
->Set(StringToSymbol(isolate
, "define"), GetDefineTemplate(isolate
));
109 ModuleRegistry
* ModuleRegistry::From(v8::Handle
<Context
> context
) {
110 Isolate
* isolate
= context
->GetIsolate();
111 v8::Handle
<String
> key
= GetHiddenValueKey(isolate
);
112 v8::Handle
<Value
> value
= context
->Global()->GetHiddenValue(key
);
113 v8::Handle
<External
> external
;
114 if (value
.IsEmpty() || !ConvertFromV8(isolate
, value
, &external
)) {
115 PerContextData
* data
= PerContextData::From(context
);
118 ModuleRegistry
* registry
= new ModuleRegistry(isolate
);
119 context
->Global()->SetHiddenValue(key
, External::New(isolate
, registry
));
120 data
->AddSupplement(scoped_ptr
<ContextSupplement
>(registry
));
123 return static_cast<ModuleRegistry
*>(external
->Value());
126 void ModuleRegistry::AddBuiltinModule(Isolate
* isolate
,
127 const std::string
& id
,
128 v8::Handle
<ObjectTemplate
> templ
) {
130 RegisterModule(isolate
, id
, templ
->NewInstance());
133 void ModuleRegistry::AddPendingModule(Isolate
* isolate
,
134 scoped_ptr
<PendingModule
> pending
) {
135 AttemptToLoad(isolate
, pending
.Pass());
138 void ModuleRegistry::RegisterModule(Isolate
* isolate
,
139 const std::string
& id
,
140 v8::Handle
<Value
> module
) {
141 if (id
.empty() || module
.IsEmpty())
144 unsatisfied_dependencies_
.erase(id
);
145 available_modules_
.insert(id
);
146 v8::Handle
<Object
> modules
= Local
<Object
>::New(isolate
, modules_
);
147 modules
->Set(StringToSymbol(isolate
, id
), module
);
150 void ModuleRegistry::Detach(v8::Handle
<Context
> context
) {
151 context
->Global()->SetHiddenValue(GetHiddenValueKey(context
->GetIsolate()),
152 v8::Handle
<Value
>());
155 bool ModuleRegistry::CheckDependencies(PendingModule
* pending
) {
156 size_t num_missing_dependencies
= 0;
157 size_t len
= pending
->dependencies
.size();
158 for (size_t i
= 0; i
< len
; ++i
) {
159 const std::string
& dependency
= pending
->dependencies
[i
];
160 if (available_modules_
.count(dependency
))
162 unsatisfied_dependencies_
.insert(dependency
);
163 num_missing_dependencies
++;
165 return num_missing_dependencies
== 0;
168 void ModuleRegistry::Load(Isolate
* isolate
, scoped_ptr
<PendingModule
> pending
) {
169 if (!pending
->id
.empty() && available_modules_
.count(pending
->id
))
170 return; // We've already loaded this module.
172 v8::Handle
<Object
> modules
= Local
<Object
>::New(isolate
, modules_
);
173 uint32_t argc
= static_cast<uint32_t>(pending
->dependencies
.size());
174 std::vector
<v8::Handle
<Value
> > argv(argc
);
175 for (uint32_t i
= 0; i
< argc
; ++i
) {
176 v8::Handle
<String
> key
= StringToSymbol(isolate
, pending
->dependencies
[i
]);
177 DCHECK(modules
->HasOwnProperty(key
));
178 argv
[i
] = modules
->Get(key
);
181 v8::Handle
<Value
> module
= Local
<Value
>::New(isolate
, pending
->factory
);
183 v8::Handle
<Function
> factory
;
184 if (ConvertFromV8(isolate
, module
, &factory
)) {
185 PerContextData
* data
= PerContextData::From(isolate
->GetCurrentContext());
186 Runner
* runner
= data
->runner();
187 module
= runner
->Call(factory
, runner
->global(), argc
, argv
.data());
188 if (pending
->id
.empty())
189 ConvertFromV8(isolate
, factory
->GetScriptOrigin().ResourceName(),
193 RegisterModule(isolate
, pending
->id
, module
);
196 bool ModuleRegistry::AttemptToLoad(Isolate
* isolate
,
197 scoped_ptr
<PendingModule
> pending
) {
198 if (!CheckDependencies(pending
.get())) {
199 pending_modules_
.push_back(pending
.release());
202 Load(isolate
, pending
.Pass());
206 void ModuleRegistry::AttemptToLoadMoreModules(Isolate
* isolate
) {
207 bool keep_trying
= true;
208 while (keep_trying
) {
210 PendingModuleVector pending_modules
;
211 pending_modules
.swap(pending_modules_
);
212 for (size_t i
= 0; i
< pending_modules
.size(); ++i
) {
213 scoped_ptr
<PendingModule
> pending(pending_modules
[i
]);
214 pending_modules
[i
] = NULL
;
215 if (AttemptToLoad(isolate
, pending
.Pass()))