Chromium Code Reviews| 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 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 |
| OLD | NEW |