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/logging.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/trace_event/trace_event.h"
14 #include "content/public/renderer/render_frame.h"
15 #include "content/public/renderer/render_view.h"
16 #include "extensions/common/extension.h"
17 #include "extensions/common/extensions_client.h"
18 #include "extensions/renderer/console.h"
19 #include "extensions/renderer/safe_builtins.h"
20 #include "extensions/renderer/script_context.h"
21 #include "gin/modules/module_registry.h"
22 #include "third_party/WebKit/public/web/WebFrame.h"
23 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
25 namespace extensions
{
29 const char* kModuleSystem
= "module_system";
30 const char* kModuleName
= "module_name";
31 const char* kModuleField
= "module_field";
32 const char* kModulesField
= "modules";
34 // Logs an error for the calling context in preparation for potentially
35 // crashing the renderer, with some added metadata about the context:
36 // - Its type (blessed, unblessed, etc).
37 // - Whether it's valid.
38 // - The extension ID, if one exists.
39 // Crashing won't happen in stable/beta releases, but is encouraged to happen
40 // in the less stable released to catch errors early.
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();
53 full_message
+= message
;
55 ExtensionsClient
* client
= ExtensionsClient::Get();
56 if (client
->ShouldSuppressFatalErrors()) {
57 console::Error(context
->isolate()->GetCallingContext(), full_message
);
58 client
->RecordDidSuppressFatalError();
60 console::Fatal(context
->isolate()->GetCallingContext(), full_message
);
64 void Warn(v8::Isolate
* isolate
, const std::string
& message
) {
65 console::Warn(isolate
->GetCallingContext(), message
);
68 // Default exception handler which logs the exception.
69 class DefaultExceptionHandler
: public ModuleSystem::ExceptionHandler
{
71 explicit DefaultExceptionHandler(ScriptContext
* context
)
72 : context_(context
) {}
74 // Fatally dumps the debug info from |try_catch| to the console.
75 // Make sure this is never used for exceptions that originate in external
77 void HandleUncaughtException(const v8::TryCatch
& try_catch
) override
{
78 v8::HandleScope
handle_scope(context_
->isolate());
79 std::string stack_trace
= "<stack trace unavailable>";
80 if (!try_catch
.StackTrace().IsEmpty()) {
81 v8::String::Utf8Value
stack_value(try_catch
.StackTrace());
83 stack_trace
.assign(*stack_value
, stack_value
.length());
85 stack_trace
= "<could not convert stack trace to string>";
87 Fatal(context_
, CreateExceptionString(try_catch
) + "{" + stack_trace
+ "}");
91 ScriptContext
* context_
;
96 std::string
ModuleSystem::ExceptionHandler::CreateExceptionString(
97 const v8::TryCatch
& try_catch
) {
98 v8::Local
<v8::Message
> message(try_catch
.Message());
99 if (message
.IsEmpty()) {
100 return "try_catch has no message";
103 std::string resource_name
= "<unknown resource>";
104 if (!message
->GetScriptOrigin().ResourceName().IsEmpty()) {
105 v8::String::Utf8Value
resource_name_v8(
106 message
->GetScriptOrigin().ResourceName());
107 resource_name
.assign(*resource_name_v8
, resource_name_v8
.length());
110 std::string error_message
= "<no error message>";
111 if (!message
->Get().IsEmpty()) {
112 v8::String::Utf8Value
error_message_v8(message
->Get());
113 error_message
.assign(*error_message_v8
, error_message_v8
.length());
116 return base::StringPrintf("%s:%d: %s",
117 resource_name
.c_str(),
118 message
->GetLineNumber(),
119 error_message
.c_str());
122 ModuleSystem::ModuleSystem(ScriptContext
* context
, SourceMap
* source_map
)
123 : ObjectBackedNativeHandler(context
),
125 source_map_(source_map
),
127 exception_handler_(new DefaultExceptionHandler(context
)),
128 weak_factory_(this) {
131 base::Bind(&ModuleSystem::RequireForJs
, base::Unretained(this)));
134 base::Bind(&ModuleSystem::RequireNative
, base::Unretained(this)));
137 base::Bind(&ModuleSystem::RequireAsync
, base::Unretained(this)));
138 RouteFunction("privates",
139 base::Bind(&ModuleSystem::Private
, base::Unretained(this)));
141 v8::Local
<v8::Object
> global(context
->v8_context()->Global());
142 v8::Isolate
* isolate
= context
->isolate();
143 global
->SetHiddenValue(v8::String::NewFromUtf8(isolate
, kModulesField
),
144 v8::Object::New(isolate
));
145 global
->SetHiddenValue(v8::String::NewFromUtf8(isolate
, kModuleSystem
),
146 v8::External::New(isolate
, this));
148 gin::ModuleRegistry::From(context
->v8_context())->AddObserver(this);
149 if (context_
->GetRenderFrame()) {
150 context_
->GetRenderFrame()->EnsureMojoBuiltinsAreAvailable(
151 context
->isolate(), context
->v8_context());
155 ModuleSystem::~ModuleSystem() {
158 void ModuleSystem::Invalidate() {
159 // Clear the module system properties from the global context. It's polite,
160 // and we use this as a signal in lazy handlers that we no longer exist.
162 v8::HandleScope
scope(GetIsolate());
163 v8::Local
<v8::Object
> global
= context()->v8_context()->Global();
164 global
->DeleteHiddenValue(
165 v8::String::NewFromUtf8(GetIsolate(), kModulesField
));
166 global
->DeleteHiddenValue(
167 v8::String::NewFromUtf8(GetIsolate(), kModuleSystem
));
170 // Invalidate all active and clobbered NativeHandlers we own.
171 for (const auto& handler
: native_handler_map_
)
172 handler
.second
->Invalidate();
173 for (const auto& clobbered_handler
: clobbered_native_handlers_
)
174 clobbered_handler
->Invalidate();
176 ObjectBackedNativeHandler::Invalidate();
179 ModuleSystem::NativesEnabledScope::NativesEnabledScope(
180 ModuleSystem
* module_system
)
181 : module_system_(module_system
) {
182 module_system_
->natives_enabled_
++;
185 ModuleSystem::NativesEnabledScope::~NativesEnabledScope() {
186 module_system_
->natives_enabled_
--;
187 CHECK_GE(module_system_
->natives_enabled_
, 0);
190 void ModuleSystem::HandleException(const v8::TryCatch
& try_catch
) {
191 exception_handler_
->HandleUncaughtException(try_catch
);
194 v8::Local
<v8::Value
> ModuleSystem::Require(const std::string
& module_name
) {
195 v8::EscapableHandleScope
handle_scope(GetIsolate());
196 return handle_scope
.Escape(RequireForJsInner(
197 v8::String::NewFromUtf8(GetIsolate(), module_name
.c_str())));
200 void ModuleSystem::RequireForJs(
201 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
202 v8::Local
<v8::String
> module_name
= args
[0]->ToString(args
.GetIsolate());
203 args
.GetReturnValue().Set(RequireForJsInner(module_name
));
206 v8::Local
<v8::Value
> ModuleSystem::RequireForJsInner(
207 v8::Local
<v8::String
> module_name
) {
208 v8::EscapableHandleScope
handle_scope(GetIsolate());
209 v8::Context::Scope
context_scope(context()->v8_context());
211 v8::Local
<v8::Object
> global(context()->v8_context()->Global());
213 // The module system might have been deleted. This can happen if a different
214 // context keeps a reference to us, but our frame is destroyed (e.g.
215 // background page keeps reference to chrome object in a closed popup).
216 v8::Local
<v8::Value
> modules_value
= global
->GetHiddenValue(
217 v8::String::NewFromUtf8(GetIsolate(), kModulesField
));
218 if (modules_value
.IsEmpty() || modules_value
->IsUndefined()) {
219 Warn(GetIsolate(), "Extension view no longer exists");
220 return v8::Undefined(GetIsolate());
223 v8::Local
<v8::Object
> modules(v8::Local
<v8::Object
>::Cast(modules_value
));
224 v8::Local
<v8::Value
> exports(modules
->Get(module_name
));
225 if (!exports
->IsUndefined())
226 return handle_scope
.Escape(exports
);
228 exports
= LoadModule(*v8::String::Utf8Value(module_name
));
229 modules
->Set(module_name
, exports
);
230 return handle_scope
.Escape(exports
);
233 v8::Local
<v8::Value
> ModuleSystem::CallModuleMethod(
234 const std::string
& module_name
,
235 const std::string
& method_name
) {
236 v8::EscapableHandleScope
handle_scope(GetIsolate());
237 v8::Local
<v8::Value
> no_args
;
238 return handle_scope
.Escape(
239 CallModuleMethod(module_name
, method_name
, 0, &no_args
));
242 v8::Local
<v8::Value
> ModuleSystem::CallModuleMethod(
243 const std::string
& module_name
,
244 const std::string
& method_name
,
245 std::vector
<v8::Local
<v8::Value
>>* args
) {
246 return CallModuleMethod(
247 module_name
, method_name
, args
->size(), vector_as_array(args
));
250 v8::Local
<v8::Value
> ModuleSystem::CallModuleMethod(
251 const std::string
& module_name
,
252 const std::string
& method_name
,
254 v8::Local
<v8::Value
> argv
[]) {
256 "v8.callModuleMethod",
262 v8::EscapableHandleScope
handle_scope(GetIsolate());
263 v8::Context::Scope
context_scope(context()->v8_context());
265 v8::Local
<v8::Value
> module
;
267 NativesEnabledScope
natives_enabled(this);
268 module
= RequireForJsInner(
269 v8::String::NewFromUtf8(GetIsolate(), module_name
.c_str()));
272 if (module
.IsEmpty() || !module
->IsObject()) {
274 "Failed to get module " + module_name
+ " to call " + method_name
);
275 return handle_scope
.Escape(
276 v8::Local
<v8::Primitive
>(v8::Undefined(GetIsolate())));
279 v8::Local
<v8::Value
> value
= v8::Local
<v8::Object
>::Cast(module
)->Get(
280 v8::String::NewFromUtf8(GetIsolate(), method_name
.c_str()));
281 if (value
.IsEmpty() || !value
->IsFunction()) {
282 Fatal(context_
, module_name
+ "." + method_name
+ " is not a function");
283 return handle_scope
.Escape(
284 v8::Local
<v8::Primitive
>(v8::Undefined(GetIsolate())));
287 v8::Local
<v8::Function
> func
= v8::Local
<v8::Function
>::Cast(value
);
288 v8::Local
<v8::Value
> result
;
290 v8::TryCatch try_catch
;
291 try_catch
.SetCaptureMessage(true);
292 result
= context_
->CallFunction(func
, argc
, argv
);
293 if (try_catch
.HasCaught())
294 HandleException(try_catch
);
296 return handle_scope
.Escape(result
);
299 void ModuleSystem::RegisterNativeHandler(
300 const std::string
& name
,
301 scoped_ptr
<NativeHandler
> native_handler
) {
302 ClobberExistingNativeHandler(name
);
303 native_handler_map_
[name
] =
304 linked_ptr
<NativeHandler
>(native_handler
.release());
307 void ModuleSystem::OverrideNativeHandlerForTest(const std::string
& name
) {
308 ClobberExistingNativeHandler(name
);
309 overridden_native_handlers_
.insert(name
);
312 void ModuleSystem::RunString(const std::string
& code
, const std::string
& name
) {
313 v8::HandleScope
handle_scope(GetIsolate());
314 RunString(v8::String::NewFromUtf8(GetIsolate(), code
.c_str()),
315 v8::String::NewFromUtf8(GetIsolate(), name
.c_str()));
319 void ModuleSystem::NativeLazyFieldGetter(
320 v8::Local
<v8::String
> property
,
321 const v8::PropertyCallbackInfo
<v8::Value
>& info
) {
322 LazyFieldGetterInner(property
, info
, &ModuleSystem::RequireNativeFromString
);
326 void ModuleSystem::LazyFieldGetter(
327 v8::Local
<v8::String
> property
,
328 const v8::PropertyCallbackInfo
<v8::Value
>& info
) {
329 LazyFieldGetterInner(property
, info
, &ModuleSystem::Require
);
333 void ModuleSystem::LazyFieldGetterInner(
334 v8::Local
<v8::String
> property
,
335 const v8::PropertyCallbackInfo
<v8::Value
>& info
,
336 RequireFunction require_function
) {
337 CHECK(!info
.Data().IsEmpty());
338 CHECK(info
.Data()->IsObject());
339 v8::HandleScope
handle_scope(info
.GetIsolate());
340 v8::Local
<v8::Object
> parameters
= v8::Local
<v8::Object
>::Cast(info
.Data());
341 // This context should be the same as context()->v8_context().
342 v8::Local
<v8::Context
> context
= parameters
->CreationContext();
343 v8::Local
<v8::Object
> global(context
->Global());
344 v8::Local
<v8::Value
> module_system_value
= global
->GetHiddenValue(
345 v8::String::NewFromUtf8(info
.GetIsolate(), kModuleSystem
));
346 if (module_system_value
.IsEmpty() || !module_system_value
->IsExternal()) {
347 // ModuleSystem has been deleted.
348 // TODO(kalman): See comment in header file.
349 Warn(info
.GetIsolate(),
350 "Module system has been deleted, does extension view exist?");
354 ModuleSystem
* module_system
= static_cast<ModuleSystem
*>(
355 v8::Local
<v8::External
>::Cast(module_system_value
)->Value());
357 std::string name
= *v8::String::Utf8Value(parameters
->Get(
358 v8::String::NewFromUtf8(info
.GetIsolate(), kModuleName
)));
360 // Switch to our v8 context because we need functions created while running
361 // the require()d module to belong to our context, not the current one.
362 v8::Context::Scope
context_scope(context
);
363 NativesEnabledScope
natives_enabled_scope(module_system
);
365 v8::TryCatch try_catch
;
366 v8::Local
<v8::Value
> module_value
= (module_system
->*require_function
)(name
);
367 if (try_catch
.HasCaught()) {
368 module_system
->HandleException(try_catch
);
371 if (module_value
.IsEmpty() || !module_value
->IsObject()) {
372 // require_function will have already logged this, we don't need to.
376 v8::Local
<v8::Object
> module
= v8::Local
<v8::Object
>::Cast(module_value
);
377 v8::Local
<v8::String
> field
=
378 parameters
->Get(v8::String::NewFromUtf8(info
.GetIsolate(), kModuleField
))
379 ->ToString(info
.GetIsolate());
381 if (!module
->Has(field
)) {
382 std::string field_str
= *v8::String::Utf8Value(field
);
383 Fatal(module_system
->context_
,
384 "Lazy require of " + name
+ "." + field_str
+ " did not set the " +
385 field_str
+ " field");
389 v8::Local
<v8::Value
> new_field
= module
->Get(field
);
390 if (try_catch
.HasCaught()) {
391 module_system
->HandleException(try_catch
);
395 // Ok for it to be undefined, among other things it's how bindings signify
396 // that the extension doesn't have permission to use them.
397 CHECK(!new_field
.IsEmpty());
399 // Delete the getter and set this field to |new_field| so the same object is
400 // returned every time a certain API is accessed.
401 v8::Local
<v8::Value
> val
= info
.This();
402 if (val
->IsObject()) {
403 v8::Local
<v8::Object
> object
= v8::Local
<v8::Object
>::Cast(val
);
404 object
->Delete(property
);
405 object
->Set(property
, new_field
);
409 info
.GetReturnValue().Set(new_field
);
412 void ModuleSystem::SetLazyField(v8::Local
<v8::Object
> object
,
413 const std::string
& field
,
414 const std::string
& module_name
,
415 const std::string
& module_field
) {
417 object
, field
, module_name
, module_field
, &ModuleSystem::LazyFieldGetter
);
420 void ModuleSystem::SetLazyField(v8::Local
<v8::Object
> object
,
421 const std::string
& field
,
422 const std::string
& module_name
,
423 const std::string
& module_field
,
424 v8::AccessorGetterCallback getter
) {
425 v8::HandleScope
handle_scope(GetIsolate());
426 v8::Local
<v8::Object
> parameters
= v8::Object::New(GetIsolate());
427 parameters
->Set(v8::String::NewFromUtf8(GetIsolate(), kModuleName
),
428 v8::String::NewFromUtf8(GetIsolate(), module_name
.c_str()));
429 parameters
->Set(v8::String::NewFromUtf8(GetIsolate(), kModuleField
),
430 v8::String::NewFromUtf8(GetIsolate(), module_field
.c_str()));
431 object
->SetAccessor(v8::String::NewFromUtf8(GetIsolate(), field
.c_str()),
437 void ModuleSystem::SetNativeLazyField(v8::Local
<v8::Object
> object
,
438 const std::string
& field
,
439 const std::string
& module_name
,
440 const std::string
& module_field
) {
445 &ModuleSystem::NativeLazyFieldGetter
);
448 v8::Local
<v8::Value
> ModuleSystem::RunString(v8::Local
<v8::String
> code
,
449 v8::Local
<v8::String
> name
) {
450 v8::EscapableHandleScope
handle_scope(GetIsolate());
451 v8::Context::Scope
context_scope(context()->v8_context());
453 // Prepend extensions:: to |name| so that internal code can be differentiated
454 // from external code in stack traces. This has no effect on behaviour.
455 std::string internal_name
=
456 base::StringPrintf("extensions::%s", *v8::String::Utf8Value(name
));
458 blink::WebScopedMicrotaskSuppression suppression
;
459 v8::TryCatch try_catch
;
460 try_catch
.SetCaptureMessage(true);
461 v8::Local
<v8::Script
> script(v8::Script::Compile(
462 code
, v8::String::NewFromUtf8(GetIsolate(), internal_name
.c_str(),
463 v8::String::kNormalString
,
464 internal_name
.size())));
465 if (try_catch
.HasCaught()) {
466 HandleException(try_catch
);
467 return v8::Undefined(GetIsolate());
470 v8::Local
<v8::Value
> result
= script
->Run();
471 if (try_catch
.HasCaught()) {
472 HandleException(try_catch
);
473 return v8::Undefined(GetIsolate());
476 return handle_scope
.Escape(result
);
479 v8::Local
<v8::Value
> ModuleSystem::GetSource(const std::string
& module_name
) {
480 v8::EscapableHandleScope
handle_scope(GetIsolate());
481 if (!source_map_
->Contains(module_name
))
482 return v8::Undefined(GetIsolate());
483 return handle_scope
.Escape(
484 v8::Local
<v8::Value
>(source_map_
->GetSource(GetIsolate(), module_name
)));
487 void ModuleSystem::RequireNative(
488 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
489 CHECK_EQ(1, args
.Length());
490 std::string native_name
= *v8::String::Utf8Value(args
[0]);
491 args
.GetReturnValue().Set(RequireNativeFromString(native_name
));
494 v8::Local
<v8::Value
> ModuleSystem::RequireNativeFromString(
495 const std::string
& native_name
) {
496 if (natives_enabled_
== 0) {
497 // HACK: if in test throw exception so that we can test the natives-disabled
498 // logic; however, under normal circumstances, this is programmer error so
500 if (exception_handler_
) {
501 return GetIsolate()->ThrowException(
502 v8::String::NewFromUtf8(GetIsolate(), "Natives disabled"));
504 Fatal(context_
, "Natives disabled for requireNative(" + native_name
+ ")");
505 return v8::Undefined(GetIsolate());
508 if (overridden_native_handlers_
.count(native_name
) > 0u) {
509 return RequireForJsInner(
510 v8::String::NewFromUtf8(GetIsolate(), native_name
.c_str()));
513 NativeHandlerMap::iterator i
= native_handler_map_
.find(native_name
);
514 if (i
== native_handler_map_
.end()) {
516 "Couldn't find native for requireNative(" + native_name
+ ")");
517 return v8::Undefined(GetIsolate());
519 return i
->second
->NewInstance();
522 void ModuleSystem::RequireAsync(
523 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
524 CHECK_EQ(1, args
.Length());
525 std::string module_name
= *v8::String::Utf8Value(args
[0]);
526 v8::Local
<v8::Promise::Resolver
> resolver(
527 v8::Promise::Resolver::New(GetIsolate()));
528 args
.GetReturnValue().Set(resolver
->GetPromise());
529 scoped_ptr
<v8::Global
<v8::Promise::Resolver
>> global_resolver(
530 new v8::Global
<v8::Promise::Resolver
>(GetIsolate(), resolver
));
531 gin::ModuleRegistry
* module_registry
=
532 gin::ModuleRegistry::From(context_
->v8_context());
533 if (!module_registry
) {
534 Warn(GetIsolate(), "Extension view no longer exists");
535 resolver
->Reject(v8::Exception::Error(v8::String::NewFromUtf8(
536 GetIsolate(), "Extension view no longer exists")));
539 module_registry
->LoadModule(
540 GetIsolate(), module_name
,
541 base::Bind(&ModuleSystem::OnModuleLoaded
, weak_factory_
.GetWeakPtr(),
542 base::Passed(&global_resolver
)));
543 if (module_registry
->available_modules().count(module_name
) == 0)
544 LoadModule(module_name
);
547 v8::Local
<v8::String
> ModuleSystem::WrapSource(v8::Local
<v8::String
> source
) {
548 v8::EscapableHandleScope
handle_scope(GetIsolate());
549 // Keep in order with the arguments in RequireForJsInner.
550 v8::Local
<v8::String
> left
= v8::String::NewFromUtf8(
552 "(function(define, require, requireNative, requireAsync, exports, "
554 "$Array, $Function, $JSON, $Object, $RegExp, $String, $Error) {"
556 v8::Local
<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 if (!args
[0]->IsObject() || args
[0]->IsNull()) {
564 GetIsolate()->ThrowException(
565 v8::Exception::TypeError(v8::String::NewFromUtf8(GetIsolate(),
566 args
[0]->IsUndefined()
567 ? "Method called without a valid receiver (this). "
568 "Did you forget to call .bind()?"
569 : "Invalid invocation: receiver is not an object!")));
572 v8::Local
<v8::Object
> obj
= args
[0].As
<v8::Object
>();
573 v8::Local
<v8::String
> privates_key
=
574 v8::String::NewFromUtf8(GetIsolate(), "privates");
575 v8::Local
<v8::Value
> privates
= obj
->GetHiddenValue(privates_key
);
576 if (privates
.IsEmpty()) {
577 privates
= v8::Object::New(args
.GetIsolate());
578 if (privates
.IsEmpty()) {
579 GetIsolate()->ThrowException(
580 v8::String::NewFromUtf8(GetIsolate(), "Failed to create privates"));
583 obj
->SetHiddenValue(privates_key
, privates
);
585 args
.GetReturnValue().Set(privates
);
588 v8::Local
<v8::Value
> ModuleSystem::LoadModule(const std::string
& module_name
) {
589 v8::EscapableHandleScope
handle_scope(GetIsolate());
590 v8::Context::Scope
context_scope(context()->v8_context());
592 v8::Local
<v8::Value
> source(GetSource(module_name
));
593 if (source
.IsEmpty() || source
->IsUndefined()) {
594 Fatal(context_
, "No source for require(" + module_name
+ ")");
595 return v8::Undefined(GetIsolate());
597 v8::Local
<v8::String
> wrapped_source(
598 WrapSource(v8::Local
<v8::String
>::Cast(source
)));
599 // Modules are wrapped in (function(){...}) so they always return functions.
600 v8::Local
<v8::Value
> func_as_value
=
601 RunString(wrapped_source
,
602 v8::String::NewFromUtf8(GetIsolate(), module_name
.c_str()));
603 if (func_as_value
.IsEmpty() || func_as_value
->IsUndefined()) {
604 Fatal(context_
, "Bad source for require(" + module_name
+ ")");
605 return v8::Undefined(GetIsolate());
608 v8::Local
<v8::Function
> func
= v8::Local
<v8::Function
>::Cast(func_as_value
);
610 v8::Local
<v8::Object
> define_object
= v8::Object::New(GetIsolate());
611 gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object
);
613 v8::Local
<v8::Value
> exports
= v8::Object::New(GetIsolate());
614 v8::Local
<v8::Object
> natives(NewInstance());
615 CHECK(!natives
.IsEmpty()); // this can happen if v8 has issues
617 // These must match the argument order in WrapSource.
618 v8::Local
<v8::Value
> args
[] = {
620 define_object
->Get(v8::String::NewFromUtf8(GetIsolate(), "define")),
622 natives
->Get(v8::String::NewFromUtf8(GetIsolate(), "require",
623 v8::String::kInternalizedString
)),
624 natives
->Get(v8::String::NewFromUtf8(GetIsolate(), "requireNative",
625 v8::String::kInternalizedString
)),
626 natives
->Get(v8::String::NewFromUtf8(GetIsolate(), "requireAsync",
627 v8::String::kInternalizedString
)),
629 // Libraries that we magically expose to every module.
630 console::AsV8Object(GetIsolate()),
631 natives
->Get(v8::String::NewFromUtf8(GetIsolate(), "privates",
632 v8::String::kInternalizedString
)),
633 // Each safe builtin. Keep in order with the arguments in WrapSource.
634 context_
->safe_builtins()->GetArray(),
635 context_
->safe_builtins()->GetFunction(),
636 context_
->safe_builtins()->GetJSON(),
637 context_
->safe_builtins()->GetObjekt(),
638 context_
->safe_builtins()->GetRegExp(),
639 context_
->safe_builtins()->GetString(),
640 context_
->safe_builtins()->GetError(),
643 v8::TryCatch try_catch
;
644 try_catch
.SetCaptureMessage(true);
645 context_
->CallFunction(func
, arraysize(args
), args
);
646 if (try_catch
.HasCaught()) {
647 HandleException(try_catch
);
648 return v8::Undefined(GetIsolate());
651 return handle_scope
.Escape(exports
);
654 void ModuleSystem::OnDidAddPendingModule(
655 const std::string
& id
,
656 const std::vector
<std::string
>& dependencies
) {
657 bool module_system_managed
= source_map_
->Contains(id
);
659 gin::ModuleRegistry
* registry
=
660 gin::ModuleRegistry::From(context_
->v8_context());
662 for (const auto& dependency
: dependencies
) {
663 // If a dependency is not available, and either the module or this
664 // dependency is managed by ModuleSystem, attempt to load it. Other
665 // gin::ModuleRegistry users (WebUI and users of the mojoPrivate API) are
666 // responsible for loading their module dependencies when required.
667 if (registry
->available_modules().count(dependency
) == 0 &&
668 (module_system_managed
|| source_map_
->Contains(dependency
))) {
669 LoadModule(dependency
);
672 registry
->AttemptToLoadMoreModules(GetIsolate());
675 void ModuleSystem::OnModuleLoaded(
676 scoped_ptr
<v8::Global
<v8::Promise::Resolver
>> resolver
,
677 v8::Local
<v8::Value
> value
) {
680 v8::HandleScope
handle_scope(GetIsolate());
681 v8::Local
<v8::Promise::Resolver
> resolver_local(
682 v8::Local
<v8::Promise::Resolver
>::New(GetIsolate(), *resolver
));
683 resolver_local
->Resolve(value
);
686 void ModuleSystem::ClobberExistingNativeHandler(const std::string
& name
) {
687 NativeHandlerMap::iterator existing_handler
= native_handler_map_
.find(name
);
688 if (existing_handler
!= native_handler_map_
.end()) {
689 clobbered_native_handlers_
.push_back(existing_handler
->second
);
690 native_handler_map_
.erase(existing_handler
);
694 } // namespace extensions