Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2012 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 "chrome/renderer/extensions/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 "chrome/common/chrome_switches.h"
     14 #include "chrome/common/extensions/extension_messages.h"
     15 #include "chrome/common/extensions/features/feature_channel.h"
     16 #include "chrome/renderer/extensions/chrome_v8_context.h"
     17 #include "chrome/renderer/extensions/console.h"
     18 #include "chrome/renderer/extensions/safe_builtins.h"
     19 #include "content/public/renderer/render_view.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(ChromeV8Context* 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   // <= dev means dev, canary, and trunk.
     57   if (GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV)
     58     console::Fatal(context->isolate()->GetCallingContext(), full_message);
     59   else
     60     console::Error(context->isolate()->GetCallingContext(), full_message);
     61 }
     62 
     63 void Warn(v8::Isolate* isolate, const std::string& message) {
     64   console::Warn(isolate->GetCallingContext(), message);
     65 }
     66 
     67 // Default exception handler which logs the exception.
     68 class DefaultExceptionHandler : public ModuleSystem::ExceptionHandler {
     69  public:
     70   explicit DefaultExceptionHandler(ChromeV8Context* context)
     71       : context_(context) {}
     72 
     73   // Fatally dumps the debug info from |try_catch| to the console.
     74   // Make sure this is never used for exceptions that originate in external
     75   // code!
     76   virtual void HandleUncaughtException(const v8::TryCatch& try_catch) OVERRIDE {
     77     v8::HandleScope handle_scope(context_->isolate());
     78     std::string stack_trace = "<stack trace unavailable>";
     79     if (!try_catch.StackTrace().IsEmpty()) {
     80       v8::String::Utf8Value stack_value(try_catch.StackTrace());
     81       if (*stack_value)
     82         stack_trace.assign(*stack_value, stack_value.length());
     83       else
     84         stack_trace = "<could not convert stack trace to string>";
     85     }
     86     Fatal(context_, CreateExceptionString(try_catch) + "{" + stack_trace + "}");
     87   }
     88 
     89  private:
     90   ChromeV8Context* context_;
     91 };
     92 
     93 } // namespace
     94 
     95 std::string ModuleSystem::ExceptionHandler::CreateExceptionString(
     96     const v8::TryCatch& try_catch) {
     97   v8::Handle<v8::Message> message(try_catch.Message());
     98   if (message.IsEmpty()) {
     99     return "try_catch has no message";
    100   }
    101 
    102   std::string resource_name = "<unknown resource>";
    103   if (!message->GetScriptResourceName().IsEmpty()) {
    104     v8::String::Utf8Value resource_name_v8(
    105         message->GetScriptResourceName()->ToString());
    106     resource_name.assign(*resource_name_v8, resource_name_v8.length());
    107   }
    108 
    109   std::string error_message = "<no error message>";
    110   if (!message->Get().IsEmpty()) {
    111     v8::String::Utf8Value error_message_v8(message->Get());
    112     error_message.assign(*error_message_v8, error_message_v8.length());
    113   }
    114 
    115   return base::StringPrintf("%s:%d: %s",
    116                             resource_name.c_str(),
    117                             message->GetLineNumber(),
    118                             error_message.c_str());
    119 }
    120 
    121 ModuleSystem::ModuleSystem(ChromeV8Context* context, SourceMap* source_map)
    122     : ObjectBackedNativeHandler(context),
    123       context_(context),
    124       source_map_(source_map),
    125       natives_enabled_(0),
    126       exception_handler_(new DefaultExceptionHandler(context)) {
    127   RouteFunction("require",
    128       base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this)));
    129   RouteFunction("requireNative",
    130       base::Bind(&ModuleSystem::RequireNative, base::Unretained(this)));
    131   RouteFunction("privates",
    132       base::Bind(&ModuleSystem::Private, base::Unretained(this)));
    133 
    134   v8::Handle<v8::Object> global(context->v8_context()->Global());
    135   global->SetHiddenValue(
    136       v8::String::NewFromUtf8(context->isolate(), kModulesField),
    137       v8::Object::New());
    138   global->SetHiddenValue(
    139       v8::String::NewFromUtf8(context->isolate(), kModuleSystem),
    140       v8::External::New(context->isolate(), this));
    141 }
    142 
    143 ModuleSystem::~ModuleSystem() {
    144   Invalidate();
    145 }
    146 
    147 void ModuleSystem::Invalidate() {
    148   if (!is_valid())
    149     return;
    150 
    151   // Clear the module system properties from the global context. It's polite,
    152   // and we use this as a signal in lazy handlers that we no longer exist.
    153   {
    154     v8::HandleScope scope(GetIsolate());
    155     v8::Handle<v8::Object> global = context()->v8_context()->Global();
    156     global->DeleteHiddenValue(
    157         v8::String::NewFromUtf8(GetIsolate(), kModulesField));
    158     global->DeleteHiddenValue(
    159         v8::String::NewFromUtf8(GetIsolate(), kModuleSystem));
    160   }
    161 
    162   // Invalidate all of the successfully required handlers we own.
    163   for (NativeHandlerMap::iterator it = native_handler_map_.begin();
    164        it != native_handler_map_.end(); ++it) {
    165     it->second->Invalidate();
    166   }
    167 
    168   ObjectBackedNativeHandler::Invalidate();
    169 }
    170 
    171 ModuleSystem::NativesEnabledScope::NativesEnabledScope(
    172     ModuleSystem* module_system)
    173     : module_system_(module_system) {
    174   module_system_->natives_enabled_++;
    175 }
    176 
    177 ModuleSystem::NativesEnabledScope::~NativesEnabledScope() {
    178   module_system_->natives_enabled_--;
    179   CHECK_GE(module_system_->natives_enabled_, 0);
    180 }
    181 
    182 void ModuleSystem::HandleException(const v8::TryCatch& try_catch) {
    183   exception_handler_->HandleUncaughtException(try_catch);
    184 }
    185 
    186 v8::Handle<v8::Value> ModuleSystem::Require(const std::string& module_name) {
    187   v8::EscapableHandleScope handle_scope(GetIsolate());
    188   return handle_scope.Escape(RequireForJsInner(
    189       v8::String::NewFromUtf8(GetIsolate(), module_name.c_str())));
    190 }
    191 
    192 void ModuleSystem::RequireForJs(
    193   const v8::FunctionCallbackInfo<v8::Value>& args) {
    194   v8::Handle<v8::String> module_name = args[0]->ToString();
    195   args.GetReturnValue().Set(RequireForJsInner(module_name));
    196 }
    197 
    198 v8::Local<v8::Value> ModuleSystem::RequireForJsInner(
    199     v8::Handle<v8::String> module_name) {
    200   v8::EscapableHandleScope handle_scope(GetIsolate());
    201   v8::Context::Scope context_scope(context()->v8_context());
    202 
    203   v8::Handle<v8::Object> global(context()->v8_context()->Global());
    204 
    205   // The module system might have been deleted. This can happen if a different
    206   // context keeps a reference to us, but our frame is destroyed (e.g.
    207   // background page keeps reference to chrome object in a closed popup).
    208   v8::Handle<v8::Value> modules_value = global->GetHiddenValue(
    209       v8::String::NewFromUtf8(GetIsolate(), kModulesField));
    210   if (modules_value.IsEmpty() || modules_value->IsUndefined()) {
    211     Warn(GetIsolate(), "Extension view no longer exists");
    212     return v8::Undefined(GetIsolate());
    213   }
    214 
    215   v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(modules_value));
    216   v8::Local<v8::Value> exports(modules->Get(module_name));
    217   if (!exports->IsUndefined())
    218     return handle_scope.Escape(exports);
    219 
    220   std::string module_name_str = *v8::String::Utf8Value(module_name);
    221   v8::Handle<v8::Value> source(GetSource(module_name_str));
    222   if (source.IsEmpty() || source->IsUndefined()) {
    223     Fatal(context_, "No source for require(" + module_name_str + ")");
    224     return v8::Undefined(GetIsolate());
    225   }
    226   v8::Handle<v8::String> wrapped_source(WrapSource(
    227       v8::Handle<v8::String>::Cast(source)));
    228   // Modules are wrapped in (function(){...}) so they always return functions.
    229   v8::Handle<v8::Value> func_as_value = RunString(wrapped_source, module_name);
    230   if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) {
    231     Fatal(context_, "Bad source for require(" + module_name_str + ")");
    232     return v8::Undefined(GetIsolate());
    233   }
    234 
    235   v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value);
    236 
    237   exports = v8::Object::New();
    238   v8::Handle<v8::Object> natives(NewInstance());
    239   CHECK(!natives.IsEmpty());  // this can happen if v8 has issues
    240 
    241   // These must match the argument order in WrapSource.
    242   v8::Handle<v8::Value> args[] = {
    243       // CommonJS.
    244       natives->Get(v8::String::NewFromUtf8(
    245           GetIsolate(), "require", v8::String::kInternalizedString)),
    246       natives->Get(v8::String::NewFromUtf8(
    247             GetIsolate(), "requireNative", v8::String::kInternalizedString)),
    248       exports,
    249       // Libraries that we magically expose to every module.
    250       console::AsV8Object(),
    251       natives->Get(v8::String::NewFromUtf8(
    252             GetIsolate(), "privates", v8::String::kInternalizedString)),
    253       // Each safe builtin. Keep in order with the arguments in WrapSource.
    254       context_->safe_builtins()->GetArray(),
    255       context_->safe_builtins()->GetFunction(),
    256       context_->safe_builtins()->GetJSON(),
    257       context_->safe_builtins()->GetObjekt(),
    258       context_->safe_builtins()->GetRegExp(),
    259       context_->safe_builtins()->GetString(), };
    260   {
    261     v8::TryCatch try_catch;
    262     try_catch.SetCaptureMessage(true);
    263     context_->CallFunction(func, arraysize(args), args);
    264     if (try_catch.HasCaught()) {
    265       HandleException(try_catch);
    266       return v8::Undefined(GetIsolate());
    267     }
    268   }
    269   modules->Set(module_name, exports);
    270   return handle_scope.Escape(exports);
    271 }
    272 
    273 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
    274     const std::string& module_name,
    275     const std::string& method_name) {
    276   v8::HandleScope handle_scope(GetIsolate());
    277   v8::Handle<v8::Value> no_args;
    278   return CallModuleMethod(module_name, method_name, 0, &no_args);
    279 }
    280 
    281 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
    282     const std::string& module_name,
    283     const std::string& method_name,
    284     std::vector<v8::Handle<v8::Value> >* args) {
    285   return CallModuleMethod(
    286       module_name, method_name, args->size(), vector_as_array(args));
    287 }
    288 
    289 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
    290     const std::string& module_name,
    291     const std::string& method_name,
    292     int argc,
    293     v8::Handle<v8::Value> argv[]) {
    294   TRACE_EVENT2("v8", "v8.callModuleMethod",
    295                "module_name", module_name,
    296                "method_name", method_name);
    297 
    298   v8::EscapableHandleScope handle_scope(GetIsolate());
    299   v8::Context::Scope context_scope(context()->v8_context());
    300 
    301   v8::Local<v8::Value> module;
    302   {
    303     NativesEnabledScope natives_enabled(this);
    304     module = RequireForJsInner(
    305         v8::String::NewFromUtf8(GetIsolate(), module_name.c_str()));
    306   }
    307 
    308   if (module.IsEmpty() || !module->IsObject()) {
    309     Fatal(context_,
    310           "Failed to get module " + module_name + " to call " + method_name);
    311     return handle_scope.Escape(
    312         v8::Local<v8::Primitive>(v8::Undefined(GetIsolate())));
    313   }
    314 
    315   v8::Local<v8::Value> value =
    316       v8::Handle<v8::Object>::Cast(module)->Get(
    317           v8::String::NewFromUtf8(GetIsolate(), method_name.c_str()));
    318   if (value.IsEmpty() || !value->IsFunction()) {
    319     Fatal(context_, module_name + "." + method_name + " is not a function");
    320     return handle_scope.Escape(
    321         v8::Local<v8::Primitive>(v8::Undefined(GetIsolate())));
    322   }
    323 
    324   v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
    325   v8::Local<v8::Value> result;
    326   {
    327     v8::TryCatch try_catch;
    328     try_catch.SetCaptureMessage(true);
    329     result = context_->CallFunction(func, argc, argv);
    330     if (try_catch.HasCaught())
    331       HandleException(try_catch);
    332   }
    333   return handle_scope.Escape(result);
    334 }
    335 
    336 void ModuleSystem::RegisterNativeHandler(const std::string& name,
    337     scoped_ptr<NativeHandler> native_handler) {
    338   native_handler_map_[name] =
    339       linked_ptr<NativeHandler>(native_handler.release());
    340 }
    341 
    342 void ModuleSystem::OverrideNativeHandlerForTest(const std::string& name) {
    343   overridden_native_handlers_.insert(name);
    344 }
    345 
    346 void ModuleSystem::RunString(const std::string& code, const std::string& name) {
    347   v8::HandleScope handle_scope(GetIsolate());
    348   RunString(v8::String::NewFromUtf8(GetIsolate(), code.c_str()),
    349             v8::String::NewFromUtf8(GetIsolate(), name.c_str()));
    350 }
    351 
    352 // static
    353 void ModuleSystem::NativeLazyFieldGetter(
    354     v8::Local<v8::String> property,
    355     const v8::PropertyCallbackInfo<v8::Value>& info) {
    356   LazyFieldGetterInner(property,
    357                        info,
    358                        &ModuleSystem::RequireNativeFromString);
    359 }
    360 
    361 // static
    362 void ModuleSystem::LazyFieldGetter(
    363     v8::Local<v8::String> property,
    364     const v8::PropertyCallbackInfo<v8::Value>& info) {
    365   LazyFieldGetterInner(property, info, &ModuleSystem::Require);
    366 }
    367 
    368 // static
    369 void ModuleSystem::LazyFieldGetterInner(
    370     v8::Local<v8::String> property,
    371     const v8::PropertyCallbackInfo<v8::Value>& info,
    372     RequireFunction require_function) {
    373   CHECK(!info.Data().IsEmpty());
    374   CHECK(info.Data()->IsObject());
    375   v8::HandleScope handle_scope(info.GetIsolate());
    376   v8::Handle<v8::Object> parameters = v8::Handle<v8::Object>::Cast(info.Data());
    377   // This context should be the same as context()->v8_context().
    378   v8::Handle<v8::Context> context = parameters->CreationContext();
    379   v8::Handle<v8::Object> global(context->Global());
    380   v8::Handle<v8::Value> module_system_value = global->GetHiddenValue(
    381       v8::String::NewFromUtf8(info.GetIsolate(), kModuleSystem));
    382   if (module_system_value.IsEmpty() || !module_system_value->IsExternal()) {
    383     // ModuleSystem has been deleted.
    384     // TODO(kalman): See comment in header file.
    385     Warn(info.GetIsolate(),
    386          "Module system has been deleted, does extension view exist?");
    387     return;
    388   }
    389 
    390   ModuleSystem* module_system = static_cast<ModuleSystem*>(
    391       v8::Handle<v8::External>::Cast(module_system_value)->Value());
    392 
    393   std::string name = *v8::String::Utf8Value(parameters->Get(
    394       v8::String::NewFromUtf8(info.GetIsolate(), kModuleName))->ToString());
    395 
    396   // Switch to our v8 context because we need functions created while running
    397   // the require()d module to belong to our context, not the current one.
    398   v8::Context::Scope context_scope(context);
    399   NativesEnabledScope natives_enabled_scope(module_system);
    400 
    401   v8::TryCatch try_catch;
    402   v8::Handle<v8::Value> module_value = (module_system->*require_function)(name);
    403   if (try_catch.HasCaught()) {
    404     module_system->HandleException(try_catch);
    405     return;
    406   }
    407   if (module_value.IsEmpty() || !module_value->IsObject()) {
    408     // require_function will have already logged this, we don't need to.
    409     return;
    410   }
    411 
    412   v8::Handle<v8::Object> module = v8::Handle<v8::Object>::Cast(module_value);
    413   v8::Handle<v8::String> field =
    414       parameters->Get(v8::String::NewFromUtf8(info.GetIsolate(), kModuleField))
    415           ->ToString();
    416 
    417   if (!module->Has(field)) {
    418     std::string field_str = *v8::String::Utf8Value(field);
    419     Fatal(module_system->context_,
    420           "Lazy require of " + name + "." + field_str + " did not set the " +
    421               field_str + " field");
    422     return;
    423   }
    424 
    425   v8::Local<v8::Value> new_field = module->Get(field);
    426   if (try_catch.HasCaught()) {
    427     module_system->HandleException(try_catch);
    428     return;
    429   }
    430 
    431   // Ok for it to be undefined, among other things it's how bindings signify
    432   // that the extension doesn't have permission to use them.
    433   CHECK(!new_field.IsEmpty());
    434 
    435   // Delete the getter and set this field to |new_field| so the same object is
    436   // returned every time a certain API is accessed.
    437   v8::Handle<v8::Object> object = info.This();
    438   object->Delete(property);
    439   object->Set(property, new_field);
    440   info.GetReturnValue().Set(new_field);
    441 }
    442 
    443 void ModuleSystem::SetLazyField(v8::Handle<v8::Object> object,
    444                                 const std::string& field,
    445                                 const std::string& module_name,
    446                                 const std::string& module_field) {
    447   SetLazyField(object, field, module_name, module_field,
    448       &ModuleSystem::LazyFieldGetter);
    449 }
    450 
    451 void ModuleSystem::SetLazyField(v8::Handle<v8::Object> object,
    452                                 const std::string& field,
    453                                 const std::string& module_name,
    454                                 const std::string& module_field,
    455                                 v8::AccessorGetterCallback getter) {
    456   v8::HandleScope handle_scope(GetIsolate());
    457   v8::Handle<v8::Object> parameters = v8::Object::New();
    458   parameters->Set(v8::String::NewFromUtf8(GetIsolate(), kModuleName),
    459                   v8::String::NewFromUtf8(GetIsolate(), module_name.c_str()));
    460   parameters->Set(v8::String::NewFromUtf8(GetIsolate(), kModuleField),
    461                   v8::String::NewFromUtf8(GetIsolate(), module_field.c_str()));
    462   object->SetAccessor(v8::String::NewFromUtf8(GetIsolate(), field.c_str()),
    463                       getter,
    464                       NULL,
    465                       parameters);
    466 }
    467 
    468 void ModuleSystem::SetNativeLazyField(v8::Handle<v8::Object> object,
    469                                       const std::string& field,
    470                                       const std::string& module_name,
    471                                       const std::string& module_field) {
    472   SetLazyField(object, field, module_name, module_field,
    473       &ModuleSystem::NativeLazyFieldGetter);
    474 }
    475 
    476 
    477 v8::Isolate* ModuleSystem::GetIsolate() const {
    478   return context_->isolate();
    479 }
    480 
    481 v8::Handle<v8::Value> ModuleSystem::RunString(v8::Handle<v8::String> code,
    482                                               v8::Handle<v8::String> name) {
    483   v8::EscapableHandleScope handle_scope(GetIsolate());
    484   v8::Context::Scope context_scope(context()->v8_context());
    485 
    486   // Prepend extensions:: to |name| so that internal code can be differentiated
    487   // from external code in stack traces. This has no effect on behaviour.
    488   std::string internal_name = base::StringPrintf("extensions::%s",
    489                                                  *v8::String::Utf8Value(name));
    490 
    491   blink::WebScopedMicrotaskSuppression suppression;
    492   v8::TryCatch try_catch;
    493   try_catch.SetCaptureMessage(true);
    494   v8::Handle<v8::Script> script(
    495       v8::Script::New(code,
    496                       v8::String::NewFromUtf8(GetIsolate(),
    497                                               internal_name.c_str(),
    498                                               v8::String::kNormalString,
    499                                               internal_name.size())));
    500   if (try_catch.HasCaught()) {
    501     HandleException(try_catch);
    502     return v8::Undefined(GetIsolate());
    503   }
    504 
    505   v8::Local<v8::Value> result = script->Run();
    506   if (try_catch.HasCaught()) {
    507     HandleException(try_catch);
    508     return v8::Undefined(GetIsolate());
    509   }
    510 
    511   return handle_scope.Escape(result);
    512 }
    513 
    514 v8::Handle<v8::Value> ModuleSystem::GetSource(const std::string& module_name) {
    515   v8::EscapableHandleScope handle_scope(GetIsolate());
    516   if (!source_map_->Contains(module_name))
    517     return v8::Undefined(GetIsolate());
    518   return handle_scope.Escape(
    519       v8::Local<v8::Value>(source_map_->GetSource(GetIsolate(), module_name)));
    520 }
    521 
    522 void ModuleSystem::RequireNative(
    523     const v8::FunctionCallbackInfo<v8::Value>& args) {
    524   CHECK_EQ(1, args.Length());
    525   std::string native_name = *v8::String::Utf8Value(args[0]->ToString());
    526   args.GetReturnValue().Set(RequireNativeFromString(native_name));
    527 }
    528 
    529 v8::Handle<v8::Value> ModuleSystem::RequireNativeFromString(
    530     const std::string& native_name) {
    531   if (natives_enabled_ == 0) {
    532     // HACK: if in test throw exception so that we can test the natives-disabled
    533     // logic; however, under normal circumstances, this is programmer error so
    534     // we could crash.
    535     if (exception_handler_) {
    536       return GetIsolate()->ThrowException(
    537           v8::String::NewFromUtf8(GetIsolate(), "Natives disabled"));
    538     }
    539     Fatal(context_, "Natives disabled for requireNative(" + native_name + ")");
    540     return v8::Undefined(GetIsolate());
    541   }
    542 
    543   if (overridden_native_handlers_.count(native_name) > 0u) {
    544     return RequireForJsInner(
    545         v8::String::NewFromUtf8(GetIsolate(), native_name.c_str()));
    546   }
    547 
    548   NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
    549   if (i == native_handler_map_.end()) {
    550     Fatal(context_,
    551           "Couldn't find native for requireNative(" + native_name + ")");
    552     return v8::Undefined(GetIsolate());
    553   }
    554   return i->second->NewInstance();
    555 }
    556 
    557 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) {
    558   v8::EscapableHandleScope handle_scope(GetIsolate());
    559   // Keep in order with the arguments in RequireForJsInner.
    560   v8::Handle<v8::String> left = v8::String::NewFromUtf8(GetIsolate(),
    561       "(function(require, requireNative, exports, "
    562                 "console, privates, "
    563                 "$Array, $Function, $JSON, $Object, $RegExp, $String) {"
    564        "'use strict';");
    565   v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})");
    566   return handle_scope.Escape(v8::Local<v8::String>(
    567       v8::String::Concat(left, v8::String::Concat(source, right))));
    568 }
    569 
    570 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) {
    571   CHECK_EQ(1, args.Length());
    572   CHECK(args[0]->IsObject());
    573   v8::Local<v8::Object> obj = args[0].As<v8::Object>();
    574   v8::Local<v8::String> privates_key =
    575       v8::String::NewFromUtf8(GetIsolate(), "privates");
    576   v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key);
    577   if (privates.IsEmpty()) {
    578     privates = v8::Object::New();
    579     obj->SetHiddenValue(privates_key, privates);
    580   }
    581   args.GetReturnValue().Set(privates);
    582 }
    583 
    584 }  // namespace extensions
    585