Home | History | Annotate | Download | only in renderer
      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
      3 // found in the LICENSE file.
      4 
      5 #include "extensions/renderer/module_system.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/debug/trace_event.h"
     10 #include "base/stl_util.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/strings/stringprintf.h"
     13 #include "content/public/renderer/render_view.h"
     14 #include "extensions/common/extension.h"
     15 #include "extensions/common/extensions_client.h"
     16 #include "extensions/renderer/console.h"
     17 #include "extensions/renderer/safe_builtins.h"
     18 #include "extensions/renderer/script_context.h"
     19 #include "gin/modules/module_registry.h"
     20 #include "third_party/WebKit/public/web/WebFrame.h"
     21 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
     22 
     23 namespace extensions {
     24 
     25 namespace {
     26 
     27 const char* kModuleSystem = "module_system";
     28 const char* kModuleName = "module_name";
     29 const char* kModuleField = "module_field";
     30 const char* kModulesField = "modules";
     31 
     32 // Logs a fatal error for the calling context, with some added metadata about
     33 // the context:
     34 //  - Its type (blessed, unblessed, etc).
     35 //  - Whether it's valid.
     36 //  - The extension ID, if one exists.
     37 //
     38 // This will only actual be fatal in in dev/canary, since in too many cases
     39 // we're at the mercy of the extension or web page's environment. They can mess
     40 // up our JS in unexpected ways. Hopefully dev/canary channel will pick up such
     41 // problems, but given the wider variety on stable/beta it's impossible to know.
     42 void Fatal(ScriptContext* context, const std::string& message) {
     43   // Prepend some context metadata.
     44   std::string full_message = "(";
     45   if (!context->is_valid())
     46     full_message += "Invalid ";
     47   full_message += context->GetContextTypeDescription();
     48   full_message += " context";
     49   if (context->extension()) {
     50     full_message += " for ";
     51     full_message += context->extension()->id();
     52   }
     53   full_message += ") ";
     54   full_message += message;
     55 
     56   if (ExtensionsClient::Get()->ShouldSuppressFatalErrors())
     57     console::Error(context->isolate()->GetCallingContext(), full_message);
     58   else
     59     console::Fatal(context->isolate()->GetCallingContext(), full_message);
     60 }
     61 
     62 void Warn(v8::Isolate* isolate, const std::string& message) {
     63   console::Warn(isolate->GetCallingContext(), message);
     64 }
     65 
     66 // Default exception handler which logs the exception.
     67 class DefaultExceptionHandler : public ModuleSystem::ExceptionHandler {
     68  public:
     69   explicit DefaultExceptionHandler(ScriptContext* context)
     70       : context_(context) {}
     71 
     72   // Fatally dumps the debug info from |try_catch| to the console.
     73   // Make sure this is never used for exceptions that originate in external
     74   // code!
     75   virtual void HandleUncaughtException(const v8::TryCatch& try_catch) OVERRIDE {
     76     v8::HandleScope handle_scope(context_->isolate());
     77     std::string stack_trace = "<stack trace unavailable>";
     78     if (!try_catch.StackTrace().IsEmpty()) {
     79       v8::String::Utf8Value stack_value(try_catch.StackTrace());
     80       if (*stack_value)
     81         stack_trace.assign(*stack_value, stack_value.length());
     82       else
     83         stack_trace = "<could not convert stack trace to string>";
     84     }
     85     Fatal(context_, CreateExceptionString(try_catch) + "{" + stack_trace + "}");
     86   }
     87 
     88  private:
     89   ScriptContext* context_;
     90 };
     91 
     92 }  // namespace
     93 
     94 std::string ModuleSystem::ExceptionHandler::CreateExceptionString(
     95     const v8::TryCatch& try_catch) {
     96   v8::Handle<v8::Message> message(try_catch.Message());
     97   if (message.IsEmpty()) {
     98     return "try_catch has no message";
     99   }
    100 
    101   std::string resource_name = "<unknown resource>";
    102   if (!message->GetScriptOrigin().ResourceName().IsEmpty()) {
    103     v8::String::Utf8Value resource_name_v8(
    104         message->GetScriptOrigin().ResourceName()->ToString());
    105     resource_name.assign(*resource_name_v8, resource_name_v8.length());
    106   }
    107 
    108   std::string error_message = "<no error message>";
    109   if (!message->Get().IsEmpty()) {
    110     v8::String::Utf8Value error_message_v8(message->Get());
    111     error_message.assign(*error_message_v8, error_message_v8.length());
    112   }
    113 
    114   return base::StringPrintf("%s:%d: %s",
    115                             resource_name.c_str(),
    116                             message->GetLineNumber(),
    117                             error_message.c_str());
    118 }
    119 
    120 ModuleSystem::ModuleSystem(ScriptContext* context, SourceMap* source_map)
    121     : ObjectBackedNativeHandler(context),
    122       context_(context),
    123       source_map_(source_map),
    124       natives_enabled_(0),
    125       exception_handler_(new DefaultExceptionHandler(context)),
    126       weak_factory_(this) {
    127   RouteFunction(
    128       "require",
    129       base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this)));
    130   RouteFunction(
    131       "requireNative",
    132       base::Bind(&ModuleSystem::RequireNative, base::Unretained(this)));
    133   RouteFunction(
    134       "requireAsync",
    135       base::Bind(&ModuleSystem::RequireAsync, base::Unretained(this)));
    136   RouteFunction("privates",
    137                 base::Bind(&ModuleSystem::Private, base::Unretained(this)));
    138 
    139   v8::Handle<v8::Object> global(context->v8_context()->Global());
    140   v8::Isolate* isolate = context->isolate();
    141   global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModulesField),
    142                          v8::Object::New(isolate));
    143   global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModuleSystem),
    144                          v8::External::New(isolate, this));
    145 
    146   gin::ModuleRegistry::From(context->v8_context())->AddObserver(this);
    147 }
    148 
    149 ModuleSystem::~ModuleSystem() { Invalidate(); }
    150 
    151 void ModuleSystem::Invalidate() {
    152   if (!is_valid())
    153     return;
    154 
    155   // Clear the module system properties from the global context. It's polite,
    156   // and we use this as a signal in lazy handlers that we no longer exist.
    157   {
    158     v8::HandleScope scope(GetIsolate());
    159     v8::Handle<v8::Object> global = context()->v8_context()->Global();
    160     global->DeleteHiddenValue(
    161         v8::String::NewFromUtf8(GetIsolate(), kModulesField));
    162     global->DeleteHiddenValue(
    163         v8::String::NewFromUtf8(GetIsolate(), kModuleSystem));
    164   }
    165 
    166   // Invalidate all of the successfully required handlers we own.
    167   for (NativeHandlerMap::iterator it = native_handler_map_.begin();
    168        it != native_handler_map_.end();
    169        ++it) {
    170     it->second->Invalidate();
    171   }
    172 
    173   ObjectBackedNativeHandler::Invalidate();
    174 }
    175 
    176 ModuleSystem::NativesEnabledScope::NativesEnabledScope(
    177     ModuleSystem* module_system)
    178     : module_system_(module_system) {
    179   module_system_->natives_enabled_++;
    180 }
    181 
    182 ModuleSystem::NativesEnabledScope::~NativesEnabledScope() {
    183   module_system_->natives_enabled_--;
    184   CHECK_GE(module_system_->natives_enabled_, 0);
    185 }
    186 
    187 void ModuleSystem::HandleException(const v8::TryCatch& try_catch) {
    188   exception_handler_->HandleUncaughtException(try_catch);
    189 }
    190 
    191 v8::Handle<v8::Value> ModuleSystem::Require(const std::string& module_name) {
    192   v8::EscapableHandleScope handle_scope(GetIsolate());
    193   return handle_scope.Escape(RequireForJsInner(
    194       v8::String::NewFromUtf8(GetIsolate(), module_name.c_str())));
    195 }
    196 
    197 void ModuleSystem::RequireForJs(
    198     const v8::FunctionCallbackInfo<v8::Value>& args) {
    199   v8::Handle<v8::String> module_name = args[0]->ToString();
    200   args.GetReturnValue().Set(RequireForJsInner(module_name));
    201 }
    202 
    203 v8::Local<v8::Value> ModuleSystem::RequireForJsInner(
    204     v8::Handle<v8::String> module_name) {
    205   v8::EscapableHandleScope handle_scope(GetIsolate());
    206   v8::Context::Scope context_scope(context()->v8_context());
    207 
    208   v8::Handle<v8::Object> global(context()->v8_context()->Global());
    209 
    210   // The module system might have been deleted. This can happen if a different
    211   // context keeps a reference to us, but our frame is destroyed (e.g.
    212   // background page keeps reference to chrome object in a closed popup).
    213   v8::Handle<v8::Value> modules_value = global->GetHiddenValue(
    214       v8::String::NewFromUtf8(GetIsolate(), kModulesField));
    215   if (modules_value.IsEmpty() || modules_value->IsUndefined()) {
    216     Warn(GetIsolate(), "Extension view no longer exists");
    217     return v8::Undefined(GetIsolate());
    218   }
    219 
    220   v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(modules_value));
    221   v8::Local<v8::Value> exports(modules->Get(module_name));
    222   if (!exports->IsUndefined())
    223     return handle_scope.Escape(exports);
    224 
    225   exports = LoadModule(*v8::String::Utf8Value(module_name));
    226   modules->Set(module_name, exports);
    227   return handle_scope.Escape(exports);
    228 }
    229 
    230 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
    231     const std::string& module_name,
    232     const std::string& method_name) {
    233   v8::EscapableHandleScope handle_scope(GetIsolate());
    234   v8::Handle<v8::Value> no_args;
    235   return handle_scope.Escape(
    236       CallModuleMethod(module_name, method_name, 0, &no_args));
    237 }
    238 
    239 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
    240     const std::string& module_name,
    241     const std::string& method_name,
    242     std::vector<v8::Handle<v8::Value> >* args) {
    243   return CallModuleMethod(
    244       module_name, method_name, args->size(), vector_as_array(args));
    245 }
    246 
    247 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
    248     const std::string& module_name,
    249     const std::string& method_name,
    250     int argc,
    251     v8::Handle<v8::Value> argv[]) {
    252   TRACE_EVENT2("v8",
    253                "v8.callModuleMethod",
    254                "module_name",
    255                module_name,
    256                "method_name",
    257                method_name);
    258 
    259   v8::EscapableHandleScope handle_scope(GetIsolate());
    260   v8::Context::Scope context_scope(context()->v8_context());
    261 
    262   v8::Local<v8::Value> module;
    263   {
    264     NativesEnabledScope natives_enabled(this);
    265     module = RequireForJsInner(
    266         v8::String::NewFromUtf8(GetIsolate(), module_name.c_str()));
    267   }
    268 
    269   if (module.IsEmpty() || !module->IsObject()) {
    270     Fatal(context_,
    271           "Failed to get module " + module_name + " to call " + method_name);
    272     return handle_scope.Escape(
    273         v8::Local<v8::Primitive>(v8::Undefined(GetIsolate())));
    274   }
    275 
    276   v8::Local<v8::Value> value = v8::Handle<v8::Object>::Cast(module)->Get(
    277       v8::String::NewFromUtf8(GetIsolate(), method_name.c_str()));
    278   if (value.IsEmpty() || !value->IsFunction()) {
    279     Fatal(context_, module_name + "." + method_name + " is not a function");
    280     return handle_scope.Escape(
    281         v8::Local<v8::Primitive>(v8::Undefined(GetIsolate())));
    282   }
    283 
    284   v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
    285   v8::Local<v8::Value> result;
    286   {
    287     v8::TryCatch try_catch;
    288     try_catch.SetCaptureMessage(true);
    289     result = context_->CallFunction(func, argc, argv);
    290     if (try_catch.HasCaught())
    291       HandleException(try_catch);
    292   }
    293   return handle_scope.Escape(result);
    294 }
    295 
    296 void ModuleSystem::RegisterNativeHandler(
    297     const std::string& name,
    298     scoped_ptr<NativeHandler> native_handler) {
    299   native_handler_map_[name] =
    300       linked_ptr<NativeHandler>(native_handler.release());
    301 }
    302 
    303 void ModuleSystem::OverrideNativeHandlerForTest(const std::string& name) {
    304   overridden_native_handlers_.insert(name);
    305 }
    306 
    307 void ModuleSystem::RunString(const std::string& code, const std::string& name) {
    308   v8::HandleScope handle_scope(GetIsolate());
    309   RunString(v8::String::NewFromUtf8(GetIsolate(), code.c_str()),
    310             v8::String::NewFromUtf8(GetIsolate(), name.c_str()));
    311 }
    312 
    313 // static
    314 void ModuleSystem::NativeLazyFieldGetter(
    315     v8::Local<v8::String> property,
    316     const v8::PropertyCallbackInfo<v8::Value>& info) {
    317   LazyFieldGetterInner(property, info, &ModuleSystem::RequireNativeFromString);
    318 }
    319 
    320 // static
    321 void ModuleSystem::LazyFieldGetter(
    322     v8::Local<v8::String> property,
    323     const v8::PropertyCallbackInfo<v8::Value>& info) {
    324   LazyFieldGetterInner(property, info, &ModuleSystem::Require);
    325 }
    326 
    327 // static
    328 void ModuleSystem::LazyFieldGetterInner(
    329     v8::Local<v8::String> property,
    330     const v8::PropertyCallbackInfo<v8::Value>& info,
    331     RequireFunction require_function) {
    332   CHECK(!info.Data().IsEmpty());
    333   CHECK(info.Data()->IsObject());
    334   v8::HandleScope handle_scope(info.GetIsolate());
    335   v8::Handle<v8::Object> parameters = v8::Handle<v8::Object>::Cast(info.Data());
    336   // This context should be the same as context()->v8_context().
    337   v8::Handle<v8::Context> context = parameters->CreationContext();
    338   v8::Handle<v8::Object> global(context->Global());
    339   v8::Handle<v8::Value> module_system_value = global->GetHiddenValue(
    340       v8::String::NewFromUtf8(info.GetIsolate(), kModuleSystem));
    341   if (module_system_value.IsEmpty() || !module_system_value->IsExternal()) {
    342     // ModuleSystem has been deleted.
    343     // TODO(kalman): See comment in header file.
    344     Warn(info.GetIsolate(),
    345          "Module system has been deleted, does extension view exist?");
    346     return;
    347   }
    348 
    349   ModuleSystem* module_system = static_cast<ModuleSystem*>(
    350       v8::Handle<v8::External>::Cast(module_system_value)->Value());
    351 
    352   std::string name =
    353       *v8::String::Utf8Value(
    354           parameters->Get(v8::String::NewFromUtf8(info.GetIsolate(),
    355                                                   kModuleName))->ToString());
    356 
    357   // Switch to our v8 context because we need functions created while running
    358   // the require()d module to belong to our context, not the current one.
    359   v8::Context::Scope context_scope(context);
    360   NativesEnabledScope natives_enabled_scope(module_system);
    361 
    362   v8::TryCatch try_catch;
    363   v8::Handle<v8::Value> module_value = (module_system->*require_function)(name);
    364   if (try_catch.HasCaught()) {
    365     module_system->HandleException(try_catch);
    366     return;
    367   }
    368   if (module_value.IsEmpty() || !module_value->IsObject()) {
    369     // require_function will have already logged this, we don't need to.
    370     return;
    371   }
    372 
    373   v8::Handle<v8::Object> module = v8::Handle<v8::Object>::Cast(module_value);
    374   v8::Handle<v8::String> field =
    375       parameters->Get(v8::String::NewFromUtf8(info.GetIsolate(), kModuleField))
    376           ->ToString();
    377 
    378   if (!module->Has(field)) {
    379     std::string field_str = *v8::String::Utf8Value(field);
    380     Fatal(module_system->context_,
    381           "Lazy require of " + name + "." + field_str + " did not set the " +
    382               field_str + " field");
    383     return;
    384   }
    385 
    386   v8::Local<v8::Value> new_field = module->Get(field);
    387   if (try_catch.HasCaught()) {
    388     module_system->HandleException(try_catch);
    389     return;
    390   }
    391 
    392   // Ok for it to be undefined, among other things it's how bindings signify
    393   // that the extension doesn't have permission to use them.
    394   CHECK(!new_field.IsEmpty());
    395 
    396   // Delete the getter and set this field to |new_field| so the same object is
    397   // returned every time a certain API is accessed.
    398   v8::Handle<v8::Value> val = info.This();
    399   if (val->IsObject()) {
    400     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(val);
    401     object->Delete(property);
    402     object->Set(property, new_field);
    403   } else {
    404     NOTREACHED();
    405   }
    406   info.GetReturnValue().Set(new_field);
    407 }
    408 
    409 void ModuleSystem::SetLazyField(v8::Handle<v8::Object> object,
    410                                 const std::string& field,
    411                                 const std::string& module_name,
    412                                 const std::string& module_field) {
    413   SetLazyField(
    414       object, field, module_name, module_field, &ModuleSystem::LazyFieldGetter);
    415 }
    416 
    417 void ModuleSystem::SetLazyField(v8::Handle<v8::Object> object,
    418                                 const std::string& field,
    419                                 const std::string& module_name,
    420                                 const std::string& module_field,
    421                                 v8::AccessorGetterCallback getter) {
    422   v8::HandleScope handle_scope(GetIsolate());
    423   v8::Handle<v8::Object> parameters = v8::Object::New(GetIsolate());
    424   parameters->Set(v8::String::NewFromUtf8(GetIsolate(), kModuleName),
    425                   v8::String::NewFromUtf8(GetIsolate(), module_name.c_str()));
    426   parameters->Set(v8::String::NewFromUtf8(GetIsolate(), kModuleField),
    427                   v8::String::NewFromUtf8(GetIsolate(), module_field.c_str()));
    428   object->SetAccessor(v8::String::NewFromUtf8(GetIsolate(), field.c_str()),
    429                       getter,
    430                       NULL,
    431                       parameters);
    432 }
    433 
    434 void ModuleSystem::SetNativeLazyField(v8::Handle<v8::Object> object,
    435                                       const std::string& field,
    436                                       const std::string& module_name,
    437                                       const std::string& module_field) {
    438   SetLazyField(object,
    439                field,
    440                module_name,
    441                module_field,
    442                &ModuleSystem::NativeLazyFieldGetter);
    443 }
    444 
    445 v8::Handle<v8::Value> ModuleSystem::RunString(v8::Handle<v8::String> code,
    446                                               v8::Handle<v8::String> name) {
    447   v8::EscapableHandleScope handle_scope(GetIsolate());
    448   v8::Context::Scope context_scope(context()->v8_context());
    449 
    450   // Prepend extensions:: to |name| so that internal code can be differentiated
    451   // from external code in stack traces. This has no effect on behaviour.
    452   std::string internal_name =
    453       base::StringPrintf("extensions::%s", *v8::String::Utf8Value(name));
    454 
    455   blink::WebScopedMicrotaskSuppression suppression;
    456   v8::TryCatch try_catch;
    457   try_catch.SetCaptureMessage(true);
    458   v8::Handle<v8::Script> script(
    459       v8::Script::Compile(code,
    460                           v8::String::NewFromUtf8(GetIsolate(),
    461                                                   internal_name.c_str(),
    462                                                   v8::String::kNormalString,
    463                                                   internal_name.size())));
    464   if (try_catch.HasCaught()) {
    465     HandleException(try_catch);
    466     return v8::Undefined(GetIsolate());
    467   }
    468 
    469   v8::Local<v8::Value> result = script->Run();
    470   if (try_catch.HasCaught()) {
    471     HandleException(try_catch);
    472     return v8::Undefined(GetIsolate());
    473   }
    474 
    475   return handle_scope.Escape(result);
    476 }
    477 
    478 v8::Handle<v8::Value> ModuleSystem::GetSource(const std::string& module_name) {
    479   v8::EscapableHandleScope handle_scope(GetIsolate());
    480   if (!source_map_->Contains(module_name))
    481     return v8::Undefined(GetIsolate());
    482   return handle_scope.Escape(
    483       v8::Local<v8::Value>(source_map_->GetSource(GetIsolate(), module_name)));
    484 }
    485 
    486 void ModuleSystem::RequireNative(
    487     const v8::FunctionCallbackInfo<v8::Value>& args) {
    488   CHECK_EQ(1, args.Length());
    489   std::string native_name = *v8::String::Utf8Value(args[0]->ToString());
    490   args.GetReturnValue().Set(RequireNativeFromString(native_name));
    491 }
    492 
    493 v8::Handle<v8::Value> ModuleSystem::RequireNativeFromString(
    494     const std::string& native_name) {
    495   if (natives_enabled_ == 0) {
    496     // HACK: if in test throw exception so that we can test the natives-disabled
    497     // logic; however, under normal circumstances, this is programmer error so
    498     // we could crash.
    499     if (exception_handler_) {
    500       return GetIsolate()->ThrowException(
    501           v8::String::NewFromUtf8(GetIsolate(), "Natives disabled"));
    502     }
    503     Fatal(context_, "Natives disabled for requireNative(" + native_name + ")");
    504     return v8::Undefined(GetIsolate());
    505   }
    506 
    507   if (overridden_native_handlers_.count(native_name) > 0u) {
    508     return RequireForJsInner(
    509         v8::String::NewFromUtf8(GetIsolate(), native_name.c_str()));
    510   }
    511 
    512   NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
    513   if (i == native_handler_map_.end()) {
    514     Fatal(context_,
    515           "Couldn't find native for requireNative(" + native_name + ")");
    516     return v8::Undefined(GetIsolate());
    517   }
    518   return i->second->NewInstance();
    519 }
    520 
    521 void ModuleSystem::RequireAsync(
    522     const v8::FunctionCallbackInfo<v8::Value>& args) {
    523   CHECK_EQ(1, args.Length());
    524   std::string module_name = *v8::String::Utf8Value(args[0]->ToString());
    525   v8::Handle<v8::Promise::Resolver> resolver(
    526       v8::Promise::Resolver::New(GetIsolate()));
    527   args.GetReturnValue().Set(resolver->GetPromise());
    528   scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > persistent_resolver(
    529       new v8::UniquePersistent<v8::Promise::Resolver>(GetIsolate(), resolver));
    530   gin::ModuleRegistry* module_registry =
    531       gin::ModuleRegistry::From(context_->v8_context());
    532   if (!module_registry) {
    533     Warn(GetIsolate(), "Extension view no longer exists");
    534     resolver->Reject(v8::Exception::Error(v8::String::NewFromUtf8(
    535         GetIsolate(), "Extension view no longer exists")));
    536     return;
    537   }
    538   module_registry->LoadModule(GetIsolate(),
    539                               module_name,
    540                               base::Bind(&ModuleSystem::OnModuleLoaded,
    541                                          weak_factory_.GetWeakPtr(),
    542                                          base::Passed(&persistent_resolver)));
    543   if (module_registry->available_modules().count(module_name) == 0)
    544     LoadModule(module_name);
    545 }
    546 
    547 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) {
    548   v8::EscapableHandleScope handle_scope(GetIsolate());
    549   // Keep in order with the arguments in RequireForJsInner.
    550   v8::Handle<v8::String> left = v8::String::NewFromUtf8(
    551       GetIsolate(),
    552       "(function(define, require, requireNative, requireAsync, exports, "
    553       "console, privates,"
    554       "$Array, $Function, $JSON, $Object, $RegExp, $String, $Error) {"
    555       "'use strict';");
    556   v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})");
    557   return handle_scope.Escape(v8::Local<v8::String>(
    558       v8::String::Concat(left, v8::String::Concat(source, right))));
    559 }
    560 
    561 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) {
    562   CHECK_EQ(1, args.Length());
    563   CHECK(args[0]->IsObject());
    564   v8::Local<v8::Object> obj = args[0].As<v8::Object>();
    565   v8::Local<v8::String> privates_key =
    566       v8::String::NewFromUtf8(GetIsolate(), "privates");
    567   v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key);
    568   if (privates.IsEmpty()) {
    569     privates = v8::Object::New(args.GetIsolate());
    570     obj->SetHiddenValue(privates_key, privates);
    571   }
    572   args.GetReturnValue().Set(privates);
    573 }
    574 
    575 v8::Handle<v8::Value> ModuleSystem::LoadModule(const std::string& module_name) {
    576   v8::EscapableHandleScope handle_scope(GetIsolate());
    577   v8::Context::Scope context_scope(context()->v8_context());
    578 
    579   v8::Handle<v8::Value> source(GetSource(module_name));
    580   if (source.IsEmpty() || source->IsUndefined()) {
    581     Fatal(context_, "No source for require(" + module_name + ")");
    582     return v8::Undefined(GetIsolate());
    583   }
    584   v8::Handle<v8::String> wrapped_source(
    585       WrapSource(v8::Handle<v8::String>::Cast(source)));
    586   // Modules are wrapped in (function(){...}) so they always return functions.
    587   v8::Handle<v8::Value> func_as_value =
    588       RunString(wrapped_source,
    589                 v8::String::NewFromUtf8(GetIsolate(), module_name.c_str()));
    590   if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) {
    591     Fatal(context_, "Bad source for require(" + module_name + ")");
    592     return v8::Undefined(GetIsolate());
    593   }
    594 
    595   v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value);
    596 
    597   v8::Handle<v8::Object> define_object = v8::Object::New(GetIsolate());
    598   gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object);
    599 
    600   v8::Local<v8::Value> exports = v8::Object::New(GetIsolate());
    601   v8::Handle<v8::Object> natives(NewInstance());
    602   CHECK(!natives.IsEmpty());  // this can happen if v8 has issues
    603 
    604   // These must match the argument order in WrapSource.
    605   v8::Handle<v8::Value> args[] = {
    606       // AMD.
    607       define_object->Get(v8::String::NewFromUtf8(GetIsolate(), "define")),
    608       // CommonJS.
    609       natives->Get(v8::String::NewFromUtf8(
    610           GetIsolate(), "require", v8::String::kInternalizedString)),
    611       natives->Get(v8::String::NewFromUtf8(
    612           GetIsolate(), "requireNative", v8::String::kInternalizedString)),
    613       natives->Get(v8::String::NewFromUtf8(
    614           GetIsolate(), "requireAsync", v8::String::kInternalizedString)),
    615       exports,
    616       // Libraries that we magically expose to every module.
    617       console::AsV8Object(),
    618       natives->Get(v8::String::NewFromUtf8(
    619           GetIsolate(), "privates", v8::String::kInternalizedString)),
    620       // Each safe builtin. Keep in order with the arguments in WrapSource.
    621       context_->safe_builtins()->GetArray(),
    622       context_->safe_builtins()->GetFunction(),
    623       context_->safe_builtins()->GetJSON(),
    624       context_->safe_builtins()->GetObjekt(),
    625       context_->safe_builtins()->GetRegExp(),
    626       context_->safe_builtins()->GetString(),
    627       context_->safe_builtins()->GetError(),
    628   };
    629   {
    630     v8::TryCatch try_catch;
    631     try_catch.SetCaptureMessage(true);
    632     context_->CallFunction(func, arraysize(args), args);
    633     if (try_catch.HasCaught()) {
    634       HandleException(try_catch);
    635       return v8::Undefined(GetIsolate());
    636     }
    637   }
    638   return handle_scope.Escape(exports);
    639 }
    640 
    641 void ModuleSystem::OnDidAddPendingModule(
    642     const std::string& id,
    643     const std::vector<std::string>& dependencies) {
    644   if (!source_map_->Contains(id))
    645     return;
    646 
    647   gin::ModuleRegistry* registry =
    648       gin::ModuleRegistry::From(context_->v8_context());
    649   DCHECK(registry);
    650   for (std::vector<std::string>::const_iterator it = dependencies.begin();
    651        it != dependencies.end();
    652        ++it) {
    653     if (registry->available_modules().count(*it) == 0)
    654       LoadModule(*it);
    655   }
    656   registry->AttemptToLoadMoreModules(GetIsolate());
    657 }
    658 
    659 void ModuleSystem::OnModuleLoaded(
    660     scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > resolver,
    661     v8::Handle<v8::Value> value) {
    662   if (!is_valid())
    663     return;
    664   v8::HandleScope handle_scope(GetIsolate());
    665   v8::Handle<v8::Promise::Resolver> resolver_local(
    666       v8::Local<v8::Promise::Resolver>::New(GetIsolate(), *resolver));
    667   resolver_local->Resolve(value);
    668 }
    669 
    670 }  // namespace extensions
    671