| Index: webkit/port/bindings/v8/v8_proxy.cpp
|
| ===================================================================
|
| --- webkit/port/bindings/v8/v8_proxy.cpp (revision 18892)
|
| +++ webkit/port/bindings/v8/v8_proxy.cpp (working copy)
|
| @@ -40,6 +40,7 @@
|
| #include "v8_binding.h"
|
| #include "V8Collection.h"
|
| #include "V8DOMWindow.h"
|
| +#include "V8IsolatedWorld.h"
|
|
|
| #include "ChromiumBridge.h"
|
| #include "CSSMutableStyleDeclaration.h"
|
| @@ -166,6 +167,7 @@
|
| typedef HashMap<void*, v8::Object*> DOMObjectMap;
|
|
|
| #ifndef NDEBUG
|
| +
|
| static void EnumerateDOMObjectMap(DOMObjectMap& wrapper_map)
|
| {
|
| for (DOMObjectMap::iterator it = wrapper_map.begin(), end = wrapper_map.end();
|
| @@ -178,16 +180,23 @@
|
| }
|
| }
|
|
|
| +class DOMObjectVisitor : public DOMWrapperMap<void>::Visitor {
|
| + public:
|
| + void visitDOMWrapper(void* object, v8::Persistent<v8::Object> wrapper) {
|
| + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper);
|
| + USE_VAR(type);
|
| + USE_VAR(object);
|
| + }
|
| +};
|
|
|
| -static void EnumerateDOMNodeMap(DOMNodeMap& node_map)
|
| -{
|
| - for (DOMNodeMap::iterator it = node_map.begin(), end = node_map.end();
|
| - it != end; ++it) {
|
| - Node* node = it->first;
|
| - USE_VAR(node);
|
| - ASSERT(v8::Persistent<v8::Object>(it->second).IsWeak());
|
| +class EnsureWeakDOMNodeVisitor : public DOMWrapperMap<Node>::Visitor {
|
| + public:
|
| + void visitDOMWrapper(Node* object, v8::Persistent<v8::Object> wrapper) {
|
| + USE_VAR(object);
|
| + ASSERT(wrapper.IsWeak());
|
| }
|
| -}
|
| +};
|
| +
|
| #endif // NDEBUG
|
|
|
| #if ENABLE(SVG)
|
| @@ -323,32 +332,18 @@
|
| wrapper.Dispose();
|
| }
|
|
|
| -
|
| -// Create object groups for DOM tree nodes.
|
| -static void GCPrologue()
|
| -{
|
| - v8::HandleScope scope;
|
| -
|
| -#ifndef NDEBUG
|
| - EnumerateDOMObjectMap(getDOMObjectMap().impl());
|
| -#endif
|
| -
|
| - // Run through all objects with possible pending activity making their
|
| - // wrappers non weak if there is pending activity.
|
| - DOMObjectMap active_map = getActiveDOMObjectMap().impl();
|
| - for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end();
|
| - it != end; ++it) {
|
| - void* obj = it->first;
|
| - v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>(it->second);
|
| +class GCPrologueVisitor : public DOMWrapperMap<void>::Visitor {
|
| + public:
|
| + void visitDOMWrapper(void* object, v8::Persistent<v8::Object> wrapper) {
|
| ASSERT(wrapper.IsWeak());
|
| V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper);
|
| switch (type) {
|
| -#define MAKE_CASE(TYPE, NAME) \
|
| - case V8ClassIndex::TYPE: { \
|
| - NAME* impl = static_cast<NAME*>(obj); \
|
| - if (impl->hasPendingActivity()) \
|
| - wrapper.ClearWeak(); \
|
| - break; \
|
| +#define MAKE_CASE(TYPE, NAME) \
|
| + case V8ClassIndex::TYPE: { \
|
| + NAME* impl = static_cast<NAME*>(object); \
|
| + if (impl->hasPendingActivity()) \
|
| + wrapper.ClearWeak(); \
|
| + break; \
|
| }
|
| ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
|
| default:
|
| @@ -364,7 +359,7 @@
|
| // GC even though their entnaglement most likely is still the same.
|
| if (type == V8ClassIndex::MESSAGEPORT) {
|
| // Get the port and its entangled port.
|
| - MessagePort* port1 = static_cast<MessagePort*>(obj);
|
| + MessagePort* port1 = static_cast<MessagePort*>(object);
|
| MessagePortProxy* port2 = port1->entangledPort();
|
| if (port2 != NULL) {
|
| // As ports are always entangled in pairs only perform the entanglement
|
| @@ -393,19 +388,36 @@
|
| }
|
| }
|
| }
|
| +};
|
|
|
| - // Create object groups.
|
| - typedef std::pair<uintptr_t, Node*> GrouperPair;
|
| - typedef Vector<GrouperPair> GrouperList;
|
| +class GrouperItem {
|
| + public:
|
| + GrouperItem(uintptr_t group_id, Node* node, v8::Persistent<v8::Object> wrapper)
|
| + : group_id_(group_id), node_(node), wrapper_(wrapper) { }
|
| +
|
| + uintptr_t group_id() const { return group_id_; }
|
| + Node* node() const { return node_; }
|
| + v8::Persistent<v8::Object> wrapper() const { return wrapper_; }
|
|
|
| - DOMNodeMap node_map = getDOMNodeMap().impl();
|
| - GrouperList grouper;
|
| - grouper.reserveCapacity(node_map.size());
|
| + private:
|
| + uintptr_t group_id_;
|
| + Node* node_;
|
| + v8::Persistent<v8::Object> wrapper_;
|
| +};
|
|
|
| - for (DOMNodeMap::iterator it = node_map.begin(), end = node_map.end();
|
| - it != end; ++it) {
|
| - Node* node = it->first;
|
| +bool operator<(const GrouperItem& a, const GrouperItem& b) {
|
| + return a.group_id() < b.group_id();
|
| +}
|
|
|
| +typedef Vector<GrouperItem> GrouperList;
|
| +
|
| +class ObjectGrouperVisitor : public DOMWrapperMap<Node>::Visitor {
|
| + public:
|
| + ObjectGrouperVisitor() {
|
| + // TODO(abarth): grouper_.reserveCapacity(node_map.size()); ?
|
| + }
|
| +
|
| + void visitDOMWrapper(Node* node, v8::Persistent<v8::Object> wrapper) {
|
| // If the node is in document, put it in the ownerDocument's object group.
|
| //
|
| // If an image element was created by JavaScript "new Image",
|
| @@ -427,85 +439,106 @@
|
| // If the node is alone in its DOM tree (doesn't have a parent or any
|
| // children) then the group will be filtered out later anyway.
|
| if (root == node && !node->hasChildNodes())
|
| - continue;
|
| + return;
|
|
|
| group_id = reinterpret_cast<uintptr_t>(root);
|
| }
|
| - grouper.append(GrouperPair(group_id, node));
|
| + grouper_.append(GrouperItem(group_id, node, wrapper));
|
| }
|
|
|
| - // Group by sorting by the group id. This will use the std::pair operator<,
|
| - // which will really sort by both the group id and the Node*. However the
|
| - // Node* is only involved to sort within a group id, so it will be fine.
|
| - std::sort(grouper.begin(), grouper.end());
|
| + void ApplyGrouping() {
|
| + // Group by sorting by the group id.
|
| + std::sort(grouper_.begin(), grouper_.end());
|
|
|
| - // TODO(deanm): Should probably work in iterators here, but indexes were
|
| - // easier for my simple mind.
|
| - for (size_t i = 0; i < grouper.size(); ) {
|
| - // Seek to the next key (or the end of the list).
|
| - size_t next_key_index = grouper.size();
|
| - for (size_t j = i; j < grouper.size(); ++j) {
|
| - if (grouper[i].first != grouper[j].first) {
|
| - next_key_index = j;
|
| - break;
|
| + // TODO(deanm): Should probably work in iterators here, but indexes were
|
| + // easier for my simple mind.
|
| + for (size_t i = 0; i < grouper_.size(); ) {
|
| + // Seek to the next key (or the end of the list).
|
| + size_t next_key_index = grouper_.size();
|
| + for (size_t j = i; j < grouper_.size(); ++j) {
|
| + if (grouper_[i].group_id() != grouper_[j].group_id()) {
|
| + next_key_index = j;
|
| + break;
|
| + }
|
| }
|
| - }
|
|
|
| - ASSERT(next_key_index > i);
|
| + ASSERT(next_key_index > i);
|
|
|
| - // We only care about a group if it has more than one object. If it only
|
| - // has one object, it has nothing else that needs to be kept alive.
|
| - if (next_key_index - i <= 1) {
|
| - i = next_key_index;
|
| - continue;
|
| - }
|
| + // We only care about a group if it has more than one object. If it only
|
| + // has one object, it has nothing else that needs to be kept alive.
|
| + if (next_key_index - i <= 1) {
|
| + i = next_key_index;
|
| + continue;
|
| + }
|
|
|
| - Vector<v8::Persistent<v8::Value> > group;
|
| - group.reserveCapacity(next_key_index - i);
|
| - for (; i < next_key_index; ++i) {
|
| - Node* node = grouper[i].second;
|
| - v8::Persistent<v8::Value> wrapper =
|
| - getDOMNodeMap().get(node);
|
| - if (!wrapper.IsEmpty())
|
| - group.append(wrapper);
|
| - // If the node is styled and there is a wrapper for the inline
|
| - // style declaration, we need to keep that style declaration
|
| - // wrapper alive as well, so we add it to the object group.
|
| - if (node->isStyledElement()) {
|
| - StyledElement* element = reinterpret_cast<StyledElement*>(node);
|
| - CSSStyleDeclaration* style = element->inlineStyleDecl();
|
| - if (style != NULL) {
|
| - wrapper = getDOMObjectMap().get(style);
|
| - if (!wrapper.IsEmpty())
|
| - group.append(wrapper);
|
| + Vector<v8::Persistent<v8::Value> > group;
|
| + group.reserveCapacity(next_key_index - i);
|
| + for (; i < next_key_index; ++i) {
|
| + Node* node = grouper_[i].node();
|
| + v8::Persistent<v8::Value> wrapper = grouper_[i].wrapper();
|
| + if (!wrapper.IsEmpty())
|
| + group.append(wrapper);
|
| + /* TODO(abarth): Re-enabled this code to avoid GCing these wrappers!
|
| + Currently this depends on looking up the wrapper
|
| + during a GC, but we don't know which isolated world
|
| + we're in, so it's unclear which map to look in...
|
| +
|
| + // If the node is styled and there is a wrapper for the inline
|
| + // style declaration, we need to keep that style declaration
|
| + // wrapper alive as well, so we add it to the object group.
|
| + if (node->isStyledElement()) {
|
| + StyledElement* element = reinterpret_cast<StyledElement*>(node);
|
| + CSSStyleDeclaration* style = element->inlineStyleDecl();
|
| + if (style != NULL) {
|
| + wrapper = getDOMObjectMap().get(style);
|
| + if (!wrapper.IsEmpty())
|
| + group.append(wrapper);
|
| + }
|
| }
|
| + */
|
| }
|
| - }
|
|
|
| - if (group.size() > 1)
|
| - v8::V8::AddObjectGroup(&group[0], group.size());
|
| + if (group.size() > 1)
|
| + v8::V8::AddObjectGroup(&group[0], group.size());
|
|
|
| - ASSERT(i == next_key_index);
|
| + ASSERT(i == next_key_index);
|
| + }
|
| }
|
| -}
|
| +
|
| + private:
|
| + GrouperList grouper_;
|
| +};
|
|
|
| -
|
| -static void GCEpilogue()
|
| +// Create object groups for DOM tree nodes.
|
| +static void GCPrologue()
|
| {
|
| v8::HandleScope scope;
|
|
|
| - // Run through all objects with pending activity making their wrappers weak
|
| - // again.
|
| - DOMObjectMap active_map = getActiveDOMObjectMap().impl();
|
| - for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end();
|
| - it != end; ++it) {
|
| - void* obj = it->first;
|
| - v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>(it->second);
|
| +#ifndef NDEBUG
|
| + DOMObjectVisitor domObjectVisitor;
|
| + visitDOMObjectsInCurrentThread(&domObjectVisitor);
|
| +#endif
|
| +
|
| + // Run through all objects with possible pending activity making their
|
| + // wrappers non weak if there is pending activity.
|
| + GCPrologueVisitor prologueVisitor;
|
| + visitActiveDOMObjectsInCurrentThread(&prologueVisitor);
|
| +
|
| + // Create object groups.
|
| + ObjectGrouperVisitor objectGrouperVisitor;
|
| + visitDOMNodesInCurrentThread(&objectGrouperVisitor);
|
| + objectGrouperVisitor.ApplyGrouping();
|
| +}
|
| +
|
| +class GCEpilogueVisitor : public DOMWrapperMap<void>::Visitor {
|
| + public:
|
| + void visitDOMWrapper(void* object, v8::Persistent<v8::Object> wrapper)
|
| + {
|
| V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper);
|
| switch (type) {
|
| #define MAKE_CASE(TYPE, NAME) \
|
| case V8ClassIndex::TYPE: { \
|
| - NAME* impl = static_cast<NAME*>(obj); \
|
| + NAME* impl = static_cast<NAME*>(object); \
|
| if (impl->hasPendingActivity()) { \
|
| ASSERT(!wrapper.IsWeak()); \
|
| wrapper.MakeWeak(impl, &weakActiveDOMObjectCallback); \
|
| @@ -518,11 +551,25 @@
|
| #undef MAKE_CASE
|
| }
|
| }
|
| +};
|
|
|
| +static void GCEpilogue()
|
| +{
|
| + v8::HandleScope scope;
|
| +
|
| + // Run through all objects with pending activity making their wrappers weak
|
| + // again.
|
| + GCEpilogueVisitor epilogueVisitor;
|
| + visitActiveDOMObjectsInCurrentThread(&epilogueVisitor);
|
| +
|
| #ifndef NDEBUG
|
| // Check all survivals are weak.
|
| - EnumerateDOMObjectMap(getDOMObjectMap().impl());
|
| - EnumerateDOMNodeMap(getDOMNodeMap().impl());
|
| + DOMObjectVisitor domObjectVisitor;
|
| + visitDOMObjectsInCurrentThread(&domObjectVisitor);
|
| +
|
| + EnsureWeakDOMNodeVisitor weakDOMNodeVisitor;
|
| + visitDOMNodesInCurrentThread(&weakDOMNodeVisitor);
|
| +
|
| EnumerateDOMObjectMap(gc_protected_map());
|
| EnumerateGlobalHandles();
|
| #undef USE_VAR
|
| @@ -997,6 +1044,12 @@
|
| return true;
|
| }
|
|
|
| +void V8Proxy::evaluateInNewWorld(const Vector<ScriptSourceCode>& sources)
|
| +{
|
| + InitContextIfNeeded();
|
| + V8IsolatedWorld::evaluate(sources, this);
|
| +}
|
| +
|
| void V8Proxy::evaluateInNewContext(const Vector<ScriptSourceCode>& sources)
|
| {
|
| InitContextIfNeeded();
|
| @@ -2118,6 +2171,38 @@
|
| return result;
|
| }
|
|
|
| +bool V8Proxy::installDOMWindow(v8::Handle<v8::Context> context,
|
| + DOMWindow* window)
|
| +{
|
| + v8::Handle<v8::String> implicit_proto_string = v8::String::New("__proto__");
|
| + if (implicit_proto_string.IsEmpty())
|
| + return false;
|
| +
|
| + // Create a new JS window object and use it as the prototype for the
|
| + // shadow global object.
|
| + v8::Handle<v8::Function> window_constructor =
|
| + GetConstructor(V8ClassIndex::DOMWINDOW);
|
| + v8::Local<v8::Object> js_window =
|
| + SafeAllocation::NewInstance(window_constructor);
|
| + // Bail out if allocation failed.
|
| + if (js_window.IsEmpty())
|
| + return false;
|
| +
|
| + // Wrap the window.
|
| + SetDOMWrapper(js_window,
|
| + V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW),
|
| + window);
|
| +
|
| + window->ref();
|
| + V8Proxy::SetJSWrapperForDOMObject(window,
|
| + v8::Persistent<v8::Object>::New(js_window));
|
| +
|
| + // Insert the window instance as the prototype of the shadow object.
|
| + v8::Handle<v8::Object> v8_global = context->Global();
|
| + v8_global->Set(implicit_proto_string, js_window);
|
| + return true;
|
| +}
|
| +
|
| // Create a new environment and setup the global object.
|
| //
|
| // The global object corresponds to a DOMWindow instance. However, to
|
| @@ -2205,11 +2290,9 @@
|
| // Allocate strings used during initialization.
|
| v8::Handle<v8::String> object_string = v8::String::New("Object");
|
| v8::Handle<v8::String> prototype_string = v8::String::New("prototype");
|
| - v8::Handle<v8::String> implicit_proto_string = v8::String::New("__proto__");
|
| // Bail out if allocation failed.
|
| if (object_string.IsEmpty() ||
|
| - prototype_string.IsEmpty() ||
|
| - implicit_proto_string.IsEmpty()) {
|
| + prototype_string.IsEmpty()) {
|
| DisposeContextHandles();
|
| return;
|
| }
|
| @@ -2231,33 +2314,9 @@
|
| RegisterGlobalHandle(PROXY, this, m_wrapper_boilerplates);
|
| #endif
|
|
|
| - // Create a new JS window object and use it as the prototype for the
|
| - // shadow global object.
|
| - v8::Handle<v8::Function> window_constructor =
|
| - GetConstructor(V8ClassIndex::DOMWINDOW);
|
| - v8::Local<v8::Object> js_window =
|
| - SafeAllocation::NewInstance(window_constructor);
|
| - // Bail out if allocation failed.
|
| - if (js_window.IsEmpty()) {
|
| + if (!installDOMWindow(context, m_frame->domWindow()))
|
| DisposeContextHandles();
|
| - return;
|
| - }
|
|
|
| - DOMWindow* window = m_frame->domWindow();
|
| -
|
| - // Wrap the window.
|
| - SetDOMWrapper(js_window,
|
| - V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW),
|
| - window);
|
| -
|
| - window->ref();
|
| - V8Proxy::SetJSWrapperForDOMObject(window,
|
| - v8::Persistent<v8::Object>::New(js_window));
|
| -
|
| - // Insert the window instance as the prototype of the shadow object.
|
| - v8::Handle<v8::Object> v8_global = context->Global();
|
| - v8_global->Set(implicit_proto_string, js_window);
|
| -
|
| updateDocument();
|
|
|
| SetSecurityToken();
|
|
|