| Index: extensions/renderer/module_system.cc
|
| diff --git a/extensions/renderer/module_system.cc b/extensions/renderer/module_system.cc
|
| index a10fabd350e406b443a4a963fd42ebfd57325570..553b7f8e412bce36ad91449333e7c5770aedea37 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"
|
|
|
| @@ -26,7 +27,6 @@ namespace {
|
| const char* kModuleSystem = "module_system";
|
| const char* kModuleName = "module_name";
|
| const char* kModuleField = "module_field";
|
| -const char* kModulesField = "modules";
|
|
|
| // Logs a fatal error for the calling context, with some added metadata about
|
| // the context:
|
| @@ -133,10 +133,45 @@ ModuleSystem::ModuleSystem(ScriptContext* context, SourceMap* source_map)
|
|
|
| v8::Handle<v8::Object> global(context->v8_context()->Global());
|
| v8::Isolate* isolate = context->isolate();
|
| - global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModulesField),
|
| - v8::Object::New(isolate));
|
| global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModuleSystem),
|
| v8::External::New(isolate, this));
|
| +
|
| + gin::ModuleRegistry* registry =
|
| + gin::ModuleRegistry::From(context->v8_context());
|
| + DCHECK(registry);
|
| + registry->AddObserver(this);
|
| + registry->AddBuiltinModule(
|
| + GetIsolate(), "array", context->safe_builtins()->GetArray());
|
| + registry->AddBuiltinModule(GetIsolate(), "console", console::AsV8Object());
|
| + registry->AddBuiltinModule(
|
| + GetIsolate(), "function", context->safe_builtins()->GetFunction());
|
| + registry->AddBuiltinModule(
|
| + GetIsolate(), "json", context->safe_builtins()->GetJSON());
|
| + registry->AddBuiltinModule(
|
| + GetIsolate(), "object", context->safe_builtins()->GetObjekt());
|
| + registry->AddBuiltinModule(
|
| + GetIsolate(), "regexp", context->safe_builtins()->GetRegExp());
|
| + registry->AddBuiltinModule(
|
| + GetIsolate(), "string", context->safe_builtins()->GetString());
|
| + v8::Handle<v8::Object> natives(NewInstance());
|
| + registry->AddBuiltinModule(
|
| + GetIsolate(),
|
| + "require",
|
| + natives->Get(v8::String::NewFromUtf8(
|
| + GetIsolate(), "require", v8::String::kInternalizedString)));
|
| + registry->AddBuiltinModule(
|
| + GetIsolate(),
|
| + "requireNative",
|
| + natives->Get(v8::String::NewFromUtf8(
|
| + GetIsolate(), "requireNative", v8::String::kInternalizedString)));
|
| + registry->AddBuiltinModule(
|
| + GetIsolate(),
|
| + "privates",
|
| + natives->Get(v8::String::NewFromUtf8(
|
| + GetIsolate(), "privates", v8::String::kInternalizedString)));
|
| +
|
| + modules_supporting_amd_.insert("app.runtime");
|
| + modules_supporting_amd_.insert("entryIdManager");
|
| }
|
|
|
| ModuleSystem::~ModuleSystem() { Invalidate(); }
|
| @@ -151,8 +186,6 @@ void ModuleSystem::Invalidate() {
|
| v8::HandleScope scope(GetIsolate());
|
| v8::Handle<v8::Object> global = context()->v8_context()->Global();
|
| global->DeleteHiddenValue(
|
| - v8::String::NewFromUtf8(GetIsolate(), kModulesField));
|
| - global->DeleteHiddenValue(
|
| v8::String::NewFromUtf8(GetIsolate(), kModuleSystem));
|
| }
|
|
|
| @@ -198,74 +231,116 @@ v8::Local<v8::Value> ModuleSystem::RequireForJsInner(
|
| v8::EscapableHandleScope handle_scope(GetIsolate());
|
| v8::Context::Scope context_scope(context()->v8_context());
|
|
|
| - v8::Handle<v8::Object> global(context()->v8_context()->Global());
|
| + std::string module_name_str =
|
| + std::string(*v8::String::Utf8Value(module_name));
|
| + gin::ModuleRegistry* registry =
|
| + gin::ModuleRegistry::From(context()->v8_context());
|
| + if (!registry) {
|
| + return handle_scope.Escape(
|
| + v8::Local<v8::Primitive>(v8::Undefined(GetIsolate())));
|
| + }
|
|
|
| - // The module system might have been deleted. This can happen if a different
|
| - // context keeps a reference to us, but our frame is destroyed (e.g.
|
| - // background page keeps reference to chrome object in a closed popup).
|
| - v8::Handle<v8::Value> modules_value = global->GetHiddenValue(
|
| - v8::String::NewFromUtf8(GetIsolate(), kModulesField));
|
| - if (modules_value.IsEmpty() || modules_value->IsUndefined()) {
|
| - Warn(GetIsolate(), "Extension view no longer exists");
|
| - return v8::Undefined(GetIsolate());
|
| + if (registry->available_modules().count(module_name_str) == 0 &&
|
| + !LoadModule(module_name_str)) {
|
| + return handle_scope.Escape(
|
| + v8::Local<v8::Primitive>(v8::Undefined(GetIsolate())));
|
| }
|
| + return handle_scope.Escape(
|
| + v8::Local<v8::Value>(registry->GetModule(GetIsolate(), module_name_str)));
|
| +}
|
| +
|
| +bool ModuleSystem::LoadModule(const std::string& module_name) {
|
| + if (failed_module_loads_.count(module_name) != 0)
|
| + return false;
|
|
|
| - v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(modules_value));
|
| - v8::Local<v8::Value> exports(modules->Get(module_name));
|
| - if (!exports->IsUndefined())
|
| - return handle_scope.Escape(exports);
|
| + gin::ModuleRegistry* registry =
|
| + gin::ModuleRegistry::From(context()->v8_context());
|
| + DCHECK_EQ(0u, registry->available_modules().count(module_name));
|
| + v8::HandleScope handle_scope(GetIsolate());
|
| + v8::Context::Scope context_scope(context()->v8_context());
|
|
|
| - std::string module_name_str = *v8::String::Utf8Value(module_name);
|
| - v8::Handle<v8::Value> source(GetSource(module_name_str));
|
| + if (LoadNative(module_name))
|
| + return true;
|
| +
|
| + v8::Handle<v8::Value> source(GetSource(module_name));
|
| if (source.IsEmpty() || source->IsUndefined()) {
|
| - Fatal(context_, "No source for require(" + module_name_str + ")");
|
| - return v8::Undefined(GetIsolate());
|
| + Fatal(context_, "No source for module " + module_name);
|
| + return false;
|
| }
|
| v8::Handle<v8::String> wrapped_source(
|
| - WrapSource(v8::Handle<v8::String>::Cast(source)));
|
| + WrapSource(v8::Handle<v8::String>::Cast(source), module_name));
|
| // Modules are wrapped in (function(){...}) so they always return functions.
|
| - v8::Handle<v8::Value> func_as_value = RunString(wrapped_source, module_name);
|
| + v8::Handle<v8::String> module_name_js(
|
| + v8::String::NewFromUtf8(GetIsolate(), module_name.c_str()));
|
| + v8::Handle<v8::Value> func_as_value =
|
| + RunString(wrapped_source, module_name_js);
|
| if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) {
|
| - Fatal(context_, "Bad source for require(" + module_name_str + ")");
|
| - return v8::Undefined(GetIsolate());
|
| + Fatal(context_, "Bad source for module " + module_name);
|
| + return false;
|
| }
|
|
|
| v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value);
|
|
|
| - exports = v8::Object::New(GetIsolate());
|
| - v8::Handle<v8::Object> natives(NewInstance());
|
| - CHECK(!natives.IsEmpty()); // this can happen if v8 has issues
|
| + v8::Handle<v8::Object> define_object = v8::Object::New(GetIsolate());
|
| + gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object);
|
|
|
| - // These must match the argument order in WrapSource.
|
| + // These must match the argument order in WrapAmdSource.
|
| v8::Handle<v8::Value> args[] = {
|
| - // CommonJS.
|
| - natives->Get(v8::String::NewFromUtf8(
|
| - GetIsolate(), "require", v8::String::kInternalizedString)),
|
| - natives->Get(v8::String::NewFromUtf8(
|
| - GetIsolate(), "requireNative", v8::String::kInternalizedString)),
|
| - exports,
|
| - // Libraries that we magically expose to every module.
|
| - console::AsV8Object(),
|
| - natives->Get(v8::String::NewFromUtf8(
|
| - GetIsolate(), "privates", v8::String::kInternalizedString)),
|
| - // Each safe builtin. Keep in order with the arguments in WrapSource.
|
| - context_->safe_builtins()->GetArray(),
|
| - context_->safe_builtins()->GetFunction(),
|
| - context_->safe_builtins()->GetJSON(),
|
| - context_->safe_builtins()->GetObjekt(),
|
| - context_->safe_builtins()->GetRegExp(),
|
| - context_->safe_builtins()->GetString(), };
|
| + 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()) {
|
| + if (try_catch.HasCaught())
|
| HandleException(try_catch);
|
| - return v8::Undefined(GetIsolate());
|
| - }
|
| }
|
| - modules->Set(module_name, exports);
|
| - return handle_scope.Escape(exports);
|
| + if (registry->available_modules().count(module_name) == 0) {
|
| + failed_module_loads_.insert(module_name);
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool ModuleSystem::LoadNative(const std::string& native_name) {
|
| + if (natives_enabled_ == 0)
|
| + return false;
|
| +
|
| + v8::HandleScope scope(GetIsolate());
|
| + gin::ModuleRegistry* registry =
|
| + gin::ModuleRegistry::From(context_->v8_context());
|
| + if (overridden_native_handlers_.count(native_name) > 0u)
|
| + return false;
|
| +
|
| + NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
|
| + if (i == native_handler_map_.end()) {
|
| + return false;
|
| + }
|
| +
|
| + registry->AddBuiltinModule(
|
| + GetIsolate(), native_name, i->second->NewInstance());
|
| + return true;
|
| +}
|
| +
|
| +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)
|
| + continue;
|
| +
|
| + if (!LoadModule(*it))
|
| + LOG(DFATAL) << "Invalid dependency " << *it << " in module " << id;
|
| + }
|
| + gin::ModuleRegistry::From(context_->v8_context())
|
| + ->AttemptToLoadMoreModules(GetIsolate());
|
| }
|
|
|
| v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
|
| @@ -543,30 +618,59 @@ v8::Handle<v8::Value> ModuleSystem::RequireNativeFromString(
|
| Fatal(context_, "Natives disabled for requireNative(" + native_name + ")");
|
| return v8::Undefined(GetIsolate());
|
| }
|
| + gin::ModuleRegistry* registry =
|
| + gin::ModuleRegistry::From(context()->v8_context());
|
| + if (!registry)
|
| + return v8::Undefined(GetIsolate());
|
|
|
| - if (overridden_native_handlers_.count(native_name) > 0u) {
|
| - return RequireForJsInner(
|
| - v8::String::NewFromUtf8(GetIsolate(), native_name.c_str()));
|
| - }
|
| -
|
| - NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
|
| - if (i == native_handler_map_.end()) {
|
| + if (registry->available_modules().count(native_name) == 0 &&
|
| + !LoadModule(native_name)) {
|
| Fatal(context_,
|
| "Couldn't find native for requireNative(" + native_name + ")");
|
| return v8::Undefined(GetIsolate());
|
| }
|
| - return i->second->NewInstance();
|
| + return registry->GetModule(GetIsolate(), native_name);
|
| }
|
|
|
| -v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) {
|
| +v8::Handle<v8::String> ModuleSystem::WrapSource(
|
| + v8::Handle<v8::String> source,
|
| + const std::string& module_name) {
|
| + if (modules_supporting_amd_.count(module_name) != 0 ||
|
| + module_name.find('/') != std::string::npos) {
|
| + return WrapAmdSource(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, "
|
| - "console, privates,"
|
| - "$Array, $Function, $JSON, $Object, $RegExp, $String) {"
|
| - "'use strict';");
|
| + v8::Handle<v8::String> left =
|
| + v8::String::NewFromUtf8(GetIsolate(),
|
| + ("define('" + module_name +
|
| + "', ["
|
| + "'require',"
|
| + "'requireNative',"
|
| + "'privates',"
|
| + "'array',"
|
| + "'function',"
|
| + "'json',"
|
| + "'object',"
|
| + "'regexp',"
|
| + "'string',"
|
| + "'console',"
|
| + "], function(require, requireNative, privates, "
|
| + "$Array, $Function, $JSON, "
|
| + "$Object, $RegExp, $String, console) {"
|
| + "var exports = {};").c_str());
|
| + v8::Handle<v8::String> right =
|
| + v8::String::NewFromUtf8(GetIsolate(), "\nreturn exports;})");
|
| + return handle_scope.Escape(v8::Local<v8::String>(WrapAmdSource(
|
| + 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 LoadModule.
|
| + v8::Handle<v8::String> left =
|
| + v8::String::NewFromUtf8(GetIsolate(), "(function(define) {'use strict';");
|
| 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))));
|
|
|