OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "gin/modules/module_registry.h" | |
6 | |
7 #include <assert.h> | |
8 #include <string> | |
9 #include <vector> | |
10 #include "gin/arguments.h" | |
11 #include "gin/converter.h" | |
12 #include "gin/per_isolate_data.h" | |
13 #include "gin/wrapper_info.h" | |
14 | |
15 using v8::Handle; | |
16 using v8::Isolate; | |
17 using v8::ObjectTemplate; | |
18 | |
19 namespace gin { | |
20 | |
21 struct PendingModule { | |
22 PendingModule(); | |
23 ~PendingModule(); | |
24 | |
25 std::string id; | |
26 std::vector<std::string> dependencies; | |
27 v8::Persistent<v8::Value> factory; | |
28 }; | |
29 | |
30 namespace { | |
31 | |
32 void Define(const v8::FunctionCallbackInfo<v8::Value>& info) { | |
33 Arguments args(info); | |
34 | |
35 if (!info.Length()) | |
36 return args.ThrowTypeError("At least one argument is required."); | |
37 | |
38 std::string id; | |
39 std::vector<std::string> dependencies; | |
40 Handle<v8::Value> factory; | |
41 | |
42 if (args.PeekNext()->IsString()) | |
43 args.GetNext(&id); | |
44 if (args.PeekNext()->IsArray()) | |
45 args.GetNext(&dependencies); | |
46 if (!args.GetNext(&factory)) | |
Aaron Boodman
2013/11/15 18:56:06
"Factory" seems like a weird name for the function
abarth-chromium
2013/11/15 19:13:37
In AMD, you can either supply a function or an obj
| |
47 return args.ThrowError(); | |
48 | |
49 PendingModule* pending = new PendingModule; | |
50 pending->id = id; | |
51 pending->dependencies = dependencies; | |
52 pending->factory.Reset(args.isolate(), factory); | |
53 | |
54 ModuleRegistry* registry = | |
55 ModuleRegistry::From(args.isolate()->GetCurrentContext()); | |
56 registry->AddPendingModule(args.isolate(), pending); | |
57 } | |
58 | |
59 WrapperInfo g_wrapper_info = {}; | |
60 | |
61 v8::Local<v8::FunctionTemplate> GetDefineTemplate(v8::Isolate* isolate) { | |
62 PerIsolateData* data = PerIsolateData::From(isolate); | |
63 v8::Local<v8::FunctionTemplate> templ = data->GetFunctionTemplate( | |
64 &g_wrapper_info); | |
65 if (templ.IsEmpty()) { | |
66 templ = v8::FunctionTemplate::New(Define); | |
67 templ->SetLength(3); | |
Aaron Boodman
2013/11/15 18:56:06
I don't think this is really necessary, fwiw.
abarth-chromium
2013/11/15 19:13:37
Ok, I'll remove it. It's visible in JavaScript, b
| |
68 data->SetFunctionTemplate(&g_wrapper_info, templ); | |
69 } | |
70 return templ; | |
71 } | |
72 | |
73 } // namespace gin | |
74 | |
75 | |
76 PendingModule::PendingModule() { | |
77 } | |
78 | |
79 PendingModule::~PendingModule() { | |
80 factory.Reset(); | |
81 } | |
82 | |
83 ModuleRegistry::ModuleRegistry(v8::Isolate* isolate) | |
84 : modules_(isolate, v8::Object::New()) { | |
85 } | |
86 | |
87 ModuleRegistry::~ModuleRegistry() { | |
88 for (PendingModuleList::iterator it = pending_modules_.begin(); | |
89 it != pending_modules_.end(); ++it) { | |
90 delete *it; | |
91 } | |
92 modules_.Reset(); | |
93 } | |
94 | |
95 void ModuleRegistry::RegisterGlobals(v8::Isolate* isolate, | |
96 Handle<v8::ObjectTemplate> templ) { | |
97 templ->Set(StringToSymbol(isolate, "define"), GetDefineTemplate(isolate)); | |
98 } | |
99 | |
100 void ModuleRegistry::AddBuiltinModule(Isolate* isolate, | |
101 const std::string& id, | |
102 Handle<ObjectTemplate> templ) { | |
103 assert(!id.empty()); | |
104 Handle<v8::Object> modules = v8::Local<v8::Object>::New(isolate, modules_); | |
105 modules->Set(StringToV8(isolate, id), templ->NewInstance()); | |
106 } | |
107 | |
108 ModuleRegistry* ModuleRegistry::From(Handle<v8::Context> context) { | |
109 v8::Isolate* isolate = context->GetIsolate(); | |
110 Handle<v8::String> key = Key(isolate); | |
111 Handle<v8::Value> encoded = context->Global()->GetHiddenValue(key); | |
Aaron Boodman
2013/11/15 18:56:06
Why is this variable called "encoded"?
abarth-chromium
2013/11/15 19:13:37
Just because it's a pointer encoded into a v8 obje
| |
112 if (encoded.IsEmpty() || !encoded->IsExternal()) { | |
113 PerContextData* data = PerContextData::From(context); | |
114 if (!data) | |
115 return NULL; | |
116 ModuleRegistry* registry = new ModuleRegistry(isolate); | |
117 context->Global()->SetHiddenValue(key, v8::External::New(registry)); | |
118 data->AddSupplement(registry); | |
119 return registry; | |
120 } | |
121 Handle<v8::External> external = Handle<v8::External>::Cast(encoded); | |
122 return static_cast<ModuleRegistry*>(external->Value()); | |
123 } | |
124 | |
125 void ModuleRegistry::AddPendingModule(v8::Isolate* isolate, | |
126 PendingModule* pending) { | |
127 if (AttemptToLoad(isolate, pending)) | |
128 AttemptToLoadPendingModules(isolate); | |
129 } | |
130 | |
131 Handle<v8::String> ModuleRegistry::Key(v8::Isolate* isolate) { | |
Aaron Boodman
2013/11/15 18:56:06
::GetHiddenValueKey(). Also, this could just be a
abarth-chromium
2013/11/15 19:13:37
Will do.
| |
132 return StringToSymbol(isolate, "::gin::ModuleRegistry"); | |
133 } | |
134 | |
135 void ModuleRegistry::Detach(Handle<v8::Context> context) { | |
136 context->Global()->SetHiddenValue(Key(context->GetIsolate()), | |
137 Handle<v8::Value>()); | |
138 } | |
139 | |
140 bool ModuleRegistry::AttemptToLoad(v8::Isolate* isolate, | |
141 PendingModule* pending) { | |
142 Handle<v8::Object> modules = v8::Local<v8::Object>::New(isolate, modules_); | |
143 Handle<v8::String> key = StringToV8(isolate, pending->id); | |
144 | |
145 if (!pending->id.empty() && modules->HasOwnProperty(key)) { | |
146 // We've already loaded a module with this name. Ignore the new one. | |
147 delete pending; | |
148 return true; | |
149 } | |
150 | |
151 size_t argc = pending->dependencies.size(); | |
152 std::vector<Handle<v8::Value> > argv(argc); | |
153 for (size_t i = 0; i < argc; ++i) { | |
154 Handle<v8::String> key = StringToV8(isolate, pending->dependencies[i]); | |
155 if (!modules->HasOwnProperty(key)) { | |
156 pending_modules_.push_back(pending); | |
157 return false; | |
158 } | |
159 argv[i] = modules->Get(key); | |
160 } | |
161 | |
162 Handle<v8::Value> module = v8::Local<v8::Value>::New( | |
163 isolate, pending->factory); | |
164 | |
165 Handle<v8::Function> factory; | |
166 if (ConvertFromV8(module, &factory)) { | |
167 v8::Handle<v8::Object> global = isolate->GetCurrentContext()->Global(); | |
168 module = factory->Call(global, argc, argv.data()); | |
169 // TODO(abarth): What should we do with exceptions? | |
170 } | |
171 | |
172 if (!pending->id.empty() && !module.IsEmpty()) | |
173 modules->Set(key, module); | |
174 | |
175 delete pending; | |
176 return true; | |
177 } | |
178 | |
179 void ModuleRegistry::AttemptToLoadPendingModules(v8::Isolate* isolate) { | |
180 PendingModuleList pending_modules; | |
181 pending_modules.swap(pending_modules_); | |
182 for (PendingModuleList::iterator it = pending_modules.begin(); | |
183 it != pending_modules.end(); ++it) { | |
184 AttemptToLoad(isolate, *it); | |
185 } | |
186 } | |
187 | |
188 } // namespace gin | |
OLD | NEW |