diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/script/api/qscriptengine.cpp | 148 | ||||
-rw-r--r-- | src/script/api/qscriptengine_p.h | 9 | ||||
-rw-r--r-- | src/script/api/qscriptvalue.cpp | 9 | ||||
-rw-r--r-- | src/script/bridge/qscriptqobject.cpp | 25 | ||||
-rw-r--r-- | src/script/bridge/qscriptvariant.cpp | 8 |
5 files changed, 165 insertions, 34 deletions
diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index 2f7e976..1b7d0e4 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -321,7 +321,7 @@ struct GlobalClientData : public JSC::JSGlobalData::ClientData class GlobalObject : public JSC::JSGlobalObject { public: - GlobalObject(QScriptEnginePrivate*); + GlobalObject(); virtual ~GlobalObject(); virtual JSC::UString className() const { return "global"; } virtual void mark(); @@ -337,7 +337,44 @@ public: virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&); public: - QScriptEnginePrivate *engine; + JSC::JSObject *customGlobalObject; +}; + +class OriginalGlobalObjectProxy : public JSC::JSObject +{ +public: + explicit OriginalGlobalObjectProxy(WTF::PassRefPtr<JSC::Structure> sid, + JSC::JSGlobalObject *object) + : JSC::JSObject(sid), originalGlobalObject(object) + {} + virtual ~OriginalGlobalObjectProxy() + {} + virtual JSC::UString className() const + { return originalGlobalObject->className(); } + virtual void mark() + { + Q_ASSERT(!marked()); + if (!originalGlobalObject->marked()) + originalGlobalObject->JSC::JSGlobalObject::mark(); + JSC::JSObject::mark(); + } + virtual bool getOwnPropertySlot(JSC::ExecState* exec, + const JSC::Identifier& propertyName, + JSC::PropertySlot& slot) + { return originalGlobalObject->JSC::JSGlobalObject::getOwnPropertySlot(exec, propertyName, slot); } + virtual void put(JSC::ExecState* exec, const JSC::Identifier& propertyName, + JSC::JSValue value, JSC::PutPropertySlot& slot) + { originalGlobalObject->JSC::JSGlobalObject::put(exec, propertyName, value, slot); } + virtual bool deleteProperty(JSC::ExecState* exec, + const JSC::Identifier& propertyName) + { return originalGlobalObject->JSC::JSGlobalObject::deleteProperty(exec, propertyName); } + virtual bool getPropertyAttributes(JSC::ExecState* exec, const JSC::Identifier& propertyName, + unsigned& attributes) const + { return originalGlobalObject->JSC::JSGlobalObject::getPropertyAttributes(exec, propertyName, attributes); } + virtual void getPropertyNames(JSC::ExecState* exec, JSC::PropertyNameArray& propertyNames) + { originalGlobalObject->JSC::JSGlobalObject::getPropertyNames(exec, propertyNames); } +private: + JSC::JSGlobalObject *originalGlobalObject; }; static int toDigit(char c) @@ -585,8 +622,8 @@ JSC::JSValue functionConnect(JSC::ExecState *exec, JSC::JSObject */*callee*/, JS #endif // QT_NO_QOBJECT } -GlobalObject::GlobalObject(QScriptEnginePrivate *eng) - : JSC::JSGlobalObject(), engine(eng) +GlobalObject::GlobalObject() + : JSC::JSGlobalObject(), customGlobalObject(0) { } @@ -596,37 +633,52 @@ GlobalObject::~GlobalObject() void GlobalObject::mark() { + Q_ASSERT(!marked()); JSC::JSGlobalObject::mark(); + if (customGlobalObject && !customGlobalObject->marked()) + customGlobalObject->mark(); } bool GlobalObject::getOwnPropertySlot(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertySlot& slot) { + if (customGlobalObject) + return customGlobalObject->getOwnPropertySlot(exec, propertyName, slot); return JSC::JSGlobalObject::getOwnPropertySlot(exec, propertyName, slot); } void GlobalObject::put(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::JSValue value, JSC::PutPropertySlot& slot) { - JSC::JSGlobalObject::put(exec, propertyName, value, slot); + if (customGlobalObject) + customGlobalObject->put(exec, propertyName, value, slot); + else + JSC::JSGlobalObject::put(exec, propertyName, value, slot); } bool GlobalObject::deleteProperty(JSC::ExecState* exec, const JSC::Identifier& propertyName) { + if (customGlobalObject) + return customGlobalObject->deleteProperty(exec, propertyName); return JSC::JSGlobalObject::deleteProperty(exec, propertyName); } bool GlobalObject::getPropertyAttributes(JSC::ExecState* exec, const JSC::Identifier& propertyName, unsigned& attributes) const { + if (customGlobalObject) + return customGlobalObject->getPropertyAttributes(exec, propertyName, attributes); return JSC::JSGlobalObject::getPropertyAttributes(exec, propertyName, attributes); } void GlobalObject::getPropertyNames(JSC::ExecState* exec, JSC::PropertyNameArray& propertyNames) { - JSC::JSGlobalObject::getPropertyNames(exec, propertyNames); + if (customGlobalObject) + customGlobalObject->getPropertyNames(exec, propertyNames); + else + JSC::JSGlobalObject::getPropertyNames(exec, propertyNames); } static JSC::JSValue JSC_HOST_CALL functionPrint(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&); @@ -785,6 +837,7 @@ JSC::JSValue stringProtoFuncArg(JSC::ExecState *exec, JSC::JSObject*, JSC::JSVal namespace JSC { ASSERT_CLASS_FITS_IN_CELL(QScript::GlobalObject); +ASSERT_CLASS_FITS_IN_CELL(QScript::OriginalGlobalObjectProxy); } // namespace JSC @@ -796,7 +849,7 @@ QScriptEnginePrivate::QScriptEnginePrivate() : idGenerator(1) globalData = JSC::JSGlobalData::create().releaseRef(); globalData->clientData = new QScript::GlobalClientData(this); - JSC::JSGlobalObject *globalObject = new (globalData)QScript::GlobalObject(this); + JSC::JSGlobalObject *globalObject = new (globalData)QScript::GlobalObject(); JSC::ExecState* exec = globalObject->globalExec(); @@ -821,7 +874,7 @@ QScriptEnginePrivate::QScriptEnginePrivate() : idGenerator(1) currentFrame = exec; - customGlobalObject = 0; + originalGlobalObjectProxy = 0; agent = 0; processEventsInterval = -1; } @@ -1029,20 +1082,79 @@ void QScriptEnginePrivate::releaseContextForFrame(JSC::ExecState *frame) delete ctx; } -JSC::JSGlobalObject *QScriptEnginePrivate::globalObject() const +JSC::JSGlobalObject *QScriptEnginePrivate::originalGlobalObject() const { return globalData->head; } +JSC::JSObject *QScriptEnginePrivate::customGlobalObject() const +{ + QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject()); + return glob->customGlobalObject; +} + +JSC::JSObject *QScriptEnginePrivate::getOriginalGlobalObjectProxy() +{ + if (!originalGlobalObjectProxy) { + JSC::ExecState* exec = currentFrame; + originalGlobalObjectProxy = new (exec)QScript::OriginalGlobalObjectProxy(scriptObjectStructure, originalGlobalObject()); + } + return originalGlobalObjectProxy; +} + +JSC::JSObject *QScriptEnginePrivate::globalObject() const +{ + QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject()); + if (glob->customGlobalObject) + return glob->customGlobalObject; + return glob; +} + +void QScriptEnginePrivate::setGlobalObject(JSC::JSObject *object) +{ + if (object == globalObject()) + return; + QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject()); + if (object == originalGlobalObjectProxy) + glob->customGlobalObject = 0; + else { + Q_ASSERT(object != originalGlobalObject()); + glob->customGlobalObject = object; + } +} + JSC::ExecState *QScriptEnginePrivate::globalExec() const { - return globalObject()->globalExec(); + return originalGlobalObject()->globalExec(); +} + +/*! + \internal + + If the given \a value is the original global object, returns the custom + global object or a proxy to the original global object; otherwise returns \a + value. +*/ +JSC::JSValue QScriptEnginePrivate::toUsableValue(JSC::JSValue value) +{ + if (!value || !value.isObject() || !JSC::asObject(value)->isGlobalObject()) + return value; + Q_ASSERT(JSC::asObject(value) == originalGlobalObject()); + if (customGlobalObject()) + return customGlobalObject(); + if (!originalGlobalObjectProxy) + originalGlobalObjectProxy = new (currentFrame)QScript::OriginalGlobalObjectProxy(scriptObjectStructure, originalGlobalObject()); + return originalGlobalObjectProxy; } void QScriptEnginePrivate::mark() { - if (customGlobalObject && !customGlobalObject->marked()) - customGlobalObject->mark(); + if (!originalGlobalObject()->marked()) + originalGlobalObject()->mark(); + if (!globalObject()->marked()) + globalObject()->mark(); + if (originalGlobalObjectProxy && !originalGlobalObjectProxy->marked()) + originalGlobalObjectProxy->mark(); if (qobjectPrototype && !qobjectPrototype->marked()) qobjectPrototype->mark(); @@ -1086,9 +1198,6 @@ bool QScriptEnginePrivate::isCollecting() const void QScriptEnginePrivate::collectGarbage() { - // ### why isn't the global object always marked by the Collector? - if (!globalObject()->marked()) - globalObject()->mark(); JSC::JSLock lock(false); globalData->heap.collect(); } @@ -1385,11 +1494,10 @@ QScriptValue QScriptEngine::globalObject() const void QScriptEngine::setGlobalObject(const QScriptValue &object) { Q_D(QScriptEngine); - if (!object.isObject() || globalObject().strictlyEquals(object)) + if (!object.isObject()) return; JSC::JSObject *jscObject = JSC::asObject(d->scriptValueToJSCValue(object)); - qWarning("QScriptEngine::setGlobalObject() is not implemented"); -// d->customGlobalObject = jscObject; + d->setGlobalObject(jscObject); } /*! @@ -2410,7 +2518,7 @@ QScriptValue QScriptEnginePrivate::create(int type, const void *ptr) } } if (result.isObject() && info && info->prototype - && JSC::JSValue::strictEqual(scriptValueToJSCValue(result.prototype()), globalObject()->objectPrototype())) { + && JSC::JSValue::strictEqual(scriptValueToJSCValue(result.prototype()), originalGlobalObject()->objectPrototype())) { result.setPrototype(scriptValueFromJSCValue(info->prototype)); } return result; @@ -2671,7 +2779,7 @@ void QScriptEngine::installTranslatorFunctions(const QScriptValue &object) Q_D(QScriptEngine); JSC::ExecState* exec = d->currentFrame; JSC::JSValue jscObject = d->scriptValueToJSCValue(object); - JSC::JSGlobalObject *glob = d->globalObject(); + JSC::JSGlobalObject *glob = d->originalGlobalObject(); if (!jscObject || !jscObject.isObject()) jscObject = glob; // unsigned attribs = JSC::DontEnum; diff --git a/src/script/api/qscriptengine_p.h b/src/script/api/qscriptengine_p.h index 4db77c0..c0f5e13 100644 --- a/src/script/api/qscriptengine_p.h +++ b/src/script/api/qscriptengine_p.h @@ -110,8 +110,13 @@ public: QScriptContext *contextForFrame(JSC::ExecState *frame); void releaseContextForFrame(JSC::ExecState *frame); - JSC::JSGlobalObject *globalObject() const; + JSC::JSGlobalObject *originalGlobalObject() const; + JSC::JSObject *getOriginalGlobalObjectProxy(); + JSC::JSObject *customGlobalObject() const; + JSC::JSObject *globalObject() const; + void setGlobalObject(JSC::JSObject *object); JSC::ExecState *globalExec() const; + JSC::JSValue toUsableValue(JSC::JSValue value); void mark(); bool isCollecting() const; @@ -162,7 +167,7 @@ public: #endif JSC::JSGlobalData *globalData; - JSC::JSObject *customGlobalObject; + JSC::JSObject *originalGlobalObjectProxy; JSC::ExecState *currentFrame; QHash<JSC::ExecState*, QScriptContext*> contextForFrameHash; diff --git a/src/script/api/qscriptvalue.cpp b/src/script/api/qscriptvalue.cpp index 5ace14d..59e6729 100644 --- a/src/script/api/qscriptvalue.cpp +++ b/src/script/api/qscriptvalue.cpp @@ -276,19 +276,20 @@ QScriptValuePrivate::QScriptValueAutoRegister& QScriptValuePrivate::QScriptValue return *this; }; - void QScriptValuePrivate::initFromJSCValue(JSC::JSValue value) { - type = JSC; - jscValue = value; if (value.isCell()) { - JSC::JSCell *cell = value.asCell(); Q_ASSERT(engine != 0); QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine); + value = eng_p->toUsableValue(value); + JSC::JSCell *cell = JSC::asCell(value); + Q_ASSERT(cell != eng_p->originalGlobalObject()); if (!eng_p->keepAliveValues.contains(cell)) eng_p->keepAliveValues[cell] = 0; eng_p->keepAliveValues[cell].ref(); } + type = JSC; + jscValue = value; } void QScriptValuePrivate::initFromNumber(double value) diff --git a/src/script/bridge/qscriptqobject.cpp b/src/script/bridge/qscriptqobject.cpp index b065f5c..94bd8f9 100644 --- a/src/script/bridge/qscriptqobject.cpp +++ b/src/script/bridge/qscriptqobject.cpp @@ -487,6 +487,7 @@ JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue, const QMetaObject *meta = qobj->metaObject(); QObject *thisQObject = 0; + thisValue = engine->toUsableValue(thisValue); if (thisValue.isObject(&QScriptObject::info)) { delegate = static_cast<QScriptObject*>(JSC::asObject(thisValue))->delegate(); if (delegate && (delegate->type() == QScriptObjectDelegate::QtObject)) @@ -1029,6 +1030,7 @@ JSC::JSValue QtPropertyFunction::execute(JSC::ExecState *exec, // ### don't go via QScriptValue QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + thisValue = engine->toUsableValue(thisValue); QScriptValue object = engine->scriptValueFromJSCValue(thisValue); QObject *qobject = object.toQObject(); while ((!qobject || (qobject->metaObject() != data->meta)) @@ -1168,7 +1170,7 @@ bool QObjectDelegate::getOwnPropertySlot(QScriptObject *object, JSC::ExecState * || (index >= meta->methodOffset())) { QtFunction *fun = new (exec)QtFunction( object, index, /*maybeOverloaded=*/false, - &exec->globalData(), eng->globalObject()->functionStructure(), + &exec->globalData(), eng->originalGlobalObject()->functionStructure(), propertyName); slot.setValue(fun); data->cachedMembers.insert(name, fun); @@ -1187,7 +1189,7 @@ bool QObjectDelegate::getOwnPropertySlot(QScriptObject *object, JSC::ExecState * if (GeneratePropertyFunctions) { QtPropertyFunction *fun = new (exec)QtPropertyFunction( meta, index, &exec->globalData(), - eng->globalObject()->functionStructure(), + eng->originalGlobalObject()->functionStructure(), propertyName); data->cachedMembers.insert(name, fun); slot.setGetterSlot(fun); @@ -1219,7 +1221,7 @@ bool QObjectDelegate::getOwnPropertySlot(QScriptObject *object, JSC::ExecState * && (methodName(method) == name)) { QtFunction *fun = new (exec)QtFunction( object, index, /*maybeOverloaded=*/true, - &exec->globalData(), eng->globalObject()->functionStructure(), + &exec->globalData(), eng->originalGlobalObject()->functionStructure(), propertyName); slot.setValue(fun); data->cachedMembers.insert(name, fun); @@ -1292,7 +1294,7 @@ void QObjectDelegate::put(QScriptObject *object, JSC::ExecState* exec, } else { fun = new (exec)QtPropertyFunction( meta, index, &exec->globalData(), - eng->globalObject()->functionStructure(), + eng->originalGlobalObject()->functionStructure(), propertyName); data->cachedMembers.insert(name, fun); } @@ -1520,6 +1522,8 @@ void QObjectDelegate::mark(QScriptObject *object) static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChild(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisValue, const JSC::ArgList &args) { + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + thisValue = engine->toUsableValue(thisValue); if (!thisValue.isObject(&QScriptObject::info)) return throwError(exec, JSC::TypeError, "this object is not a QObject"); QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(thisValue)); @@ -1532,13 +1536,14 @@ static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChild(JSC::ExecState *exec name = QScript::qtStringFromJSCUString(args.at(0).toString(exec)); QObject *child = qFindChild<QObject*>(obj, name); QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject; - QScriptEnginePrivate *engine = scriptEngineFromExec(exec); return engine->newQObject(child, QScriptEngine::QtOwnership, opt); } static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChildren(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisValue, const JSC::ArgList &args) { + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + thisValue = engine->toUsableValue(thisValue); // extract the QObject if (!thisValue.isObject(&QScriptObject::info)) return throwError(exec, JSC::TypeError, "this object is not a QObject"); @@ -1547,7 +1552,6 @@ static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChildren(JSC::ExecState *e if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject)) return throwError(exec, JSC::TypeError, "this object is not a QObject"); const QObject *const obj = static_cast<QObjectDelegate*>(delegate)->value(); - QScriptEnginePrivate *engine = scriptEngineFromExec(exec); // find the children QList<QObject *> children; @@ -1562,7 +1566,7 @@ static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChildren(JSC::ExecState *e for (int i = 0; i < allChildrenCount; ++i) { QObject *const child = allChildren.at(i); const JSC::UString childName = qtStringToJSCUString(child->objectName()); - JSC::RegExpConstructor* regExpConstructor = engine->globalObject()->regExpConstructor(); + JSC::RegExpConstructor* regExpConstructor = engine->originalGlobalObject()->regExpConstructor(); int position; int length; regExpConstructor->performMatch(regexp->regExp(), childName, 0, position, length); @@ -1591,6 +1595,8 @@ static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChildren(JSC::ExecState *e static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncToString(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisValue, const JSC::ArgList&) { + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + thisValue = engine->toUsableValue(thisValue); if (!thisValue.isObject(&QScriptObject::info)) return JSC::jsUndefined(); QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(thisValue)); @@ -1771,10 +1777,11 @@ JSC::JSValue JSC_HOST_CALL QMetaObjectWrapperObject::call( JSC::ExecState *exec, JSC::JSObject *callee, JSC::JSValue thisValue, const JSC::ArgList &args) { + QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec); + thisValue = eng_p->toUsableValue(thisValue); if (!callee->isObject(&QMetaObjectWrapperObject::info)) return throwError(exec, JSC::TypeError, "callee is not a QMetaObject"); QMetaObjectWrapperObject *self = static_cast<QMetaObjectWrapperObject*>(callee); - QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec); JSC::ExecState *previousFrame = eng_p->currentFrame; eng_p->currentFrame = exec; JSC::JSValue result = self->execute(exec, args); @@ -1832,6 +1839,8 @@ struct StaticQtMetaObject : public QObject static JSC::JSValue JSC_HOST_CALL qmetaobjectProtoFuncClassName( JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisValue, const JSC::ArgList&) { + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + thisValue = engine->toUsableValue(thisValue); if (!thisValue.isObject(&QMetaObjectWrapperObject::info)) return throwError(exec, JSC::TypeError, "this object is not a QMetaObject"); const QMetaObject *meta = static_cast<QMetaObjectWrapperObject*>(JSC::asObject(thisValue))->value(); diff --git a/src/script/bridge/qscriptvariant.cpp b/src/script/bridge/qscriptvariant.cpp index 46da70a..752dd09 100644 --- a/src/script/bridge/qscriptvariant.cpp +++ b/src/script/bridge/qscriptvariant.cpp @@ -13,6 +13,9 @@ #ifndef QT_NO_SCRIPT +#include "../api/qscriptengine.h" +#include "../api/qscriptengine_p.h" + #include "Error.h" #include "PrototypeFunction.h" #include "JSString.h" @@ -28,6 +31,7 @@ namespace QScript { JSC::UString qtStringToJSCUString(const QString &str); +QScriptEnginePrivate *scriptEngineFromExec(JSC::ExecState*); QVariantDelegate::QVariantDelegate(const QVariant &value) : m_value(value) @@ -56,6 +60,8 @@ QScriptObjectDelegate::Type QVariantDelegate::type() const static JSC::JSValue JSC_HOST_CALL variantProtoFuncToString(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisValue, const JSC::ArgList&) { + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + thisValue = engine->toUsableValue(thisValue); if (!thisValue.isObject(&QScriptObject::info)) return throwError(exec, JSC::TypeError, "This object is not a QVariant"); QScriptObjectDelegate *delegate = static_cast<QScriptObject*>(JSC::asObject(thisValue))->delegate(); @@ -69,6 +75,8 @@ static JSC::JSValue JSC_HOST_CALL variantProtoFuncToString(JSC::ExecState *exec, static JSC::JSValue JSC_HOST_CALL variantProtoFuncValueOf(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisValue, const JSC::ArgList&) { + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + thisValue = engine->toUsableValue(thisValue); if (!thisValue.isObject(&QScriptObject::info)) return throwError(exec, JSC::TypeError); QScriptObjectDelegate *delegate = static_cast<QScriptObject*>(JSC::asObject(thisValue))->delegate(); |