OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 args.GetReturnValue().Set(resolver->GetPromise()); |
| 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 if (!module_registry) { |
| 532 Warn(GetIsolate(), "Extension view no longer exists"); |
| 533 resolver->Reject(v8::Exception::Error(v8::String::NewFromUtf8( |
| 534 GetIsolate(), "Extension view no longer exists"))); |
| 535 return; |
| 536 } |
| 537 module_registry->LoadModule(GetIsolate(), |
| 538 module_name, |
| 539 base::Bind(&ModuleSystem::OnModuleLoaded, |
| 540 weak_factory_.GetWeakPtr(), |
| 541 base::Passed(&persistent_resolver))); |
| 542 if (module_registry->available_modules().count(module_name) == 0) |
| 543 LoadModule(module_name); |
| 544 } |
| 545 |
561 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { | 546 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { |
562 v8::EscapableHandleScope handle_scope(GetIsolate()); | 547 v8::EscapableHandleScope handle_scope(GetIsolate()); |
563 // Keep in order with the arguments in RequireForJsInner. | 548 // Keep in order with the arguments in RequireForJsInner. |
564 v8::Handle<v8::String> left = v8::String::NewFromUtf8( | 549 v8::Handle<v8::String> left = v8::String::NewFromUtf8( |
565 GetIsolate(), | 550 GetIsolate(), |
566 "(function(require, requireNative, exports, " | 551 "(function(define, require, requireNative, requireAsync, exports, " |
567 "console, privates," | 552 "console, privates," |
568 "$Array, $Function, $JSON, $Object, $RegExp, $String) {" | 553 "$Array, $Function, $JSON, $Object, $RegExp, $String) {" |
569 "'use strict';"); | 554 "'use strict';"); |
570 v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})"); | 555 v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})"); |
571 return handle_scope.Escape(v8::Local<v8::String>( | 556 return handle_scope.Escape(v8::Local<v8::String>( |
572 v8::String::Concat(left, v8::String::Concat(source, right)))); | 557 v8::String::Concat(left, v8::String::Concat(source, right)))); |
573 } | 558 } |
574 | 559 |
575 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) { | 560 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) { |
576 CHECK_EQ(1, args.Length()); | 561 CHECK_EQ(1, args.Length()); |
577 CHECK(args[0]->IsObject()); | 562 CHECK(args[0]->IsObject()); |
578 v8::Local<v8::Object> obj = args[0].As<v8::Object>(); | 563 v8::Local<v8::Object> obj = args[0].As<v8::Object>(); |
579 v8::Local<v8::String> privates_key = | 564 v8::Local<v8::String> privates_key = |
580 v8::String::NewFromUtf8(GetIsolate(), "privates"); | 565 v8::String::NewFromUtf8(GetIsolate(), "privates"); |
581 v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key); | 566 v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key); |
582 if (privates.IsEmpty()) { | 567 if (privates.IsEmpty()) { |
583 privates = v8::Object::New(args.GetIsolate()); | 568 privates = v8::Object::New(args.GetIsolate()); |
584 obj->SetHiddenValue(privates_key, privates); | 569 obj->SetHiddenValue(privates_key, privates); |
585 } | 570 } |
586 args.GetReturnValue().Set(privates); | 571 args.GetReturnValue().Set(privates); |
587 } | 572 } |
588 | 573 |
| 574 v8::Handle<v8::Value> ModuleSystem::LoadModule(const std::string& module_name) { |
| 575 v8::EscapableHandleScope handle_scope(GetIsolate()); |
| 576 v8::Context::Scope context_scope(context()->v8_context()); |
| 577 |
| 578 v8::Handle<v8::Value> source(GetSource(module_name)); |
| 579 if (source.IsEmpty() || source->IsUndefined()) { |
| 580 Fatal(context_, "No source for require(" + module_name + ")"); |
| 581 return v8::Undefined(GetIsolate()); |
| 582 } |
| 583 v8::Handle<v8::String> wrapped_source( |
| 584 WrapSource(v8::Handle<v8::String>::Cast(source))); |
| 585 // Modules are wrapped in (function(){...}) so they always return functions. |
| 586 v8::Handle<v8::Value> func_as_value = |
| 587 RunString(wrapped_source, |
| 588 v8::String::NewFromUtf8(GetIsolate(), module_name.c_str())); |
| 589 if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) { |
| 590 Fatal(context_, "Bad source for require(" + module_name + ")"); |
| 591 return v8::Undefined(GetIsolate()); |
| 592 } |
| 593 |
| 594 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value); |
| 595 |
| 596 v8::Handle<v8::Object> define_object = v8::Object::New(GetIsolate()); |
| 597 gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object); |
| 598 |
| 599 v8::Local<v8::Value> exports = v8::Object::New(GetIsolate()); |
| 600 v8::Handle<v8::Object> natives(NewInstance()); |
| 601 CHECK(!natives.IsEmpty()); // this can happen if v8 has issues |
| 602 |
| 603 // These must match the argument order in WrapSource. |
| 604 v8::Handle<v8::Value> args[] = { |
| 605 // AMD. |
| 606 define_object->Get(v8::String::NewFromUtf8(GetIsolate(), "define")), |
| 607 // CommonJS. |
| 608 natives->Get(v8::String::NewFromUtf8( |
| 609 GetIsolate(), "require", v8::String::kInternalizedString)), |
| 610 natives->Get(v8::String::NewFromUtf8( |
| 611 GetIsolate(), "requireNative", v8::String::kInternalizedString)), |
| 612 natives->Get(v8::String::NewFromUtf8( |
| 613 GetIsolate(), "requireAsync", v8::String::kInternalizedString)), |
| 614 exports, |
| 615 // Libraries that we magically expose to every module. |
| 616 console::AsV8Object(), |
| 617 natives->Get(v8::String::NewFromUtf8( |
| 618 GetIsolate(), "privates", v8::String::kInternalizedString)), |
| 619 // Each safe builtin. Keep in order with the arguments in WrapSource. |
| 620 context_->safe_builtins()->GetArray(), |
| 621 context_->safe_builtins()->GetFunction(), |
| 622 context_->safe_builtins()->GetJSON(), |
| 623 context_->safe_builtins()->GetObjekt(), |
| 624 context_->safe_builtins()->GetRegExp(), |
| 625 context_->safe_builtins()->GetString(), |
| 626 }; |
| 627 { |
| 628 v8::TryCatch try_catch; |
| 629 try_catch.SetCaptureMessage(true); |
| 630 context_->CallFunction(func, arraysize(args), args); |
| 631 if (try_catch.HasCaught()) { |
| 632 HandleException(try_catch); |
| 633 return v8::Undefined(GetIsolate()); |
| 634 } |
| 635 } |
| 636 return handle_scope.Escape(exports); |
| 637 } |
| 638 |
| 639 void ModuleSystem::OnDidAddPendingModule( |
| 640 const std::string& id, |
| 641 const std::vector<std::string>& dependencies) { |
| 642 if (!source_map_->Contains(id)) |
| 643 return; |
| 644 |
| 645 gin::ModuleRegistry* registry = |
| 646 gin::ModuleRegistry::From(context_->v8_context()); |
| 647 DCHECK(registry); |
| 648 for (std::vector<std::string>::const_iterator it = dependencies.begin(); |
| 649 it != dependencies.end(); |
| 650 ++it) { |
| 651 if (registry->available_modules().count(*it) == 0) |
| 652 LoadModule(*it); |
| 653 } |
| 654 registry->AttemptToLoadMoreModules(GetIsolate()); |
| 655 } |
| 656 |
| 657 void ModuleSystem::OnModuleLoaded( |
| 658 scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > resolver, |
| 659 v8::Handle<v8::Value> value) { |
| 660 if (!is_valid()) |
| 661 return; |
| 662 v8::HandleScope handle_scope(GetIsolate()); |
| 663 v8::Handle<v8::Promise::Resolver> resolver_local( |
| 664 v8::Local<v8::Promise::Resolver>::New(GetIsolate(), *resolver)); |
| 665 resolver_local->Resolve(value); |
| 666 } |
| 667 |
589 } // namespace extensions | 668 } // namespace extensions |
OLD | NEW |