diff options
author | fqian@google.com <fqian@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-06 01:09:45 +0000 |
---|---|---|
committer | fqian@google.com <fqian@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-06 01:09:45 +0000 |
commit | fe844b527a6a8409d09dcf1960a2af1f65465f51 (patch) | |
tree | 040653be9a5630351606c6af752cdb4c0fb379c7 | |
parent | e205cbad92cbb4de9ca696078edab113c876366c (diff) | |
download | chromium_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.pm | 5 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_index.h | 1 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.cpp | 78 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.h | 23 |
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. |