| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "extensions/renderer/module_system.h" | 5 #include "extensions/renderer/module_system.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 232 void ModuleSystem::HandleException(const v8::TryCatch& try_catch) { | 232 void ModuleSystem::HandleException(const v8::TryCatch& try_catch) { |
| 233 exception_handler_->HandleUncaughtException(try_catch); | 233 exception_handler_->HandleUncaughtException(try_catch); |
| 234 } | 234 } |
| 235 | 235 |
| 236 v8::MaybeLocal<v8::Object> ModuleSystem::Require( | 236 v8::MaybeLocal<v8::Object> ModuleSystem::Require( |
| 237 const std::string& module_name) { | 237 const std::string& module_name) { |
| 238 v8::Local<v8::String> v8_module_name; | 238 v8::Local<v8::String> v8_module_name; |
| 239 if (!ToV8String(GetIsolate(), module_name, &v8_module_name)) | 239 if (!ToV8String(GetIsolate(), module_name, &v8_module_name)) |
| 240 return v8::MaybeLocal<v8::Object>(); | 240 return v8::MaybeLocal<v8::Object>(); |
| 241 v8::EscapableHandleScope handle_scope(GetIsolate()); | 241 v8::EscapableHandleScope handle_scope(GetIsolate()); |
| 242 v8::Local<v8::Value> value = RequireForJsInner( | 242 v8::Local<v8::Value> value = |
| 243 v8_module_name); | 243 RequireForJsInner(v8_module_name, true /* create */); |
| 244 if (value.IsEmpty() || !value->IsObject()) | 244 if (value.IsEmpty() || !value->IsObject()) |
| 245 return v8::MaybeLocal<v8::Object>(); | 245 return v8::MaybeLocal<v8::Object>(); |
| 246 return handle_scope.Escape(value.As<v8::Object>()); | 246 return handle_scope.Escape(value.As<v8::Object>()); |
| 247 } | 247 } |
| 248 | 248 |
| 249 void ModuleSystem::RequireForJs( | 249 void ModuleSystem::RequireForJs( |
| 250 const v8::FunctionCallbackInfo<v8::Value>& args) { | 250 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 251 if (!args[0]->IsString()) { | 251 if (!args[0]->IsString()) { |
| 252 NOTREACHED() << "require() called with a non-string argument"; | 252 NOTREACHED() << "require() called with a non-string argument"; |
| 253 return; | 253 return; |
| 254 } | 254 } |
| 255 v8::Local<v8::String> module_name = args[0].As<v8::String>(); | 255 v8::Local<v8::String> module_name = args[0].As<v8::String>(); |
| 256 args.GetReturnValue().Set(RequireForJsInner(module_name)); | 256 args.GetReturnValue().Set(RequireForJsInner(module_name, true /* create */)); |
| 257 } | 257 } |
| 258 | 258 |
| 259 v8::Local<v8::Value> ModuleSystem::RequireForJsInner( | 259 v8::Local<v8::Value> ModuleSystem::RequireForJsInner( |
| 260 v8::Local<v8::String> module_name) { | 260 v8::Local<v8::String> module_name, |
| 261 bool create) { |
| 261 v8::EscapableHandleScope handle_scope(GetIsolate()); | 262 v8::EscapableHandleScope handle_scope(GetIsolate()); |
| 262 v8::Local<v8::Context> v8_context = context()->v8_context(); | 263 v8::Local<v8::Context> v8_context = context()->v8_context(); |
| 263 v8::Context::Scope context_scope(v8_context); | 264 v8::Context::Scope context_scope(v8_context); |
| 264 | 265 |
| 265 v8::Local<v8::Object> global(context()->v8_context()->Global()); | 266 v8::Local<v8::Object> global(context()->v8_context()->Global()); |
| 266 | 267 |
| 267 // The module system might have been deleted. This can happen if a different | 268 // The module system might have been deleted. This can happen if a different |
| 268 // context keeps a reference to us, but our frame is destroyed (e.g. | 269 // context keeps a reference to us, but our frame is destroyed (e.g. |
| 269 // background page keeps reference to chrome object in a closed popup). | 270 // background page keeps reference to chrome object in a closed popup). |
| 270 v8::Local<v8::Value> modules_value; | 271 v8::Local<v8::Value> modules_value; |
| 271 if (!GetPrivate(global, kModulesField, &modules_value) || | 272 if (!GetPrivate(global, kModulesField, &modules_value) || |
| 272 modules_value->IsUndefined()) { | 273 modules_value->IsUndefined()) { |
| 273 Warn(GetIsolate(), "Extension view no longer exists"); | 274 Warn(GetIsolate(), "Extension view no longer exists"); |
| 274 return v8::Undefined(GetIsolate()); | 275 return v8::Undefined(GetIsolate()); |
| 275 } | 276 } |
| 276 | 277 |
| 277 v8::Local<v8::Object> modules(v8::Local<v8::Object>::Cast(modules_value)); | 278 v8::Local<v8::Object> modules(v8::Local<v8::Object>::Cast(modules_value)); |
| 278 v8::Local<v8::Value> exports; | 279 v8::Local<v8::Value> exports; |
| 279 if (!GetPrivateProperty(v8_context, modules, module_name, &exports) || | 280 if (!GetPrivateProperty(v8_context, modules, module_name, &exports) || |
| 280 !exports->IsUndefined()) | 281 !exports->IsUndefined()) |
| 281 return handle_scope.Escape(exports); | 282 return handle_scope.Escape(exports); |
| 282 | 283 |
| 284 if (!create) |
| 285 return v8::Undefined(GetIsolate()); |
| 286 |
| 283 exports = LoadModule(*v8::String::Utf8Value(module_name)); | 287 exports = LoadModule(*v8::String::Utf8Value(module_name)); |
| 284 SetPrivateProperty(v8_context, modules, module_name, exports); | 288 SetPrivateProperty(v8_context, modules, module_name, exports); |
| 285 return handle_scope.Escape(exports); | 289 return handle_scope.Escape(exports); |
| 286 } | 290 } |
| 287 | 291 |
| 288 void ModuleSystem::CallModuleMethodSafe(const std::string& module_name, | 292 void ModuleSystem::CallModuleMethodSafe(const std::string& module_name, |
| 289 const std::string& method_name) { | 293 const std::string& method_name) { |
| 290 v8::HandleScope handle_scope(GetIsolate()); | 294 v8::HandleScope handle_scope(GetIsolate()); |
| 291 v8::Local<v8::Value> no_args; | 295 v8::Local<v8::Value> no_args; |
| 292 CallModuleMethodSafe(module_name, method_name, 0, &no_args, | 296 CallModuleMethodSafe(module_name, method_name, 0, &no_args, |
| (...skipping 25 matching lines...) Expand all Loading... |
| 318 TRACE_EVENT2("v8", "v8.callModuleMethodSafe", "module_name", module_name, | 322 TRACE_EVENT2("v8", "v8.callModuleMethodSafe", "module_name", module_name, |
| 319 "method_name", method_name); | 323 "method_name", method_name); |
| 320 | 324 |
| 321 v8::HandleScope handle_scope(GetIsolate()); | 325 v8::HandleScope handle_scope(GetIsolate()); |
| 322 v8::Local<v8::Context> v8_context = context()->v8_context(); | 326 v8::Local<v8::Context> v8_context = context()->v8_context(); |
| 323 v8::Context::Scope context_scope(v8_context); | 327 v8::Context::Scope context_scope(v8_context); |
| 324 | 328 |
| 325 v8::Local<v8::Function> function = | 329 v8::Local<v8::Function> function = |
| 326 GetModuleFunction(module_name, method_name); | 330 GetModuleFunction(module_name, method_name); |
| 327 if (function.IsEmpty()) { | 331 if (function.IsEmpty()) { |
| 328 NOTREACHED() << "GetModuleFunction() returns empty function handle"; | 332 // This can legitimately happen when the module hasn't been loaded in the |
| 333 // context (since GetModuleFunction() does not load an unloaded module). |
| 334 // Typically, we won't do this, but we can in the case of, e.g., dispatching |
| 335 // events (where we'll try to dispatch to each context in a process). In |
| 336 // these cases, though, we can know that there are no listeners registered, |
| 337 // since the event module hasn't been loaded. |
| 329 return; | 338 return; |
| 330 } | 339 } |
| 331 | 340 |
| 332 { | 341 { |
| 333 v8::TryCatch try_catch(GetIsolate()); | 342 v8::TryCatch try_catch(GetIsolate()); |
| 334 try_catch.SetCaptureMessage(true); | 343 try_catch.SetCaptureMessage(true); |
| 335 context_->SafeCallFunction(function, argc, argv, callback); | 344 context_->SafeCallFunction(function, argc, argv, callback); |
| 336 if (try_catch.HasCaught()) | 345 if (try_catch.HasCaught()) |
| 337 HandleException(try_catch); | 346 HandleException(try_catch); |
| 338 } | 347 } |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 594 GetIsolate()->ThrowException( | 603 GetIsolate()->ThrowException( |
| 595 ToV8StringUnsafe(GetIsolate(), "Natives disabled")); | 604 ToV8StringUnsafe(GetIsolate(), "Natives disabled")); |
| 596 return v8::MaybeLocal<v8::Object>(); | 605 return v8::MaybeLocal<v8::Object>(); |
| 597 } | 606 } |
| 598 Fatal(context_, "Natives disabled for requireNative(" + native_name + ")"); | 607 Fatal(context_, "Natives disabled for requireNative(" + native_name + ")"); |
| 599 return v8::MaybeLocal<v8::Object>(); | 608 return v8::MaybeLocal<v8::Object>(); |
| 600 } | 609 } |
| 601 | 610 |
| 602 if (overridden_native_handlers_.count(native_name) > 0u) { | 611 if (overridden_native_handlers_.count(native_name) > 0u) { |
| 603 v8::Local<v8::Value> value = RequireForJsInner( | 612 v8::Local<v8::Value> value = RequireForJsInner( |
| 604 ToV8StringUnsafe(GetIsolate(), native_name.c_str())); | 613 ToV8StringUnsafe(GetIsolate(), native_name.c_str()), true /* create */); |
| 605 if (value.IsEmpty() || !value->IsObject()) | 614 if (value.IsEmpty() || !value->IsObject()) |
| 606 return v8::MaybeLocal<v8::Object>(); | 615 return v8::MaybeLocal<v8::Object>(); |
| 607 return value.As<v8::Object>(); | 616 return value.As<v8::Object>(); |
| 608 } | 617 } |
| 609 | 618 |
| 610 NativeHandlerMap::iterator i = native_handler_map_.find(native_name); | 619 NativeHandlerMap::iterator i = native_handler_map_.find(native_name); |
| 611 if (i == native_handler_map_.end()) { | 620 if (i == native_handler_map_.end()) { |
| 612 Fatal(context_, | 621 Fatal(context_, |
| 613 "Couldn't find native for requireNative(" + native_name + ")"); | 622 "Couldn't find native for requireNative(" + native_name + ")"); |
| 614 return v8::MaybeLocal<v8::Object>(); | 623 return v8::MaybeLocal<v8::Object>(); |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 851 clobbered_native_handlers_.push_back(std::move(existing_handler->second)); | 860 clobbered_native_handlers_.push_back(std::move(existing_handler->second)); |
| 852 native_handler_map_.erase(existing_handler); | 861 native_handler_map_.erase(existing_handler); |
| 853 } | 862 } |
| 854 } | 863 } |
| 855 | 864 |
| 856 v8::Local<v8::Function> ModuleSystem::GetModuleFunction( | 865 v8::Local<v8::Function> ModuleSystem::GetModuleFunction( |
| 857 const std::string& module_name, | 866 const std::string& module_name, |
| 858 const std::string& method_name) { | 867 const std::string& method_name) { |
| 859 v8::Local<v8::String> v8_module_name; | 868 v8::Local<v8::String> v8_module_name; |
| 860 v8::Local<v8::String> v8_method_name; | 869 v8::Local<v8::String> v8_method_name; |
| 861 v8::Local<v8::Function> function; | |
| 862 if (!ToV8String(GetIsolate(), module_name.c_str(), &v8_module_name) || | 870 if (!ToV8String(GetIsolate(), module_name.c_str(), &v8_module_name) || |
| 863 !ToV8String(GetIsolate(), method_name.c_str(), &v8_method_name)) { | 871 !ToV8String(GetIsolate(), method_name.c_str(), &v8_method_name)) { |
| 864 return function; | 872 return v8::Local<v8::Function>(); |
| 865 } | 873 } |
| 866 | 874 |
| 867 v8::Local<v8::Value> module; | 875 v8::Local<v8::Value> module; |
| 868 { | 876 // Important: don't create the module if it doesn't exist. Doing so would |
| 869 NativesEnabledScope natives_enabled(this); | 877 // force a call into JS, which is something we want to avoid in case it has |
| 870 module = RequireForJsInner(v8_module_name); | 878 // been suspended. Additionally, we should only be calling module methods for |
| 871 } | 879 // modules that have been instantiated. |
| 880 bool create = false; |
| 881 module = RequireForJsInner(v8_module_name, create); |
| 882 |
| 883 // RequireForJsInner() returns Undefined in the case of a module not being |
| 884 // loaded, since we don't create it here. |
| 885 if (!module.IsEmpty() && module->IsUndefined()) |
| 886 return v8::Local<v8::Function>(); |
| 872 | 887 |
| 873 if (module.IsEmpty() || !module->IsObject()) { | 888 if (module.IsEmpty() || !module->IsObject()) { |
| 874 Fatal(context_, | 889 Fatal(context_, |
| 875 "Failed to get module " + module_name + " to call " + method_name); | 890 "Failed to get module " + module_name + " to call " + method_name); |
| 876 return function; | 891 return v8::Local<v8::Function>(); |
| 877 } | 892 } |
| 878 | 893 |
| 879 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(module); | 894 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(module); |
| 880 v8::Local<v8::Value> value; | 895 v8::Local<v8::Value> value; |
| 881 if (!GetProperty(context()->v8_context(), object, v8_method_name, &value) || | 896 if (!GetProperty(context()->v8_context(), object, v8_method_name, &value) || |
| 882 !value->IsFunction()) { | 897 !value->IsFunction()) { |
| 883 Fatal(context_, module_name + "." + method_name + " is not a function"); | 898 Fatal(context_, module_name + "." + method_name + " is not a function"); |
| 884 return function; | 899 return v8::Local<v8::Function>(); |
| 885 } | 900 } |
| 886 | 901 |
| 887 function = v8::Local<v8::Function>::Cast(value); | 902 return v8::Local<v8::Function>::Cast(value); |
| 888 return function; | |
| 889 } | 903 } |
| 890 | 904 |
| 891 } // namespace extensions | 905 } // namespace extensions |
| OLD | NEW |