Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / extensions / renderer / module_system.cc
blob26b323f1042590c109d4a2d91f5cdb4a9e1b3a22
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"
7 #include "base/bind.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 "extensions/renderer/script_context_set.h"
22 #include "extensions/renderer/v8_helpers.h"
23 #include "gin/modules/module_registry.h"
24 #include "third_party/WebKit/public/web/WebFrame.h"
25 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
27 namespace extensions {
29 using namespace v8_helpers;
31 namespace {
33 const char* kModuleSystem = "module_system";
34 const char* kModuleName = "module_name";
35 const char* kModuleField = "module_field";
36 const char* kModulesField = "modules";
38 // Logs an error for the calling context in preparation for potentially
39 // crashing the renderer, with some added metadata about the context:
40 // - Its type (blessed, unblessed, etc).
41 // - Whether it's valid.
42 // - The extension ID, if one exists.
43 // Crashing won't happen in stable/beta releases, but is encouraged to happen
44 // in the less stable released to catch errors early.
45 void Fatal(ScriptContext* context, const std::string& message) {
46 // Prepend some context metadata.
47 std::string full_message = "(";
48 if (!context->is_valid())
49 full_message += "Invalid ";
50 full_message += context->GetContextTypeDescription();
51 full_message += " context";
52 if (context->extension()) {
53 full_message += " for ";
54 full_message += context->extension()->id();
56 full_message += ") ";
57 full_message += message;
59 ExtensionsClient* client = ExtensionsClient::Get();
60 if (client->ShouldSuppressFatalErrors()) {
61 console::Error(context->GetRenderFrame(), full_message);
62 client->RecordDidSuppressFatalError();
63 } else {
64 console::Fatal(context->GetRenderFrame(), full_message);
68 void Warn(v8::Isolate* isolate, const std::string& message) {
69 ScriptContext* script_context =
70 ScriptContextSet::GetContextByV8Context(isolate->GetCallingContext());
71 console::Warn(script_context ? script_context->GetRenderFrame() : nullptr,
72 message);
75 // Default exception handler which logs the exception.
76 class DefaultExceptionHandler : public ModuleSystem::ExceptionHandler {
77 public:
78 explicit DefaultExceptionHandler(ScriptContext* context)
79 : ModuleSystem::ExceptionHandler(context) {}
81 // Fatally dumps the debug info from |try_catch| to the console.
82 // Make sure this is never used for exceptions that originate in external
83 // code!
84 void HandleUncaughtException(const v8::TryCatch& try_catch) override {
85 v8::HandleScope handle_scope(context_->isolate());
86 std::string stack_trace = "<stack trace unavailable>";
87 v8::Local<v8::Value> v8_stack_trace;
88 if (try_catch.StackTrace(context_->v8_context()).ToLocal(&v8_stack_trace)) {
89 v8::String::Utf8Value stack_value(v8_stack_trace);
90 if (*stack_value)
91 stack_trace.assign(*stack_value, stack_value.length());
92 else
93 stack_trace = "<could not convert stack trace to string>";
95 Fatal(context_, CreateExceptionString(try_catch) + "{" + stack_trace + "}");
99 } // namespace
101 std::string ModuleSystem::ExceptionHandler::CreateExceptionString(
102 const v8::TryCatch& try_catch) {
103 v8::Local<v8::Message> message(try_catch.Message());
104 if (message.IsEmpty()) {
105 return "try_catch has no message";
108 std::string resource_name = "<unknown resource>";
109 if (!message->GetScriptOrigin().ResourceName().IsEmpty()) {
110 v8::String::Utf8Value resource_name_v8(
111 message->GetScriptOrigin().ResourceName());
112 resource_name.assign(*resource_name_v8, resource_name_v8.length());
115 std::string error_message = "<no error message>";
116 if (!message->Get().IsEmpty()) {
117 v8::String::Utf8Value error_message_v8(message->Get());
118 error_message.assign(*error_message_v8, error_message_v8.length());
121 auto maybe = message->GetLineNumber(context_->v8_context());
122 int line_number = maybe.IsJust() ? maybe.FromJust() : 0;
123 return base::StringPrintf("%s:%d: %s",
124 resource_name.c_str(),
125 line_number,
126 error_message.c_str());
129 ModuleSystem::ModuleSystem(ScriptContext* context, SourceMap* source_map)
130 : ObjectBackedNativeHandler(context),
131 context_(context),
132 source_map_(source_map),
133 natives_enabled_(0),
134 exception_handler_(new DefaultExceptionHandler(context)),
135 weak_factory_(this) {
136 RouteFunction(
137 "require",
138 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this)));
139 RouteFunction(
140 "requireNative",
141 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this)));
142 RouteFunction(
143 "requireAsync",
144 base::Bind(&ModuleSystem::RequireAsync, base::Unretained(this)));
145 RouteFunction("privates",
146 base::Bind(&ModuleSystem::Private, base::Unretained(this)));
148 v8::Local<v8::Object> global(context->v8_context()->Global());
149 v8::Isolate* isolate = context->isolate();
150 global->SetHiddenValue(ToV8StringUnsafe(isolate, kModulesField),
151 v8::Object::New(isolate));
152 global->SetHiddenValue(ToV8StringUnsafe(isolate, kModuleSystem),
153 v8::External::New(isolate, this));
155 gin::ModuleRegistry::From(context->v8_context())->AddObserver(this);
156 if (context_->GetRenderFrame()) {
157 context_->GetRenderFrame()->EnsureMojoBuiltinsAreAvailable(
158 context->isolate(), context->v8_context());
162 ModuleSystem::~ModuleSystem() {
165 void ModuleSystem::Invalidate() {
166 // Clear the module system properties from the global context. It's polite,
167 // and we use this as a signal in lazy handlers that we no longer exist.
169 v8::HandleScope scope(GetIsolate());
170 v8::Local<v8::Object> global = context()->v8_context()->Global();
171 global->DeleteHiddenValue(ToV8StringUnsafe(GetIsolate(), kModulesField));
172 global->DeleteHiddenValue(ToV8StringUnsafe(GetIsolate(), kModuleSystem));
175 // Invalidate all active and clobbered NativeHandlers we own.
176 for (const auto& handler : native_handler_map_)
177 handler.second->Invalidate();
178 for (const auto& clobbered_handler : clobbered_native_handlers_)
179 clobbered_handler->Invalidate();
181 ObjectBackedNativeHandler::Invalidate();
184 ModuleSystem::NativesEnabledScope::NativesEnabledScope(
185 ModuleSystem* module_system)
186 : module_system_(module_system) {
187 module_system_->natives_enabled_++;
190 ModuleSystem::NativesEnabledScope::~NativesEnabledScope() {
191 module_system_->natives_enabled_--;
192 CHECK_GE(module_system_->natives_enabled_, 0);
195 void ModuleSystem::HandleException(const v8::TryCatch& try_catch) {
196 exception_handler_->HandleUncaughtException(try_catch);
199 v8::MaybeLocal<v8::Object> ModuleSystem::Require(
200 const std::string& module_name) {
201 v8::Local<v8::String> v8_module_name;
202 if (!ToV8String(GetIsolate(), module_name, &v8_module_name))
203 return v8::MaybeLocal<v8::Object>();
204 v8::EscapableHandleScope handle_scope(GetIsolate());
205 v8::Local<v8::Value> value = RequireForJsInner(
206 v8_module_name);
207 if (value.IsEmpty() || !value->IsObject())
208 return v8::MaybeLocal<v8::Object>();
209 return handle_scope.Escape(value.As<v8::Object>());
212 void ModuleSystem::RequireForJs(
213 const v8::FunctionCallbackInfo<v8::Value>& args) {
214 if (!args[0]->IsString()) {
215 NOTREACHED() << "require() called with a non-string argument";
216 return;
218 v8::Local<v8::String> module_name = args[0].As<v8::String>();
219 args.GetReturnValue().Set(RequireForJsInner(module_name));
222 v8::Local<v8::Value> ModuleSystem::RequireForJsInner(
223 v8::Local<v8::String> module_name) {
224 v8::EscapableHandleScope handle_scope(GetIsolate());
225 v8::Local<v8::Context> v8_context = context()->v8_context();
226 v8::Context::Scope context_scope(v8_context);
228 v8::Local<v8::Object> global(context()->v8_context()->Global());
230 // The module system might have been deleted. This can happen if a different
231 // context keeps a reference to us, but our frame is destroyed (e.g.
232 // background page keeps reference to chrome object in a closed popup).
233 v8::Local<v8::Value> modules_value = global->GetHiddenValue(
234 ToV8StringUnsafe(GetIsolate(), kModulesField));
235 if (modules_value.IsEmpty() || modules_value->IsUndefined()) {
236 Warn(GetIsolate(), "Extension view no longer exists");
237 return v8::Undefined(GetIsolate());
240 v8::Local<v8::Object> modules(v8::Local<v8::Object>::Cast(modules_value));
241 v8::Local<v8::Value> exports;
242 if (!GetProperty(v8_context, modules, module_name, &exports) ||
243 !exports->IsUndefined())
244 return handle_scope.Escape(exports);
246 exports = LoadModule(*v8::String::Utf8Value(module_name));
247 SetProperty(v8_context, modules, module_name, exports);
248 return handle_scope.Escape(exports);
251 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
252 const std::string& module_name,
253 const std::string& method_name) {
254 v8::EscapableHandleScope handle_scope(GetIsolate());
255 v8::Local<v8::Value> no_args;
256 return handle_scope.Escape(
257 CallModuleMethod(module_name, method_name, 0, &no_args));
260 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
261 const std::string& module_name,
262 const std::string& method_name,
263 std::vector<v8::Local<v8::Value>>* args) {
264 return CallModuleMethod(
265 module_name, method_name, args->size(), vector_as_array(args));
268 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
269 const std::string& module_name,
270 const std::string& method_name,
271 int argc,
272 v8::Local<v8::Value> argv[]) {
273 TRACE_EVENT2("v8",
274 "v8.callModuleMethod",
275 "module_name",
276 module_name,
277 "method_name",
278 method_name);
280 v8::EscapableHandleScope handle_scope(GetIsolate());
281 v8::Local<v8::Context> v8_context = context()->v8_context();
282 v8::Context::Scope context_scope(v8_context);
284 v8::Local<v8::String> v8_module_name;
285 v8::Local<v8::String> v8_method_name;
286 if (!ToV8String(GetIsolate(), module_name.c_str(), &v8_module_name) ||
287 !ToV8String(GetIsolate(), method_name.c_str(), &v8_method_name)) {
288 return handle_scope.Escape(v8::Undefined(GetIsolate()));
291 v8::Local<v8::Value> module;
293 NativesEnabledScope natives_enabled(this);
294 module = RequireForJsInner(v8_module_name);
297 if (module.IsEmpty() || !module->IsObject()) {
298 Fatal(context_,
299 "Failed to get module " + module_name + " to call " + method_name);
300 return handle_scope.Escape(v8::Undefined(GetIsolate()));
303 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(module);
304 v8::Local<v8::Value> value;
305 if (!GetProperty(v8_context, object, v8_method_name, &value) ||
306 !value->IsFunction()) {
307 Fatal(context_, module_name + "." + method_name + " is not a function");
308 return handle_scope.Escape(v8::Undefined(GetIsolate()));
311 v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(value);
312 v8::Local<v8::Value> result;
314 v8::TryCatch try_catch(GetIsolate());
315 try_catch.SetCaptureMessage(true);
316 result = context_->CallFunction(func, argc, argv);
317 if (try_catch.HasCaught()) {
318 HandleException(try_catch);
319 result = v8::Undefined(GetIsolate());
322 return handle_scope.Escape(result);
325 void ModuleSystem::RegisterNativeHandler(
326 const std::string& name,
327 scoped_ptr<NativeHandler> native_handler) {
328 ClobberExistingNativeHandler(name);
329 native_handler_map_[name] =
330 linked_ptr<NativeHandler>(native_handler.release());
333 void ModuleSystem::OverrideNativeHandlerForTest(const std::string& name) {
334 ClobberExistingNativeHandler(name);
335 overridden_native_handlers_.insert(name);
338 void ModuleSystem::RunString(const std::string& code, const std::string& name) {
339 v8::HandleScope handle_scope(GetIsolate());
340 v8::Local<v8::String> v8_code;
341 v8::Local<v8::String> v8_name;
342 if (!ToV8String(GetIsolate(), code.c_str(), &v8_code) ||
343 !ToV8String(GetIsolate(), name.c_str(), &v8_name)) {
344 Warn(GetIsolate(), "Too long code or name.");
345 return;
347 RunString(v8_code, v8_name);
350 // static
351 void ModuleSystem::NativeLazyFieldGetter(
352 v8::Local<v8::Name> property,
353 const v8::PropertyCallbackInfo<v8::Value>& info) {
354 LazyFieldGetterInner(property.As<v8::String>(), info,
355 &ModuleSystem::RequireNativeFromString);
358 // static
359 void ModuleSystem::LazyFieldGetter(
360 v8::Local<v8::Name> property,
361 const v8::PropertyCallbackInfo<v8::Value>& info) {
362 LazyFieldGetterInner(property.As<v8::String>(), info, &ModuleSystem::Require);
365 // static
366 void ModuleSystem::LazyFieldGetterInner(
367 v8::Local<v8::String> property,
368 const v8::PropertyCallbackInfo<v8::Value>& info,
369 RequireFunction require_function) {
370 CHECK(!info.Data().IsEmpty());
371 CHECK(info.Data()->IsObject());
372 v8::HandleScope handle_scope(info.GetIsolate());
373 v8::Local<v8::Object> parameters = v8::Local<v8::Object>::Cast(info.Data());
374 // This context should be the same as context()->v8_context().
375 v8::Local<v8::Context> context = parameters->CreationContext();
376 v8::Local<v8::Object> global(context->Global());
377 v8::Local<v8::Value> module_system_value = global->GetHiddenValue(
378 ToV8StringUnsafe(info.GetIsolate(), kModuleSystem));
379 if (module_system_value.IsEmpty() || !module_system_value->IsExternal()) {
380 // ModuleSystem has been deleted.
381 // TODO(kalman): See comment in header file.
382 Warn(info.GetIsolate(),
383 "Module system has been deleted, does extension view exist?");
384 return;
387 ModuleSystem* module_system = static_cast<ModuleSystem*>(
388 v8::Local<v8::External>::Cast(module_system_value)->Value());
390 v8::Local<v8::Value> v8_module_name;
391 if (!GetProperty(context, parameters, kModuleName, &v8_module_name)) {
392 Warn(info.GetIsolate(), "Cannot find module.");
393 return;
395 std::string name = *v8::String::Utf8Value(v8_module_name);
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);
402 v8::TryCatch try_catch(info.GetIsolate());
403 v8::Local<v8::Value> module_value;
404 if (!(module_system->*require_function)(name).ToLocal(&module_value)) {
405 module_system->HandleException(try_catch);
406 return;
409 v8::Local<v8::Object> module = v8::Local<v8::Object>::Cast(module_value);
410 v8::Local<v8::Value> field_value;
411 if (!GetProperty(context, parameters, kModuleField, &field_value)) {
412 module_system->HandleException(try_catch);
413 return;
415 v8::Local<v8::String> field;
416 if (!field_value->ToString(context).ToLocal(&field)) {
417 module_system->HandleException(try_catch);
418 return;
421 if (!IsTrue(module->Has(context, field))) {
422 std::string field_str = *v8::String::Utf8Value(field);
423 Fatal(module_system->context_,
424 "Lazy require of " + name + "." + field_str + " did not set the " +
425 field_str + " field");
426 return;
429 v8::Local<v8::Value> new_field;
430 if (!GetProperty(context, module, field, &new_field)) {
431 module_system->HandleException(try_catch);
432 return;
435 // Ok for it to be undefined, among other things it's how bindings signify
436 // that the extension doesn't have permission to use them.
437 CHECK(!new_field.IsEmpty());
439 // Delete the getter and set this field to |new_field| so the same object is
440 // returned every time a certain API is accessed.
441 v8::Local<v8::Value> val = info.This();
442 if (val->IsObject()) {
443 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(val);
444 object->Delete(context, property);
445 SetProperty(context, object, property, new_field);
446 } else {
447 NOTREACHED();
449 info.GetReturnValue().Set(new_field);
452 void ModuleSystem::SetLazyField(v8::Local<v8::Object> object,
453 const std::string& field,
454 const std::string& module_name,
455 const std::string& module_field) {
456 SetLazyField(
457 object, field, module_name, module_field, &ModuleSystem::LazyFieldGetter);
460 void ModuleSystem::SetLazyField(v8::Local<v8::Object> object,
461 const std::string& field,
462 const std::string& module_name,
463 const std::string& module_field,
464 v8::AccessorNameGetterCallback getter) {
465 CHECK(field.size() < v8::String::kMaxLength);
466 CHECK(module_name.size() < v8::String::kMaxLength);
467 CHECK(module_field.size() < v8::String::kMaxLength);
468 v8::HandleScope handle_scope(GetIsolate());
469 v8::Local<v8::Object> parameters = v8::Object::New(GetIsolate());
470 v8::Local<v8::Context> context = context_->v8_context();
471 SetProperty(context, parameters, kModuleName,
472 ToV8StringUnsafe(GetIsolate(), module_name.c_str()));
473 SetProperty(context, parameters, kModuleField,
474 ToV8StringUnsafe(GetIsolate(), module_field.c_str()));
475 auto maybe = object->SetAccessor(
476 context, ToV8StringUnsafe(GetIsolate(), field.c_str()), getter, NULL,
477 parameters);
478 CHECK(IsTrue(maybe));
481 void ModuleSystem::SetNativeLazyField(v8::Local<v8::Object> object,
482 const std::string& field,
483 const std::string& module_name,
484 const std::string& module_field) {
485 SetLazyField(object,
486 field,
487 module_name,
488 module_field,
489 &ModuleSystem::NativeLazyFieldGetter);
492 v8::Local<v8::Value> ModuleSystem::RunString(v8::Local<v8::String> code,
493 v8::Local<v8::String> name) {
494 v8::EscapableHandleScope handle_scope(GetIsolate());
495 v8::Local<v8::Context> v8_context = context()->v8_context();
496 v8::Context::Scope context_scope(v8_context);
498 // Prepend extensions:: to |name| so that internal code can be differentiated
499 // from external code in stack traces. This has no effect on behaviour.
500 std::string internal_name =
501 base::StringPrintf("extensions::%s", *v8::String::Utf8Value(name));
503 if (internal_name.size() >= v8::String::kMaxLength) {
504 NOTREACHED() << "internal_name is too long.";
505 return v8::Undefined(GetIsolate());
508 blink::WebScopedMicrotaskSuppression suppression;
509 v8::TryCatch try_catch(GetIsolate());
510 try_catch.SetCaptureMessage(true);
511 v8::ScriptOrigin origin(
512 ToV8StringUnsafe(GetIsolate(), internal_name.c_str()));
513 v8::Local<v8::Script> script;
514 if (!v8::Script::Compile(v8_context, code, &origin).ToLocal(&script)) {
515 HandleException(try_catch);
516 return v8::Undefined(GetIsolate());
519 v8::Local<v8::Value> result;
520 if (!script->Run(v8_context).ToLocal(&result)) {
521 HandleException(try_catch);
522 return v8::Undefined(GetIsolate());
525 return handle_scope.Escape(result);
528 v8::Local<v8::Value> ModuleSystem::GetSource(const std::string& module_name) {
529 v8::EscapableHandleScope handle_scope(GetIsolate());
530 if (!source_map_->Contains(module_name))
531 return v8::Undefined(GetIsolate());
532 return handle_scope.Escape(
533 v8::Local<v8::Value>(source_map_->GetSource(GetIsolate(), module_name)));
536 void ModuleSystem::RequireNative(
537 const v8::FunctionCallbackInfo<v8::Value>& args) {
538 CHECK_EQ(1, args.Length());
539 std::string native_name = *v8::String::Utf8Value(args[0]);
540 v8::Local<v8::Object> object;
541 if (RequireNativeFromString(native_name).ToLocal(&object))
542 args.GetReturnValue().Set(object);
545 v8::MaybeLocal<v8::Object> ModuleSystem::RequireNativeFromString(
546 const std::string& native_name) {
547 if (natives_enabled_ == 0) {
548 // HACK: if in test throw exception so that we can test the natives-disabled
549 // logic; however, under normal circumstances, this is programmer error so
550 // we could crash.
551 if (exception_handler_) {
552 GetIsolate()->ThrowException(
553 ToV8StringUnsafe(GetIsolate(), "Natives disabled"));
554 return v8::MaybeLocal<v8::Object>();
556 Fatal(context_, "Natives disabled for requireNative(" + native_name + ")");
557 return v8::MaybeLocal<v8::Object>();
560 if (overridden_native_handlers_.count(native_name) > 0u) {
561 v8::Local<v8::Value> value = RequireForJsInner(
562 ToV8StringUnsafe(GetIsolate(), native_name.c_str()));
563 if (value.IsEmpty() || !value->IsObject())
564 return v8::MaybeLocal<v8::Object>();
565 return value.As<v8::Object>();
568 NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
569 if (i == native_handler_map_.end()) {
570 Fatal(context_,
571 "Couldn't find native for requireNative(" + native_name + ")");
572 return v8::MaybeLocal<v8::Object>();
574 return i->second->NewInstance();
577 void ModuleSystem::RequireAsync(
578 const v8::FunctionCallbackInfo<v8::Value>& args) {
579 CHECK_EQ(1, args.Length());
580 std::string module_name = *v8::String::Utf8Value(args[0]);
581 v8::Local<v8::Context> v8_context = context_->v8_context();
582 v8::Local<v8::Promise::Resolver> resolver(
583 v8::Promise::Resolver::New(v8_context).ToLocalChecked());
584 args.GetReturnValue().Set(resolver->GetPromise());
585 scoped_ptr<v8::Global<v8::Promise::Resolver>> global_resolver(
586 new v8::Global<v8::Promise::Resolver>(GetIsolate(), resolver));
587 gin::ModuleRegistry* module_registry =
588 gin::ModuleRegistry::From(v8_context);
589 if (!module_registry) {
590 Warn(GetIsolate(), "Extension view no longer exists");
591 resolver->Reject(v8_context, v8::Exception::Error(ToV8StringUnsafe(
592 GetIsolate(), "Extension view no longer exists")));
593 return;
595 module_registry->LoadModule(
596 GetIsolate(), module_name,
597 base::Bind(&ModuleSystem::OnModuleLoaded, weak_factory_.GetWeakPtr(),
598 base::Passed(&global_resolver)));
599 if (module_registry->available_modules().count(module_name) == 0)
600 LoadModule(module_name);
603 v8::Local<v8::String> ModuleSystem::WrapSource(v8::Local<v8::String> source) {
604 v8::EscapableHandleScope handle_scope(GetIsolate());
605 // Keep in order with the arguments in RequireForJsInner.
606 v8::Local<v8::String> left = ToV8StringUnsafe(
607 GetIsolate(),
608 "(function(define, require, requireNative, requireAsync, exports, "
609 "console, privates,"
610 "$Array, $Function, $JSON, $Object, $RegExp, $String, $Error) {"
611 "'use strict';");
612 v8::Local<v8::String> right = ToV8StringUnsafe(GetIsolate(), "\n})");
613 return handle_scope.Escape(v8::Local<v8::String>(
614 v8::String::Concat(left, v8::String::Concat(source, right))));
617 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) {
618 CHECK_EQ(1, args.Length());
619 if (!args[0]->IsObject() || args[0]->IsNull()) {
620 GetIsolate()->ThrowException(
621 v8::Exception::TypeError(ToV8StringUnsafe(GetIsolate(),
622 args[0]->IsUndefined()
623 ? "Method called without a valid receiver (this). "
624 "Did you forget to call .bind()?"
625 : "Invalid invocation: receiver is not an object!")));
626 return;
628 v8::Local<v8::Object> obj = args[0].As<v8::Object>();
629 v8::Local<v8::String> privates_key =
630 ToV8StringUnsafe(GetIsolate(), "privates");
631 v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key);
632 if (privates.IsEmpty()) {
633 privates = v8::Object::New(args.GetIsolate());
634 if (privates.IsEmpty()) {
635 GetIsolate()->ThrowException(
636 ToV8StringUnsafe(GetIsolate(), "Failed to create privates"));
637 return;
639 obj->SetHiddenValue(privates_key, privates);
641 args.GetReturnValue().Set(privates);
644 v8::Local<v8::Value> ModuleSystem::LoadModule(const std::string& module_name) {
645 v8::EscapableHandleScope handle_scope(GetIsolate());
646 v8::Local<v8::Context> v8_context = context()->v8_context();
647 v8::Context::Scope context_scope(v8_context);
649 v8::Local<v8::Value> source(GetSource(module_name));
650 if (source.IsEmpty() || source->IsUndefined()) {
651 Fatal(context_, "No source for require(" + module_name + ")");
652 return v8::Undefined(GetIsolate());
654 v8::Local<v8::String> wrapped_source(
655 WrapSource(v8::Local<v8::String>::Cast(source)));
656 v8::Local<v8::String> v8_module_name;
657 if (!ToV8String(GetIsolate(), module_name.c_str(), &v8_module_name)) {
658 NOTREACHED() << "module_name is too long";
659 return v8::Undefined(GetIsolate());
661 // Modules are wrapped in (function(){...}) so they always return functions.
662 v8::Local<v8::Value> func_as_value =
663 RunString(wrapped_source, v8_module_name);
664 if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) {
665 Fatal(context_, "Bad source for require(" + module_name + ")");
666 return v8::Undefined(GetIsolate());
669 v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(func_as_value);
671 v8::Local<v8::Object> define_object = v8::Object::New(GetIsolate());
672 gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object);
674 v8::Local<v8::Value> exports = v8::Object::New(GetIsolate());
675 v8::Local<v8::Object> natives(NewInstance());
676 CHECK(!natives.IsEmpty()); // this can fail if v8 has issues
678 // These must match the argument order in WrapSource.
679 v8::Local<v8::Value> args[] = {
680 // AMD.
681 GetPropertyUnsafe(v8_context, define_object, "define"),
682 // CommonJS.
683 GetPropertyUnsafe(v8_context, natives, "require",
684 v8::NewStringType::kInternalized),
685 GetPropertyUnsafe(v8_context, natives, "requireNative",
686 v8::NewStringType::kInternalized),
687 GetPropertyUnsafe(v8_context, natives, "requireAsync",
688 v8::NewStringType::kInternalized),
689 exports,
690 // Libraries that we magically expose to every module.
691 console::AsV8Object(GetIsolate()),
692 GetPropertyUnsafe(v8_context, natives, "privates",
693 v8::NewStringType::kInternalized),
694 // Each safe builtin. Keep in order with the arguments in WrapSource.
695 context_->safe_builtins()->GetArray(),
696 context_->safe_builtins()->GetFunction(),
697 context_->safe_builtins()->GetJSON(),
698 context_->safe_builtins()->GetObjekt(),
699 context_->safe_builtins()->GetRegExp(),
700 context_->safe_builtins()->GetString(),
701 context_->safe_builtins()->GetError(),
704 v8::TryCatch try_catch(GetIsolate());
705 try_catch.SetCaptureMessage(true);
706 context_->CallFunction(func, arraysize(args), args);
707 if (try_catch.HasCaught()) {
708 HandleException(try_catch);
709 return v8::Undefined(GetIsolate());
712 return handle_scope.Escape(exports);
715 void ModuleSystem::OnDidAddPendingModule(
716 const std::string& id,
717 const std::vector<std::string>& dependencies) {
718 bool module_system_managed = source_map_->Contains(id);
720 gin::ModuleRegistry* registry =
721 gin::ModuleRegistry::From(context_->v8_context());
722 DCHECK(registry);
723 for (const auto& dependency : dependencies) {
724 // If a dependency is not available, and either the module or this
725 // dependency is managed by ModuleSystem, attempt to load it. Other
726 // gin::ModuleRegistry users (WebUI and users of the mojoPrivate API) are
727 // responsible for loading their module dependencies when required.
728 if (registry->available_modules().count(dependency) == 0 &&
729 (module_system_managed || source_map_->Contains(dependency))) {
730 LoadModule(dependency);
733 registry->AttemptToLoadMoreModules(GetIsolate());
736 void ModuleSystem::OnModuleLoaded(
737 scoped_ptr<v8::Global<v8::Promise::Resolver>> resolver,
738 v8::Local<v8::Value> value) {
739 if (!is_valid())
740 return;
741 v8::HandleScope handle_scope(GetIsolate());
742 v8::Local<v8::Promise::Resolver> resolver_local(
743 v8::Local<v8::Promise::Resolver>::New(GetIsolate(), *resolver));
744 resolver_local->Resolve(context()->v8_context(), value);
747 void ModuleSystem::ClobberExistingNativeHandler(const std::string& name) {
748 NativeHandlerMap::iterator existing_handler = native_handler_map_.find(name);
749 if (existing_handler != native_handler_map_.end()) {
750 clobbered_native_handlers_.push_back(existing_handler->second);
751 native_handler_map_.erase(existing_handler);
755 } // namespace extensions