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