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 |