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

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

Issue 359413004: Add support for using AMD modules from extensions modules. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: address comments Created 6 years, 5 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 | Annotate | Revision Log
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";
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 resource_name.c_str(), 115 resource_name.c_str(),
115 message->GetLineNumber(), 116 message->GetLineNumber(),
116 error_message.c_str()); 117 error_message.c_str());
117 } 118 }
118 119
119 ModuleSystem::ModuleSystem(ScriptContext* context, SourceMap* source_map) 120 ModuleSystem::ModuleSystem(ScriptContext* context, SourceMap* source_map)
120 : ObjectBackedNativeHandler(context), 121 : ObjectBackedNativeHandler(context),
121 context_(context), 122 context_(context),
122 source_map_(source_map), 123 source_map_(source_map),
123 natives_enabled_(0), 124 natives_enabled_(0),
124 exception_handler_(new DefaultExceptionHandler(context)) { 125 exception_handler_(new DefaultExceptionHandler(context)),
126 weak_factory_(this) {
125 RouteFunction( 127 RouteFunction(
126 "require", 128 "require",
127 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this))); 129 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this)));
128 RouteFunction( 130 RouteFunction(
129 "requireNative", 131 "requireNative",
130 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this))); 132 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this)));
133 RouteFunction(
134 "requireAsync",
135 base::Bind(&ModuleSystem::RequireAsync, base::Unretained(this)));
131 RouteFunction("privates", 136 RouteFunction("privates",
132 base::Bind(&ModuleSystem::Private, base::Unretained(this))); 137 base::Bind(&ModuleSystem::Private, base::Unretained(this)));
133 138
134 v8::Handle<v8::Object> global(context->v8_context()->Global()); 139 v8::Handle<v8::Object> global(context->v8_context()->Global());
135 v8::Isolate* isolate = context->isolate(); 140 v8::Isolate* isolate = context->isolate();
136 global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModulesField), 141 global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModulesField),
137 v8::Object::New(isolate)); 142 v8::Object::New(isolate));
138 global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModuleSystem), 143 global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModuleSystem),
139 v8::External::New(isolate, this)); 144 v8::External::New(isolate, this));
145
146 gin::ModuleRegistry::From(context->v8_context())->AddObserver(this);
140 } 147 }
141 148
142 ModuleSystem::~ModuleSystem() { Invalidate(); } 149 ModuleSystem::~ModuleSystem() { Invalidate(); }
143 150
144 void ModuleSystem::Invalidate() { 151 void ModuleSystem::Invalidate() {
145 if (!is_valid()) 152 if (!is_valid())
146 return; 153 return;
147 154
148 // Clear the module system properties from the global context. It's polite, 155 // 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. 156 // and we use this as a signal in lazy handlers that we no longer exist.
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 if (modules_value.IsEmpty() || modules_value->IsUndefined()) { 215 if (modules_value.IsEmpty() || modules_value->IsUndefined()) {
209 Warn(GetIsolate(), "Extension view no longer exists"); 216 Warn(GetIsolate(), "Extension view no longer exists");
210 return v8::Undefined(GetIsolate()); 217 return v8::Undefined(GetIsolate());
211 } 218 }
212 219
213 v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(modules_value)); 220 v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(modules_value));
214 v8::Local<v8::Value> exports(modules->Get(module_name)); 221 v8::Local<v8::Value> exports(modules->Get(module_name));
215 if (!exports->IsUndefined()) 222 if (!exports->IsUndefined())
216 return handle_scope.Escape(exports); 223 return handle_scope.Escape(exports);
217 224
218 std::string module_name_str = *v8::String::Utf8Value(module_name); 225 exports = LoadModule(*v8::String::Utf8Value(module_name));
219 v8::Handle<v8::Value> source(GetSource(module_name_str));
220 if (source.IsEmpty() || source->IsUndefined()) {
221 Fatal(context_, "No source for require(" + module_name_str + ")");
222 return v8::Undefined(GetIsolate());
223 }
224 v8::Handle<v8::String> wrapped_source(
225 WrapSource(v8::Handle<v8::String>::Cast(source)));
226 // Modules are wrapped in (function(){...}) so they always return functions.
227 v8::Handle<v8::Value> func_as_value = RunString(wrapped_source, module_name);
228 if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) {
229 Fatal(context_, "Bad source for require(" + module_name_str + ")");
230 return v8::Undefined(GetIsolate());
231 }
232
233 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value);
234
235 exports = v8::Object::New(GetIsolate());
236 v8::Handle<v8::Object> natives(NewInstance());
237 CHECK(!natives.IsEmpty()); // this can happen if v8 has issues
238
239 // These must match the argument order in WrapSource.
240 v8::Handle<v8::Value> args[] = {
241 // CommonJS.
242 natives->Get(v8::String::NewFromUtf8(
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 {
259 v8::TryCatch try_catch;
260 try_catch.SetCaptureMessage(true);
261 context_->CallFunction(func, arraysize(args), args);
262 if (try_catch.HasCaught()) {
263 HandleException(try_catch);
264 return v8::Undefined(GetIsolate());
265 }
266 }
267 modules->Set(module_name, exports); 226 modules->Set(module_name, exports);
268 return handle_scope.Escape(exports); 227 return handle_scope.Escape(exports);
269 } 228 }
270 229
271 v8::Local<v8::Value> ModuleSystem::CallModuleMethod( 230 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
272 const std::string& module_name, 231 const std::string& module_name,
273 const std::string& method_name) { 232 const std::string& method_name) {
274 v8::HandleScope handle_scope(GetIsolate()); 233 v8::HandleScope handle_scope(GetIsolate());
275 v8::Handle<v8::Value> no_args; 234 v8::Handle<v8::Value> no_args;
276 return CallModuleMethod(module_name, method_name, 0, &no_args); 235 return CallModuleMethod(module_name, method_name, 0, &no_args);
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after
551 510
552 NativeHandlerMap::iterator i = native_handler_map_.find(native_name); 511 NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
553 if (i == native_handler_map_.end()) { 512 if (i == native_handler_map_.end()) {
554 Fatal(context_, 513 Fatal(context_,
555 "Couldn't find native for requireNative(" + native_name + ")"); 514 "Couldn't find native for requireNative(" + native_name + ")");
556 return v8::Undefined(GetIsolate()); 515 return v8::Undefined(GetIsolate());
557 } 516 }
558 return i->second->NewInstance(); 517 return i->second->NewInstance();
559 } 518 }
560 519
520 void ModuleSystem::RequireAsync(
521 const v8::FunctionCallbackInfo<v8::Value>& args) {
522 CHECK_EQ(1, args.Length());
523 std::string module_name = *v8::String::Utf8Value(args[0]->ToString());
524 v8::Handle<v8::Promise::Resolver> resolver(
525 v8::Promise::Resolver::New(GetIsolate()));
526 v8::Handle<v8::Promise> promise(resolver->GetPromise());
not at google - send to devlin 2014/07/02 22:07:45 nit: inline |promise|, only used once?
Sam McNally 2014/07/03 10:56:54 Done.
527 scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > persistent_resolver(
528 new v8::UniquePersistent<v8::Promise::Resolver>(GetIsolate(), resolver));
529 gin::ModuleRegistry* module_registry =
530 gin::ModuleRegistry::From(context_->v8_context());
531 module_registry->LoadModule(GetIsolate(),
532 module_name,
533 base::Bind(&ModuleSystem::OnModuleLoaded,
534 weak_factory_.GetWeakPtr(),
535 base::Passed(&persistent_resolver)));
536 args.GetReturnValue().Set(promise);
537 if (module_registry->available_modules().count(module_name) == 0)
538 LoadModule(module_name);
539 }
540
561 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { 541 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) {
562 v8::EscapableHandleScope handle_scope(GetIsolate()); 542 v8::EscapableHandleScope handle_scope(GetIsolate());
563 // Keep in order with the arguments in RequireForJsInner. 543 // Keep in order with the arguments in RequireForJsInner.
564 v8::Handle<v8::String> left = v8::String::NewFromUtf8( 544 v8::Handle<v8::String> left = v8::String::NewFromUtf8(
565 GetIsolate(), 545 GetIsolate(),
566 "(function(require, requireNative, exports, " 546 "(function(define, require, requireNative, requireAsync, exports, "
567 "console, privates," 547 "console, privates,"
568 "$Array, $Function, $JSON, $Object, $RegExp, $String) {" 548 "$Array, $Function, $JSON, $Object, $RegExp, $String) {"
569 "'use strict';"); 549 "'use strict';");
570 v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})"); 550 v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})");
571 return handle_scope.Escape(v8::Local<v8::String>( 551 return handle_scope.Escape(v8::Local<v8::String>(
572 v8::String::Concat(left, v8::String::Concat(source, right)))); 552 v8::String::Concat(left, v8::String::Concat(source, right))));
573 } 553 }
574 554
575 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) { 555 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) {
576 CHECK_EQ(1, args.Length()); 556 CHECK_EQ(1, args.Length());
577 CHECK(args[0]->IsObject()); 557 CHECK(args[0]->IsObject());
578 v8::Local<v8::Object> obj = args[0].As<v8::Object>(); 558 v8::Local<v8::Object> obj = args[0].As<v8::Object>();
579 v8::Local<v8::String> privates_key = 559 v8::Local<v8::String> privates_key =
580 v8::String::NewFromUtf8(GetIsolate(), "privates"); 560 v8::String::NewFromUtf8(GetIsolate(), "privates");
581 v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key); 561 v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key);
582 if (privates.IsEmpty()) { 562 if (privates.IsEmpty()) {
583 privates = v8::Object::New(args.GetIsolate()); 563 privates = v8::Object::New(args.GetIsolate());
584 obj->SetHiddenValue(privates_key, privates); 564 obj->SetHiddenValue(privates_key, privates);
585 } 565 }
586 args.GetReturnValue().Set(privates); 566 args.GetReturnValue().Set(privates);
587 } 567 }
588 568
569 v8::Handle<v8::Value> ModuleSystem::LoadModule(const std::string& module_name) {
570 v8::EscapableHandleScope handle_scope(GetIsolate());
571 v8::Context::Scope context_scope(context()->v8_context());
572
573 v8::Handle<v8::Value> source(GetSource(module_name));
574 if (source.IsEmpty() || source->IsUndefined()) {
575 Fatal(context_, "No source for require(" + module_name + ")");
576 return v8::Undefined(GetIsolate());
577 }
578 v8::Handle<v8::String> wrapped_source(
579 WrapSource(v8::Handle<v8::String>::Cast(source)));
580 // Modules are wrapped in (function(){...}) so they always return functions.
581 v8::Handle<v8::Value> func_as_value =
582 RunString(wrapped_source,
583 v8::String::NewFromUtf8(GetIsolate(), module_name.c_str()));
584 if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) {
585 Fatal(context_, "Bad source for require(" + module_name + ")");
586 return v8::Undefined(GetIsolate());
587 }
588
589 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value);
590
591 v8::Handle<v8::Object> define_object = v8::Object::New(GetIsolate());
592 gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object);
593
594 v8::Local<v8::Value> exports = v8::Object::New(GetIsolate());
595 v8::Handle<v8::Object> natives(NewInstance());
596 CHECK(!natives.IsEmpty()); // this can happen if v8 has issues
597
598 // These must match the argument order in WrapSource.
599 v8::Handle<v8::Value> args[] = {
600 // AMD.
601 define_object->Get(v8::String::NewFromUtf8(GetIsolate(), "define")),
602 // CommonJS.
603 natives->Get(v8::String::NewFromUtf8(
604 GetIsolate(), "require", v8::String::kInternalizedString)),
605 natives->Get(v8::String::NewFromUtf8(
606 GetIsolate(), "requireNative", v8::String::kInternalizedString)),
607 natives->Get(v8::String::NewFromUtf8(
608 GetIsolate(), "requireAsync", v8::String::kInternalizedString)),
609 exports,
610 // Libraries that we magically expose to every module.
611 console::AsV8Object(),
612 natives->Get(v8::String::NewFromUtf8(
613 GetIsolate(), "privates", v8::String::kInternalizedString)),
614 // Each safe builtin. Keep in order with the arguments in WrapSource.
615 context_->safe_builtins()->GetArray(),
616 context_->safe_builtins()->GetFunction(),
617 context_->safe_builtins()->GetJSON(),
618 context_->safe_builtins()->GetObjekt(),
619 context_->safe_builtins()->GetRegExp(),
620 context_->safe_builtins()->GetString(),
621 };
622 {
623 v8::TryCatch try_catch;
624 try_catch.SetCaptureMessage(true);
625 context_->CallFunction(func, arraysize(args), args);
626 if (try_catch.HasCaught()) {
627 HandleException(try_catch);
628 return v8::Undefined(GetIsolate());
629 }
630 }
631 return handle_scope.Escape(exports);
632 }
633
634 void ModuleSystem::OnDidAddPendingModule(
635 const std::string& id,
636 const std::vector<std::string>& dependencies) {
637 if (!source_map_->Contains(id))
638 return;
639
640 gin::ModuleRegistry* registry =
641 gin::ModuleRegistry::From(context_->v8_context());
642 for (std::vector<std::string>::const_iterator it = dependencies.begin();
643 it != dependencies.end();
644 ++it) {
645 if (registry->available_modules().count(*it) == 0)
646 LoadModule(*it);
647 }
648 registry->AttemptToLoadMoreModules(GetIsolate());
649 }
650
651 void ModuleSystem::OnModuleLoaded(
652 scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > resolver,
653 v8::Handle<v8::Value> value) {
654 if (!is_valid())
655 return;
656 v8::HandleScope handle_scope(GetIsolate());
657 v8::Handle<v8::Promise::Resolver> resolver_local(
not at google - send to devlin 2014/07/02 22:07:45 why do you need to create a new handle?
Sam McNally 2014/07/03 10:56:53 UniquePersistent doesn't provide a way to get at t
658 v8::Local<v8::Promise::Resolver>::New(GetIsolate(), *resolver));
659 resolver_local->Resolve(value);
660 }
661
589 } // namespace extensions 662 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698