示例#1
0
void ScriptExecutionContext::suspendActiveDOMObjectIfNeeded(ActiveDOMObject& activeDOMObject)
{
    ASSERT(m_activeDOMObjects.contains(&activeDOMObject));
    if (m_activeDOMObjectsAreSuspended)
        activeDOMObject.suspend(m_reasonForSuspendingActiveDOMObjects);
    if (m_activeDOMObjectsAreStopped)
        activeDOMObject.stop();
}
示例#2
0
    void visitDOMWrapper(DOMDataStore* store, T* object, v8::Persistent<v8::Object> wrapper)
    {
        WrapperTypeInfo* typeInfo = V8DOMWrapper::domWrapperType(wrapper);  

        if (!S::process(object, wrapper, typeInfo)) {
            ActiveDOMObject* activeDOMObject = typeInfo->toActiveDOMObject(wrapper);
            if (activeDOMObject && activeDOMObject->hasPendingActivity())
                wrapper.ClearWeak();
        }
    }
示例#3
0
    virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override
    {
        // A minor DOM GC can collect only Nodes.
        if (classId != WrapperTypeInfo::NodeClassId)
            return;

        // To make minor GC cycle time bounded, we limit the number of wrappers handled
        // by each minor GC cycle to 10000. This value was selected so that the minor
        // GC cycle time is bounded to 20 ms in a case where the new space size
        // is 16 MB and it is full of wrappers (which is almost the worst case).
        // Practically speaking, as far as I crawled real web applications,
        // the number of wrappers handled by each minor GC cycle is at most 3000.
        // So this limit is mainly for pathological micro benchmarks.
        const unsigned wrappersHandledByEachMinorGC = 10000;
        if (m_nodesInNewSpace.size() >= wrappersHandledByEachMinorGC)
            return;

        // Casting to a Handle is safe here, since the Persistent doesn't get GCd
        // during the GC prologue.
        ASSERT((*reinterpret_cast<v8::Handle<v8::Value>*>(value))->IsObject());
        v8::Handle<v8::Object>* wrapper = reinterpret_cast<v8::Handle<v8::Object>*>(value);
        ASSERT(V8DOMWrapper::isDOMWrapper(*wrapper));
        ASSERT(V8Node::hasInstance(*wrapper, m_isolate));
        Node* node = V8Node::toImpl(*wrapper);
        // A minor DOM GC can handle only node wrappers in the main world.
        // Note that node->wrapper().IsEmpty() returns true for nodes that
        // do not have wrappers in the main world.
        if (node->containsWrapper()) {
            const WrapperTypeInfo* type = toWrapperTypeInfo(*wrapper);
            ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(*wrapper);
            if (activeDOMObject && activeDOMObject->hasPendingActivity())
                return;
            // FIXME: Remove the special handling for image elements.
            // The same special handling is in V8GCController::opaqueRootForGC().
            // Maybe should image elements be active DOM nodes?
            // See https://code.google.com/p/chromium/issues/detail?id=164882
            if (isHTMLImageElement(*node) && toHTMLImageElement(*node).hasPendingActivity())
                return;
            // FIXME: Remove the special handling for SVG elements.
            // We currently can't collect SVG Elements from minor gc, as we have
            // strong references from SVG property tear-offs keeping context SVG element alive.
            if (node->isSVGElement())
                return;

            m_nodesInNewSpace.append(node);
            node->markV8CollectableDuringMinorGC();
        }
    }
示例#4
0
 void visitDOMWrapper(DOMDataStore* store, T* object, v8::Persistent<v8::Object> wrapper)
 {
     WrapperTypeInfo* typeInfo = V8DOMWrapper::domWrapperType(wrapper);
     if (!S::process(object, wrapper, typeInfo)) {
         ActiveDOMObject* activeDOMObject = typeInfo->toActiveDOMObject(wrapper);
         if (activeDOMObject && activeDOMObject->hasPendingActivity()) {
             ASSERT(!wrapper.IsWeak());
             // NOTE: To re-enable weak status of the active object we use
             // |object| from the map and not |activeDOMObject|. The latter
             // may be a different pointer (in case ActiveDOMObject is not
             // the main base class of the object's class) and pointer
             // identity is required by DOM map functions.
             wrapper.MakeWeak(object, callback);
         }
     }
 }
