Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / extensions / renderer / module_system.cc
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