| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/renderer/extensions/module_system.h" | 5 #include "chrome/renderer/extensions/module_system.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/debug/alias.h" |
| 8 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
| 10 #include "base/string_util.h" |
| 9 #include "base/stringprintf.h" | 11 #include "base/stringprintf.h" |
| 10 #include "chrome/common/extensions/extension_messages.h" | 12 #include "chrome/common/extensions/extension_messages.h" |
| 11 #include "chrome/renderer/extensions/chrome_v8_context.h" | 13 #include "chrome/renderer/extensions/chrome_v8_context.h" |
| 12 #include "content/public/renderer/render_view.h" | 14 #include "content/public/renderer/render_view.h" |
| 13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScopedMicrotaskSup
pression.h" | 15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScopedMicrotaskSup
pression.h" |
| 14 | 16 |
| 15 namespace { | 17 namespace { |
| 16 | 18 |
| 17 const char* kModuleSystem = "module_system"; | 19 const char* kModuleSystem = "module_system"; |
| 18 const char* kModuleName = "module_name"; | 20 const char* kModuleName = "module_name"; |
| 19 const char* kModuleField = "module_field"; | 21 const char* kModuleField = "module_field"; |
| 20 const char* kModulesField = "modules"; | 22 const char* kModulesField = "modules"; |
| 21 | 23 |
| 22 } // namespace | 24 } // namespace |
| 23 | 25 |
| 24 namespace extensions { | 26 namespace extensions { |
| 25 | 27 |
| 26 ModuleSystem::ModuleSystem(v8::Handle<v8::Context> context, | 28 ModuleSystem::ModuleSystem(v8::Handle<v8::Context> context, |
| 27 SourceMap* source_map) | 29 SourceMap* source_map) |
| 28 : ObjectBackedNativeHandler(context), | 30 : ObjectBackedNativeHandler(context), |
| 29 source_map_(source_map), | 31 source_map_(source_map), |
| 30 natives_enabled_(0), | 32 natives_enabled_(0) { |
| 31 is_valid_(true) { | |
| 32 RouteFunction("require", | 33 RouteFunction("require", |
| 33 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this))); | 34 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this))); |
| 34 RouteFunction("requireNative", | 35 RouteFunction("requireNative", |
| 35 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this))); | 36 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this))); |
| 36 | 37 |
| 37 v8::Handle<v8::Object> global(context->Global()); | 38 v8::Handle<v8::Object> global(context->Global()); |
| 38 global->SetHiddenValue(v8::String::New(kModulesField), v8::Object::New()); | 39 global->SetHiddenValue(v8::String::New(kModulesField), v8::Object::New()); |
| 39 global->SetHiddenValue(v8::String::New(kModuleSystem), | 40 global->SetHiddenValue(v8::String::New(kModuleSystem), |
| 40 v8::External::New(this)); | 41 v8::External::New(this)); |
| 41 } | 42 } |
| 42 | 43 |
| 43 ModuleSystem::~ModuleSystem() { | 44 ModuleSystem::~ModuleSystem() { |
| 44 Invalidate(); | 45 Invalidate(); |
| 45 } | 46 } |
| 46 | 47 |
| 47 bool ModuleSystem::Invalidate() { | 48 void ModuleSystem::Invalidate() { |
| 48 if (!ObjectBackedNativeHandler::Invalidate()) | 49 if (!is_valid()) |
| 49 return false; | 50 return; |
| 50 | 51 for (NativeHandlerMap::iterator it = native_handler_map_.begin(); |
| 51 v8::HandleScope handle_scope; | 52 it != native_handler_map_.end(); ++it) { |
| 52 // Deleting this value here prevents future lazy field accesses from | 53 it->second->Invalidate(); |
| 53 // referencing ModuleSystem after it has been freed. | 54 } |
| 54 v8_context()->Global()->DeleteHiddenValue(v8::String::New(kModuleSystem)); | 55 ObjectBackedNativeHandler::Invalidate(); |
| 55 | |
| 56 return true; | |
| 57 } | 56 } |
| 58 | 57 |
| 59 ModuleSystem::NativesEnabledScope::NativesEnabledScope( | 58 ModuleSystem::NativesEnabledScope::NativesEnabledScope( |
| 60 ModuleSystem* module_system) | 59 ModuleSystem* module_system) |
| 61 : module_system_(module_system) { | 60 : module_system_(module_system) { |
| 62 module_system_->natives_enabled_++; | 61 module_system_->natives_enabled_++; |
| 63 } | 62 } |
| 64 | 63 |
| 65 ModuleSystem::NativesEnabledScope::~NativesEnabledScope() { | 64 ModuleSystem::NativesEnabledScope::~NativesEnabledScope() { |
| 66 module_system_->natives_enabled_--; | 65 module_system_->natives_enabled_--; |
| 67 CHECK_GE(module_system_->natives_enabled_, 0); | 66 CHECK_GE(module_system_->natives_enabled_, 0); |
| 68 } | 67 } |
| 69 | 68 |
| 70 // static | |
| 71 bool ModuleSystem::IsPresentInCurrentContext() { | |
| 72 // XXX(kalman): Not sure if this is safe. Investigate. | |
| 73 v8::Handle<v8::Object> global(v8::Context::GetCurrent()->Global()); | |
| 74 if (global.IsEmpty()) | |
| 75 return false; | |
| 76 v8::Handle<v8::Value> module_system = | |
| 77 global->GetHiddenValue(v8::String::New(kModuleSystem)); | |
| 78 return !module_system.IsEmpty() && !module_system->IsUndefined(); | |
| 79 } | |
| 80 | |
| 81 void ModuleSystem::HandleException(const v8::TryCatch& try_catch) { | 69 void ModuleSystem::HandleException(const v8::TryCatch& try_catch) { |
| 82 DumpException(try_catch); | 70 DumpException(try_catch); |
| 83 if (exception_handler_.get()) | 71 if (exception_handler_.get()) |
| 84 exception_handler_->HandleUncaughtException(); | 72 exception_handler_->HandleUncaughtException(); |
| 85 } | 73 } |
| 86 | 74 |
| 87 // static | 75 // static |
| 88 std::string ModuleSystem::CreateExceptionString(const v8::TryCatch& try_catch) { | 76 std::string ModuleSystem::CreateExceptionString(const v8::TryCatch& try_catch) { |
| 89 v8::Handle<v8::Message> message(try_catch.Message()); | 77 v8::Handle<v8::Message> message(try_catch.Message()); |
| 90 if (message.IsEmpty()) { | 78 if (message.IsEmpty()) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 } | 118 } |
| 131 | 119 |
| 132 v8::Handle<v8::Value> ModuleSystem::RequireForJs(const v8::Arguments& args) { | 120 v8::Handle<v8::Value> ModuleSystem::RequireForJs(const v8::Arguments& args) { |
| 133 v8::HandleScope handle_scope; | 121 v8::HandleScope handle_scope; |
| 134 v8::Handle<v8::String> module_name = args[0]->ToString(); | 122 v8::Handle<v8::String> module_name = args[0]->ToString(); |
| 135 return handle_scope.Close(RequireForJsInner(module_name)); | 123 return handle_scope.Close(RequireForJsInner(module_name)); |
| 136 } | 124 } |
| 137 | 125 |
| 138 v8::Handle<v8::Value> ModuleSystem::RequireForJsInner( | 126 v8::Handle<v8::Value> ModuleSystem::RequireForJsInner( |
| 139 v8::Handle<v8::String> module_name) { | 127 v8::Handle<v8::String> module_name) { |
| 140 CHECK(is_valid_); | |
| 141 v8::HandleScope handle_scope; | 128 v8::HandleScope handle_scope; |
| 142 v8::Handle<v8::Object> global(v8_context()->Global()); | 129 v8::Handle<v8::Object> global(v8_context()->Global()); |
| 143 v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast( | 130 v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast( |
| 144 global->GetHiddenValue(v8::String::New(kModulesField)))); | 131 global->GetHiddenValue(v8::String::New(kModulesField)))); |
| 145 v8::Handle<v8::Value> exports(modules->Get(module_name)); | 132 v8::Handle<v8::Value> exports(modules->Get(module_name)); |
| 146 if (!exports->IsUndefined()) | 133 if (!exports->IsUndefined()) |
| 147 return handle_scope.Close(exports); | 134 return handle_scope.Close(exports); |
| 148 | 135 |
| 149 v8::Handle<v8::Value> source(GetSource(module_name)); | 136 v8::Handle<v8::Value> source(GetSource(module_name)); |
| 150 if (source->IsUndefined()) | 137 if (source->IsUndefined()) |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 // static | 233 // static |
| 247 v8::Handle<v8::Value> ModuleSystem::LazyFieldGetter( | 234 v8::Handle<v8::Value> ModuleSystem::LazyFieldGetter( |
| 248 v8::Local<v8::String> property, const v8::AccessorInfo& info) { | 235 v8::Local<v8::String> property, const v8::AccessorInfo& info) { |
| 249 return LazyFieldGetterInner(property, info, &ModuleSystem::Require); | 236 return LazyFieldGetterInner(property, info, &ModuleSystem::Require); |
| 250 } | 237 } |
| 251 | 238 |
| 252 // static | 239 // static |
| 253 v8::Handle<v8::Value> ModuleSystem::LazyFieldGetterInner( | 240 v8::Handle<v8::Value> ModuleSystem::LazyFieldGetterInner( |
| 254 v8::Local<v8::String> property, | 241 v8::Local<v8::String> property, |
| 255 const v8::AccessorInfo& info, | 242 const v8::AccessorInfo& info, |
| 256 GetModuleFunc get_module) { | 243 RequireFunction require_function) { |
| 257 CHECK(!info.Data().IsEmpty()); | 244 CHECK(!info.Data().IsEmpty()); |
| 258 CHECK(info.Data()->IsObject()); | 245 CHECK(info.Data()->IsObject()); |
| 259 v8::HandleScope handle_scope; | 246 v8::HandleScope handle_scope; |
| 260 v8::Handle<v8::Object> parameters = v8::Handle<v8::Object>::Cast(info.Data()); | 247 v8::Handle<v8::Object> parameters = v8::Handle<v8::Object>::Cast(info.Data()); |
| 261 v8::Handle<v8::Object> global(parameters->CreationContext()->Global()); | 248 v8::Handle<v8::Object> global(parameters->CreationContext()->Global()); |
| 262 v8::Handle<v8::Value> module_system_value = | 249 v8::Handle<v8::Value> module_system_value = |
| 263 global->GetHiddenValue(v8::String::New(kModuleSystem)); | 250 global->GetHiddenValue(v8::String::New(kModuleSystem)); |
| 264 if (module_system_value.IsEmpty() || module_system_value->IsUndefined()) { | 251 if (module_system_value.IsEmpty() || module_system_value->IsUndefined()) { |
| 265 // ModuleSystem has been deleted. | 252 // ModuleSystem has been deleted. |
| 266 return v8::Undefined(); | 253 return v8::Undefined(); |
| 267 } | 254 } |
| 268 ModuleSystem* module_system = static_cast<ModuleSystem*>( | 255 ModuleSystem* module_system = static_cast<ModuleSystem*>( |
| 269 v8::Handle<v8::External>::Cast(module_system_value)->Value()); | 256 v8::Handle<v8::External>::Cast(module_system_value)->Value()); |
| 270 | 257 |
| 271 std::string name = *v8::String::AsciiValue( | 258 std::string name = *v8::String::AsciiValue( |
| 272 parameters->Get(v8::String::New(kModuleName))->ToString()); | 259 parameters->Get(v8::String::New(kModuleName))->ToString()); |
| 273 | 260 |
| 274 // HACK(kalman): Switch to the context of the owner module system while | |
| 275 // lazily requiring modules. | |
| 276 // | |
| 277 // It seems to be a common incorrect assumption throughout code that the | |
| 278 // current context is the owner context. This makes that assumption true for | |
| 279 // at least the period where the JavaScript is first evaluated, which is when | |
| 280 // things are most likely to go wrong. | |
| 281 v8::Context::Scope context_scope(parameters->CreationContext()); | |
| 282 | |
| 283 NativesEnabledScope natives_enabled_scope(module_system); | 261 NativesEnabledScope natives_enabled_scope(module_system); |
| 284 | |
| 285 v8::TryCatch try_catch; | 262 v8::TryCatch try_catch; |
| 286 v8::Handle<v8::Object> module = v8::Handle<v8::Object>::Cast( | 263 v8::Handle<v8::Object> module = v8::Handle<v8::Object>::Cast( |
| 287 (module_system->*get_module)(name)); | 264 (module_system->*require_function)(name)); |
| 288 if (try_catch.HasCaught()) { | 265 if (try_catch.HasCaught()) { |
| 289 module_system->HandleException(try_catch); | 266 module_system->HandleException(try_catch); |
| 290 return handle_scope.Close(v8::Handle<v8::Value>()); | 267 return handle_scope.Close(v8::Handle<v8::Value>()); |
| 291 } | 268 } |
| 292 | 269 |
| 293 if (module.IsEmpty()) | 270 if (module.IsEmpty()) |
| 294 return handle_scope.Close(v8::Handle<v8::Value>()); | 271 return handle_scope.Close(v8::Handle<v8::Value>()); |
| 295 | 272 |
| 296 v8::Handle<v8::String> field = | 273 v8::Handle<v8::String> field = |
| 297 parameters->Get(v8::String::New(kModuleField))->ToString(); | 274 parameters->Get(v8::String::New(kModuleField))->ToString(); |
| 298 | 275 |
| 276 // http://crbug.com/179741. |
| 277 std::string field_name = *v8::String::AsciiValue(field); |
| 278 char stack_debug[64]; |
| 279 base::debug::Alias(&stack_debug); |
| 280 base::snprintf(stack_debug, arraysize(stack_debug), |
| 281 "%s.%s", name.c_str(), field_name.c_str()); |
| 282 |
| 299 v8::Local<v8::Value> new_field = module->Get(field); | 283 v8::Local<v8::Value> new_field = module->Get(field); |
| 300 v8::Handle<v8::Object> object = info.This(); | 284 v8::Handle<v8::Object> object = info.This(); |
| 301 // Delete the getter and set this field to |new_field| so the same object is | 285 // Delete the getter and set this field to |new_field| so the same object is |
| 302 // returned every time a certain API is accessed. | 286 // returned every time a certain API is accessed. |
| 287 // CHECK is for http://crbug.com/179741. |
| 288 CHECK(!new_field.IsEmpty()) << "Empty require " << name << "." << field_name; |
| 303 if (!new_field->IsUndefined()) { | 289 if (!new_field->IsUndefined()) { |
| 304 object->Delete(property); | 290 object->Delete(property); |
| 305 object->Set(property, new_field); | 291 object->Set(property, new_field); |
| 306 } | 292 } |
| 307 return handle_scope.Close(new_field); | 293 return handle_scope.Close(new_field); |
| 308 } | 294 } |
| 309 | 295 |
| 310 void ModuleSystem::SetLazyField(v8::Handle<v8::Object> object, | 296 void ModuleSystem::SetLazyField(v8::Handle<v8::Object> object, |
| 311 const std::string& field, | 297 const std::string& field, |
| 312 const std::string& module_name, | 298 const std::string& module_name, |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 v8::Handle<v8::String> right = v8::String::New("\n})"); | 380 v8::Handle<v8::String> right = v8::String::New("\n})"); |
| 395 return handle_scope.Close( | 381 return handle_scope.Close( |
| 396 v8::String::Concat(left, v8::String::Concat(source, right))); | 382 v8::String::Concat(left, v8::String::Concat(source, right))); |
| 397 } | 383 } |
| 398 | 384 |
| 399 v8::Handle<v8::Value> ModuleSystem::ThrowException(const std::string& message) { | 385 v8::Handle<v8::Value> ModuleSystem::ThrowException(const std::string& message) { |
| 400 return v8::ThrowException(v8::String::New(message.c_str())); | 386 return v8::ThrowException(v8::String::New(message.c_str())); |
| 401 } | 387 } |
| 402 | 388 |
| 403 } // extensions | 389 } // extensions |
| OLD | NEW |