Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4232)

Unified Diff: chrome/renderer/extensions/module_system.cc

Issue 234413005: Move most of ChromeV8Context to a base ScriptContext (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: factor feature_channel out of module_system Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/renderer/extensions/module_system.h ('k') | chrome/renderer/extensions/module_system_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/renderer/extensions/module_system.cc
diff --git a/chrome/renderer/extensions/module_system.cc b/chrome/renderer/extensions/module_system.cc
deleted file mode 100644
index b050a9a8129edae812b94da4f8bffbf697b5d766..0000000000000000000000000000000000000000
--- a/chrome/renderer/extensions/module_system.cc
+++ /dev/null
@@ -1,582 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/renderer/extensions/module_system.h"
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/features/feature_channel.h"
-#include "chrome/renderer/extensions/chrome_v8_context.h"
-#include "chrome/renderer/extensions/console.h"
-#include "chrome/renderer/extensions/safe_builtins.h"
-#include "content/public/renderer/render_view.h"
-#include "extensions/common/extension_messages.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
-#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
-
-namespace extensions {
-
-namespace {
-
-const char* kModuleSystem = "module_system";
-const char* kModuleName = "module_name";
-const char* kModuleField = "module_field";
-const char* kModulesField = "modules";
-
-// Logs a fatal error for the calling context, with some added metadata about
-// the context:
-// - Its type (blessed, unblessed, etc).
-// - Whether it's valid.
-// - The extension ID, if one exists.
-//
-// This will only actual be fatal in in dev/canary, since in too many cases
-// we're at the mercy of the extension or web page's environment. They can mess
-// up our JS in unexpected ways. Hopefully dev/canary channel will pick up such
-// problems, but given the wider variety on stable/beta it's impossible to know.
-void Fatal(ChromeV8Context* context, const std::string& message) {
- // Prepend some context metadata.
- std::string full_message = "(";
- if (!context->is_valid())
- full_message += "Invalid ";
- full_message += context->GetContextTypeDescription();
- full_message += " context";
- if (context->extension()) {
- full_message += " for ";
- full_message += context->extension()->id();
- }
- full_message += ") ";
- full_message += message;
-
- // <= dev means dev, canary, and trunk.
- if (GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV)
- console::Fatal(context->isolate()->GetCallingContext(), full_message);
- else
- console::Error(context->isolate()->GetCallingContext(), full_message);
-}
-
-void Warn(v8::Isolate* isolate, const std::string& message) {
- console::Warn(isolate->GetCallingContext(), message);
-}
-
-// Default exception handler which logs the exception.
-class DefaultExceptionHandler : public ModuleSystem::ExceptionHandler {
- public:
- explicit DefaultExceptionHandler(ChromeV8Context* context)
- : context_(context) {}
-
- // Fatally dumps the debug info from |try_catch| to the console.
- // Make sure this is never used for exceptions that originate in external
- // code!
- virtual void HandleUncaughtException(const v8::TryCatch& try_catch) OVERRIDE {
- v8::HandleScope handle_scope(context_->isolate());
- std::string stack_trace = "<stack trace unavailable>";
- if (!try_catch.StackTrace().IsEmpty()) {
- v8::String::Utf8Value stack_value(try_catch.StackTrace());
- if (*stack_value)
- stack_trace.assign(*stack_value, stack_value.length());
- else
- stack_trace = "<could not convert stack trace to string>";
- }
- Fatal(context_, CreateExceptionString(try_catch) + "{" + stack_trace + "}");
- }
-
- private:
- ChromeV8Context* context_;
-};
-
-} // namespace
-
-std::string ModuleSystem::ExceptionHandler::CreateExceptionString(
- const v8::TryCatch& try_catch) {
- v8::Handle<v8::Message> message(try_catch.Message());
- if (message.IsEmpty()) {
- return "try_catch has no message";
- }
-
- std::string resource_name = "<unknown resource>";
- if (!message->GetScriptResourceName().IsEmpty()) {
- v8::String::Utf8Value resource_name_v8(
- message->GetScriptResourceName()->ToString());
- resource_name.assign(*resource_name_v8, resource_name_v8.length());
- }
-
- std::string error_message = "<no error message>";
- if (!message->Get().IsEmpty()) {
- v8::String::Utf8Value error_message_v8(message->Get());
- error_message.assign(*error_message_v8, error_message_v8.length());
- }
-
- return base::StringPrintf("%s:%d: %s",
- resource_name.c_str(),
- message->GetLineNumber(),
- error_message.c_str());
-}
-
-ModuleSystem::ModuleSystem(ChromeV8Context* context, SourceMap* source_map)
- : ObjectBackedNativeHandler(context),
- context_(context),
- source_map_(source_map),
- natives_enabled_(0),
- exception_handler_(new DefaultExceptionHandler(context)) {
- RouteFunction("require",
- base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this)));
- RouteFunction("requireNative",
- base::Bind(&ModuleSystem::RequireNative, base::Unretained(this)));
- RouteFunction("privates",
- base::Bind(&ModuleSystem::Private, base::Unretained(this)));
-
- v8::Handle<v8::Object> global(context->v8_context()->Global());
- v8::Isolate* isolate = context->isolate();
- global->SetHiddenValue(
- v8::String::NewFromUtf8(isolate, kModulesField),
- v8::Object::New(isolate));
- global->SetHiddenValue(
- v8::String::NewFromUtf8(isolate, kModuleSystem),
- v8::External::New(isolate, this));
-}
-
-ModuleSystem::~ModuleSystem() {
- Invalidate();
-}
-
-void ModuleSystem::Invalidate() {
- if (!is_valid())
- return;
-
- // Clear the module system properties from the global context. It's polite,
- // and we use this as a signal in lazy handlers that we no longer exist.
- {
- v8::HandleScope scope(GetIsolate());
- v8::Handle<v8::Object> global = context()->v8_context()->Global();
- global->DeleteHiddenValue(
- v8::String::NewFromUtf8(GetIsolate(), kModulesField));
- global->DeleteHiddenValue(
- v8::String::NewFromUtf8(GetIsolate(), kModuleSystem));
- }
-
- // Invalidate all of the successfully required handlers we own.
- for (NativeHandlerMap::iterator it = native_handler_map_.begin();
- it != native_handler_map_.end(); ++it) {
- it->second->Invalidate();
- }
-
- ObjectBackedNativeHandler::Invalidate();
-}
-
-ModuleSystem::NativesEnabledScope::NativesEnabledScope(
- ModuleSystem* module_system)
- : module_system_(module_system) {
- module_system_->natives_enabled_++;
-}
-
-ModuleSystem::NativesEnabledScope::~NativesEnabledScope() {
- module_system_->natives_enabled_--;
- CHECK_GE(module_system_->natives_enabled_, 0);
-}
-
-void ModuleSystem::HandleException(const v8::TryCatch& try_catch) {
- exception_handler_->HandleUncaughtException(try_catch);
-}
-
-v8::Handle<v8::Value> ModuleSystem::Require(const std::string& module_name) {
- v8::EscapableHandleScope handle_scope(GetIsolate());
- return handle_scope.Escape(RequireForJsInner(
- v8::String::NewFromUtf8(GetIsolate(), module_name.c_str())));
-}
-
-void ModuleSystem::RequireForJs(
- const v8::FunctionCallbackInfo<v8::Value>& args) {
- v8::Handle<v8::String> module_name = args[0]->ToString();
- args.GetReturnValue().Set(RequireForJsInner(module_name));
-}
-
-v8::Local<v8::Value> ModuleSystem::RequireForJsInner(
- v8::Handle<v8::String> module_name) {
- v8::EscapableHandleScope handle_scope(GetIsolate());
- v8::Context::Scope context_scope(context()->v8_context());
-
- v8::Handle<v8::Object> global(context()->v8_context()->Global());
-
- // The module system might have been deleted. This can happen if a different
- // context keeps a reference to us, but our frame is destroyed (e.g.
- // background page keeps reference to chrome object in a closed popup).
- v8::Handle<v8::Value> modules_value = global->GetHiddenValue(
- v8::String::NewFromUtf8(GetIsolate(), kModulesField));
- if (modules_value.IsEmpty() || modules_value->IsUndefined()) {
- Warn(GetIsolate(), "Extension view no longer exists");
- return v8::Undefined(GetIsolate());
- }
-
- v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(modules_value));
- v8::Local<v8::Value> exports(modules->Get(module_name));
- if (!exports->IsUndefined())
- return handle_scope.Escape(exports);
-
- std::string module_name_str = *v8::String::Utf8Value(module_name);
- v8::Handle<v8::Value> source(GetSource(module_name_str));
- if (source.IsEmpty() || source->IsUndefined()) {
- Fatal(context_, "No source for require(" + module_name_str + ")");
- return v8::Undefined(GetIsolate());
- }
- v8::Handle<v8::String> wrapped_source(WrapSource(
- v8::Handle<v8::String>::Cast(source)));
- // Modules are wrapped in (function(){...}) so they always return functions.
- v8::Handle<v8::Value> func_as_value = RunString(wrapped_source, module_name);
- if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) {
- Fatal(context_, "Bad source for require(" + module_name_str + ")");
- return v8::Undefined(GetIsolate());
- }
-
- v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value);
-
- exports = v8::Object::New(GetIsolate());
- v8::Handle<v8::Object> natives(NewInstance());
- CHECK(!natives.IsEmpty()); // this can happen if v8 has issues
-
- // These must match the argument order in WrapSource.
- v8::Handle<v8::Value> args[] = {
- // CommonJS.
- natives->Get(v8::String::NewFromUtf8(
- GetIsolate(), "require", v8::String::kInternalizedString)),
- natives->Get(v8::String::NewFromUtf8(
- GetIsolate(), "requireNative", v8::String::kInternalizedString)),
- exports,
- // Libraries that we magically expose to every module.
- console::AsV8Object(),
- natives->Get(v8::String::NewFromUtf8(
- GetIsolate(), "privates", v8::String::kInternalizedString)),
- // Each safe builtin. Keep in order with the arguments in WrapSource.
- context_->safe_builtins()->GetArray(),
- context_->safe_builtins()->GetFunction(),
- context_->safe_builtins()->GetJSON(),
- context_->safe_builtins()->GetObjekt(),
- context_->safe_builtins()->GetRegExp(),
- context_->safe_builtins()->GetString(), };
- {
- v8::TryCatch try_catch;
- try_catch.SetCaptureMessage(true);
- context_->CallFunction(func, arraysize(args), args);
- if (try_catch.HasCaught()) {
- HandleException(try_catch);
- return v8::Undefined(GetIsolate());
- }
- }
- modules->Set(module_name, exports);
- return handle_scope.Escape(exports);
-}
-
-v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
- const std::string& module_name,
- const std::string& method_name) {
- v8::HandleScope handle_scope(GetIsolate());
- v8::Handle<v8::Value> no_args;
- return CallModuleMethod(module_name, method_name, 0, &no_args);
-}
-
-v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
- const std::string& module_name,
- const std::string& method_name,
- std::vector<v8::Handle<v8::Value> >* args) {
- return CallModuleMethod(
- module_name, method_name, args->size(), vector_as_array(args));
-}
-
-v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
- const std::string& module_name,
- const std::string& method_name,
- int argc,
- v8::Handle<v8::Value> argv[]) {
- TRACE_EVENT2("v8", "v8.callModuleMethod",
- "module_name", module_name,
- "method_name", method_name);
-
- v8::EscapableHandleScope handle_scope(GetIsolate());
- v8::Context::Scope context_scope(context()->v8_context());
-
- v8::Local<v8::Value> module;
- {
- NativesEnabledScope natives_enabled(this);
- module = RequireForJsInner(
- v8::String::NewFromUtf8(GetIsolate(), module_name.c_str()));
- }
-
- if (module.IsEmpty() || !module->IsObject()) {
- Fatal(context_,
- "Failed to get module " + module_name + " to call " + method_name);
- return handle_scope.Escape(
- v8::Local<v8::Primitive>(v8::Undefined(GetIsolate())));
- }
-
- v8::Local<v8::Value> value =
- v8::Handle<v8::Object>::Cast(module)->Get(
- v8::String::NewFromUtf8(GetIsolate(), method_name.c_str()));
- if (value.IsEmpty() || !value->IsFunction()) {
- Fatal(context_, module_name + "." + method_name + " is not a function");
- return handle_scope.Escape(
- v8::Local<v8::Primitive>(v8::Undefined(GetIsolate())));
- }
-
- v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
- v8::Local<v8::Value> result;
- {
- v8::TryCatch try_catch;
- try_catch.SetCaptureMessage(true);
- result = context_->CallFunction(func, argc, argv);
- if (try_catch.HasCaught())
- HandleException(try_catch);
- }
- return handle_scope.Escape(result);
-}
-
-void ModuleSystem::RegisterNativeHandler(const std::string& name,
- scoped_ptr<NativeHandler> native_handler) {
- native_handler_map_[name] =
- linked_ptr<NativeHandler>(native_handler.release());
-}
-
-void ModuleSystem::OverrideNativeHandlerForTest(const std::string& name) {
- overridden_native_handlers_.insert(name);
-}
-
-void ModuleSystem::RunString(const std::string& code, const std::string& name) {
- v8::HandleScope handle_scope(GetIsolate());
- RunString(v8::String::NewFromUtf8(GetIsolate(), code.c_str()),
- v8::String::NewFromUtf8(GetIsolate(), name.c_str()));
-}
-
-// static
-void ModuleSystem::NativeLazyFieldGetter(
- v8::Local<v8::String> property,
- const v8::PropertyCallbackInfo<v8::Value>& info) {
- LazyFieldGetterInner(property,
- info,
- &ModuleSystem::RequireNativeFromString);
-}
-
-// static
-void ModuleSystem::LazyFieldGetter(
- v8::Local<v8::String> property,
- const v8::PropertyCallbackInfo<v8::Value>& info) {
- LazyFieldGetterInner(property, info, &ModuleSystem::Require);
-}
-
-// static
-void ModuleSystem::LazyFieldGetterInner(
- v8::Local<v8::String> property,
- const v8::PropertyCallbackInfo<v8::Value>& info,
- RequireFunction require_function) {
- CHECK(!info.Data().IsEmpty());
- CHECK(info.Data()->IsObject());
- v8::HandleScope handle_scope(info.GetIsolate());
- v8::Handle<v8::Object> parameters = v8::Handle<v8::Object>::Cast(info.Data());
- // This context should be the same as context()->v8_context().
- 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::NewFromUtf8(info.GetIsolate(), kModuleSystem));
- if (module_system_value.IsEmpty() || !module_system_value->IsExternal()) {
- // ModuleSystem has been deleted.
- // TODO(kalman): See comment in header file.
- Warn(info.GetIsolate(),
- "Module system has been deleted, does extension view exist?");
- return;
- }
-
- ModuleSystem* module_system = static_cast<ModuleSystem*>(
- v8::Handle<v8::External>::Cast(module_system_value)->Value());
-
- std::string name = *v8::String::Utf8Value(parameters->Get(
- v8::String::NewFromUtf8(info.GetIsolate(), 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::Value> module_value = (module_system->*require_function)(name);
- if (try_catch.HasCaught()) {
- module_system->HandleException(try_catch);
- return;
- }
- if (module_value.IsEmpty() || !module_value->IsObject()) {
- // require_function will have already logged this, we don't need to.
- return;
- }
-
- v8::Handle<v8::Object> module = v8::Handle<v8::Object>::Cast(module_value);
- v8::Handle<v8::String> field =
- parameters->Get(v8::String::NewFromUtf8(info.GetIsolate(), kModuleField))
- ->ToString();
-
- if (!module->Has(field)) {
- std::string field_str = *v8::String::Utf8Value(field);
- Fatal(module_system->context_,
- "Lazy require of " + name + "." + field_str + " did not set the " +
- field_str + " field");
- return;
- }
-
- v8::Local<v8::Value> new_field = module->Get(field);
- if (try_catch.HasCaught()) {
- module_system->HandleException(try_catch);
- return;
- }
-
- // Ok for it to be undefined, among other things it's how bindings signify
- // that the extension doesn't have permission to use them.
- CHECK(!new_field.IsEmpty());
-
- // Delete the getter and set this field to |new_field| so the same object is
- // returned every time a certain API is accessed.
- v8::Handle<v8::Object> object = info.This();
- object->Delete(property);
- object->Set(property, new_field);
- info.GetReturnValue().Set(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::AccessorGetterCallback getter) {
- v8::HandleScope handle_scope(GetIsolate());
- v8::Handle<v8::Object> parameters = v8::Object::New(GetIsolate());
- parameters->Set(v8::String::NewFromUtf8(GetIsolate(), kModuleName),
- v8::String::NewFromUtf8(GetIsolate(), module_name.c_str()));
- parameters->Set(v8::String::NewFromUtf8(GetIsolate(), kModuleField),
- v8::String::NewFromUtf8(GetIsolate(), module_field.c_str()));
- object->SetAccessor(v8::String::NewFromUtf8(GetIsolate(), field.c_str()),
- 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::EscapableHandleScope handle_scope(GetIsolate());
- v8::Context::Scope context_scope(context()->v8_context());
-
- // Prepend extensions:: to |name| so that internal code can be differentiated
- // from external code in stack traces. This has no effect on behaviour.
- std::string internal_name = base::StringPrintf("extensions::%s",
- *v8::String::Utf8Value(name));
-
- blink::WebScopedMicrotaskSuppression suppression;
- v8::TryCatch try_catch;
- try_catch.SetCaptureMessage(true);
- v8::Handle<v8::Script> script(
- v8::Script::Compile(code,
- v8::String::NewFromUtf8(GetIsolate(),
- internal_name.c_str(),
- v8::String::kNormalString,
- internal_name.size())));
- if (try_catch.HasCaught()) {
- HandleException(try_catch);
- return v8::Undefined(GetIsolate());
- }
-
- v8::Local<v8::Value> result = script->Run();
- if (try_catch.HasCaught()) {
- HandleException(try_catch);
- return v8::Undefined(GetIsolate());
- }
-
- return handle_scope.Escape(result);
-}
-
-v8::Handle<v8::Value> ModuleSystem::GetSource(const std::string& module_name) {
- v8::EscapableHandleScope handle_scope(GetIsolate());
- if (!source_map_->Contains(module_name))
- return v8::Undefined(GetIsolate());
- return handle_scope.Escape(
- v8::Local<v8::Value>(source_map_->GetSource(GetIsolate(), module_name)));
-}
-
-void ModuleSystem::RequireNative(
- const v8::FunctionCallbackInfo<v8::Value>& args) {
- CHECK_EQ(1, args.Length());
- std::string native_name = *v8::String::Utf8Value(args[0]->ToString());
- args.GetReturnValue().Set(RequireNativeFromString(native_name));
-}
-
-v8::Handle<v8::Value> ModuleSystem::RequireNativeFromString(
- const std::string& native_name) {
- if (natives_enabled_ == 0) {
- // HACK: if in test throw exception so that we can test the natives-disabled
- // logic; however, under normal circumstances, this is programmer error so
- // we could crash.
- if (exception_handler_) {
- return GetIsolate()->ThrowException(
- v8::String::NewFromUtf8(GetIsolate(), "Natives disabled"));
- }
- Fatal(context_, "Natives disabled for requireNative(" + native_name + ")");
- return v8::Undefined(GetIsolate());
- }
-
- if (overridden_native_handlers_.count(native_name) > 0u) {
- return RequireForJsInner(
- v8::String::NewFromUtf8(GetIsolate(), native_name.c_str()));
- }
-
- NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
- if (i == native_handler_map_.end()) {
- Fatal(context_,
- "Couldn't find native for requireNative(" + native_name + ")");
- return v8::Undefined(GetIsolate());
- }
- return i->second->NewInstance();
-}
-
-v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) {
- v8::EscapableHandleScope handle_scope(GetIsolate());
- // Keep in order with the arguments in RequireForJsInner.
- v8::Handle<v8::String> left = v8::String::NewFromUtf8(
- GetIsolate(),
- "(function(require, requireNative, exports, "
- "console, privates,"
- "$Array, $Function, $JSON, $Object, $RegExp, $String) {"
- "'use strict';");
- v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})");
- return handle_scope.Escape(v8::Local<v8::String>(
- v8::String::Concat(left, v8::String::Concat(source, right))));
-}
-
-void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) {
- CHECK_EQ(1, args.Length());
- CHECK(args[0]->IsObject());
- v8::Local<v8::Object> obj = args[0].As<v8::Object>();
- v8::Local<v8::String> privates_key =
- v8::String::NewFromUtf8(GetIsolate(), "privates");
- v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key);
- if (privates.IsEmpty()) {
- privates = v8::Object::New(args.GetIsolate());
- obj->SetHiddenValue(privates_key, privates);
- }
- args.GetReturnValue().Set(privates);
-}
-
-} // namespace extensions
« no previous file with comments | « chrome/renderer/extensions/module_system.h ('k') | chrome/renderer/extensions/module_system_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698