summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfqian@google.com <fqian@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-06 01:09:45 +0000
committerfqian@google.com <fqian@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-06 01:09:45 +0000
commitfe844b527a6a8409d09dcf1960a2af1f65465f51 (patch)
tree040653be9a5630351606c6af752cdb4c0fb379c7
parente205cbad92cbb4de9ca696078edab113c876366c (diff)
downloadchromium_src-fe844b527a6a8409d09dcf1960a2af1f65465f51.zip
chromium_src-fe844b527a6a8409d09dcf1960a2af1f65465f51.tar.gz
chromium_src-fe844b527a6a8409d09dcf1960a2af1f65465f51.tar.bz2
This is a cleaned up fix of Christian's original patch in
http://codereview.chromium.org/13176 I cleaned it a bit so it does not leak memory. There is a corner case that can crash a test, so I have to make a workaround. Review URL: http://codereview.chromium.org/13224 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@6472 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--webkit/port/bindings/scripts/CodeGeneratorV8.pm5
-rw-r--r--webkit/port/bindings/v8/v8_index.h1
-rw-r--r--webkit/port/bindings/v8/v8_proxy.cpp78
-rw-r--r--webkit/port/bindings/v8/v8_proxy.h23
4 files changed, 93 insertions, 14 deletions
diff --git a/webkit/port/bindings/scripts/CodeGeneratorV8.pm b/webkit/port/bindings/scripts/CodeGeneratorV8.pm
index 44947c8..72d5a80 100644
--- a/webkit/port/bindings/scripts/CodeGeneratorV8.pm
+++ b/webkit/port/bindings/scripts/CodeGeneratorV8.pm
@@ -418,10 +418,7 @@ sub GenerateConstructorGetter
V8ClassIndex::V8WrapperType type = V8ClassIndex::FromInt(data->Int32Value());
- v8::Handle<v8::FunctionTemplate> desc = V8Proxy::GetTemplate(type);
- v8::Handle<v8::Function> func = desc->GetFunction();
- ASSERT(func->IsFunction());
- return func;
+ return V8Proxy::retrieve()->GetConstructor(type);
}
END
diff --git a/webkit/port/bindings/v8/v8_index.h b/webkit/port/bindings/v8/v8_index.h
index fd5849c..2334773 100644
--- a/webkit/port/bindings/v8/v8_index.h
+++ b/webkit/port/bindings/v8/v8_index.h
@@ -443,6 +443,7 @@ class V8ClassIndex {
ALL_WRAPPER_TYPES(DEFINE_ENUM)
#undef DEFINE_ENUM
CLASSINDEX_END,
+ WRAPPER_TYPE_COUNT = CLASSINDEX_END
};
static int ToInt(V8WrapperType type) { return static_cast<int>(type); }
diff --git a/webkit/port/bindings/v8/v8_proxy.cpp b/webkit/port/bindings/v8/v8_proxy.cpp
index 5981ef8b..8b90f54 100644
--- a/webkit/port/bindings/v8/v8_proxy.cpp
+++ b/webkit/port/bindings/v8/v8_proxy.cpp
@@ -1358,6 +1358,32 @@ v8::Local<v8::Value> V8Proxy::CallFunction(v8::Handle<v8::Function> function,
}
+v8::Local<v8::Function> V8Proxy::GetConstructor(V8ClassIndex::V8WrapperType t)
+{
+ ASSERT(ContextInitialized());
+ v8::Local<v8::Value> cached =
+ m_dom_constructor_cache->Get(v8::Integer::New(V8ClassIndex::ToInt(t)));
+ if (cached->IsFunction()) {
+ return v8::Local<v8::Function>::Cast(cached);
+ }
+
+ // Not in cache.
+ {
+ v8::Handle<v8::FunctionTemplate> templ = GetTemplate(t);
+ v8::TryCatch try_catch;
+ // This might fail if we're running out of stack or memory.
+ v8::Local<v8::Function> value = templ->GetFunction();
+ if (value.IsEmpty())
+ return v8::Local<v8::Function>();
+ m_dom_constructor_cache->Set(v8::Integer::New(t), value);
+ // Hotmail fix, see comments in v8_proxy.h above
+ // m_dom_constructor_cache.
+ value->Set(v8::String::New("__proto__"), m_object_prototype);
+ return value;
+ }
+}
+
+
v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate(
V8ClassIndex::V8WrapperType type)
{
@@ -1808,14 +1834,32 @@ void V8Proxy::ClearDocumentWrapper()
}
+void V8Proxy::DisposeContext() {
+ ASSERT(!m_context.IsEmpty());
+ m_context.Dispose();
+ m_context.Clear();
+
+#ifndef NDEBUG
+ UnregisterGlobalHandle(this, m_object_prototype);
+ UnregisterGlobalHandle(this, m_dom_constructor_cache);
+#endif
+
+ ASSERT(!m_dom_constructor_cache.IsEmpty());
+ m_dom_constructor_cache.Dispose();
+ m_dom_constructor_cache.Clear();
+
+ ASSERT(!m_object_prototype.IsEmpty());
+ m_object_prototype.Dispose();
+ m_object_prototype.Clear();
+}
+
void V8Proxy::clearForClose()
{
if (!m_context.IsEmpty()) {
v8::HandleScope handle_scope;
ClearDocumentWrapper();
- m_context.Dispose();
- m_context.Clear();
+ DisposeContext();
}
}
@@ -1845,8 +1889,7 @@ void V8Proxy::clearForNavigation()
// Separate the context from its global object.
m_context->DetachGlobal();
- m_context.Dispose();
- m_context.Clear();
+ DisposeContext();
// Reinitialize the context so the global object points to
// the new DOM window.
@@ -2101,12 +2144,23 @@ void V8Proxy::initContextIfNeeded()
#endif
}
+ v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(
+ m_global->Get(v8::String::New("Object")));
+ m_object_prototype = v8::Persistent<v8::Value>::New(
+ object->Get(v8::String::New("prototype")));
+ m_dom_constructor_cache = v8::Persistent<v8::Array>::New(
+ v8::Array::New(V8ClassIndex::WRAPPER_TYPE_COUNT));
+#ifndef NDEBUG
+ RegisterGlobalHandle(PROXY, this, m_object_prototype);
+ RegisterGlobalHandle(PROXY, this, m_dom_constructor_cache);
+#endif
+
// Create a new JS window object and use it as the prototype for the
// shadow global object.
- v8::Persistent<v8::FunctionTemplate> window_descriptor =
- GetTemplate(V8ClassIndex::DOMWINDOW);
+ v8::Handle<v8::Function> window_constructor =
+ GetConstructor(V8ClassIndex::DOMWINDOW);
v8::Local<v8::Object> js_window =
- SafeAllocation::NewInstance(window_descriptor->GetFunction());
+ SafeAllocation::NewInstance(window_constructor);
if (js_window.IsEmpty())
return;
@@ -2420,8 +2474,14 @@ v8::Local<v8::Object> V8Proxy::InstantiateV8Object(
desc_type = V8ClassIndex::UNDETECTABLEHTMLCOLLECTION;
}
- v8::Persistent<v8::FunctionTemplate> desc = GetTemplate(desc_type);
- v8::Local<v8::Function> function = desc->GetFunction();
+ v8::Local<v8::Function> function;
+ V8Proxy* proxy = V8Proxy::retrieve();
+ if (proxy) {
+ // Constructor is configured.
+ function = proxy->GetConstructor(desc_type);
+ } else {
+ function = GetTemplate(desc_type)->GetFunction();
+ }
v8::Local<v8::Object> instance = SafeAllocation::NewInstance(function);
if (!instance.IsEmpty()) {
// Avoid setting the DOM wrapper for failed allocations.
diff --git a/webkit/port/bindings/v8/v8_proxy.h b/webkit/port/bindings/v8/v8_proxy.h
index 4450dcc..91792b3 100644
--- a/webkit/port/bindings/v8/v8_proxy.h
+++ b/webkit/port/bindings/v8/v8_proxy.h
@@ -238,6 +238,9 @@ class V8Proxy {
int argc,
v8::Handle<v8::Value> argv[]);
+ // Returns the dom constructor function for the given node type.
+ v8::Local<v8::Function> GetConstructor(V8ClassIndex::V8WrapperType type);
+
// Returns the window object of the currently executing context.
static DOMWindow* retrieveWindow();
// Returns the window object associated with a context.
@@ -432,6 +435,8 @@ class V8Proxy {
void SetSecurityToken();
void ClearDocumentWrapper();
void UpdateDocumentWrapper(v8::Handle<v8::Value> wrapper);
+ // Dispose global handles of m_contexts and friends.
+ void DisposeContext();
static bool CanAccessPrivate(DOMWindow* target);
@@ -512,9 +517,25 @@ class V8Proxy {
}
Frame* m_frame;
+
v8::Persistent<v8::Context> m_context;
+ // DOM constructors are cached per context. A DOM constructor is a function
+ // instance created from a DOM constructor template. There is one instance
+ // per context. A DOM constructor is different from a normal function in
+ // two ways: 1) it cannot be called as constructor (aka, used to create
+ // a DOM object); 2) its __proto__ points to Object.prototype rather than
+ // Function.prototype. The reason for 2) is that, in Safari, a DOM constructor
+ // is a normal JS object, but not a function. Hotmail relies on the fact
+ // that, in Safari, HTMLElement.__proto__ == Object.prototype.
+ //
+ // m_object_prototype is a cache of the original Object.prototype.
+ //
+ // Both handles must be disposed when the context is disposed. Otherwise,
+ // it can keep all objects alive.
+ v8::Persistent<v8::Array> m_dom_constructor_cache;
+ v8::Persistent<v8::Value> m_object_prototype;
+
v8::Persistent<v8::Object> m_global;
-
v8::Persistent<v8::Value> m_document;
// Utility context holding JavaScript functions used internally.