Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: extensions/renderer/module_system.cc

Issue 302463005: Add support for AMD to the extensions module system. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/renderer/module_system.h" 5 #include "extensions/renderer/module_system.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/debug/trace_event.h" 9 #include "base/debug/trace_event.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h" 11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h" 12 #include "base/strings/stringprintf.h"
13 #include "content/public/renderer/render_view.h" 13 #include "content/public/renderer/render_view.h"
14 #include "extensions/common/extension_messages.h" 14 #include "extensions/common/extension_messages.h"
15 #include "extensions/common/extensions_client.h" 15 #include "extensions/common/extensions_client.h"
16 #include "extensions/renderer/console.h" 16 #include "extensions/renderer/console.h"
17 #include "extensions/renderer/safe_builtins.h" 17 #include "extensions/renderer/safe_builtins.h"
18 #include "extensions/renderer/script_context.h" 18 #include "extensions/renderer/script_context.h"
19 #include "gin/modules/module_registry.h"
19 #include "third_party/WebKit/public/web/WebFrame.h" 20 #include "third_party/WebKit/public/web/WebFrame.h"
20 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" 21 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
21 22
22 namespace extensions { 23 namespace extensions {
23 24
24 namespace { 25 namespace {
25 26
26 const char* kModuleSystem = "module_system"; 27 const char* kModuleSystem = "module_system";
27 const char* kModuleName = "module_name"; 28 const char* kModuleName = "module_name";
28 const char* kModuleField = "module_field"; 29 const char* kModuleField = "module_field";
29 const char* kModulesField = "modules";
30 30
31 // Logs a fatal error for the calling context, with some added metadata about 31 // Logs a fatal error for the calling context, with some added metadata about
32 // the context: 32 // the context:
33 // - Its type (blessed, unblessed, etc). 33 // - Its type (blessed, unblessed, etc).
34 // - Whether it's valid. 34 // - Whether it's valid.
35 // - The extension ID, if one exists. 35 // - The extension ID, if one exists.
36 // 36 //
37 // This will only actual be fatal in in dev/canary, since in too many cases 37 // This will only actual be fatal in in dev/canary, since in too many cases
38 // we're at the mercy of the extension or web page's environment. They can mess 38 // we're at the mercy of the extension or web page's environment. They can mess
39 // up our JS in unexpected ways. Hopefully dev/canary channel will pick up such 39 // up our JS in unexpected ways. Hopefully dev/canary channel will pick up such
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 "require", 126 "require",
127 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this))); 127 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this)));
128 RouteFunction( 128 RouteFunction(
129 "requireNative", 129 "requireNative",
130 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this))); 130 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this)));
131 RouteFunction("privates", 131 RouteFunction("privates",
132 base::Bind(&ModuleSystem::Private, base::Unretained(this))); 132 base::Bind(&ModuleSystem::Private, base::Unretained(this)));
133 133
134 v8::Handle<v8::Object> global(context->v8_context()->Global()); 134 v8::Handle<v8::Object> global(context->v8_context()->Global());
135 v8::Isolate* isolate = context->isolate(); 135 v8::Isolate* isolate = context->isolate();
136 global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModulesField),
137 v8::Object::New(isolate));
138 global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModuleSystem), 136 global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModuleSystem),
139 v8::External::New(isolate, this)); 137 v8::External::New(isolate, this));
138
139 gin::ModuleRegistry* registry =
140 gin::ModuleRegistry::From(context->v8_context());
141 DCHECK(registry);
142 registry->AddObserver(this);
143 registry->AddBuiltinModule(
144 GetIsolate(), "array", context->safe_builtins()->GetArray());
145 registry->AddBuiltinModule(GetIsolate(), "console", console::AsV8Object());
146 registry->AddBuiltinModule(
147 GetIsolate(), "function", context->safe_builtins()->GetFunction());
148 registry->AddBuiltinModule(
149 GetIsolate(), "json", context->safe_builtins()->GetJSON());
150 registry->AddBuiltinModule(
151 GetIsolate(), "object", context->safe_builtins()->GetObjekt());
152 registry->AddBuiltinModule(
153 GetIsolate(), "regexp", context->safe_builtins()->GetRegExp());
154 registry->AddBuiltinModule(
155 GetIsolate(), "string", context->safe_builtins()->GetString());
156 v8::Handle<v8::Object> natives(NewInstance());
157 registry->AddBuiltinModule(
158 GetIsolate(),
159 "require",
160 natives->Get(v8::String::NewFromUtf8(
161 GetIsolate(), "require", v8::String::kInternalizedString)));
162 registry->AddBuiltinModule(
163 GetIsolate(),
164 "requireNative",
165 natives->Get(v8::String::NewFromUtf8(
166 GetIsolate(), "requireNative", v8::String::kInternalizedString)));
167 registry->AddBuiltinModule(
168 GetIsolate(),
169 "privates",
170 natives->Get(v8::String::NewFromUtf8(
171 GetIsolate(), "privates", v8::String::kInternalizedString)));
172
173 modules_supporting_amd_.insert("app.runtime");
174 modules_supporting_amd_.insert("entryIdManager");
140 } 175 }
141 176
142 ModuleSystem::~ModuleSystem() { Invalidate(); } 177 ModuleSystem::~ModuleSystem() { Invalidate(); }
143 178
144 void ModuleSystem::Invalidate() { 179 void ModuleSystem::Invalidate() {
145 if (!is_valid()) 180 if (!is_valid())
146 return; 181 return;
147 182
148 // Clear the module system properties from the global context. It's polite, 183 // Clear the module system properties from the global context. It's polite,
149 // and we use this as a signal in lazy handlers that we no longer exist. 184 // and we use this as a signal in lazy handlers that we no longer exist.
150 { 185 {
151 v8::HandleScope scope(GetIsolate()); 186 v8::HandleScope scope(GetIsolate());
152 v8::Handle<v8::Object> global = context()->v8_context()->Global(); 187 v8::Handle<v8::Object> global = context()->v8_context()->Global();
153 global->DeleteHiddenValue( 188 global->DeleteHiddenValue(
154 v8::String::NewFromUtf8(GetIsolate(), kModulesField));
155 global->DeleteHiddenValue(
156 v8::String::NewFromUtf8(GetIsolate(), kModuleSystem)); 189 v8::String::NewFromUtf8(GetIsolate(), kModuleSystem));
157 } 190 }
158 191
159 // Invalidate all of the successfully required handlers we own. 192 // Invalidate all of the successfully required handlers we own.
160 for (NativeHandlerMap::iterator it = native_handler_map_.begin(); 193 for (NativeHandlerMap::iterator it = native_handler_map_.begin();
161 it != native_handler_map_.end(); 194 it != native_handler_map_.end();
162 ++it) { 195 ++it) {
163 it->second->Invalidate(); 196 it->second->Invalidate();
164 } 197 }
165 198
(...skipping 25 matching lines...) Expand all
191 const v8::FunctionCallbackInfo<v8::Value>& args) { 224 const v8::FunctionCallbackInfo<v8::Value>& args) {
192 v8::Handle<v8::String> module_name = args[0]->ToString(); 225 v8::Handle<v8::String> module_name = args[0]->ToString();
193 args.GetReturnValue().Set(RequireForJsInner(module_name)); 226 args.GetReturnValue().Set(RequireForJsInner(module_name));
194 } 227 }
195 228
196 v8::Local<v8::Value> ModuleSystem::RequireForJsInner( 229 v8::Local<v8::Value> ModuleSystem::RequireForJsInner(
197 v8::Handle<v8::String> module_name) { 230 v8::Handle<v8::String> module_name) {
198 v8::EscapableHandleScope handle_scope(GetIsolate()); 231 v8::EscapableHandleScope handle_scope(GetIsolate());
199 v8::Context::Scope context_scope(context()->v8_context()); 232 v8::Context::Scope context_scope(context()->v8_context());
200 233
201 v8::Handle<v8::Object> global(context()->v8_context()->Global()); 234 std::string module_name_str =
202 235 std::string(*v8::String::Utf8Value(module_name));
203 // The module system might have been deleted. This can happen if a different 236 gin::ModuleRegistry* registry =
204 // context keeps a reference to us, but our frame is destroyed (e.g. 237 gin::ModuleRegistry::From(context()->v8_context());
205 // background page keeps reference to chrome object in a closed popup). 238 if (!registry) {
206 v8::Handle<v8::Value> modules_value = global->GetHiddenValue( 239 return handle_scope.Escape(
207 v8::String::NewFromUtf8(GetIsolate(), kModulesField)); 240 v8::Local<v8::Primitive>(v8::Undefined(GetIsolate())));
208 if (modules_value.IsEmpty() || modules_value->IsUndefined()) {
209 Warn(GetIsolate(), "Extension view no longer exists");
210 return v8::Undefined(GetIsolate());
211 } 241 }
212 242
213 v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(modules_value)); 243 if (registry->available_modules().count(module_name_str) == 0 &&
214 v8::Local<v8::Value> exports(modules->Get(module_name)); 244 !LoadModule(module_name_str)) {
215 if (!exports->IsUndefined()) 245 return handle_scope.Escape(
216 return handle_scope.Escape(exports); 246 v8::Local<v8::Primitive>(v8::Undefined(GetIsolate())));
247 }
248 return handle_scope.Escape(
249 v8::Local<v8::Value>(registry->GetModule(GetIsolate(), module_name_str)));
250 }
217 251
218 std::string module_name_str = *v8::String::Utf8Value(module_name); 252 bool ModuleSystem::LoadModule(const std::string& module_name) {
219 v8::Handle<v8::Value> source(GetSource(module_name_str)); 253 if (failed_module_loads_.count(module_name) != 0)
254 return false;
255
256 gin::ModuleRegistry* registry =
257 gin::ModuleRegistry::From(context()->v8_context());
258 DCHECK_EQ(0u, registry->available_modules().count(module_name));
259 v8::HandleScope handle_scope(GetIsolate());
260 v8::Context::Scope context_scope(context()->v8_context());
261
262 if (LoadNative(module_name))
263 return true;
264
265 v8::Handle<v8::Value> source(GetSource(module_name));
220 if (source.IsEmpty() || source->IsUndefined()) { 266 if (source.IsEmpty() || source->IsUndefined()) {
221 Fatal(context_, "No source for require(" + module_name_str + ")"); 267 Fatal(context_, "No source for module " + module_name);
222 return v8::Undefined(GetIsolate()); 268 return false;
223 } 269 }
224 v8::Handle<v8::String> wrapped_source( 270 v8::Handle<v8::String> wrapped_source(
225 WrapSource(v8::Handle<v8::String>::Cast(source))); 271 WrapSource(v8::Handle<v8::String>::Cast(source), module_name));
226 // Modules are wrapped in (function(){...}) so they always return functions. 272 // Modules are wrapped in (function(){...}) so they always return functions.
227 v8::Handle<v8::Value> func_as_value = RunString(wrapped_source, module_name); 273 v8::Handle<v8::String> module_name_js(
274 v8::String::NewFromUtf8(GetIsolate(), module_name.c_str()));
275 v8::Handle<v8::Value> func_as_value =
276 RunString(wrapped_source, module_name_js);
228 if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) { 277 if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) {
229 Fatal(context_, "Bad source for require(" + module_name_str + ")"); 278 Fatal(context_, "Bad source for module " + module_name);
230 return v8::Undefined(GetIsolate()); 279 return false;
231 } 280 }
232 281
233 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value); 282 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value);
234 283
235 exports = v8::Object::New(GetIsolate()); 284 v8::Handle<v8::Object> define_object = v8::Object::New(GetIsolate());
236 v8::Handle<v8::Object> natives(NewInstance()); 285 gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object);
237 CHECK(!natives.IsEmpty()); // this can happen if v8 has issues
238 286
239 // These must match the argument order in WrapSource. 287 // These must match the argument order in WrapAmdSource.
240 v8::Handle<v8::Value> args[] = { 288 v8::Handle<v8::Value> args[] = {
241 // CommonJS. 289 define_object->Get(v8::String::NewFromUtf8(GetIsolate(), "define")),
242 natives->Get(v8::String::NewFromUtf8( 290 };
243 GetIsolate(), "require", v8::String::kInternalizedString)),
244 natives->Get(v8::String::NewFromUtf8(
245 GetIsolate(), "requireNative", v8::String::kInternalizedString)),
246 exports,
247 // Libraries that we magically expose to every module.
248 console::AsV8Object(),
249 natives->Get(v8::String::NewFromUtf8(
250 GetIsolate(), "privates", v8::String::kInternalizedString)),
251 // Each safe builtin. Keep in order with the arguments in WrapSource.
252 context_->safe_builtins()->GetArray(),
253 context_->safe_builtins()->GetFunction(),
254 context_->safe_builtins()->GetJSON(),
255 context_->safe_builtins()->GetObjekt(),
256 context_->safe_builtins()->GetRegExp(),
257 context_->safe_builtins()->GetString(), };
258 { 291 {
259 v8::TryCatch try_catch; 292 v8::TryCatch try_catch;
260 try_catch.SetCaptureMessage(true); 293 try_catch.SetCaptureMessage(true);
261 context_->CallFunction(func, arraysize(args), args); 294 context_->CallFunction(func, arraysize(args), args);
262 if (try_catch.HasCaught()) { 295 if (try_catch.HasCaught())
263 HandleException(try_catch); 296 HandleException(try_catch);
264 return v8::Undefined(GetIsolate());
265 }
266 } 297 }
267 modules->Set(module_name, exports); 298 if (registry->available_modules().count(module_name) == 0) {
268 return handle_scope.Escape(exports); 299 failed_module_loads_.insert(module_name);
300 return false;
301 }
302 return true;
303 }
304
305 bool ModuleSystem::LoadNative(const std::string& native_name) {
306 if (natives_enabled_ == 0)
307 return false;
308
309 v8::HandleScope scope(GetIsolate());
310 gin::ModuleRegistry* registry =
311 gin::ModuleRegistry::From(context_->v8_context());
312 if (overridden_native_handlers_.count(native_name) > 0u)
313 return false;
314
315 NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
316 if (i == native_handler_map_.end()) {
317 return false;
318 }
319
320 registry->AddBuiltinModule(
321 GetIsolate(), native_name, i->second->NewInstance());
322 return true;
323 }
324
325 void ModuleSystem::OnDidAddPendingModule(
326 const std::string& id,
327 const std::vector<std::string>& dependencies) {
328 if (!source_map_->Contains(id))
329 return;
330
331 gin::ModuleRegistry* registry =
332 gin::ModuleRegistry::From(context_->v8_context());
333 for (std::vector<std::string>::const_iterator it = dependencies.begin();
334 it != dependencies.end();
335 ++it) {
336 if (registry->available_modules().count(*it) != 0)
337 continue;
338
339 if (!LoadModule(*it))
340 LOG(DFATAL) << "Invalid dependency " << *it << " in module " << id;
341 }
342 gin::ModuleRegistry::From(context_->v8_context())
343 ->AttemptToLoadMoreModules(GetIsolate());
269 } 344 }
270 345
271 v8::Local<v8::Value> ModuleSystem::CallModuleMethod( 346 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
272 const std::string& module_name, 347 const std::string& module_name,
273 const std::string& method_name) { 348 const std::string& method_name) {
274 v8::HandleScope handle_scope(GetIsolate()); 349 v8::HandleScope handle_scope(GetIsolate());
275 v8::Handle<v8::Value> no_args; 350 v8::Handle<v8::Value> no_args;
276 return CallModuleMethod(module_name, method_name, 0, &no_args); 351 return CallModuleMethod(module_name, method_name, 0, &no_args);
277 } 352 }
278 353
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 // HACK: if in test throw exception so that we can test the natives-disabled 611 // HACK: if in test throw exception so that we can test the natives-disabled
537 // logic; however, under normal circumstances, this is programmer error so 612 // logic; however, under normal circumstances, this is programmer error so
538 // we could crash. 613 // we could crash.
539 if (exception_handler_) { 614 if (exception_handler_) {
540 return GetIsolate()->ThrowException( 615 return GetIsolate()->ThrowException(
541 v8::String::NewFromUtf8(GetIsolate(), "Natives disabled")); 616 v8::String::NewFromUtf8(GetIsolate(), "Natives disabled"));
542 } 617 }
543 Fatal(context_, "Natives disabled for requireNative(" + native_name + ")"); 618 Fatal(context_, "Natives disabled for requireNative(" + native_name + ")");
544 return v8::Undefined(GetIsolate()); 619 return v8::Undefined(GetIsolate());
545 } 620 }
621 gin::ModuleRegistry* registry =
622 gin::ModuleRegistry::From(context()->v8_context());
623 if (!registry)
624 return v8::Undefined(GetIsolate());
546 625
547 if (overridden_native_handlers_.count(native_name) > 0u) { 626 if (registry->available_modules().count(native_name) == 0 &&
548 return RequireForJsInner( 627 !LoadModule(native_name)) {
549 v8::String::NewFromUtf8(GetIsolate(), native_name.c_str()));
550 }
551
552 NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
553 if (i == native_handler_map_.end()) {
554 Fatal(context_, 628 Fatal(context_,
555 "Couldn't find native for requireNative(" + native_name + ")"); 629 "Couldn't find native for requireNative(" + native_name + ")");
556 return v8::Undefined(GetIsolate()); 630 return v8::Undefined(GetIsolate());
557 } 631 }
558 return i->second->NewInstance(); 632 return registry->GetModule(GetIsolate(), native_name);
559 } 633 }
560 634
561 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { 635 v8::Handle<v8::String> ModuleSystem::WrapSource(
636 v8::Handle<v8::String> source,
637 const std::string& module_name) {
638 if (modules_supporting_amd_.count(module_name) != 0 ||
639 module_name.find('/') != std::string::npos) {
640 return WrapAmdSource(source);
641 }
642
562 v8::EscapableHandleScope handle_scope(GetIsolate()); 643 v8::EscapableHandleScope handle_scope(GetIsolate());
563 // Keep in order with the arguments in RequireForJsInner. 644 v8::Handle<v8::String> left =
564 v8::Handle<v8::String> left = v8::String::NewFromUtf8( 645 v8::String::NewFromUtf8(GetIsolate(),
565 GetIsolate(), 646 ("define('" + module_name +
566 "(function(require, requireNative, exports, " 647 "', ["
567 "console, privates," 648 "'require',"
568 "$Array, $Function, $JSON, $Object, $RegExp, $String) {" 649 "'requireNative',"
569 "'use strict';"); 650 "'privates',"
651 "'array',"
652 "'function',"
653 "'json',"
654 "'object',"
655 "'regexp',"
656 "'string',"
657 "'console',"
658 "], function(require, requireNative, privates, "
659 "$Array, $Function, $JSON, "
660 "$Object, $RegExp, $String, console) {"
661 "var exports = {};").c_str());
662 v8::Handle<v8::String> right =
663 v8::String::NewFromUtf8(GetIsolate(), "\nreturn exports;})");
664 return handle_scope.Escape(v8::Local<v8::String>(WrapAmdSource(
665 v8::String::Concat(left, v8::String::Concat(source, right)))));
666 }
667
668 v8::Handle<v8::String> ModuleSystem::WrapAmdSource(
669 v8::Handle<v8::String> source) {
670 v8::EscapableHandleScope handle_scope(GetIsolate());
671 // Keep in order with the arguments in LoadModule.
672 v8::Handle<v8::String> left =
673 v8::String::NewFromUtf8(GetIsolate(), "(function(define) {'use strict';");
570 v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})"); 674 v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})");
571 return handle_scope.Escape(v8::Local<v8::String>( 675 return handle_scope.Escape(v8::Local<v8::String>(
572 v8::String::Concat(left, v8::String::Concat(source, right)))); 676 v8::String::Concat(left, v8::String::Concat(source, right))));
573 } 677 }
574 678
575 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) { 679 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) {
576 CHECK_EQ(1, args.Length()); 680 CHECK_EQ(1, args.Length());
577 CHECK(args[0]->IsObject()); 681 CHECK(args[0]->IsObject());
578 v8::Local<v8::Object> obj = args[0].As<v8::Object>(); 682 v8::Local<v8::Object> obj = args[0].As<v8::Object>();
579 v8::Local<v8::String> privates_key = 683 v8::Local<v8::String> privates_key =
580 v8::String::NewFromUtf8(GetIsolate(), "privates"); 684 v8::String::NewFromUtf8(GetIsolate(), "privates");
581 v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key); 685 v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key);
582 if (privates.IsEmpty()) { 686 if (privates.IsEmpty()) {
583 privates = v8::Object::New(args.GetIsolate()); 687 privates = v8::Object::New(args.GetIsolate());
584 obj->SetHiddenValue(privates_key, privates); 688 obj->SetHiddenValue(privates_key, privates);
585 } 689 }
586 args.GetReturnValue().Set(privates); 690 args.GetReturnValue().Set(privates);
587 } 691 }
588 692
589 } // namespace extensions 693 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/module_system.h ('k') | extensions/renderer/resources/app_runtime_custom_bindings.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698