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_messages.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 "third_party/WebKit/public/web/WebFrame.h"
     20 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
     21 
     22 namespace extensions {
     23 
     24 namespace {
     25 
     26 const char* kModuleSystem = "module_system";
     27 const char* kModuleName = "module_name";
     28 const char* kModuleField = "module_field";
     29 const char* kModulesField = "modules";
     30 
     31 // Logs a fatal error for the calling context, with some added metadata about
     32 // the context:
     33 //  - Its type (blessed, unblessed, etc).
     34 //  - Whether it's valid.
     35 //  - The extension ID, if one exists.
     36 //
     37 // This will only actual be fatal in in dev/canary, since in too many cases
     38 // we're at the mercy of the extension or web page's environment. They can mess
     39 // up our JS in unexpected ways. Hopefully dev/canary channel will pick up such
     40 // problems, but given the wider variety on stable/beta it's impossible to know.
     41 void Fatal(ScriptContext* context, const std::string& message) {
     42   // Prepend some context metadata.
     43   std::string full_message = "(";
     44   if (!context->is_valid())
     45     full_message += "Invalid ";
     46   full_message += context->GetContextTypeDescription();
     47   full_message += " context";
     48   if (context->extension()) {
     49     full_message += " for ";
     50     full_message += context->extension()->id();
     51   }
     52   full_message += ") ";
     53   full_message += message;
     54 
     55   if (ExtensionsClient::Get()->ShouldSuppressFatalErrors())
     56     console::Error(context->isolate()->GetCallingContext(), full_message);
     57   else
     58     console::Fatal(context->isolate()->GetCallingContext(), full_message);
     59 }
     60 
     61 void Warn(v8::Isolate* isolate, const std::string& message) {
     62   console::Warn(isolate->GetCallingContext(), message);
     63 }
     64 
     65 // Default exception handler which logs the exception.
     66 class DefaultExceptionHandler : public ModuleSystem::ExceptionHandler {
     67  public:
     68   explicit DefaultExceptionHandler(ScriptContext* context)
     69       : context_(context) {}
     70 
     71   // Fatally dumps the debug info from |try_catch| to the console.
     72   // Make sure this is never used for exceptions that originate in external
     73   // code!
     74   virtual void HandleUncaughtException(const v8::TryCatch& try_catch) OVERRIDE {
     75     v8::HandleScope handle_scope(context_->isolate());
     76     std::string stack_trace = "<stack trace unavailable>";
     77     if (!try_catch.StackTrace().IsEmpty()) {
     78       v8::String::Utf8Value stack_value(try_catch.StackTrace());
     79       if (*stack_value)
     80         stack_trace.assign(*stack_value, stack_value.length());
     81       else
     82         stack_trace = "<could not convert stack trace to string>";
     83     }
     84     Fatal(context_, CreateExceptionString(try_catch) + "{" + stack_trace + "}");
     85   }
     86 
     87  private:
     88   ScriptContext* context_;
     89 };
     90 
     91 }  // namespace
     92 
     93 std::string ModuleSystem::ExceptionHandler::CreateExceptionString(
     94     const v8::TryCatch& try_catch) {
     95   v8::Handle<v8::Message> message(try_catch.Message());
     96   if (message.IsEmpty()) {
     97     return "try_catch has no message";
     98   }
     99 
    100   std::string resource_name = "<unknown resource>";
    101   if (!message->GetScriptResourceName().IsEmpty()) {
    102     v8::String::Utf8Value resource_name_v8(
    103         message->GetScriptResourceName()->ToString());
    104     resource_name.assign(*resource_name_v8, resource_name_v8.length());
    105   }
    106 
    107   std::string error_message = "<no error message>";
    108   if (!message->Get().IsEmpty()) {
    109     v8::String::Utf8Value error_message_v8(message->Get());
    110     error_message.assign(*error_message_v8, error_message_v8.length());
    111   }
    112 
    113   return base::StringPrintf("%s:%d: %s",
    114                             resource_name.c_str(),
    115                             message->GetLineNumber(),
    116                             error_message.c_str());
    117 }
    118 
    119 ModuleSystem::ModuleSystem(ScriptContext* context, SourceMap* source_map)
    120     : ObjectBackedNativeHandler(context),
    121       context_(context),
    122       source_map_(source_map),
    123       natives_enabled_(0),
    124       exception_handler_(new DefaultExceptionHandler(context)) {
    125   RouteFunction(
    126       "require",
    127       base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this)));
    128   RouteFunction(
    129       "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   v8::Isolate* isolate = context->isolate();
    136   global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModulesField),
    137                          v8::Object::New(isolate));
    138   global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModuleSystem),
    139                          v8::External::New(isolate, this));
    140 }
    141 
    142 ModuleSystem::~ModuleSystem() { Invalidate(); }
    143 
    144 void ModuleSystem::Invalidate() {
    145   if (!is_valid())
    146     return;
    147 
    148   // 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.
    150   {
    151     v8::HandleScope scope(GetIsolate());
    152     v8::Handle<v8::Object> global = context()->v8_context()->Global();
    153     global->DeleteHiddenValue(
    154         v8::String::NewFromUtf8(GetIsolate(), kModulesField));
    155     global->DeleteHiddenValue(
    156         v8::String::NewFromUtf8(GetIsolate(), kModuleSystem));
    157   }
    158 
    159   // Invalidate all of the successfully required handlers we own.
    160   for (NativeHandlerMap::iterator it = native_handler_map_.begin();
    161        it != native_handler_map_.end();
    162        ++it) {
    163     it->second->Invalidate();
    164   }
    165 
    166   ObjectBackedNativeHandler::Invalidate();
    167 }
    168 
    169 ModuleSystem::NativesEnabledScope::NativesEnabledScope(
    170     ModuleSystem* module_system)
    171     : module_system_(module_system) {
    172   module_system_->natives_enabled_++;
    173 }
    174 
    175 ModuleSystem::NativesEnabledScope::~NativesEnabledScope() {
    176   module_system_->natives_enabled_--;
    177   CHECK_GE(module_system_->natives_enabled_, 0);
    178 }
    179 
    180 void ModuleSystem::HandleException(const v8::TryCatch& try_catch) {
    181   exception_handler_->HandleUncaughtException(try_catch);
    182 }
    183 
    184 v8::Handle<v8::Value> ModuleSystem::Require(const std::string& module_name) {
    185   v8::EscapableHandleScope handle_scope(GetIsolate());
    186   return handle_scope.Escape(RequireForJsInner(
    187       v8::String::NewFromUtf8(GetIsolate(), module_name.c_str())));
    188 }
    189 
    190 void ModuleSystem::RequireForJs(
    191     const v8::FunctionCallbackInfo<v8::Value>& args) {
    192   v8::Handle<v8::String> module_name = args[0]->ToString();
    193   args.GetReturnValue().Set(RequireForJsInner(module_name));
    194 }
    195 
    196 v8::Local<v8::Value> ModuleSystem::RequireForJsInner(
    197     v8::Handle<v8::String> module_name) {
    198   v8::EscapableHandleScope handle_scope(GetIsolate());
    199   v8::Context::Scope context_scope(context()->v8_context());
    200 
    201   v8::Handle<v8::Object> global(context()->v8_context()->Global());
    202 
    203   // The module system might have been deleted. This can happen if a different
    204   // context keeps a reference to us, but our frame is destroyed (e.g.
    205   // background page keeps reference to chrome object in a closed popup).
    206   v8::Handle<v8::Value> modules_value = global->GetHiddenValue(
    207       v8::String::NewFromUtf8(GetIsolate(), kModulesField));
    208   if (modules_value.IsEmpty() || modules_value->IsUndefined()) {
    209     Warn(GetIsolate(), "Extension view no longer exists");
    210     return v8::Undefined(GetIsolate());
    211   }
    212 
    213   v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(modules_value));
    214   v8::Local<v8::Value> exports(modules->Get(module_name));
    215   if (!exports->IsUndefined())
    216     return handle_scope.Escape(exports);
    217 
    218   std::string module_name_str = *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);
    268   return handle_scope.Escape(exports);
    269 }
    270 
    271 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
    272     const std::string& module_name,
    273     const std::string& method_name) {
    274   v8::HandleScope handle_scope(GetIsolate());
    275   v8::Handle<v8::Value> no_args;
    276   return CallModuleMethod(module_name, method_name, 0, &no_args);
    277 }
    278 
    279 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
    280     const std::string& module_name,
    281     const std::string& method_name,
    282     std::vector<v8::Handle<v8::Value> >* args) {
    283   return CallModuleMethod(
    284       module_name, method_name, args->size(), vector_as_array(args));
    285 }
    286 
    287 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
    288     const std::string& module_name,
    289     const std::string& method_name,
    290     int argc,
    291     v8::Handle<v8::Value> argv[]) {
    292   TRACE_EVENT2("v8",
    293                "v8.callModuleMethod",
    294                "module_name",
    295                module_name,
    296                "method_name",
    297                method_name);
    298 
    299   v8::EscapableHandleScope handle_scope(GetIsolate());
    300   v8::Context::Scope context_scope(context()->v8_context());
    301 
    302   v8::Local<v8::Value> module;
    303   {
    304     NativesEnabledScope natives_enabled(this);
    305     module = RequireForJsInner(
    306         v8::String::NewFromUtf8(GetIsolate(), module_name.c_str()));
    307   }
    308 
    309   if (module.IsEmpty() || !module->IsObject()) {
    310     Fatal(context_,
    311           "Failed to get module " + module_name + " to call " + method_name);
    312     return handle_scope.Escape(
    313         v8::Local<v8::Primitive>(v8::Undefined(GetIsolate())));
    314   }
    315 
    316   v8::Local<v8::Value> value = 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(
    337     const std::string& name,
    338     scoped_ptr<NativeHandler> native_handler) {
    339   native_handler_map_[name] =
    340       linked_ptr<NativeHandler>(native_handler.release());
    341 }
    342 
    343 void ModuleSystem::OverrideNativeHandlerForTest(const std::string& name) {
    344   overridden_native_handlers_.insert(name);
    345 }
    346 
    347 void ModuleSystem::RunString(const std::string& code, const std::string& name) {
    348   v8::HandleScope handle_scope(GetIsolate());
    349   RunString(v8::String::NewFromUtf8(GetIsolate(), code.c_str()),
    350             v8::String::NewFromUtf8(GetIsolate(), name.c_str()));
    351 }
    352 
    353 // static
    354 void ModuleSystem::NativeLazyFieldGetter(
    355     v8::Local<v8::String> property,
    356     const v8::PropertyCallbackInfo<v8::Value>& info) {
    357   LazyFieldGetterInner(property, info, &ModuleSystem::RequireNativeFromString);
    358 }
    359 
    360 // static
    361 void ModuleSystem::LazyFieldGetter(
    362     v8::Local<v8::String> property,
    363     const v8::PropertyCallbackInfo<v8::Value>& info) {
    364   LazyFieldGetterInner(property, info, &ModuleSystem::Require);
    365 }
    366 
    367 // static
    368 void ModuleSystem::LazyFieldGetterInner(
    369     v8::Local<v8::String> property,
    370     const v8::PropertyCallbackInfo<v8::Value>& info,
    371     RequireFunction require_function) {
    372   CHECK(!info.Data().IsEmpty());
    373   CHECK(info.Data()->IsObject());
    374   v8::HandleScope handle_scope(info.GetIsolate());
    375   v8::Handle<v8::Object> parameters = v8::Handle<v8::Object>::Cast(info.Data());
    376   // This context should be the same as context()->v8_context().
    377   v8::Handle<v8::Context> context = parameters->CreationContext();
    378   v8::Handle<v8::Object> global(context->Global());
    379   v8::Handle<v8::Value> module_system_value = global->GetHiddenValue(
    380       v8::String::NewFromUtf8(info.GetIsolate(), kModuleSystem));
    381   if (module_system_value.IsEmpty() || !module_system_value->IsExternal()) {
    382     // ModuleSystem has been deleted.
    383     // TODO(kalman): See comment in header file.
    384     Warn(info.GetIsolate(),
    385          "Module system has been deleted, does extension view exist?");
    386     return;
    387   }
    388 
    389   ModuleSystem* module_system = static_cast<ModuleSystem*>(
    390       v8::Handle<v8::External>::Cast(module_system_value)->Value());
    391 
    392   std::string name =
    393       *v8::String::Utf8Value(
    394           parameters->Get(v8::String::NewFromUtf8(info.GetIsolate(),
    395                                                   kModuleName))->ToString());
    396 
    397   // Switch to our v8 context because we need functions created while running
    398   // the require()d module to belong to our context, not the current one.
    399   v8::Context::Scope context_scope(context);
    400   NativesEnabledScope natives_enabled_scope(module_system);
    401 
    402   v8::TryCatch try_catch;
    403   v8::Handle<v8::Value> module_value = (module_system->*require_function)(name);
    404   if (try_catch.HasCaught()) {
    405     module_system->HandleException(try_catch);
    406     return;
    407   }
    408   if (module_value.IsEmpty() || !module_value->IsObject()) {
    409     // require_function will have already logged this, we don't need to.
    410     return;
    411   }
    412 
    413   v8::Handle<v8::Object> module = v8::Handle<v8::Object>::Cast(module_value);
    414   v8::Handle<v8::String> field =
    415       parameters->Get(v8::String::NewFromUtf8(info.GetIsolate(), kModuleField))
    416           ->ToString();
    417 
    418   if (!module->Has(field)) {
    419     std::string field_str = *v8::String::Utf8Value(field);
    420     Fatal(module_system->context_,
    421           "Lazy require of " + name + "." + field_str + " did not set the " +
    422               field_str + " field");
    423     return;
    424   }
    425 
    426   v8::Local<v8::Value> new_field = module->Get(field);
    427   if (try_catch.HasCaught()) {
    428     module_system->HandleException(try_catch);
    429     return;
    430   }
    431 
    432   // Ok for it to be undefined, among other things it's how bindings signify
    433   // that the extension doesn't have permission to use them.
    434   CHECK(!new_field.IsEmpty());
    435 
    436   // Delete the getter and set this field to |new_field| so the same object is
    437   // returned every time a certain API is accessed.
    438   v8::Handle<v8::Value> val = info.This();
    439   if (val->IsObject()) {
    440     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(val);
    441     object->Delete(property);
    442     object->Set(property, new_field);
    443   } else {
    444     NOTREACHED();
    445   }
    446   info.GetReturnValue().Set(new_field);
    447 }
    448 
    449 void ModuleSystem::SetLazyField(v8::Handle<v8::Object> object,
    450                                 const std::string& field,
    451                                 const std::string& module_name,
    452                                 const std::string& module_field) {
    453   SetLazyField(
    454       object, field, module_name, module_field, &ModuleSystem::LazyFieldGetter);
    455 }
    456 
    457 void ModuleSystem::SetLazyField(v8::Handle<v8::Object> object,
    458                                 const std::string& field,
    459                                 const std::string& module_name,
    460                                 const std::string& module_field,
    461                                 v8::AccessorGetterCallback getter) {
    462   v8::HandleScope handle_scope(GetIsolate());
    463   v8::Handle<v8::Object> parameters = v8::Object::New(GetIsolate());
    464   parameters->Set(v8::String::NewFromUtf8(GetIsolate(), kModuleName),
    465                   v8::String::NewFromUtf8(GetIsolate(), module_name.c_str()));
    466   parameters->Set(v8::String::NewFromUtf8(GetIsolate(), kModuleField),
    467                   v8::String::NewFromUtf8(GetIsolate(), module_field.c_str()));
    468   object->SetAccessor(v8::String::NewFromUtf8(GetIsolate(), field.c_str()),
    469                       getter,
    470                       NULL,
    471                       parameters);
    472 }
    473 
    474 void ModuleSystem::SetNativeLazyField(v8::Handle<v8::Object> object,
    475                                       const std::string& field,
    476                                       const std::string& module_name,
    477                                       const std::string& module_field) {
    478   SetLazyField(object,
    479                field,
    480                module_name,
    481                module_field,
    482                &ModuleSystem::NativeLazyFieldGetter);
    483 }
    484 
    485 v8::Handle<v8::Value> ModuleSystem::RunString(v8::Handle<v8::String> code,
    486                                               v8::Handle<v8::String> name) {
    487   v8::EscapableHandleScope handle_scope(GetIsolate());
    488   v8::Context::Scope context_scope(context()->v8_context());
    489 
    490   // Prepend extensions:: to |name| so that internal code can be differentiated
    491   // from external code in stack traces. This has no effect on behaviour.
    492   std::string internal_name =
    493       base::StringPrintf("extensions::%s", *v8::String::Utf8Value(name));
    494 
    495   blink::WebScopedMicrotaskSuppression suppression;
    496   v8::TryCatch try_catch;
    497   try_catch.SetCaptureMessage(true);
    498   v8::Handle<v8::Script> script(
    499       v8::Script::Compile(code,
    500                           v8::String::NewFromUtf8(GetIsolate(),
    501                                                   internal_name.c_str(),
    502                                                   v8::String::kNormalString,
    503                                                   internal_name.size())));
    504   if (try_catch.HasCaught()) {
    505     HandleException(try_catch);
    506     return v8::Undefined(GetIsolate());
    507   }
    508 
    509   v8::Local<v8::Value> result = script->Run();
    510   if (try_catch.HasCaught()) {
    511     HandleException(try_catch);
    512     return v8::Undefined(GetIsolate());
    513   }
    514 
    515   return handle_scope.Escape(result);
    516 }
    517 
    518 v8::Handle<v8::Value> ModuleSystem::GetSource(const std::string& module_name) {
    519   v8::EscapableHandleScope handle_scope(GetIsolate());
    520   if (!source_map_->Contains(module_name))
    521     return v8::Undefined(GetIsolate());
    522   return handle_scope.Escape(
    523       v8::Local<v8::Value>(source_map_->GetSource(GetIsolate(), module_name)));
    524 }
    525 
    526 void ModuleSystem::RequireNative(
    527     const v8::FunctionCallbackInfo<v8::Value>& args) {
    528   CHECK_EQ(1, args.Length());
    529   std::string native_name = *v8::String::Utf8Value(args[0]->ToString());
    530   args.GetReturnValue().Set(RequireNativeFromString(native_name));
    531 }
    532 
    533 v8::Handle<v8::Value> ModuleSystem::RequireNativeFromString(
    534     const std::string& native_name) {
    535   if (natives_enabled_ == 0) {
    536     // HACK: if in test throw exception so that we can test the natives-disabled
    537     // logic; however, under normal circumstances, this is programmer error so
    538     // we could crash.
    539     if (exception_handler_) {
    540       return GetIsolate()->ThrowException(
    541           v8::String::NewFromUtf8(GetIsolate(), "Natives disabled"));
    542     }
    543     Fatal(context_, "Natives disabled for requireNative(" + native_name + ")");
    544     return v8::Undefined(GetIsolate());
    545   }
    546 
    547   if (overridden_native_handlers_.count(native_name) > 0u) {
    548     return RequireForJsInner(
    549         v8::String::NewFromUtf8(GetIsolate(), native_name.c_str()));
    550   }
    551 
    552   NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
    553   if (i == native_handler_map_.end()) {
    554     Fatal(context_,
    555           "Couldn't find native for requireNative(" + native_name + ")");
    556     return v8::Undefined(GetIsolate());
    557   }
    558   return i->second->NewInstance();
    559 }
    560 
    561 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) {
    562   v8::EscapableHandleScope handle_scope(GetIsolate());
    563   // Keep in order with the arguments in RequireForJsInner.
    564   v8::Handle<v8::String> left = v8::String::NewFromUtf8(
    565       GetIsolate(),
    566       "(function(require, requireNative, exports, "
    567       "console, privates,"
    568       "$Array, $Function, $JSON, $Object, $RegExp, $String) {"
    569       "'use strict';");
    570   v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})");
    571   return handle_scope.Escape(v8::Local<v8::String>(
    572       v8::String::Concat(left, v8::String::Concat(source, right))));
    573 }
    574 
    575 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) {
    576   CHECK_EQ(1, args.Length());
    577   CHECK(args[0]->IsObject());
    578   v8::Local<v8::Object> obj = args[0].As<v8::Object>();
    579   v8::Local<v8::String> privates_key =
    580       v8::String::NewFromUtf8(GetIsolate(), "privates");
    581   v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key);
    582   if (privates.IsEmpty()) {
    583     privates = v8::Object::New(args.GetIsolate());
    584     obj->SetHiddenValue(privates_key, privates);
    585   }
    586   args.GetReturnValue().Set(privates);
    587 }
    588 
    589 }  // namespace extensions
    590