| 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/command_line.h" |
| 8 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
| 9 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| 10 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
| 11 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
| 13 #include "chrome/common/chrome_switches.h" |
| 12 #include "chrome/common/extensions/extension_messages.h" | 14 #include "chrome/common/extensions/extension_messages.h" |
| 13 #include "chrome/renderer/extensions/chrome_v8_context.h" | 15 #include "chrome/renderer/extensions/chrome_v8_context.h" |
| 14 #include "chrome/renderer/extensions/console.h" | 16 #include "chrome/renderer/extensions/console.h" |
| 15 #include "chrome/renderer/extensions/safe_builtins.h" | 17 #include "chrome/renderer/extensions/safe_builtins.h" |
| 16 #include "content/public/renderer/render_view.h" | 18 #include "content/public/renderer/render_view.h" |
| 17 #include "third_party/WebKit/public/web/WebFrame.h" | 19 #include "third_party/WebKit/public/web/WebFrame.h" |
| 18 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" | 20 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" |
| 19 | 21 |
| 20 namespace extensions { | 22 namespace extensions { |
| 21 | 23 |
| 22 namespace { | 24 namespace { |
| 23 | 25 |
| 24 const char* kModuleSystem = "module_system"; | 26 const char* kModuleSystem = "module_system"; |
| 25 const char* kModuleName = "module_name"; | 27 const char* kModuleName = "module_name"; |
| 26 const char* kModuleField = "module_field"; | 28 const char* kModuleField = "module_field"; |
| 27 const char* kModulesField = "modules"; | 29 const char* kModulesField = "modules"; |
| 28 | 30 |
| 31 // Prepends |extension_id| if it's non-empty to |message|. |
| 32 std::string PrependExtensionID(const std::string& extension_id, |
| 33 const std::string& message) { |
| 34 std::string with_extension_id; |
| 35 if (!extension_id.empty()) { |
| 36 with_extension_id += "("; |
| 37 with_extension_id += extension_id; |
| 38 with_extension_id += ") "; |
| 39 } |
| 40 with_extension_id += message; |
| 41 return with_extension_id; |
| 42 } |
| 43 |
| 44 void Fatal(const std::string& extension_id, const std::string& message) { |
| 45 // Only crash web pages in dev channel. |
| 46 // Always crash extension processes, or when in single process mode (since |
| 47 // typically it's used to debug renderer crashes). |
| 48 bool is_fatal = false; |
| 49 const CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 50 if (command_line->HasSwitch(switches::kExtensionProcess) || |
| 51 command_line->HasSwitch(switches::kSingleProcess)) { |
| 52 is_fatal = true; |
| 53 } else { |
| 54 // <= dev means dev, canary, and trunk. |
| 55 is_fatal = Feature::GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV; |
| 56 } |
| 57 std::string with_extension_id = PrependExtensionID(extension_id, message); |
| 58 if (is_fatal) |
| 59 console::Fatal(v8::Context::GetCalling(), with_extension_id); |
| 60 else |
| 61 console::Error(v8::Context::GetCalling(), with_extension_id); |
| 62 } |
| 63 |
| 64 void Warn(const std::string& extension_id, const std::string& message) { |
| 65 console::Warn(v8::Context::GetCalling(), |
| 66 PrependExtensionID(extension_id, message)); |
| 67 } |
| 68 |
| 29 // Default exception handler which logs the exception. | 69 // Default exception handler which logs the exception. |
| 30 class DefaultExceptionHandler : public ModuleSystem::ExceptionHandler { | 70 class DefaultExceptionHandler : public ModuleSystem::ExceptionHandler { |
| 31 public: | 71 public: |
| 72 explicit DefaultExceptionHandler(const std::string& extension_id) |
| 73 : extension_id_(extension_id) {} |
| 74 |
| 32 // Fatally dumps the debug info from |try_catch| to the console. | 75 // Fatally dumps the debug info from |try_catch| to the console. |
| 33 // Make sure this is never used for exceptions that originate in external | 76 // Make sure this is never used for exceptions that originate in external |
| 34 // code! | 77 // code! |
| 35 virtual void HandleUncaughtException(const v8::TryCatch& try_catch) OVERRIDE { | 78 virtual void HandleUncaughtException(const v8::TryCatch& try_catch) OVERRIDE { |
| 36 v8::HandleScope handle_scope; | 79 v8::HandleScope handle_scope; |
| 37 std::string stack_trace = "<stack trace unavailable>"; | 80 std::string stack_trace = "<stack trace unavailable>"; |
| 38 if (!try_catch.StackTrace().IsEmpty()) { | 81 if (!try_catch.StackTrace().IsEmpty()) { |
| 39 v8::String::Utf8Value stack_value(try_catch.StackTrace()); | 82 v8::String::Utf8Value stack_value(try_catch.StackTrace()); |
| 40 if (*stack_value) | 83 if (*stack_value) |
| 41 stack_trace.assign(*stack_value, stack_value.length()); | 84 stack_trace.assign(*stack_value, stack_value.length()); |
| 42 else | 85 else |
| 43 stack_trace = "<could not convert stack trace to string>"; | 86 stack_trace = "<could not convert stack trace to string>"; |
| 44 } | 87 } |
| 45 console::Fatal(v8::Context::GetCalling(), | 88 Fatal(extension_id_, |
| 46 CreateExceptionString(try_catch) + "{" + stack_trace + "}"); | 89 CreateExceptionString(try_catch) + "{" + stack_trace + "}"); |
| 47 } | 90 } |
| 91 |
| 92 private: |
| 93 std::string extension_id_; |
| 48 }; | 94 }; |
| 49 | 95 |
| 50 } // namespace | 96 } // namespace |
| 51 | 97 |
| 52 std::string ModuleSystem::ExceptionHandler::CreateExceptionString( | 98 std::string ModuleSystem::ExceptionHandler::CreateExceptionString( |
| 53 const v8::TryCatch& try_catch) { | 99 const v8::TryCatch& try_catch) { |
| 54 v8::Handle<v8::Message> message(try_catch.Message()); | 100 v8::Handle<v8::Message> message(try_catch.Message()); |
| 55 if (message.IsEmpty()) { | 101 if (message.IsEmpty()) { |
| 56 return "try_catch has no message"; | 102 return "try_catch has no message"; |
| 57 } | 103 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 74 message->GetLineNumber(), | 120 message->GetLineNumber(), |
| 75 error_message.c_str()); | 121 error_message.c_str()); |
| 76 } | 122 } |
| 77 | 123 |
| 78 ModuleSystem::ModuleSystem(ChromeV8Context* context, | 124 ModuleSystem::ModuleSystem(ChromeV8Context* context, |
| 79 SourceMap* source_map) | 125 SourceMap* source_map) |
| 80 : ObjectBackedNativeHandler(context), | 126 : ObjectBackedNativeHandler(context), |
| 81 context_(context), | 127 context_(context), |
| 82 source_map_(source_map), | 128 source_map_(source_map), |
| 83 natives_enabled_(0), | 129 natives_enabled_(0), |
| 84 exception_handler_(new DefaultExceptionHandler()) { | 130 exception_handler_( |
| 131 new DefaultExceptionHandler(context->GetExtensionID())) { |
| 85 RouteFunction("require", | 132 RouteFunction("require", |
| 86 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this))); | 133 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this))); |
| 87 RouteFunction("requireNative", | 134 RouteFunction("requireNative", |
| 88 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this))); | 135 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this))); |
| 89 | 136 |
| 90 v8::Handle<v8::Object> global(context->v8_context()->Global()); | 137 v8::Handle<v8::Object> global(context->v8_context()->Global()); |
| 91 global->SetHiddenValue(v8::String::New(kModulesField), v8::Object::New()); | 138 global->SetHiddenValue(v8::String::New(kModulesField), v8::Object::New()); |
| 92 global->SetHiddenValue(v8::String::New(kModuleSystem), | 139 global->SetHiddenValue(v8::String::New(kModuleSystem), |
| 93 v8::External::New(this)); | 140 v8::External::New(this)); |
| 94 } | 141 } |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 v8::Context::Scope context_scope(context()->v8_context()); | 199 v8::Context::Scope context_scope(context()->v8_context()); |
| 153 | 200 |
| 154 v8::Handle<v8::Object> global(context()->v8_context()->Global()); | 201 v8::Handle<v8::Object> global(context()->v8_context()->Global()); |
| 155 | 202 |
| 156 // The module system might have been deleted. This can happen if a different | 203 // The module system might have been deleted. This can happen if a different |
| 157 // context keeps a reference to us, but our frame is destroyed (e.g. | 204 // context keeps a reference to us, but our frame is destroyed (e.g. |
| 158 // background page keeps reference to chrome object in a closed popup). | 205 // background page keeps reference to chrome object in a closed popup). |
| 159 v8::Handle<v8::Value> modules_value = | 206 v8::Handle<v8::Value> modules_value = |
| 160 global->GetHiddenValue(v8::String::New(kModulesField)); | 207 global->GetHiddenValue(v8::String::New(kModulesField)); |
| 161 if (modules_value.IsEmpty() || modules_value->IsUndefined()) { | 208 if (modules_value.IsEmpty() || modules_value->IsUndefined()) { |
| 162 console::Warn(v8::Context::GetCalling(), "Extension view no longer exists"); | 209 Warn(context_->GetExtensionID(), "Extension view no longer exists"); |
| 163 return v8::Undefined(); | 210 return v8::Undefined(); |
| 164 } | 211 } |
| 165 | 212 |
| 166 v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(modules_value)); | 213 v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(modules_value)); |
| 167 v8::Handle<v8::Value> exports(modules->Get(module_name)); | 214 v8::Handle<v8::Value> exports(modules->Get(module_name)); |
| 168 if (!exports->IsUndefined()) | 215 if (!exports->IsUndefined()) |
| 169 return handle_scope.Close(exports); | 216 return handle_scope.Close(exports); |
| 170 | 217 |
| 171 std::string module_name_str = *v8::String::AsciiValue(module_name); | 218 std::string module_name_str = *v8::String::AsciiValue(module_name); |
| 172 v8::Handle<v8::Value> source(GetSource(module_name_str)); | 219 v8::Handle<v8::Value> source(GetSource(module_name_str)); |
| 173 if (source.IsEmpty() || source->IsUndefined()) { | 220 if (source.IsEmpty() || source->IsUndefined()) { |
| 174 console::Error(v8::Context::GetCalling(), | 221 Fatal(context_->GetExtensionID(), |
| 175 "No source for require(" + module_name_str + ")"); | 222 "No source for require(" + module_name_str + ")"); |
| 176 return v8::Undefined(); | 223 return v8::Undefined(); |
| 177 } | 224 } |
| 178 v8::Handle<v8::String> wrapped_source(WrapSource( | 225 v8::Handle<v8::String> wrapped_source(WrapSource( |
| 179 v8::Handle<v8::String>::Cast(source))); | 226 v8::Handle<v8::String>::Cast(source))); |
| 180 // Modules are wrapped in (function(){...}) so they always return functions. | 227 // Modules are wrapped in (function(){...}) so they always return functions. |
| 181 v8::Handle<v8::Value> func_as_value = RunString(wrapped_source, module_name); | 228 v8::Handle<v8::Value> func_as_value = RunString(wrapped_source, module_name); |
| 182 if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) { | 229 if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) { |
| 183 console::Error(v8::Context::GetCalling(), | 230 Fatal(context_->GetExtensionID(), |
| 184 "Bad source for require(" + module_name_str + ")"); | 231 "Bad source for require(" + module_name_str + ")"); |
| 185 return v8::Undefined(); | 232 return v8::Undefined(); |
| 186 } | 233 } |
| 187 | 234 |
| 188 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value); | 235 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value); |
| 189 | 236 |
| 190 exports = v8::Object::New(); | 237 exports = v8::Object::New(); |
| 191 v8::Handle<v8::Object> natives(NewInstance()); | 238 v8::Handle<v8::Object> natives(NewInstance()); |
| 192 CHECK(!natives.IsEmpty()); // this can happen if v8 has issues | 239 CHECK(!natives.IsEmpty()); // this can happen if v8 has issues |
| 193 | 240 |
| 194 // These must match the argument order in WrapSource. | 241 // These must match the argument order in WrapSource. |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 v8::Context::Scope context_scope(context()->v8_context()); | 294 v8::Context::Scope context_scope(context()->v8_context()); |
| 248 | 295 |
| 249 v8::Local<v8::Value> module; | 296 v8::Local<v8::Value> module; |
| 250 { | 297 { |
| 251 NativesEnabledScope natives_enabled(this); | 298 NativesEnabledScope natives_enabled(this); |
| 252 module = v8::Local<v8::Value>::New( | 299 module = v8::Local<v8::Value>::New( |
| 253 RequireForJsInner(v8::String::New(module_name.c_str()))); | 300 RequireForJsInner(v8::String::New(module_name.c_str()))); |
| 254 } | 301 } |
| 255 | 302 |
| 256 if (module.IsEmpty() || !module->IsObject()) { | 303 if (module.IsEmpty() || !module->IsObject()) { |
| 257 console::Error( | 304 Fatal(context_->GetExtensionID(), |
| 258 v8::Context::GetCalling(), | 305 "Failed to get module " + module_name + " to call " + method_name); |
| 259 "Failed to get module " + module_name + " to call " + method_name); | |
| 260 return handle_scope.Close(v8::Undefined()); | 306 return handle_scope.Close(v8::Undefined()); |
| 261 } | 307 } |
| 262 | 308 |
| 263 v8::Local<v8::Value> value = | 309 v8::Local<v8::Value> value = |
| 264 v8::Handle<v8::Object>::Cast(module)->Get( | 310 v8::Handle<v8::Object>::Cast(module)->Get( |
| 265 v8::String::New(method_name.c_str())); | 311 v8::String::New(method_name.c_str())); |
| 266 if (value.IsEmpty() || !value->IsFunction()) { | 312 if (value.IsEmpty() || !value->IsFunction()) { |
| 267 console::Error(v8::Context::GetCalling(), | 313 Fatal(context_->GetExtensionID(), |
| 268 module_name + "." + method_name + " is not a function"); | 314 module_name + "." + method_name + " is not a function"); |
| 269 return handle_scope.Close(v8::Undefined()); | 315 return handle_scope.Close(v8::Undefined()); |
| 270 } | 316 } |
| 271 | 317 |
| 272 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value); | 318 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value); |
| 273 v8::Local<v8::Value> result; | 319 v8::Local<v8::Value> result; |
| 274 { | 320 { |
| 275 v8::TryCatch try_catch; | 321 v8::TryCatch try_catch; |
| 276 try_catch.SetCaptureMessage(true); | 322 try_catch.SetCaptureMessage(true); |
| 277 result = context_->CallFunction(func, argc, argv); | 323 result = context_->CallFunction(func, argc, argv); |
| 278 if (try_catch.HasCaught()) | 324 if (try_catch.HasCaught()) |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 322 v8::HandleScope handle_scope; | 368 v8::HandleScope handle_scope; |
| 323 v8::Handle<v8::Object> parameters = v8::Handle<v8::Object>::Cast(info.Data()); | 369 v8::Handle<v8::Object> parameters = v8::Handle<v8::Object>::Cast(info.Data()); |
| 324 // This context should be the same as context()->v8_context(). | 370 // This context should be the same as context()->v8_context(). |
| 325 v8::Handle<v8::Context> context = parameters->CreationContext(); | 371 v8::Handle<v8::Context> context = parameters->CreationContext(); |
| 326 v8::Handle<v8::Object> global(context->Global()); | 372 v8::Handle<v8::Object> global(context->Global()); |
| 327 v8::Handle<v8::Value> module_system_value = | 373 v8::Handle<v8::Value> module_system_value = |
| 328 global->GetHiddenValue(v8::String::New(kModuleSystem)); | 374 global->GetHiddenValue(v8::String::New(kModuleSystem)); |
| 329 if (module_system_value.IsEmpty() || !module_system_value->IsExternal()) { | 375 if (module_system_value.IsEmpty() || !module_system_value->IsExternal()) { |
| 330 // ModuleSystem has been deleted. | 376 // ModuleSystem has been deleted. |
| 331 // TODO(kalman): See comment in header file. | 377 // TODO(kalman): See comment in header file. |
| 332 console::Warn(v8::Context::GetCalling(), | 378 Warn("", "Module system has been deleted, does extension view exist?"); |
| 333 "Module system has been deleted, does extension view exist?"); | |
| 334 return; | 379 return; |
| 335 } | 380 } |
| 336 | 381 |
| 337 ModuleSystem* module_system = static_cast<ModuleSystem*>( | 382 ModuleSystem* module_system = static_cast<ModuleSystem*>( |
| 338 v8::Handle<v8::External>::Cast(module_system_value)->Value()); | 383 v8::Handle<v8::External>::Cast(module_system_value)->Value()); |
| 339 | 384 |
| 340 std::string name = *v8::String::AsciiValue( | 385 std::string name = *v8::String::AsciiValue( |
| 341 parameters->Get(v8::String::New(kModuleName))->ToString()); | 386 parameters->Get(v8::String::New(kModuleName))->ToString()); |
| 342 | 387 |
| 343 // Switch to our v8 context because we need functions created while running | 388 // Switch to our v8 context because we need functions created while running |
| (...skipping 11 matching lines...) Expand all Loading... |
| 355 // require_function will have already logged this, we don't need to. | 400 // require_function will have already logged this, we don't need to. |
| 356 return; | 401 return; |
| 357 } | 402 } |
| 358 | 403 |
| 359 v8::Handle<v8::Object> module = v8::Handle<v8::Object>::Cast(module_value); | 404 v8::Handle<v8::Object> module = v8::Handle<v8::Object>::Cast(module_value); |
| 360 v8::Handle<v8::String> field = | 405 v8::Handle<v8::String> field = |
| 361 parameters->Get(v8::String::New(kModuleField))->ToString(); | 406 parameters->Get(v8::String::New(kModuleField))->ToString(); |
| 362 | 407 |
| 363 if (!module->Has(field)) { | 408 if (!module->Has(field)) { |
| 364 std::string field_str = *v8::String::AsciiValue(field); | 409 std::string field_str = *v8::String::AsciiValue(field); |
| 365 console::Fatal(v8::Context::GetCalling(), | 410 Fatal(module_system->context_->GetExtensionID(), |
| 366 "Lazy require of " + name + "." + field_str + " did not " + | 411 "Lazy require of " + name + "." + field_str + " did not " + |
| 367 "set the " + field_str + " field"); | 412 "set the " + field_str + " field"); |
| 368 return; | 413 return; |
| 369 } | 414 } |
| 370 | 415 |
| 371 v8::Local<v8::Value> new_field = module->Get(field); | 416 v8::Local<v8::Value> new_field = module->Get(field); |
| 372 if (try_catch.HasCaught()) { | 417 if (try_catch.HasCaught()) { |
| 373 module_system->HandleException(try_catch); | 418 module_system->HandleException(try_catch); |
| 374 return; | 419 return; |
| 375 } | 420 } |
| 376 | 421 |
| 377 // Ok for it to be undefined, among other things it's how bindings signify | 422 // Ok for it to be undefined, among other things it's how bindings signify |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 457 } | 502 } |
| 458 | 503 |
| 459 v8::Handle<v8::Value> ModuleSystem::RequireNativeFromString( | 504 v8::Handle<v8::Value> ModuleSystem::RequireNativeFromString( |
| 460 const std::string& native_name) { | 505 const std::string& native_name) { |
| 461 if (natives_enabled_ == 0) { | 506 if (natives_enabled_ == 0) { |
| 462 // HACK: if in test throw exception so that we can test the natives-disabled | 507 // HACK: if in test throw exception so that we can test the natives-disabled |
| 463 // logic; however, under normal circumstances, this is programmer error so | 508 // logic; however, under normal circumstances, this is programmer error so |
| 464 // we could crash. | 509 // we could crash. |
| 465 if (exception_handler_) | 510 if (exception_handler_) |
| 466 return v8::ThrowException(v8::String::New("Natives disabled")); | 511 return v8::ThrowException(v8::String::New("Natives disabled")); |
| 467 console::Fatal(v8::Context::GetCalling(), | 512 Fatal(context_->GetExtensionID(), |
| 468 "Natives disabled for requireNative(" + native_name + ")"); | 513 "Natives disabled for requireNative(" + native_name + ")"); |
| 469 return v8::Undefined(); | 514 return v8::Undefined(); |
| 470 } | 515 } |
| 471 | 516 |
| 472 if (overridden_native_handlers_.count(native_name) > 0u) | 517 if (overridden_native_handlers_.count(native_name) > 0u) |
| 473 return RequireForJsInner(v8::String::New(native_name.c_str())); | 518 return RequireForJsInner(v8::String::New(native_name.c_str())); |
| 474 | 519 |
| 475 NativeHandlerMap::iterator i = native_handler_map_.find(native_name); | 520 NativeHandlerMap::iterator i = native_handler_map_.find(native_name); |
| 476 if (i == native_handler_map_.end()) { | 521 if (i == native_handler_map_.end()) { |
| 477 console::Fatal( | 522 Fatal(context_->GetExtensionID(), |
| 478 v8::Context::GetCalling(), | 523 "Couldn't find native for requireNative(" + native_name + ")"); |
| 479 "Couldn't find native for requireNative(" + native_name + ")"); | |
| 480 return v8::Undefined(); | 524 return v8::Undefined(); |
| 481 } | 525 } |
| 482 return i->second->NewInstance(); | 526 return i->second->NewInstance(); |
| 483 } | 527 } |
| 484 | 528 |
| 485 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { | 529 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { |
| 486 v8::HandleScope handle_scope; | 530 v8::HandleScope handle_scope; |
| 487 // Keep in order with the arguments in RequireForJsInner. | 531 // Keep in order with the arguments in RequireForJsInner. |
| 488 v8::Handle<v8::String> left = v8::String::New( | 532 v8::Handle<v8::String> left = v8::String::New( |
| 489 "(function(require, requireNative, exports," | 533 "(function(require, requireNative, exports," |
| 490 "$Array, $Function, $JSON, $Object, $RegExp, $String) {" | 534 "$Array, $Function, $JSON, $Object, $RegExp, $String) {" |
| 491 "'use strict';"); | 535 "'use strict';"); |
| 492 v8::Handle<v8::String> right = v8::String::New("\n})"); | 536 v8::Handle<v8::String> right = v8::String::New("\n})"); |
| 493 return handle_scope.Close( | 537 return handle_scope.Close( |
| 494 v8::String::Concat(left, v8::String::Concat(source, right))); | 538 v8::String::Concat(left, v8::String::Concat(source, right))); |
| 495 } | 539 } |
| 496 | 540 |
| 497 } // namespace extensions | 541 } // namespace extensions |
| OLD | NEW |