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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 v8::Handle<v8::Object> natives(NewInstance()); | 243 v8::Handle<v8::Object> natives(NewInstance()); |
| 237 CHECK(!natives.IsEmpty()); // this can happen if v8 has issues | 244 CHECK(!natives.IsEmpty()); // this can happen if v8 has issues |
| 238 | 245 |
| 239 // These must match the argument order in WrapSource. | 246 // These must match the argument order in WrapSource. |
| 240 v8::Handle<v8::Value> args[] = { | 247 v8::Handle<v8::Value> args[] = { |
| 241 // CommonJS. | 248 // CommonJS. |
| 242 natives->Get(v8::String::NewFromUtf8( | 249 natives->Get(v8::String::NewFromUtf8( |
| 243 GetIsolate(), "require", v8::String::kInternalizedString)), | 250 GetIsolate(), "require", v8::String::kInternalizedString)), |
| 244 natives->Get(v8::String::NewFromUtf8( | 251 natives->Get(v8::String::NewFromUtf8( |
| 245 GetIsolate(), "requireNative", v8::String::kInternalizedString)), | 252 GetIsolate(), "requireNative", v8::String::kInternalizedString)), |
| 253 natives->Get(v8::String::NewFromUtf8( | |
| 254 GetIsolate(), "requireAsync", v8::String::kInternalizedString)), | |
| 246 exports, | 255 exports, |
| 247 // Libraries that we magically expose to every module. | 256 // Libraries that we magically expose to every module. |
| 248 console::AsV8Object(), | 257 console::AsV8Object(), |
| 249 natives->Get(v8::String::NewFromUtf8( | 258 natives->Get(v8::String::NewFromUtf8( |
| 250 GetIsolate(), "privates", v8::String::kInternalizedString)), | 259 GetIsolate(), "privates", v8::String::kInternalizedString)), |
| 251 // Each safe builtin. Keep in order with the arguments in WrapSource. | 260 // Each safe builtin. Keep in order with the arguments in WrapSource. |
| 252 context_->safe_builtins()->GetArray(), | 261 context_->safe_builtins()->GetArray(), |
| 253 context_->safe_builtins()->GetFunction(), | 262 context_->safe_builtins()->GetFunction(), |
| 254 context_->safe_builtins()->GetJSON(), | 263 context_->safe_builtins()->GetJSON(), |
| 255 context_->safe_builtins()->GetObjekt(), | 264 context_->safe_builtins()->GetObjekt(), |
| 256 context_->safe_builtins()->GetRegExp(), | 265 context_->safe_builtins()->GetRegExp(), |
| 257 context_->safe_builtins()->GetString(), }; | 266 context_->safe_builtins()->GetString(), |
|
not at google - send to devlin
2014/07/01 18:13:05
btw this was git cl format being a pain, which is
Sam McNally
2014/07/02 03:26:35
I think clang format prefers this formatting now.
| |
| 267 }; | |
| 258 { | 268 { |
| 259 v8::TryCatch try_catch; | 269 v8::TryCatch try_catch; |
| 260 try_catch.SetCaptureMessage(true); | 270 try_catch.SetCaptureMessage(true); |
| 261 context_->CallFunction(func, arraysize(args), args); | 271 context_->CallFunction(func, arraysize(args), args); |
| 262 if (try_catch.HasCaught()) { | 272 if (try_catch.HasCaught()) { |
| 263 HandleException(try_catch); | 273 HandleException(try_catch); |
| 264 return v8::Undefined(GetIsolate()); | 274 return v8::Undefined(GetIsolate()); |
| 265 } | 275 } |
| 266 } | 276 } |
| 267 modules->Set(module_name, exports); | 277 modules->Set(module_name, exports); |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 551 | 561 |
| 552 NativeHandlerMap::iterator i = native_handler_map_.find(native_name); | 562 NativeHandlerMap::iterator i = native_handler_map_.find(native_name); |
| 553 if (i == native_handler_map_.end()) { | 563 if (i == native_handler_map_.end()) { |
| 554 Fatal(context_, | 564 Fatal(context_, |
| 555 "Couldn't find native for requireNative(" + native_name + ")"); | 565 "Couldn't find native for requireNative(" + native_name + ")"); |
| 556 return v8::Undefined(GetIsolate()); | 566 return v8::Undefined(GetIsolate()); |
| 557 } | 567 } |
| 558 return i->second->NewInstance(); | 568 return i->second->NewInstance(); |
| 559 } | 569 } |
| 560 | 570 |
| 571 void ModuleSystem::RequireAsync( | |
| 572 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 573 CHECK_EQ(1, args.Length()); | |
| 574 std::string module_name = *v8::String::Utf8Value(args[0]->ToString()); | |
| 575 v8::Handle<v8::Promise::Resolver> resolver( | |
| 576 v8::Promise::Resolver::New(GetIsolate())); | |
| 577 v8::Handle<v8::Promise> promise(resolver->GetPromise()); | |
| 578 scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > persistent_resolver( | |
| 579 new v8::UniquePersistent<v8::Promise::Resolver>(GetIsolate(), resolver)); | |
| 580 gin::ModuleRegistry* module_registry = | |
| 581 gin::ModuleRegistry::From(context_->v8_context()); | |
| 582 module_registry->LoadModule(GetIsolate(), | |
| 583 module_name, | |
| 584 base::Bind(&ModuleSystem::OnModuleLoaded, | |
| 585 weak_factory_.GetWeakPtr(), | |
| 586 base::Passed(&persistent_resolver))); | |
| 587 args.GetReturnValue().Set(promise); | |
| 588 if (module_registry->available_modules().count(module_name) == 0) | |
| 589 LoadAmdModule(module_name); | |
| 590 } | |
| 591 | |
| 561 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { | 592 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { |
| 562 v8::EscapableHandleScope handle_scope(GetIsolate()); | 593 v8::EscapableHandleScope handle_scope(GetIsolate()); |
| 563 // Keep in order with the arguments in RequireForJsInner. | 594 // Keep in order with the arguments in RequireForJsInner. |
| 564 v8::Handle<v8::String> left = v8::String::NewFromUtf8( | 595 v8::Handle<v8::String> left = v8::String::NewFromUtf8( |
| 565 GetIsolate(), | 596 GetIsolate(), |
| 566 "(function(require, requireNative, exports, " | 597 "(function(require, requireNative, requireAsync, exports, " |
| 567 "console, privates," | 598 "console, privates," |
| 568 "$Array, $Function, $JSON, $Object, $RegExp, $String) {" | 599 "$Array, $Function, $JSON, $Object, $RegExp, $String) {" |
| 569 "'use strict';"); | 600 "'use strict';"); |
| 570 v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})"); | 601 v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})"); |
| 571 return handle_scope.Escape(v8::Local<v8::String>( | 602 return handle_scope.Escape(v8::Local<v8::String>( |
| 572 v8::String::Concat(left, v8::String::Concat(source, right)))); | 603 v8::String::Concat(left, v8::String::Concat(source, right)))); |
| 573 } | 604 } |
| 574 | 605 |
| 606 v8::Handle<v8::String> ModuleSystem::WrapAmdSource( | |
| 607 v8::Handle<v8::String> source) { | |
| 608 v8::EscapableHandleScope handle_scope(GetIsolate()); | |
| 609 // Keep in order with the arguments in LoadAmdModule. | |
| 610 v8::Handle<v8::String> left = | |
| 611 v8::String::NewFromUtf8(GetIsolate(), "(function(define) {"); | |
| 612 v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})"); | |
| 613 return handle_scope.Escape(v8::Local<v8::String>( | |
| 614 v8::String::Concat(left, v8::String::Concat(source, right)))); | |
| 615 } | |
| 616 | |
| 575 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) { | 617 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 576 CHECK_EQ(1, args.Length()); | 618 CHECK_EQ(1, args.Length()); |
| 577 CHECK(args[0]->IsObject()); | 619 CHECK(args[0]->IsObject()); |
| 578 v8::Local<v8::Object> obj = args[0].As<v8::Object>(); | 620 v8::Local<v8::Object> obj = args[0].As<v8::Object>(); |
| 579 v8::Local<v8::String> privates_key = | 621 v8::Local<v8::String> privates_key = |
| 580 v8::String::NewFromUtf8(GetIsolate(), "privates"); | 622 v8::String::NewFromUtf8(GetIsolate(), "privates"); |
| 581 v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key); | 623 v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key); |
| 582 if (privates.IsEmpty()) { | 624 if (privates.IsEmpty()) { |
| 583 privates = v8::Object::New(args.GetIsolate()); | 625 privates = v8::Object::New(args.GetIsolate()); |
| 584 obj->SetHiddenValue(privates_key, privates); | 626 obj->SetHiddenValue(privates_key, privates); |
| 585 } | 627 } |
| 586 args.GetReturnValue().Set(privates); | 628 args.GetReturnValue().Set(privates); |
| 587 } | 629 } |
| 588 | 630 |
| 631 void ModuleSystem::LoadAmdModule(const std::string& module_name) { | |
| 632 v8::HandleScope handle_scope(GetIsolate()); | |
| 633 v8::Context::Scope context_scope(context()->v8_context()); | |
| 634 | |
| 635 v8::Handle<v8::Value> source(GetSource(module_name)); | |
| 636 if (source.IsEmpty() || source->IsUndefined()) { | |
| 637 Fatal(context_, "No source for requireAsync(" + module_name + ")"); | |
| 638 return; | |
| 639 } | |
| 640 v8::Handle<v8::String> wrapped_source( | |
| 641 WrapAmdSource(v8::Handle<v8::String>::Cast(source))); | |
| 642 // Modules are wrapped in (function(){...}) so they always return functions. | |
| 643 v8::Handle<v8::Value> func_as_value = | |
| 644 RunString(wrapped_source, | |
| 645 v8::String::NewFromUtf8(GetIsolate(), module_name.c_str())); | |
| 646 if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) { | |
| 647 Fatal(context_, "Bad source for requireAsync(" + module_name + ")"); | |
| 648 return; | |
| 649 } | |
|
not at google - send to devlin
2014/07/01 18:13:05
surely there is some code we can share with the sy
Sam McNally
2014/07/02 03:26:35
Done.
| |
| 650 | |
| 651 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value); | |
| 652 | |
| 653 v8::Handle<v8::Object> define_object = v8::Object::New(GetIsolate()); | |
| 654 gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object); | |
| 655 | |
| 656 // These must match the argument order in WrapAmdSource. | |
| 657 v8::Handle<v8::Value> args[] = { | |
| 658 define_object->Get(v8::String::NewFromUtf8(GetIsolate(), "define")), | |
| 659 }; | |
| 660 { | |
| 661 v8::TryCatch try_catch; | |
| 662 try_catch.SetCaptureMessage(true); | |
| 663 context_->CallFunction(func, arraysize(args), args); | |
| 664 if (try_catch.HasCaught()) { | |
| 665 HandleException(try_catch); | |
| 666 return; | |
| 667 } | |
| 668 } | |
| 669 } | |
| 670 | |
| 671 void ModuleSystem::OnDidAddPendingModule( | |
| 672 const std::string& id, | |
| 673 const std::vector<std::string>& dependencies) { | |
| 674 if (!source_map_->Contains(id)) | |
| 675 return; | |
| 676 | |
| 677 gin::ModuleRegistry* registry = | |
| 678 gin::ModuleRegistry::From(context_->v8_context()); | |
| 679 for (std::vector<std::string>::const_iterator it = dependencies.begin(); | |
| 680 it != dependencies.end(); | |
| 681 ++it) { | |
| 682 if (registry->available_modules().count(*it) == 0) | |
| 683 LoadAmdModule(*it); | |
| 684 } | |
| 685 registry->AttemptToLoadMoreModules(GetIsolate()); | |
| 686 } | |
| 687 | |
| 688 void ModuleSystem::OnModuleLoaded( | |
| 689 scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > resolver, | |
| 690 v8::Handle<v8::Value> value) { | |
| 691 v8::HandleScope handle_scope(GetIsolate()); | |
| 692 v8::Handle<v8::Promise::Resolver> resolver_local( | |
| 693 v8::Local<v8::Promise::Resolver>::New(GetIsolate(), *resolver)); | |
|
not at google - send to devlin
2014/07/01 18:13:05
you should also check is_valid(). the C++ lifetime
Sam McNally
2014/07/02 03:26:35
Done.
| |
| 694 resolver_local->Resolve(value); | |
| 695 } | |
| 696 | |
| 589 } // namespace extensions | 697 } // namespace extensions |
| OLD | NEW |