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(); } }
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(); } }
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); } } }
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(); } }
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); } } }
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(); } }