v8::V8::SetUserObjectComparisonCallbackFunction(ObjectComparisonCallback);
QV8GCCallback::registerGcPrologueCallback();
+ m_strongReferencer = qPersistentNew(v8::Object::New());
m_stringWrapper.init();
m_contextWrapper.init(this);
invalidateAllValues();
clearExceptions();
+ qPersistentDispose(m_strongReferencer);
+
m_sequenceWrapper.destroy();
m_valueTypeWrapper.destroy();
m_variantWrapper.destroy();
return QV8DateConverter::JSC::gregorianDateTimeToMS(tm, time.msec());
}
+v8::Persistent<v8::Object> *QV8Engine::findOwnerAndStrength(QObject *object, bool *shouldBeStrong)
+{
+ QObject *parent = object->parent();
+ if (!parent) {
+ // if the object has JS ownership, the object's v8object owns the lifetime of the persistent value.
+ if (QDeclarativeEngine::objectOwnership(object) == QDeclarativeEngine::JavaScriptOwnership) {
+ *shouldBeStrong = false;
+ return &(QDeclarativeData::get(object)->v8object);
+ }
+
+ // no parent, and has CPP ownership - doesn't have an implicit parent.
+ *shouldBeStrong = true;
+ return 0;
+ }
+
+ // if it is owned by CPP, it's root parent may still be owned by JS.
+ // in that case, the owner of the persistent handle is the root parent's v8object.
+ while (parent->parent())
+ parent = parent->parent();
+
+ if (QDeclarativeEngine::objectOwnership(parent) == QDeclarativeEngine::JavaScriptOwnership) {
+ // root parent is owned by JS. It's v8object owns the persistent value in question.
+ *shouldBeStrong = false;
+ return &(QDeclarativeData::get(parent)->v8object);
+ } else {
+ // root parent has CPP ownership. The persistent value should not be made weak.
+ *shouldBeStrong = true;
+ return 0;
+ }
+}
+
QDateTime QV8Engine::qtDateTimeFromJsDate(double jsDate)
{
// from QScriptEngine::MsToDateTime()
return convertedUTC.toLocalTime();
}
+void QV8Engine::addRelationshipForGC(QObject *object, v8::Persistent<v8::Value> handle)
+{
+ if (handle.IsEmpty())
+ return;
+
+ bool handleShouldBeStrong = false;
+ v8::Persistent<v8::Object> *implicitOwner = findOwnerAndStrength(object, &handleShouldBeStrong);
+ if (handleShouldBeStrong) {
+ v8::V8::AddImplicitReferences(m_strongReferencer, &handle, 1);
+ } else if (!implicitOwner->IsEmpty()) {
+ v8::V8::AddImplicitReferences(*implicitOwner, &handle, 1);
+ }
+}
+
+void QV8Engine::addRelationshipForGC(QObject *object, QObject *other)
+{
+ bool handleShouldBeStrong = false;
+ v8::Persistent<v8::Object> *implicitOwner = findOwnerAndStrength(object, &handleShouldBeStrong);
+ v8::Persistent<v8::Value> handle = QDeclarativeData::get(other, true)->v8object;
+ if (handleShouldBeStrong) {
+ v8::V8::AddImplicitReferences(m_strongReferencer, &handle, 1);
+ } else if (!implicitOwner->IsEmpty()) {
+ v8::V8::AddImplicitReferences(*implicitOwner, &handle, 1);
+ }
+}
+
static QThreadStorage<QV8Engine::ThreadData*> perThreadEngineData;
bool QV8Engine::hasThreadData()
QV8Engine::ThreadData *td = QV8Engine::threadData();
if (!td->gcPrologueCallbackRegistered) {
td->gcPrologueCallbackRegistered = true;
- if (!td->referencer)
- td->referencer = new QV8GCCallback::Referencer;
v8::V8::AddGCPrologueCallback(QV8GCCallback::garbageCollectorPrologueCallback, v8::kGCTypeMarkSweepCompact);
}
}
node.remove();
}
-QV8GCCallback::Referencer::~Referencer()
-{
- dispose();
-}
-
-QV8GCCallback::Referencer::Referencer()
-{
- v8::HandleScope handleScope;
- context = v8::Context::New();
- qPersistentRegister(context);
- v8::Context::Scope contextScope(context);
- strongReferencer = qPersistentNew(v8::Object::New());
-}
-
-void QV8GCCallback::Referencer::addRelationship(QObject *object, QObject *other)
-{
- bool handleShouldBeStrong = false;
- v8::Persistent<v8::Object> *implicitOwner = findOwnerAndStrength(object, &handleShouldBeStrong);
- v8::Persistent<v8::Value> handle = QDeclarativeData::get(other, true)->v8object;
- if (handleShouldBeStrong) {
- v8::V8::AddImplicitReferences(strongReferencer, &handle, 1);
- } else if (!implicitOwner->IsEmpty()) {
- v8::V8::AddImplicitReferences(*implicitOwner, &handle, 1);
- }
-}
-
-void QV8GCCallback::Referencer::dispose()
-{
- if (!strongReferencer.IsEmpty()) {
- Q_ASSERT_X(v8::Isolate::GetCurrent(), "QV8GCCallback::Referencer::~Referencer()", "called after v8::Isolate has exited");
- // automatically release the strongReferencer if it hasn't
- // been explicitly released already.
- qPersistentDispose(strongReferencer);
- }
- if (!context.IsEmpty())
- qPersistentDispose(context);
-}
-
-void QV8GCCallback::Referencer::addRelationship(QObject *object, v8::Persistent<v8::Value> handle)
-{
- if (handle.IsEmpty())
- return;
-
- bool handleShouldBeStrong = false;
- v8::Persistent<v8::Object> *implicitOwner = findOwnerAndStrength(object, &handleShouldBeStrong);
- if (handleShouldBeStrong) {
- v8::V8::AddImplicitReferences(strongReferencer, &handle, 1);
- } else if (!implicitOwner->IsEmpty()) {
- v8::V8::AddImplicitReferences(*implicitOwner, &handle, 1);
- }
-}
-
-v8::Persistent<v8::Object> *QV8GCCallback::Referencer::findOwnerAndStrength(QObject *object, bool *shouldBeStrong)
-{
- QObject *parent = object->parent();
- if (!parent) {
- // if the object has JS ownership, the object's v8object owns the lifetime of the persistent value.
- if (QDeclarativeEngine::objectOwnership(object) == QDeclarativeEngine::JavaScriptOwnership) {
- *shouldBeStrong = false;
- return &(QDeclarativeData::get(object)->v8object);
- }
-
- // no parent, and has CPP ownership - doesn't have an implicit parent.
- *shouldBeStrong = true;
- return 0;
- }
-
- // if it is owned by CPP, it's root parent may still be owned by JS.
- // in that case, the owner of the persistent handle is the root parent's v8object.
- while (parent->parent())
- parent = parent->parent();
-
- if (QDeclarativeEngine::objectOwnership(parent) == QDeclarativeEngine::JavaScriptOwnership) {
- // root parent is owned by JS. It's v8object owns the persistent value in question.
- *shouldBeStrong = false;
- return &(QDeclarativeData::get(parent)->v8object);
- } else {
- // root parent has CPP ownership. The persistent value should not be made weak.
- *shouldBeStrong = true;
- return 0;
- }
-}
-
/*
Ensure that each persistent handle is strong if it has CPP ownership
and has no implicitly JS owned object owner in its parent chain, and
return;
QV8Engine::ThreadData *td = QV8Engine::threadData();
- Q_ASSERT(td->referencer);
QV8GCCallback::Node *currNode = td->gcCallbackNodes.first();
while (currNode) {
// The client which adds itself to the list is responsible
// for maintaining the correct implicit references in the
// specified callback.
- currNode->prologueCallback(td->referencer, currNode);
+ currNode->prologueCallback(currNode);
currNode = td->gcCallbackNodes.next(currNode);
}
}
}
QV8Engine::ThreadData::ThreadData()
- : referencer(0)
- , gcPrologueCallbackRegistered(false)
+ : gcPrologueCallbackRegistered(false)
{
if (!v8::Isolate::GetCurrent()) {
isolate = v8::Isolate::New();
QV8Engine::ThreadData::~ThreadData()
{
- delete referencer;
- referencer = 0;
if (isolate) {
isolate->Exit();
isolate->Dispose();
static void garbageCollectorPrologueCallback(v8::GCType, v8::GCCallbackFlags);
static void registerGcPrologueCallback();
- class Q_AUTOTEST_EXPORT Referencer {
- public:
- ~Referencer();
- void addRelationship(QObject *object, v8::Persistent<v8::Value> handle);
- void addRelationship(QObject *object, QObject *other);
- void dispose();
- private:
- Referencer();
- static v8::Persistent<v8::Object> *findOwnerAndStrength(QObject *qobjectOwner, bool *shouldBeStrong);
- v8::Persistent<v8::Object> strongReferencer;
- v8::Persistent<v8::Context> context;
- friend class QV8GCCallback;
- };
-
class Q_AUTOTEST_EXPORT Node {
public:
- typedef void (*PrologueCallback)(Referencer *r, Node *node);
+ typedef void (*PrologueCallback)(Node *node);
Node(PrologueCallback callback);
~Node();
static QDateTime qtDateTimeFromJsDate(double jsDate);
+ void addRelationshipForGC(QObject *object, v8::Persistent<v8::Value> handle);
+ void addRelationshipForGC(QObject *object, QObject *other);
+
struct ThreadData {
ThreadData();
~ThreadData();
v8::Isolate* isolate;
- QV8GCCallback::Referencer* referencer;
bool gcPrologueCallbackRegistered;
QIntrusiveList<QV8GCCallback::Node, &QV8GCCallback::Node::node> gcCallbackNodes;
};
static ThreadData* threadData();
static void ensurePerThreadIsolate();
+ v8::Persistent<v8::Object> m_strongReferencer;
+
protected:
QJSEngine* q;
QDeclarativeEngine *m_engine;
double qtDateTimeToJsDate(const QDateTime &dt);
private:
+ static v8::Persistent<v8::Object> *findOwnerAndStrength(QObject *object, bool *shouldBeStrong);
+
typedef QScriptIntrusiveList<QJSValuePrivate, &QJSValuePrivate::m_node> ValueList;
ValueList m_values;
typedef QScriptIntrusiveList<QJSValueIteratorPrivate, &QJSValueIteratorPrivate::m_node> ValueIteratorList;
{
CircularReferenceObject *retn = new CircularReferenceObject(parent);
retn->m_dtorCount = m_dtorCount;
+ retn->m_engine = m_engine;
return retn;
}
m_referenced = other;
}
- static void callback(QV8GCCallback::Referencer *r, QV8GCCallback::Node *n)
+ static void callback(QV8GCCallback::Node *n)
{
CircularReferenceObject *cro = static_cast<CircularReferenceObject*>(n);
if (cro->m_referenced) {
- r->addRelationship(cro, cro->m_referenced);
+ cro->m_engine->addRelationshipForGC(cro, cro->m_referenced);
}
}
+ void setEngine(QDeclarativeEngine* declarativeEngine)
+ {
+ m_engine = QDeclarativeEnginePrivate::get(declarativeEngine)->v8engine();
+ }
+
private:
QObject *m_referenced;
int *m_dtorCount;
+ QV8Engine* m_engine;
};
Q_DECLARE_METATYPE(CircularReferenceObject*)
public:
CircularReferenceHandle(QObject *parent = 0)
- : QObject(parent), QV8GCCallback::Node(gccallback), m_dtorCount(0)
+ : QObject(parent), QV8GCCallback::Node(gccallback), m_dtorCount(0), m_engine(0)
{
QV8GCCallback::addGcCallbackNode(this);
}
{
CircularReferenceHandle *retn = new CircularReferenceHandle(parent);
retn->m_dtorCount = m_dtorCount;
+ retn->m_engine = m_engine;
return retn;
}
crh->m_referenced.Clear();
}
- static void gccallback(QV8GCCallback::Referencer *r, QV8GCCallback::Node *n)
+ static void gccallback(QV8GCCallback::Node *n)
{
CircularReferenceHandle *crh = static_cast<CircularReferenceHandle*>(n);
- r->addRelationship(crh, crh->m_referenced);
+ crh->m_engine->addRelationshipForGC(crh, crh->m_referenced);
+ }
+
+ void setEngine(QDeclarativeEngine* declarativeEngine)
+ {
+ m_engine = QDeclarativeEnginePrivate::get(declarativeEngine)->v8engine();
}
private:
v8::Persistent<v8::Value> m_referenced;
int *m_dtorCount;
+ QV8Engine* m_engine;
};
Q_DECLARE_METATYPE(CircularReferenceHandle*)
QObject *object = component.create();
QVERIFY(object != 0);
CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
+ cro->setEngine(&hrmEngine);
cro->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object, "createReference");
gc(engine);
QObject *object = component.create();
QVERIFY(object != 0);
CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
+ cro->setEngine(&hrmEngine);
cro->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object, "circularReference");
gc(engine);
QVERIFY(object != 0);
CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
QVERIFY(crh != 0);
+ crh->setEngine(&hrmEngine);
crh->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object, "createReference");
CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
QVERIFY(object != 0);
CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
QVERIFY(crh != 0);
+ crh->setEngine(&hrmEngine);
crh->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object, "circularReference");
CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
QVERIFY(crh1 != 0);
QVERIFY(crh2 != 0);
+ crh1->setEngine(&hrmEngine1);
+ crh2->setEngine(&hrmEngine2);
crh1->setDtorCount(&dtorCount);
crh2->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object1, "createReference");
CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
QVERIFY(crh1 != 0);
QVERIFY(crh2 != 0);
+ crh1->setEngine(&hrmEngine1);
+ crh2->setEngine(&hrmEngine2);
crh1->setDtorCount(&dtorCount);
crh2->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object1, "createReference");
CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
QVERIFY(crh1 != 0);
QVERIFY(crh2 != 0);
+ crh1->setEngine(hrmEngine1);
+ crh2->setEngine(hrmEngine2);
crh1->setDtorCount(&dtorCount);
crh2->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object1, "createReference");