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 |