Chromium Code Reviews| Index: extensions/renderer/module_system.cc |
| diff --git a/extensions/renderer/module_system.cc b/extensions/renderer/module_system.cc |
| index 4a685e34caaa25dfa358c56727c4511a64632b63..d91d40fffa5046e9ee0b220037fa18a34552d8b3 100644 |
| --- a/extensions/renderer/module_system.cc |
| +++ b/extensions/renderer/module_system.cc |
| @@ -16,6 +16,7 @@ |
| #include "extensions/renderer/console.h" |
| #include "extensions/renderer/safe_builtins.h" |
| #include "extensions/renderer/script_context.h" |
| +#include "gin/modules/module_registry.h" |
| #include "third_party/WebKit/public/web/WebFrame.h" |
| #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" |
| @@ -121,13 +122,17 @@ ModuleSystem::ModuleSystem(ScriptContext* context, SourceMap* source_map) |
| context_(context), |
| source_map_(source_map), |
| natives_enabled_(0), |
| - exception_handler_(new DefaultExceptionHandler(context)) { |
| + exception_handler_(new DefaultExceptionHandler(context)), |
| + weak_factory_(this) { |
| RouteFunction( |
| "require", |
| base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this))); |
| RouteFunction( |
| "requireNative", |
| base::Bind(&ModuleSystem::RequireNative, base::Unretained(this))); |
| + RouteFunction( |
| + "requireAsync", |
| + base::Bind(&ModuleSystem::RequireAsync, base::Unretained(this))); |
| RouteFunction("privates", |
| base::Bind(&ModuleSystem::Private, base::Unretained(this))); |
| @@ -137,6 +142,8 @@ ModuleSystem::ModuleSystem(ScriptContext* context, SourceMap* source_map) |
| v8::Object::New(isolate)); |
| global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModuleSystem), |
| v8::External::New(isolate, this)); |
| + |
| + gin::ModuleRegistry::From(context->v8_context())->AddObserver(this); |
| } |
| ModuleSystem::~ModuleSystem() { Invalidate(); } |
| @@ -243,6 +250,8 @@ v8::Local<v8::Value> ModuleSystem::RequireForJsInner( |
| GetIsolate(), "require", v8::String::kInternalizedString)), |
| natives->Get(v8::String::NewFromUtf8( |
| GetIsolate(), "requireNative", v8::String::kInternalizedString)), |
| + natives->Get(v8::String::NewFromUtf8( |
| + GetIsolate(), "requireAsync", v8::String::kInternalizedString)), |
| exports, |
| // Libraries that we magically expose to every module. |
| console::AsV8Object(), |
| @@ -254,7 +263,8 @@ v8::Local<v8::Value> ModuleSystem::RequireForJsInner( |
| context_->safe_builtins()->GetJSON(), |
| context_->safe_builtins()->GetObjekt(), |
| context_->safe_builtins()->GetRegExp(), |
| - context_->safe_builtins()->GetString(), }; |
| + 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.
|
| + }; |
| { |
| v8::TryCatch try_catch; |
| try_catch.SetCaptureMessage(true); |
| @@ -558,12 +568,33 @@ v8::Handle<v8::Value> ModuleSystem::RequireNativeFromString( |
| return i->second->NewInstance(); |
| } |
| +void ModuleSystem::RequireAsync( |
| + const v8::FunctionCallbackInfo<v8::Value>& args) { |
| + CHECK_EQ(1, args.Length()); |
| + std::string module_name = *v8::String::Utf8Value(args[0]->ToString()); |
| + v8::Handle<v8::Promise::Resolver> resolver( |
| + v8::Promise::Resolver::New(GetIsolate())); |
| + v8::Handle<v8::Promise> promise(resolver->GetPromise()); |
| + scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > persistent_resolver( |
| + new v8::UniquePersistent<v8::Promise::Resolver>(GetIsolate(), resolver)); |
| + gin::ModuleRegistry* module_registry = |
| + gin::ModuleRegistry::From(context_->v8_context()); |
| + module_registry->LoadModule(GetIsolate(), |
| + module_name, |
| + base::Bind(&ModuleSystem::OnModuleLoaded, |
| + weak_factory_.GetWeakPtr(), |
| + base::Passed(&persistent_resolver))); |
| + args.GetReturnValue().Set(promise); |
| + if (module_registry->available_modules().count(module_name) == 0) |
| + LoadAmdModule(module_name); |
| +} |
| + |
| v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { |
| v8::EscapableHandleScope handle_scope(GetIsolate()); |
| // Keep in order with the arguments in RequireForJsInner. |
| v8::Handle<v8::String> left = v8::String::NewFromUtf8( |
| GetIsolate(), |
| - "(function(require, requireNative, exports, " |
| + "(function(require, requireNative, requireAsync, exports, " |
| "console, privates," |
| "$Array, $Function, $JSON, $Object, $RegExp, $String) {" |
| "'use strict';"); |
| @@ -572,6 +603,17 @@ v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { |
| v8::String::Concat(left, v8::String::Concat(source, right)))); |
| } |
| +v8::Handle<v8::String> ModuleSystem::WrapAmdSource( |
| + v8::Handle<v8::String> source) { |
| + v8::EscapableHandleScope handle_scope(GetIsolate()); |
| + // Keep in order with the arguments in LoadAmdModule. |
| + v8::Handle<v8::String> left = |
| + v8::String::NewFromUtf8(GetIsolate(), "(function(define) {"); |
| + v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})"); |
| + return handle_scope.Escape(v8::Local<v8::String>( |
| + v8::String::Concat(left, v8::String::Concat(source, right)))); |
| +} |
| + |
| void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| CHECK_EQ(1, args.Length()); |
| CHECK(args[0]->IsObject()); |
| @@ -586,4 +628,70 @@ void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| args.GetReturnValue().Set(privates); |
| } |
| +void ModuleSystem::LoadAmdModule(const std::string& module_name) { |
| + v8::HandleScope handle_scope(GetIsolate()); |
| + v8::Context::Scope context_scope(context()->v8_context()); |
| + |
| + v8::Handle<v8::Value> source(GetSource(module_name)); |
| + if (source.IsEmpty() || source->IsUndefined()) { |
| + Fatal(context_, "No source for requireAsync(" + module_name + ")"); |
| + return; |
| + } |
| + v8::Handle<v8::String> wrapped_source( |
| + WrapAmdSource(v8::Handle<v8::String>::Cast(source))); |
| + // Modules are wrapped in (function(){...}) so they always return functions. |
| + v8::Handle<v8::Value> func_as_value = |
| + RunString(wrapped_source, |
| + v8::String::NewFromUtf8(GetIsolate(), module_name.c_str())); |
| + if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) { |
| + Fatal(context_, "Bad source for requireAsync(" + module_name + ")"); |
| + return; |
| + } |
|
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.
|
| + |
| + v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value); |
| + |
| + v8::Handle<v8::Object> define_object = v8::Object::New(GetIsolate()); |
| + gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object); |
| + |
| + // These must match the argument order in WrapAmdSource. |
| + v8::Handle<v8::Value> args[] = { |
| + define_object->Get(v8::String::NewFromUtf8(GetIsolate(), "define")), |
| + }; |
| + { |
| + v8::TryCatch try_catch; |
| + try_catch.SetCaptureMessage(true); |
| + context_->CallFunction(func, arraysize(args), args); |
| + if (try_catch.HasCaught()) { |
| + HandleException(try_catch); |
| + return; |
| + } |
| + } |
| +} |
| + |
| +void ModuleSystem::OnDidAddPendingModule( |
| + const std::string& id, |
| + const std::vector<std::string>& dependencies) { |
| + if (!source_map_->Contains(id)) |
| + return; |
| + |
| + gin::ModuleRegistry* registry = |
| + gin::ModuleRegistry::From(context_->v8_context()); |
| + for (std::vector<std::string>::const_iterator it = dependencies.begin(); |
| + it != dependencies.end(); |
| + ++it) { |
| + if (registry->available_modules().count(*it) == 0) |
| + LoadAmdModule(*it); |
| + } |
| + registry->AttemptToLoadMoreModules(GetIsolate()); |
| +} |
| + |
| +void ModuleSystem::OnModuleLoaded( |
| + scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > resolver, |
| + v8::Handle<v8::Value> value) { |
| + v8::HandleScope handle_scope(GetIsolate()); |
| + v8::Handle<v8::Promise::Resolver> resolver_local( |
| + 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.
|
| + resolver_local->Resolve(value); |
| +} |
| + |
| } // namespace extensions |