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.
5 #include "extensions/renderer/module_system.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 "gin/modules/module_registry.h"
20 #include "third_party/WebKit/public/web/WebFrame.h"
21 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
23 namespace extensions
{
27 const char* kModuleSystem
= "module_system";
28 const char* kModuleName
= "module_name";
29 const char* kModuleField
= "module_field";
30 const char* kModulesField
= "modules";
32 // Logs a fatal error for the calling context, with some added metadata about
34 // - Its type (blessed, unblessed, etc).
35 // - Whether it's valid.
36 // - The extension ID, if one exists.
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();
54 full_message
+= message
;
56 if (ExtensionsClient::Get()->ShouldSuppressFatalErrors())
57 console::Error(context
->isolate()->GetCallingContext(), full_message
);
59 console::Fatal(context
->isolate()->GetCallingContext(), full_message
);
62 void Warn(v8::Isolate
* isolate
, const std::string
& message
) {
63 console::Warn(isolate
->GetCallingContext(), message
);
66 // Default exception handler which logs the exception.
67 class DefaultExceptionHandler
: public ModuleSystem::ExceptionHandler
{
69 explicit DefaultExceptionHandler(ScriptContext
* context
)
70 : context_(context
) {}
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
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());
81 stack_trace
.assign(*stack_value
, stack_value
.length());
83 stack_trace
= "<could not convert stack trace to string>";
85 Fatal(context_
, CreateExceptionString(try_catch
) + "{" + stack_trace
+ "}");
89 ScriptContext
* context_
;
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";
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());
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());
114 return base::StringPrintf("%s:%d: %s",
115 resource_name
.c_str(),
116 message
->GetLineNumber(),
117 error_message
.c_str());
120 ModuleSystem::ModuleSystem(ScriptContext
* context
, SourceMap
* source_map
)
121 : ObjectBackedNativeHandler(context
),
123 source_map_(source_map
),
125 exception_handler_(new DefaultExceptionHandler(context
)),
126 weak_factory_(this) {
129 base::Bind(&ModuleSystem::RequireForJs
, base::Unretained(this)));
132 base::Bind(&ModuleSystem::RequireNative
, base::Unretained(this)));
135 base::Bind(&ModuleSystem::RequireAsync
, base::Unretained(this)));
136 RouteFunction("privates",
137 base::Bind(&ModuleSystem::Private
, base::Unretained(this)));
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));
146 gin::ModuleRegistry::From(context
->v8_context())->AddObserver(this);
149 ModuleSystem::~ModuleSystem() { Invalidate(); }
151 void ModuleSystem::Invalidate() {
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.
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
));
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();
170 it
->second
->Invalidate();
173 ObjectBackedNativeHandler::Invalidate();
176 ModuleSystem::NativesEnabledScope::NativesEnabledScope(
177 ModuleSystem
* module_system
)
178 : module_system_(module_system
) {
179 module_system_
->natives_enabled_
++;
182 ModuleSystem::NativesEnabledScope::~NativesEnabledScope() {
183 module_system_
->natives_enabled_
--;
184 CHECK_GE(module_system_
->natives_enabled_
, 0);
187 void ModuleSystem::HandleException(const v8::TryCatch
& try_catch
) {
188 exception_handler_
->HandleUncaughtException(try_catch
);
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())));
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
));
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());
208 v8::Handle
<v8::Object
> global(context()->v8_context()->Global());
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());
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
);
225 exports
= LoadModule(*v8::String::Utf8Value(module_name
));
226 modules
->Set(module_name
, exports
);
227 return handle_scope
.Escape(exports
);
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
));
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
));
247 v8::Local
<v8::Value
> ModuleSystem::CallModuleMethod(
248 const std::string
& module_name
,
249 const std::string
& method_name
,
251 v8::Handle
<v8::Value
> argv
[]) {
253 "v8.callModuleMethod",
259 v8::EscapableHandleScope
handle_scope(GetIsolate());
260 v8::Context::Scope
context_scope(context()->v8_context());
262 v8::Local
<v8::Value
> module
;
264 NativesEnabledScope
natives_enabled(this);
265 module
= RequireForJsInner(
266 v8::String::NewFromUtf8(GetIsolate(), module_name
.c_str()));
269 if (module
.IsEmpty() || !module
->IsObject()) {
271 "Failed to get module " + module_name
+ " to call " + method_name
);
272 return handle_scope
.Escape(
273 v8::Local
<v8::Primitive
>(v8::Undefined(GetIsolate())));
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())));
284 v8::Handle
<v8::Function
> func
= v8::Handle
<v8::Function
>::Cast(value
);
285 v8::Local
<v8::Value
> result
;
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
);
293 return handle_scope
.Escape(result
);
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());
303 void ModuleSystem::OverrideNativeHandlerForTest(const std::string
& name
) {
304 overridden_native_handlers_
.insert(name
);
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()));
314 void ModuleSystem::NativeLazyFieldGetter(
315 v8::Local
<v8::String
> property
,
316 const v8::PropertyCallbackInfo
<v8::Value
>& info
) {
317 LazyFieldGetterInner(property
, info
, &ModuleSystem::RequireNativeFromString
);
321 void ModuleSystem::LazyFieldGetter(
322 v8::Local
<v8::String
> property
,
323 const v8::PropertyCallbackInfo
<v8::Value
>& info
) {
324 LazyFieldGetterInner(property
, info
, &ModuleSystem::Require
);
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?");
349 ModuleSystem
* module_system
= static_cast<ModuleSystem
*>(
350 v8::Handle
<v8::External
>::Cast(module_system_value
)->Value());
353 *v8::String::Utf8Value(
354 parameters
->Get(v8::String::NewFromUtf8(info
.GetIsolate(),
355 kModuleName
))->ToString());
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
);
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
);
368 if (module_value
.IsEmpty() || !module_value
->IsObject()) {
369 // require_function will have already logged this, we don't need to.
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
))
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");
386 v8::Local
<v8::Value
> new_field
= module
->Get(field
);
387 if (try_catch
.HasCaught()) {
388 module_system
->HandleException(try_catch
);
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());
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
);
406 info
.GetReturnValue().Set(new_field
);
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
) {
414 object
, field
, module_name
, module_field
, &ModuleSystem::LazyFieldGetter
);
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()),
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
) {
442 &ModuleSystem::NativeLazyFieldGetter
);
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());
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
));
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());
469 v8::Local
<v8::Value
> result
= script
->Run();
470 if (try_catch
.HasCaught()) {
471 HandleException(try_catch
);
472 return v8::Undefined(GetIsolate());
475 return handle_scope
.Escape(result
);
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
)));
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
));
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
499 if (exception_handler_
) {
500 return GetIsolate()->ThrowException(
501 v8::String::NewFromUtf8(GetIsolate(), "Natives disabled"));
503 Fatal(context_
, "Natives disabled for requireNative(" + native_name
+ ")");
504 return v8::Undefined(GetIsolate());
507 if (overridden_native_handlers_
.count(native_name
) > 0u) {
508 return RequireForJsInner(
509 v8::String::NewFromUtf8(GetIsolate(), native_name
.c_str()));
512 NativeHandlerMap::iterator i
= native_handler_map_
.find(native_name
);
513 if (i
== native_handler_map_
.end()) {
515 "Couldn't find native for requireNative(" + native_name
+ ")");
516 return v8::Undefined(GetIsolate());
518 return i
->second
->NewInstance();
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")));
538 module_registry
->LoadModule(GetIsolate(),
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
);
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(
552 "(function(define, require, requireNative, requireAsync, exports, "
554 "$Array, $Function, $JSON, $Object, $RegExp, $String, $Error) {"
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
))));
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
);
572 args
.GetReturnValue().Set(privates
);
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());
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());
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());
595 v8::Handle
<v8::Function
> func
= v8::Handle
<v8::Function
>::Cast(func_as_value
);
597 v8::Handle
<v8::Object
> define_object
= v8::Object::New(GetIsolate());
598 gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object
);
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
604 // These must match the argument order in WrapSource.
605 v8::Handle
<v8::Value
> args
[] = {
607 define_object
->Get(v8::String::NewFromUtf8(GetIsolate(), "define")),
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
)),
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(),
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());
638 return handle_scope
.Escape(exports
);
641 void ModuleSystem::OnDidAddPendingModule(
642 const std::string
& id
,
643 const std::vector
<std::string
>& dependencies
) {
644 if (!source_map_
->Contains(id
))
647 gin::ModuleRegistry
* registry
=
648 gin::ModuleRegistry::From(context_
->v8_context());
650 for (std::vector
<std::string
>::const_iterator it
= dependencies
.begin();
651 it
!= dependencies
.end();
653 if (registry
->available_modules().count(*it
) == 0)
656 registry
->AttemptToLoadMoreModules(GetIsolate());
659 void ModuleSystem::OnModuleLoaded(
660 scoped_ptr
<v8::UniquePersistent
<v8::Promise::Resolver
> > resolver
,
661 v8::Handle
<v8::Value
> value
) {
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
);
670 } // namespace extensions