ScriptExecutionContext::~ScriptExecutionContext()
{
    m_inDestructor = true;
    for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != m_activeDOMObjects.end(); iter = m_activeDOMObjects.begin()) {
        ActiveDOMObject* object = iter->first;
        m_activeDOMObjects.remove(iter);
        ASSERT(object->scriptExecutionContext() == this);
        object->contextDestroyed();
    }

    HashSet<MessagePort*>::iterator messagePortsEnd = m_messagePorts.end();
    for (HashSet<MessagePort*>::iterator iter = m_messagePorts.begin(); iter != messagePortsEnd; ++iter) {
        ASSERT((*iter)->scriptExecutionContext() == this);
        (*iter)->contextDestroyed();
    }
#if ENABLE(SQL_DATABASE)
    if (m_databaseThread) {
        ASSERT(m_databaseThread->terminationRequested());
        m_databaseThread = 0;
    }
#endif
#if ENABLE(BLOB) || ENABLE(FILE_SYSTEM)
    if (m_fileThread) {
        m_fileThread->stop();
        m_fileThread = 0;
    }
#endif

#if ENABLE(BLOB)
    HashSet<String>::iterator publicBlobURLsEnd = m_publicBlobURLs.end();
    for (HashSet<String>::iterator iter = m_publicBlobURLs.begin(); iter != publicBlobURLsEnd; ++iter)
        ThreadableBlobRegistry::unregisterBlobURL(KURL(ParsedURLString, *iter));

    HashSet<DOMURL*>::iterator domUrlsEnd = m_domUrls.end();
    for (HashSet<DOMURL*>::iterator iter = m_domUrls.begin(); iter != domUrlsEnd; ++iter) {
        ASSERT((*iter)->scriptExecutionContext() == this);
        (*iter)->contextDestroyed();
    }
#endif

#if ENABLE(MEDIA_STREAM)
    HashSet<String>::iterator publicStreamURLsEnd = m_publicStreamURLs.end();
    for (HashSet<String>::iterator iter = m_publicStreamURLs.begin(); iter != publicStreamURLsEnd; ++iter)
        MediaStreamRegistry::registry().unregisterMediaStreamURL(KURL(ParsedURLString, *iter));
#endif
}
示例#6
0
void ContextLifecycleNotifier::notifyStoppingActiveDOMObjects()
{
    TemporaryChange<IterationType> scope(m_iterating, IteratingOverAll);
    Vector<UntracedMember<ContextLifecycleObserver>> snapshotOfObservers;
    copyToVector(m_observers, snapshotOfObservers);
    for (ContextLifecycleObserver* observer : snapshotOfObservers) {
        // It's possible that the ActiveDOMObject is already destructed.
        // See a FIXME above.
        if (m_observers.contains(observer)) {
            if (observer->observerType() != ContextLifecycleObserver::ActiveDOMObjectType)
                continue;
            ActiveDOMObject* activeDOMObject = static_cast<ActiveDOMObject*>(observer);
#if DCHECK_IS_ON()
            DCHECK_EQ(activeDOMObject->getExecutionContext(), context());
            DCHECK(activeDOMObject->suspendIfNeededCalled());
#endif
            activeDOMObject->stop();
        }
    }
}
示例#7
0
    void visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper)
    {
        WrapperTypeInfo* typeInfo = V8DOMWrapper::domWrapperType(wrapper);  

        // Additional handling of message port ensuring that entangled ports also
        // have their wrappers entangled. This should ideally be handled when the
        // ports are actually entangled in MessagePort::entangle, but to avoid
        // forking MessagePort.* this is postponed to GC time. Having this postponed
        // has the drawback that the wrappers are "entangled/unentangled" for each
        // GC even though their entaglement most likely is still the same.
        if (V8MessagePort::info.equals(typeInfo)) {
            // Mark each port as in-use if it's entangled. For simplicity's sake, we assume all ports are remotely entangled,
            // since the Chromium port implementation can't tell the difference.
            MessagePort* port1 = static_cast<MessagePort*>(object);
            if (port1->isEntangled() || port1->hasPendingActivity())
                wrapper.ClearWeak();
        } else {
            ActiveDOMObject* activeDOMObject = typeInfo->toActiveDOMObject(wrapper);
            if (activeDOMObject && activeDOMObject->hasPendingActivity())
                wrapper.ClearWeak();
        }
    }
