summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/extensions/module_system.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/renderer/extensions/module_system.cc')
-rw-r--r--chrome/renderer/extensions/module_system.cc172
1 files changed, 124 insertions, 48 deletions
diff --git a/chrome/renderer/extensions/module_system.cc b/chrome/renderer/extensions/module_system.cc
index 31146c8..5615c93 100644
--- a/chrome/renderer/extensions/module_system.cc
+++ b/chrome/renderer/extensions/module_system.cc
@@ -5,7 +5,13 @@
#include "chrome/renderer/extensions/module_system.h"
#include "base/bind.h"
+#include "base/debug/alias.h"
#include "base/stl_util.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "chrome/common/extensions/extension_messages.h"
+#include "chrome/renderer/extensions/chrome_v8_context.h"
+#include "content/public/renderer/render_view.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebScopedMicrotaskSuppression.h"
namespace {
@@ -21,28 +27,32 @@ namespace extensions {
ModuleSystem::ModuleSystem(v8::Handle<v8::Context> context,
SourceMap* source_map)
- : NativeHandler(context->GetIsolate()),
- context_(v8::Persistent<v8::Context>::New(context->GetIsolate(),
- context)),
+ : ObjectBackedNativeHandler(context),
source_map_(source_map),
natives_enabled_(0) {
RouteFunction("require",
base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this)));
RouteFunction("requireNative",
- base::Bind(&ModuleSystem::GetNative, base::Unretained(this)));
+ base::Bind(&ModuleSystem::RequireNative, base::Unretained(this)));
- v8::Handle<v8::Object> global(context_->Global());
+ v8::Handle<v8::Object> global(context->Global());
global->SetHiddenValue(v8::String::New(kModulesField), v8::Object::New());
global->SetHiddenValue(v8::String::New(kModuleSystem),
v8::External::New(this));
}
ModuleSystem::~ModuleSystem() {
- v8::HandleScope handle_scope;
- // Deleting this value here prevents future lazy field accesses from
- // referencing ModuleSystem after it has been freed.
- context_->Global()->DeleteHiddenValue(v8::String::New(kModuleSystem));
- context_.Dispose(context_->GetIsolate());
+ Invalidate();
+}
+
+void ModuleSystem::Invalidate() {
+ if (!is_valid())
+ return;
+ for (NativeHandlerMap::iterator it = native_handler_map_.begin();
+ it != native_handler_map_.end(); ++it) {
+ it->second->Invalidate();
+ }
+ ObjectBackedNativeHandler::Invalidate();
}
ModuleSystem::NativesEnabledScope::NativesEnabledScope(
@@ -56,16 +66,6 @@ ModuleSystem::NativesEnabledScope::~NativesEnabledScope() {
CHECK_GE(module_system_->natives_enabled_, 0);
}
-// static
-bool ModuleSystem::IsPresentInCurrentContext() {
- v8::Handle<v8::Object> global(v8::Context::GetCurrent()->Global());
- if (global.IsEmpty())
- return false;
- v8::Handle<v8::Value> module_system =
- global->GetHiddenValue(v8::String::New(kModuleSystem));
- return !module_system.IsEmpty() && !module_system->IsUndefined();
-}
-
void ModuleSystem::HandleException(const v8::TryCatch& try_catch) {
DumpException(try_catch);
if (exception_handler_.get())
@@ -73,13 +73,10 @@ void ModuleSystem::HandleException(const v8::TryCatch& try_catch) {
}
// static
-void ModuleSystem::DumpException(const v8::TryCatch& try_catch) {
- v8::HandleScope handle_scope;
-
+std::string ModuleSystem::CreateExceptionString(const v8::TryCatch& try_catch) {
v8::Handle<v8::Message> message(try_catch.Message());
if (message.IsEmpty()) {
- LOG(ERROR) << "try_catch has no message";
- return;
+ return "try_catch has no message";
}
std::string resource_name = "<unknown resource>";
@@ -92,6 +89,16 @@ void ModuleSystem::DumpException(const v8::TryCatch& try_catch) {
if (!message->Get().IsEmpty())
error_message = *v8::String::Utf8Value(message->Get());
+ return base::StringPrintf("%s:%d: %s",
+ resource_name.c_str(),
+ message->GetLineNumber(),
+ error_message.c_str());
+}
+
+// static
+void ModuleSystem::DumpException(const v8::TryCatch& try_catch) {
+ v8::HandleScope handle_scope;
+
std::string stack_trace = "<stack trace unavailable>";
if (!try_catch.StackTrace().IsEmpty()) {
v8::String::Utf8Value stack_value(try_catch.StackTrace());
@@ -101,14 +108,13 @@ void ModuleSystem::DumpException(const v8::TryCatch& try_catch) {
stack_trace = "<could not convert stack trace to string>";
}
- LOG(ERROR) << "[" << resource_name << "(" << message->GetLineNumber() << ")] "
- << error_message
- << "{" << stack_trace << "}";
+ LOG(ERROR) << CreateExceptionString(try_catch) << "{" << stack_trace << "}";
}
-void ModuleSystem::Require(const std::string& module_name) {
+v8::Handle<v8::Value> ModuleSystem::Require(const std::string& module_name) {
v8::HandleScope handle_scope;
- RequireForJsInner(v8::String::New(module_name.c_str()));
+ return handle_scope.Close(
+ RequireForJsInner(v8::String::New(module_name.c_str())));
}
v8::Handle<v8::Value> ModuleSystem::RequireForJs(const v8::Arguments& args) {
@@ -120,7 +126,7 @@ v8::Handle<v8::Value> ModuleSystem::RequireForJs(const v8::Arguments& args) {
v8::Handle<v8::Value> ModuleSystem::RequireForJsInner(
v8::Handle<v8::String> module_name) {
v8::HandleScope handle_scope;
- v8::Handle<v8::Object> global(v8::Context::GetCurrent()->Global());
+ v8::Handle<v8::Object> global(v8_context()->Global());
v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(
global->GetHiddenValue(v8::String::New(kModulesField))));
v8::Handle<v8::Value> exports(modules->Get(module_name));
@@ -160,10 +166,11 @@ v8::Handle<v8::Value> ModuleSystem::RequireForJsInner(
return handle_scope.Close(exports);
}
-void ModuleSystem::CallModuleMethod(const std::string& module_name,
- const std::string& method_name) {
+v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
+ const std::string& module_name,
+ const std::string& method_name) {
std::vector<v8::Handle<v8::Value> > args;
- CallModuleMethod(module_name, method_name, &args);
+ return CallModuleMethod(module_name, method_name, &args);
}
v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
@@ -183,8 +190,7 @@ v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
return v8::Local<v8::Value>();
v8::Handle<v8::Function> func =
v8::Handle<v8::Function>::Cast(value);
- // TODO(jeremya/koz): refer to context_ here, not the current context.
- v8::Handle<v8::Object> global(v8::Context::GetCurrent()->Global());
+ v8::Handle<v8::Object> global(v8_context()->Global());
v8::Local<v8::Value> result;
{
WebKit::WebScopedMicrotaskSuppression suppression;
@@ -197,6 +203,10 @@ v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
return handle_scope.Close(result);
}
+bool ModuleSystem::HasNativeHandler(const std::string& name) {
+ return native_handler_map_.find(name) != native_handler_map_.end();
+}
+
void ModuleSystem::RegisterNativeHandler(const std::string& name,
scoped_ptr<NativeHandler> native_handler) {
native_handler_map_[name] =
@@ -213,13 +223,31 @@ void ModuleSystem::RunString(const std::string& code, const std::string& name) {
}
// static
+v8::Handle<v8::Value> ModuleSystem::NativeLazyFieldGetter(
+ v8::Local<v8::String> property, const v8::AccessorInfo& info) {
+ return LazyFieldGetterInner(property,
+ info,
+ &ModuleSystem::RequireNativeFromString);
+}
+
+// static
v8::Handle<v8::Value> ModuleSystem::LazyFieldGetter(
v8::Local<v8::String> property, const v8::AccessorInfo& info) {
+ return LazyFieldGetterInner(property, info, &ModuleSystem::Require);
+}
+
+// static
+v8::Handle<v8::Value> ModuleSystem::LazyFieldGetterInner(
+ v8::Local<v8::String> property,
+ const v8::AccessorInfo& info,
+ RequireFunction require_function) {
CHECK(!info.Data().IsEmpty());
CHECK(info.Data()->IsObject());
v8::HandleScope handle_scope;
v8::Handle<v8::Object> parameters = v8::Handle<v8::Object>::Cast(info.Data());
- v8::Handle<v8::Object> global(v8::Context::GetCurrent()->Global());
+ // This context should be the same as v8_context_, but this method is static.
+ v8::Handle<v8::Context> context = parameters->CreationContext();
+ v8::Handle<v8::Object> global(context->Global());
v8::Handle<v8::Value> module_system_value =
global->GetHiddenValue(v8::String::New(kModuleSystem));
if (module_system_value.IsEmpty() || module_system_value->IsUndefined()) {
@@ -229,38 +257,81 @@ v8::Handle<v8::Value> ModuleSystem::LazyFieldGetter(
ModuleSystem* module_system = static_cast<ModuleSystem*>(
v8::Handle<v8::External>::Cast(module_system_value)->Value());
- v8::Handle<v8::Object> module;
- {
- NativesEnabledScope scope(module_system);
- module = v8::Handle<v8::Object>::Cast(module_system->RequireForJsInner(
- parameters->Get(v8::String::New(kModuleName))->ToString()));
+ std::string name = *v8::String::AsciiValue(
+ parameters->Get(v8::String::New(kModuleName))->ToString());
+
+ // Switch to our v8 context because we need functions created while running
+ // the require()d module to belong to our context, not the current one.
+ v8::Context::Scope context_scope(context);
+ NativesEnabledScope natives_enabled_scope(module_system);
+
+ v8::TryCatch try_catch;
+ v8::Handle<v8::Object> module = v8::Handle<v8::Object>::Cast(
+ (module_system->*require_function)(name));
+ if (try_catch.HasCaught()) {
+ module_system->HandleException(try_catch);
+ return handle_scope.Close(v8::Handle<v8::Value>());
}
+
if (module.IsEmpty())
return handle_scope.Close(v8::Handle<v8::Value>());
v8::Handle<v8::String> field =
parameters->Get(v8::String::New(kModuleField))->ToString();
- return handle_scope.Close(module->Get(field));
+ // http://crbug.com/179741.
+ std::string field_name = *v8::String::AsciiValue(field);
+ char stack_debug[64];
+ base::debug::Alias(&stack_debug);
+ base::snprintf(stack_debug, arraysize(stack_debug),
+ "%s.%s", name.c_str(), field_name.c_str());
+
+ v8::Local<v8::Value> new_field = module->Get(field);
+ v8::Handle<v8::Object> object = info.This();
+ // Delete the getter and set this field to |new_field| so the same object is
+ // returned every time a certain API is accessed.
+ // CHECK is for http://crbug.com/179741.
+ CHECK(!new_field.IsEmpty()) << "Empty require " << name << "." << field_name;
+ if (!new_field->IsUndefined()) {
+ object->Delete(property);
+ object->Set(property, new_field);
+ }
+ return handle_scope.Close(new_field);
}
void ModuleSystem::SetLazyField(v8::Handle<v8::Object> object,
const std::string& field,
const std::string& module_name,
const std::string& module_field) {
+ SetLazyField(object, field, module_name, module_field,
+ &ModuleSystem::LazyFieldGetter);
+}
+
+void ModuleSystem::SetLazyField(v8::Handle<v8::Object> object,
+ const std::string& field,
+ const std::string& module_name,
+ const std::string& module_field,
+ v8::AccessorGetter getter) {
v8::HandleScope handle_scope;
v8::Handle<v8::Object> parameters = v8::Object::New();
parameters->Set(v8::String::New(kModuleName),
v8::String::New(module_name.c_str()));
parameters->Set(v8::String::New(kModuleField),
v8::String::New(module_field.c_str()));
-
object->SetAccessor(v8::String::New(field.c_str()),
- &ModuleSystem::LazyFieldGetter,
+ getter,
NULL,
parameters);
}
+void ModuleSystem::SetNativeLazyField(v8::Handle<v8::Object> object,
+ const std::string& field,
+ const std::string& module_name,
+ const std::string& module_field) {
+ SetLazyField(object, field, module_name, module_field,
+ &ModuleSystem::NativeLazyFieldGetter);
+}
+
v8::Handle<v8::Value> ModuleSystem::RunString(v8::Handle<v8::String> code,
v8::Handle<v8::String> name) {
v8::HandleScope handle_scope;
@@ -290,13 +361,18 @@ v8::Handle<v8::Value> ModuleSystem::GetSource(
return handle_scope.Close(source_map_->GetSource(module_name));
}
-v8::Handle<v8::Value> ModuleSystem::GetNative(const v8::Arguments& args) {
+v8::Handle<v8::Value> ModuleSystem::RequireNative(const v8::Arguments& args) {
CHECK_EQ(1, args.Length());
+ std::string native_name = *v8::String::AsciiValue(args[0]->ToString());
+ return RequireNativeFromString(native_name);
+}
+
+v8::Handle<v8::Value> ModuleSystem::RequireNativeFromString(
+ const std::string& native_name) {
if (natives_enabled_ == 0)
return ThrowException("Natives disabled");
- std::string native_name = *v8::String::AsciiValue(args[0]->ToString());
if (overridden_native_handlers_.count(native_name) > 0u)
- return RequireForJs(args);
+ return RequireForJsInner(v8::String::New(native_name.c_str()));
NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
if (i == native_handler_map_.end())
return v8::Undefined();