void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override { // If we have already found any wrapper that has a pending activity, // we don't need to check other wrappers. if (m_pendingActivityFound) return; if (classId != WrapperTypeInfo::NodeClassId && classId != WrapperTypeInfo::ObjectClassId) return; const v8::Persistent<v8::Object>& wrapper = v8::Persistent<v8::Object>::Cast(*value); const WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); // The ExecutionContext check is heavy, so it should be done at the last. if (type != npObjectTypeInfo() && toScriptWrappable(wrapper)->hasPendingActivity() // TODO(haraken): Currently we don't have a way to get a creation // context from a wrapper. We should implement the way and enable // the following condition. // // This condition affects only compositor workers, where one isolate // is shared by multiple workers. If we don't have the condition, // a worker object for a compositor worker doesn't get collected // until all compositor workers in the same isolate lose pending // activities. In other words, not having the condition delays // destruction of a worker object of a compositor worker. // /* && toExecutionContext(wrapper->creationContext()) == m_executionContext */ ) m_pendingActivityFound = true; }
bool isWrappedNPObject(v8::Handle<v8::Object> object) { if (object->InternalFieldCount() == npObjectInternalFieldCount) { const WrapperTypeInfo* typeInfo = static_cast<const WrapperTypeInfo*>(object->GetAlignedPointerFromInternalField(v8DOMWrapperTypeIndex)); return typeInfo == npObjectTypeInfo(); } return false; }
void forgetV8ObjectForNPObject(NPObject* object) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::HandleScope scope(isolate); v8::Handle<v8::Object> wrapper = staticNPObjectMap().getNewLocal(isolate, object); if (!wrapper.IsEmpty()) { V8DOMWrapper::clearNativeInfo(wrapper, npObjectTypeInfo()); staticNPObjectMap().removeAndDispose(object); _NPN_ReleaseObject(object); } }
v8::Local<v8::Object> createV8ObjectForNPObject(NPObject* object, NPObject* root) { static v8::Persistent<v8::FunctionTemplate> npObjectDesc; ASSERT(v8::Context::InContext()); v8::Isolate* isolate = v8::Isolate::GetCurrent(); // If this is a v8 object, just return it. V8NPObject* v8NPObject = npObjectToV8NPObject(object); if (v8NPObject) return v8::Local<v8::Object>::New(isolate, v8NPObject->v8Object); // If we've already wrapped this object, just return it. v8::Handle<v8::Object> wrapper = staticNPObjectMap().get(object); if (!wrapper.IsEmpty()) return v8::Local<v8::Object>::New(isolate, wrapper); // FIXME: we should create a Wrapper type as a subclass of JSObject. It has two internal fields, field 0 is the wrapped // pointer, and field 1 is the type. There should be an api function that returns unused type id. The same Wrapper type // can be used by DOM bindings. if (npObjectDesc.IsEmpty()) { v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); templ->InstanceTemplate()->SetInternalFieldCount(npObjectInternalFieldCount); templ->InstanceTemplate()->SetNamedPropertyHandler(npObjectNamedPropertyGetter, npObjectNamedPropertySetter, npObjectQueryProperty, 0, npObjectNamedPropertyEnumerator); templ->InstanceTemplate()->SetIndexedPropertyHandler(npObjectIndexedPropertyGetter, npObjectIndexedPropertySetter, 0, 0, npObjectIndexedPropertyEnumerator); templ->InstanceTemplate()->SetCallAsFunctionHandler(npObjectInvokeDefaultHandler); npObjectDesc.Reset(isolate, templ); } // FIXME: Move staticNPObjectMap() to DOMDataStore. // Use V8DOMWrapper::createWrapper() and // V8DOMWrapper::associateObjectWithWrapper() // to create a wrapper object. v8::Handle<v8::Function> v8Function = v8::Local<v8::FunctionTemplate>::New(isolate, npObjectDesc)->GetFunction(); v8::Local<v8::Object> value = V8ObjectConstructor::newInstance(v8Function); if (value.IsEmpty()) return value; V8DOMWrapper::setNativeInfo(value, npObjectTypeInfo(), object); // KJS retains the object as part of its wrapper (see Bindings::CInstance). _NPN_RetainObject(object); _NPN_RegisterObject(object, root); WrapperConfiguration configuration = buildWrapperConfiguration(object, WrapperConfiguration::Dependent); staticNPObjectMap().set(object, value, configuration); ASSERT(V8DOMWrapper::maybeDOMWrapper(value)); return value; }
void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override { if (classId != WrapperTypeInfo::NodeClassId && classId != WrapperTypeInfo::ObjectClassId) { return; } // MinorGC does not collect objects because it may be expensive to // update references during minorGC if (classId == WrapperTypeInfo::ObjectClassId) { v8::Persistent<v8::Object>::Cast(*value).MarkActive(); return; } v8::Local<v8::Object> wrapper = v8::Local<v8::Object>::New(m_isolate, v8::Persistent<v8::Object>::Cast(*value)); ASSERT(V8DOMWrapper::hasInternalFieldsSet(wrapper)); const WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); if (type != npObjectTypeInfo() && toScriptWrappable(wrapper)->hasPendingActivity()) { v8::Persistent<v8::Object>::Cast(*value).MarkActive(); return; } if (classId == WrapperTypeInfo::NodeClassId) { ASSERT(V8Node::hasInstance(wrapper, m_isolate)); Node* node = V8Node::toImpl(wrapper); if (node->hasEventListeners()) { v8::Persistent<v8::Object>::Cast(*value).MarkActive(); 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()) { v8::Persistent<v8::Object>::Cast(*value).MarkActive(); 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()) { v8::Persistent<v8::Object>::Cast(*value).MarkActive(); return; } } }
NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle<v8::Object> object, DOMWindow* root, v8::Isolate* isolate) { // Check to see if this object is already wrapped. if (object->InternalFieldCount() == npObjectInternalFieldCount) { const WrapperTypeInfo* typeInfo = static_cast<const WrapperTypeInfo*>(object->GetAlignedPointerFromInternalField(v8DOMWrapperTypeIndex)); if (typeInfo == npObjectTypeInfo()) { NPObject* returnValue = v8ObjectToNPObject(object); _NPN_RetainObject(returnValue); return returnValue; } } V8NPObjectVector* objectVector = 0; if (V8PerContextData* perContextData = V8PerContextData::from(object->CreationContext())) { int v8ObjectHash = object->GetIdentityHash(); ASSERT(v8ObjectHash); V8NPObjectMap* v8NPObjectMap = perContextData->v8NPObjectMap(); V8NPObjectMap::iterator iter = v8NPObjectMap->find(v8ObjectHash); if (iter != v8NPObjectMap->end()) { V8NPObjectVector& objects = iter->value; for (size_t index = 0; index < objects.size(); ++index) { V8NPObject* v8npObject = objects.at(index); if (v8npObject->v8Object == object && v8npObject->rootObject == root) { _NPN_RetainObject(&v8npObject->object); return reinterpret_cast<NPObject*>(v8npObject); } } } else { iter = v8NPObjectMap->set(v8ObjectHash, V8NPObjectVector()).iterator; } objectVector = &iter->value; } V8NPObject* v8npObject = reinterpret_cast<V8NPObject*>(_NPN_CreateObject(npp, &V8NPObjectClass)); // This is uninitialized memory, we need to clear it so that // Persistent::Reset won't try to Dispose anything bogus. v8npObject->v8Object.Clear(); v8npObject->v8Object.Reset(isolate, object); v8npObject->rootObject = root; if (objectVector) objectVector->append(v8npObject); return reinterpret_cast<NPObject*>(v8npObject); }
NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle<v8::Object> object, DOMWindow* root) { // Check to see if this object is already wrapped. if (object->InternalFieldCount() == npObjectInternalFieldCount) { WrapperTypeInfo* typeInfo = static_cast<WrapperTypeInfo*>(object->GetAlignedPointerFromInternalField(v8DOMWrapperTypeIndex)); if (typeInfo == npObjectTypeInfo()) { NPObject* returnValue = v8ObjectToNPObject(object); _NPN_RetainObject(returnValue); return returnValue; } } V8NPObjectVector* objectVector = 0; if (V8PerContextData* perContextData = V8PerContextData::from(object->CreationContext())) { int v8ObjectHash = object->GetIdentityHash(); ASSERT(v8ObjectHash); V8NPObjectMap* v8NPObjectMap = perContextData->v8NPObjectMap(); V8NPObjectMap::iterator iter = v8NPObjectMap->find(v8ObjectHash); if (iter != v8NPObjectMap->end()) { V8NPObjectVector& objects = iter->value; for (size_t index = 0; index < objects.size(); ++index) { V8NPObject* v8npObject = objects.at(index); if (v8npObject->v8Object == object && v8npObject->rootObject == root) { _NPN_RetainObject(&v8npObject->object); return reinterpret_cast<NPObject*>(v8npObject); } } } else { iter = v8NPObjectMap->set(v8ObjectHash, V8NPObjectVector()).iterator; } objectVector = &iter->value; } V8NPObject* v8npObject = reinterpret_cast<V8NPObject*>(_NPN_CreateObject(npp, &V8NPObjectClass)); v8npObject->v8Object = v8::Persistent<v8::Object>::New(v8::Isolate::GetCurrent(), object); v8npObject->rootObject = root; if (objectVector) objectVector->append(v8npObject); return reinterpret_cast<NPObject*>(v8npObject); }
NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle<v8::Object> object, DOMWindow* root) { // Check to see if this object is already wrapped. if (object->InternalFieldCount() == npObjectInternalFieldCount) { WrapperTypeInfo* typeInfo = static_cast<WrapperTypeInfo*>(object->GetPointerFromInternalField(v8DOMWrapperTypeIndex)); if (typeInfo == npObjectTypeInfo()) { NPObject* returnValue = v8ObjectToNPObject(object); _NPN_RetainObject(returnValue); return returnValue; } } V8NPObject* v8npObject = reinterpret_cast<V8NPObject*>(_NPN_CreateObject(npp, &V8NPObjectClass)); v8npObject->v8Object = v8::Persistent<v8::Object>::New(object); #ifndef NDEBUG V8GCController::registerGlobalHandle(NPOBJECT, v8npObject, v8npObject->v8Object); #endif v8npObject->rootObject = root; return reinterpret_cast<NPObject*>(v8npObject); }
void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override { if (classId != WrapperTypeInfo::NodeClassId && classId != WrapperTypeInfo::ObjectClassId) return; v8::Local<v8::Object> wrapper = v8::Local<v8::Object>::New(m_isolate, v8::Persistent<v8::Object>::Cast(*value)); ASSERT(V8DOMWrapper::hasInternalFieldsSet(wrapper)); const WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); if (type != npObjectTypeInfo() && toScriptWrappable(wrapper)->hasPendingActivity()) { // If you hit this assert, you'll need to add a [DependentiLifetime] // extended attribute to the DOM interface. A DOM interface that // overrides hasPendingActivity must be marked as [DependentiLifetime]. RELEASE_ASSERT(!value->IsIndependent()); m_isolate->SetObjectGroupId(*value, liveRootId()); ++m_domObjectsWithPendingActivity; } if (value->IsIndependent()) return; 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, toScriptWrappable(wrapper), v8::Persistent<v8::Object>::Cast(*value)); } else { ASSERT_NOT_REACHED(); } }