示例#8
0
 void visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper)
 {
     WrapperTypeInfo* typeInfo = V8DOMWrapper::domWrapperType(wrapper);
     if (V8MessagePort::info.equals(typeInfo)) {
         MessagePort* port1 = static_cast<MessagePort*>(object);
         // We marked this port as reachable in GCPrologueVisitor.  Undo this now since the
         // port could be not reachable in the future if it gets disentangled (and also
         // GCPrologueVisitor expects to see all handles marked as weak).
         if ((!wrapper.IsWeak() && !wrapper.IsNearDeath()) || port1->hasPendingActivity())
             wrapper.MakeWeak(port1, &DOMDataStore::weakActiveDOMObjectCallback);
     } else {
         ActiveDOMObject* activeDOMObject = typeInfo->toActiveDOMObject(wrapper);
         if (activeDOMObject && activeDOMObject->hasPendingActivity()) {
             ASSERT(!wrapper.IsWeak());
             // NOTE: To re-enable weak status of the active object we use
             // |object| from the map and not |activeDOMObject|. The latter
             // may be a different pointer (in case ActiveDOMObject is not
             // the main base class of the object's class) and pointer
             // identity is required by DOM map functions.
             wrapper.MakeWeak(object, &DOMDataStore::weakActiveDOMObjectCallback);
         }
     }
 }
示例#9
0
    virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override
    {
        if (classId != WrapperTypeInfo::NodeClassId && classId != WrapperTypeInfo::ObjectClassId)
            return;

        // Casting to a Handle is safe here, since the Persistent doesn't get GCd
        // during the GC prologue.
        ASSERT((*reinterpret_cast<v8::Handle<v8::Value>*>(value))->IsObject());
        v8::Handle<v8::Object>* wrapper = reinterpret_cast<v8::Handle<v8::Object>*>(value);
        ASSERT(V8DOMWrapper::isDOMWrapper(*wrapper));

        if (value->IsIndependent())
            return;

        const WrapperTypeInfo* type = toWrapperTypeInfo(*wrapper);

        ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(*wrapper);
        if (activeDOMObject && activeDOMObject->hasPendingActivity()) {
            m_isolate->SetObjectGroupId(*value, liveRootId());
            ++m_domObjectsWithPendingActivity;
        }

        if (classId == WrapperTypeInfo::NodeClassId) {
            ASSERT(V8Node::hasInstance(*wrapper, m_isolate));
            Node* node = V8Node::toImpl(*wrapper);
            if (node->hasEventListeners())
                addReferencesForNodeWithEventListeners(m_isolate, node, v8::Persistent<v8::Object>::Cast(*value));
            Node* root = V8GCController::opaqueRootForGC(m_isolate, node);
            m_isolate->SetObjectGroupId(*value, v8::UniqueId(reinterpret_cast<intptr_t>(root)));
            if (m_constructRetainedObjectInfos)
                m_groupsWhichNeedRetainerInfo.append(root);
        } else if (classId == WrapperTypeInfo::ObjectClassId) {
            type->visitDOMWrapper(m_isolate, toScriptWrappableBase(*wrapper), v8::Persistent<v8::Object>::Cast(*value));
        } else {
            ASSERT_NOT_REACHED();
        }
    }
示例#10
0
void ContextLifecycleNotifier::notifyResumingActiveDOMObjects()
{
    TemporaryChange<IterationType> scope(m_iterating, IteratingOverAll);
    Vector<UntracedMember<ContextLifecycleObserver>> snapshotOfObservers;
    copyToVector(m_observers, snapshotOfObservers);
    for (ContextLifecycleObserver* observer : snapshotOfObservers) {
        // FIXME: Oilpan: At the moment, it's possible that a ActiveDOMObject
        // observer is destructed while iterating. Once we enable Oilpan by default
        // for all LifecycleObserver<T>s, we can remove the hack by making m_observers
        // a HeapHashSet<WeakMember<LifecycleObserver<T>>>.
        // (i.e., we can just iterate m_observers without taking a snapshot).
        // For more details, see https://codereview.chromium.org/247253002/.
        if (m_observers.contains(observer)) {
            if (observer->observerType() != ContextLifecycleObserver::ActiveDOMObjectType)
                continue;
            ActiveDOMObject* activeDOMObject = static_cast<ActiveDOMObject*>(observer);
#if DCHECK_IS_ON()
            DCHECK_EQ(activeDOMObject->getExecutionContext(), context());
            DCHECK(activeDOMObject->suspendIfNeededCalled());
#endif
            activeDOMObject->resume();
        }
    }
}