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/trace_event.h" |
8 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
9 #include "base/string_util.h" | 10 #include "base/string_util.h" |
10 #include "base/stringprintf.h" | 11 #include "base/stringprintf.h" |
11 #include "chrome/common/extensions/extension_messages.h" | 12 #include "chrome/common/extensions/extension_messages.h" |
12 #include "chrome/renderer/extensions/chrome_v8_context.h" | 13 #include "chrome/renderer/extensions/chrome_v8_context.h" |
13 #include "chrome/renderer/extensions/console.h" | 14 #include "chrome/renderer/extensions/console.h" |
14 #include "content/public/renderer/render_view.h" | 15 #include "content/public/renderer/render_view.h" |
| 16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScopedMicrotaskSup
pression.h" | 17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScopedMicrotaskSup
pression.h" |
16 | 18 |
17 namespace extensions { | 19 namespace extensions { |
18 | 20 |
19 namespace { | 21 namespace { |
20 | 22 |
21 const char* kModuleSystem = "module_system"; | 23 const char* kModuleSystem = "module_system"; |
22 const char* kModuleName = "module_name"; | 24 const char* kModuleName = "module_name"; |
23 const char* kModuleField = "module_field"; | 25 const char* kModuleField = "module_field"; |
24 const char* kModulesField = "modules"; | 26 const char* kModulesField = "modules"; |
25 | 27 |
26 // Formats |try_catch| as a nice string. | 28 // Default exception handler which logs the exception. |
27 std::string CreateExceptionString(const v8::TryCatch& try_catch) { | 29 class DefaultExceptionHandler : public ModuleSystem::ExceptionHandler { |
| 30 public: |
| 31 // Fatally dumps the debug info from |try_catch| to the console. |
| 32 // Make sure this is never used for exceptions that originate in external |
| 33 // code! |
| 34 virtual void HandleUncaughtException(const v8::TryCatch& try_catch) OVERRIDE { |
| 35 v8::HandleScope handle_scope; |
| 36 std::string stack_trace = "<stack trace unavailable>"; |
| 37 if (!try_catch.StackTrace().IsEmpty()) { |
| 38 v8::String::Utf8Value stack_value(try_catch.StackTrace()); |
| 39 if (*stack_value) |
| 40 stack_trace.assign(*stack_value, stack_value.length()); |
| 41 else |
| 42 stack_trace = "<could not convert stack trace to string>"; |
| 43 } |
| 44 console::Fatal(v8::Context::GetCalling(), |
| 45 CreateExceptionString(try_catch) + "{" + stack_trace + "}"); |
| 46 } |
| 47 }; |
| 48 |
| 49 } // namespace |
| 50 |
| 51 std::string ModuleSystem::ExceptionHandler::CreateExceptionString( |
| 52 const v8::TryCatch& try_catch) { |
28 v8::Handle<v8::Message> message(try_catch.Message()); | 53 v8::Handle<v8::Message> message(try_catch.Message()); |
29 if (message.IsEmpty()) { | 54 if (message.IsEmpty()) { |
30 return "try_catch has no message"; | 55 return "try_catch has no message"; |
31 } | 56 } |
32 | 57 |
33 std::string resource_name = "<unknown resource>"; | 58 std::string resource_name = "<unknown resource>"; |
34 if (!message->GetScriptResourceName().IsEmpty()) { | 59 if (!message->GetScriptResourceName().IsEmpty()) { |
35 v8::String::Utf8Value resource_name_v8( | 60 v8::String::Utf8Value resource_name_v8( |
36 message->GetScriptResourceName()->ToString()); | 61 message->GetScriptResourceName()->ToString()); |
37 resource_name.assign(*resource_name_v8, resource_name_v8.length()); | 62 resource_name.assign(*resource_name_v8, resource_name_v8.length()); |
38 } | 63 } |
39 | 64 |
40 std::string error_message = "<no error message>"; | 65 std::string error_message = "<no error message>"; |
41 if (!message->Get().IsEmpty()) { | 66 if (!message->Get().IsEmpty()) { |
42 v8::String::Utf8Value error_message_v8(message->Get()); | 67 v8::String::Utf8Value error_message_v8(message->Get()); |
43 error_message.assign(*error_message_v8, error_message_v8.length()); | 68 error_message.assign(*error_message_v8, error_message_v8.length()); |
44 } | 69 } |
45 | 70 |
46 return base::StringPrintf("%s:%d: %s", | 71 return base::StringPrintf("%s:%d: %s", |
47 resource_name.c_str(), | 72 resource_name.c_str(), |
48 message->GetLineNumber(), | 73 message->GetLineNumber(), |
49 error_message.c_str()); | 74 error_message.c_str()); |
50 } | 75 } |
51 | 76 |
52 // Fatally dumps the debug info from |try_catch| to the console. | |
53 // Don't use this for logging exceptions that might originate in external code! | |
54 void DumpException(const v8::TryCatch& try_catch) { | |
55 v8::HandleScope handle_scope; | |
56 | |
57 std::string stack_trace = "<stack trace unavailable>"; | |
58 if (!try_catch.StackTrace().IsEmpty()) { | |
59 v8::String::Utf8Value stack_value(try_catch.StackTrace()); | |
60 if (*stack_value) | |
61 stack_trace.assign(*stack_value, stack_value.length()); | |
62 else | |
63 stack_trace = "<could not convert stack trace to string>"; | |
64 } | |
65 | |
66 console::Fatal(v8::Context::GetCalling(), | |
67 CreateExceptionString(try_catch) + "{" + stack_trace + "}"); | |
68 } | |
69 | |
70 } // namespace | |
71 | |
72 ModuleSystem::ModuleSystem(ChromeV8Context* context, | 77 ModuleSystem::ModuleSystem(ChromeV8Context* context, |
73 SourceMap* source_map) | 78 SourceMap* source_map) |
74 : ObjectBackedNativeHandler(context), | 79 : ObjectBackedNativeHandler(context), |
| 80 context_(context), |
75 source_map_(source_map), | 81 source_map_(source_map), |
76 natives_enabled_(0) { | 82 natives_enabled_(0), |
| 83 exception_handler_(new DefaultExceptionHandler()) { |
77 RouteFunction("require", | 84 RouteFunction("require", |
78 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this))); | 85 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this))); |
79 RouteFunction("requireNative", | 86 RouteFunction("requireNative", |
80 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this))); | 87 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this))); |
81 | 88 |
82 v8::Handle<v8::Object> global(context->v8_context()->Global()); | 89 v8::Handle<v8::Object> global(context->v8_context()->Global()); |
83 global->SetHiddenValue(v8::String::New(kModulesField), v8::Object::New()); | 90 global->SetHiddenValue(v8::String::New(kModulesField), v8::Object::New()); |
84 global->SetHiddenValue(v8::String::New(kModuleSystem), | 91 global->SetHiddenValue(v8::String::New(kModuleSystem), |
85 v8::External::New(this)); | 92 v8::External::New(this)); |
86 } | 93 } |
(...skipping 29 matching lines...) Expand all Loading... |
116 : module_system_(module_system) { | 123 : module_system_(module_system) { |
117 module_system_->natives_enabled_++; | 124 module_system_->natives_enabled_++; |
118 } | 125 } |
119 | 126 |
120 ModuleSystem::NativesEnabledScope::~NativesEnabledScope() { | 127 ModuleSystem::NativesEnabledScope::~NativesEnabledScope() { |
121 module_system_->natives_enabled_--; | 128 module_system_->natives_enabled_--; |
122 CHECK_GE(module_system_->natives_enabled_, 0); | 129 CHECK_GE(module_system_->natives_enabled_, 0); |
123 } | 130 } |
124 | 131 |
125 void ModuleSystem::HandleException(const v8::TryCatch& try_catch) { | 132 void ModuleSystem::HandleException(const v8::TryCatch& try_catch) { |
126 if (exception_handler_) | 133 exception_handler_->HandleUncaughtException(try_catch); |
127 exception_handler_->HandleUncaughtException(); | |
128 else | |
129 DumpException(try_catch); | |
130 } | 134 } |
131 | 135 |
132 v8::Handle<v8::Value> ModuleSystem::Require(const std::string& module_name) { | 136 v8::Handle<v8::Value> ModuleSystem::Require(const std::string& module_name) { |
133 v8::HandleScope handle_scope; | 137 v8::HandleScope handle_scope; |
134 return handle_scope.Close( | 138 return handle_scope.Close( |
135 RequireForJsInner(v8::String::New(module_name.c_str()))); | 139 RequireForJsInner(v8::String::New(module_name.c_str()))); |
136 } | 140 } |
137 | 141 |
138 v8::Handle<v8::Value> ModuleSystem::RequireForJs(const v8::Arguments& args) { | 142 v8::Handle<v8::Value> ModuleSystem::RequireForJs(const v8::Arguments& args) { |
139 v8::HandleScope handle_scope; | 143 v8::HandleScope handle_scope; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value); | 187 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value); |
184 | 188 |
185 exports = v8::Object::New(); | 189 exports = v8::Object::New(); |
186 v8::Handle<v8::Object> natives(NewInstance()); | 190 v8::Handle<v8::Object> natives(NewInstance()); |
187 v8::Handle<v8::Value> args[] = { | 191 v8::Handle<v8::Value> args[] = { |
188 natives->Get(v8::String::NewSymbol("require")), | 192 natives->Get(v8::String::NewSymbol("require")), |
189 natives->Get(v8::String::NewSymbol("requireNative")), | 193 natives->Get(v8::String::NewSymbol("requireNative")), |
190 exports, | 194 exports, |
191 }; | 195 }; |
192 { | 196 { |
193 WebKit::WebScopedMicrotaskSuppression suppression; | |
194 v8::TryCatch try_catch; | 197 v8::TryCatch try_catch; |
195 try_catch.SetCaptureMessage(true); | 198 try_catch.SetCaptureMessage(true); |
196 func->Call(global, 3, args); | 199 context_->CallFunction(func, arraysize(args), args); |
197 if (try_catch.HasCaught()) { | 200 if (try_catch.HasCaught()) { |
198 HandleException(try_catch); | 201 HandleException(try_catch); |
199 return v8::Undefined(); | 202 return v8::Undefined(); |
200 } | 203 } |
201 } | 204 } |
202 modules->Set(module_name, exports); | 205 modules->Set(module_name, exports); |
203 return handle_scope.Close(exports); | 206 return handle_scope.Close(exports); |
204 } | 207 } |
205 | 208 |
206 v8::Local<v8::Value> ModuleSystem::CallModuleMethod( | 209 v8::Local<v8::Value> ModuleSystem::CallModuleMethod( |
207 const std::string& module_name, | 210 const std::string& module_name, |
208 const std::string& method_name) { | 211 const std::string& method_name) { |
209 std::vector<v8::Handle<v8::Value> > args; | 212 v8::HandleScope handle_scope; |
210 return CallModuleMethod(module_name, method_name, &args); | 213 v8::Handle<v8::Value> no_args; |
| 214 return CallModuleMethod(module_name, method_name, 0, &no_args); |
211 } | 215 } |
212 | 216 |
213 v8::Local<v8::Value> ModuleSystem::CallModuleMethod( | 217 v8::Local<v8::Value> ModuleSystem::CallModuleMethod( |
214 const std::string& module_name, | 218 const std::string& module_name, |
215 const std::string& method_name, | 219 const std::string& method_name, |
216 std::vector<v8::Handle<v8::Value> >* args) { | 220 std::vector<v8::Handle<v8::Value> >* args) { |
| 221 return CallModuleMethod( |
| 222 module_name, method_name, args->size(), vector_as_array(args)); |
| 223 } |
| 224 |
| 225 v8::Local<v8::Value> ModuleSystem::CallModuleMethod( |
| 226 const std::string& module_name, |
| 227 const std::string& method_name, |
| 228 int argc, |
| 229 v8::Handle<v8::Value> argv[]) { |
| 230 TRACE_EVENT2("v8", "v8.callModuleMethod", |
| 231 "module_name", module_name, |
| 232 "method_name", method_name); |
| 233 |
217 v8::HandleScope handle_scope; | 234 v8::HandleScope handle_scope; |
218 v8::Local<v8::Value> module = | 235 v8::Context::Scope context_scope(context()->v8_context()); |
219 v8::Local<v8::Value>::New( | 236 |
220 RequireForJsInner(v8::String::New(module_name.c_str()))); | 237 v8::Local<v8::Value> module; |
| 238 { |
| 239 NativesEnabledScope natives_enabled(this); |
| 240 module = v8::Local<v8::Value>::New( |
| 241 RequireForJsInner(v8::String::New(module_name.c_str()))); |
| 242 } |
| 243 |
221 if (module.IsEmpty() || !module->IsObject()) { | 244 if (module.IsEmpty() || !module->IsObject()) { |
222 console::Error( | 245 console::Error( |
223 v8::Context::GetCalling(), | 246 v8::Context::GetCalling(), |
224 "Failed to get module " + module_name + " to call " + method_name); | 247 "Failed to get module " + module_name + " to call " + method_name); |
225 return handle_scope.Close(v8::Undefined()); | 248 return handle_scope.Close(v8::Undefined()); |
226 } | 249 } |
227 | 250 |
228 v8::Local<v8::Value> value = | 251 v8::Local<v8::Value> value = |
229 v8::Handle<v8::Object>::Cast(module)->Get( | 252 v8::Handle<v8::Object>::Cast(module)->Get( |
230 v8::String::New(method_name.c_str())); | 253 v8::String::New(method_name.c_str())); |
231 if (value.IsEmpty() || !value->IsFunction()) { | 254 if (value.IsEmpty() || !value->IsFunction()) { |
232 console::Error(v8::Context::GetCalling(), | 255 console::Error(v8::Context::GetCalling(), |
233 module_name + "." + method_name + " is not a function"); | 256 module_name + "." + method_name + " is not a function"); |
234 return handle_scope.Close(v8::Undefined()); | 257 return handle_scope.Close(v8::Undefined()); |
235 } | 258 } |
236 | 259 |
237 v8::Handle<v8::Function> func = | 260 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value); |
238 v8::Handle<v8::Function>::Cast(value); | |
239 v8::Handle<v8::Object> global(context()->v8_context()->Global()); | |
240 v8::Local<v8::Value> result; | 261 v8::Local<v8::Value> result; |
241 { | 262 { |
242 WebKit::WebScopedMicrotaskSuppression suppression; | |
243 v8::TryCatch try_catch; | 263 v8::TryCatch try_catch; |
244 try_catch.SetCaptureMessage(true); | 264 try_catch.SetCaptureMessage(true); |
245 result = func->Call(global, args->size(), vector_as_array(args)); | 265 result = context_->CallFunction(func, argc, argv); |
246 if (try_catch.HasCaught()) | 266 if (try_catch.HasCaught()) |
247 HandleException(try_catch); | 267 HandleException(try_catch); |
248 } | 268 } |
249 return handle_scope.Close(result); | 269 return handle_scope.Close(result); |
250 } | 270 } |
251 | 271 |
252 void ModuleSystem::RegisterNativeHandler(const std::string& name, | 272 void ModuleSystem::RegisterNativeHandler(const std::string& name, |
253 scoped_ptr<NativeHandler> native_handler) { | 273 scoped_ptr<NativeHandler> native_handler) { |
254 native_handler_map_[name] = | 274 native_handler_map_[name] = |
255 linked_ptr<NativeHandler>(native_handler.release()); | 275 linked_ptr<NativeHandler>(native_handler.release()); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 const std::string& field, | 401 const std::string& field, |
382 const std::string& module_name, | 402 const std::string& module_name, |
383 const std::string& module_field) { | 403 const std::string& module_field) { |
384 SetLazyField(object, field, module_name, module_field, | 404 SetLazyField(object, field, module_name, module_field, |
385 &ModuleSystem::NativeLazyFieldGetter); | 405 &ModuleSystem::NativeLazyFieldGetter); |
386 } | 406 } |
387 | 407 |
388 v8::Handle<v8::Value> ModuleSystem::RunString(v8::Handle<v8::String> code, | 408 v8::Handle<v8::Value> ModuleSystem::RunString(v8::Handle<v8::String> code, |
389 v8::Handle<v8::String> name) { | 409 v8::Handle<v8::String> name) { |
390 v8::HandleScope handle_scope; | 410 v8::HandleScope handle_scope; |
| 411 v8::Context::Scope context_scope(context()->v8_context()); |
391 | 412 |
392 WebKit::WebScopedMicrotaskSuppression suppression; | 413 WebKit::WebScopedMicrotaskSuppression suppression; |
393 v8::TryCatch try_catch; | 414 v8::TryCatch try_catch; |
394 try_catch.SetCaptureMessage(true); | 415 try_catch.SetCaptureMessage(true); |
395 v8::Handle<v8::Script> script(v8::Script::New(code, name)); | 416 v8::Handle<v8::Script> script(v8::Script::New(code, name)); |
396 if (try_catch.HasCaught()) { | 417 if (try_catch.HasCaught()) { |
397 HandleException(try_catch); | 418 HandleException(try_catch); |
398 return v8::Undefined(); | 419 return v8::Undefined(); |
399 } | 420 } |
400 | 421 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { | 470 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { |
450 v8::HandleScope handle_scope; | 471 v8::HandleScope handle_scope; |
451 v8::Handle<v8::String> left = v8::String::New( | 472 v8::Handle<v8::String> left = v8::String::New( |
452 "(function(require, requireNative, exports) {'use strict';"); | 473 "(function(require, requireNative, exports) {'use strict';"); |
453 v8::Handle<v8::String> right = v8::String::New("\n})"); | 474 v8::Handle<v8::String> right = v8::String::New("\n})"); |
454 return handle_scope.Close( | 475 return handle_scope.Close( |
455 v8::String::Concat(left, v8::String::Concat(source, right))); | 476 v8::String::Concat(left, v8::String::Concat(source, right))); |
456 } | 477 } |
457 | 478 |
458 } // extensions | 479 } // extensions |
OLD | NEW |