From 34e6fb628673cfa7b56cad95b765ef3a0fc24f66 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Thu, 30 Jul 2009 16:57:15 +0200 Subject: implement QScriptContext::activationObject() --- src/script/api/qscriptcontext.cpp | 47 +++++++++++++++++++----- tests/auto/qscriptcontext/tst_qscriptcontext.cpp | 17 +++++---- tests/auto/qscriptengine/tst_qscriptengine.cpp | 7 ---- 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/script/api/qscriptcontext.cpp b/src/script/api/qscriptcontext.cpp index e820596..15e4efe 100644 --- a/src/script/api/qscriptcontext.cpp +++ b/src/script/api/qscriptcontext.cpp @@ -47,6 +47,7 @@ #include "qscriptcontextinfo.h" #include "qscriptengine.h" #include "qscriptengine_p.h" +#include "../bridge/qscriptactivationobject_p.h" #include "Arguments.h" #include "CodeBlock.h" @@ -432,14 +433,34 @@ void QScriptContext::setReturnValue(const QScriptValue &result) QScriptValue QScriptContext::activationObject() const { Q_D(const QScriptContext); - JSC::CodeBlock *codeBlock = d->frame->codeBlock(); - if (!codeBlock) { - qWarning("QScriptContext::activationObject() not implemented for native functions"); - return QScriptValue(); - } // ### this is still a bit shaky - JSC::FunctionBodyNode *body = static_cast(codeBlock->ownerNode()); - return d->engine->scriptValueFromJSCValue(new (&d->frame->globalData())JSC::JSActivation(d->frame, body)); + // if properties of the activation are accessed after this context is + // popped, we CRASH. + // Ideally we should be able to store the activation object in the callframe + // and JSC would clean it up for us. + JSC::JSObject *result = 0; + // look in scope chain + { + JSC::ScopeChainNode *node = d->frame->scopeChain(); + JSC::ScopeChainIterator it(node); + for (it = node->begin(); it != node->end(); ++it) { + if ((*it)->isVariableObject()) { + result = *it; + break; + } + } + } + if (!result) { + JSC::CodeBlock *codeBlock = d->frame->codeBlock(); + if (!codeBlock) { + // native function + result = new (d->frame)QScript::QScriptActivationObject(d->frame); + } else { + JSC::FunctionBodyNode *body = static_cast(codeBlock->ownerNode()); + result = new (d->frame)JSC::JSActivation(d->frame, body); + } + } + return d->engine->scriptValueFromJSCValue(result); } /*! @@ -450,8 +471,16 @@ QScriptValue QScriptContext::activationObject() const */ void QScriptContext::setActivationObject(const QScriptValue &activation) { - Q_ASSERT_X(false, Q_FUNC_INFO, "not implemented"); - Q_UNUSED(activation); + Q_D(QScriptContext); + if (!activation.isObject()) + return; + JSC::JSObject *object = JSC::asObject(d->engine->scriptValueToJSCValue(activation)); + if (!object->isVariableObject()) { + qWarning("QScriptContext::setActivationObject(): not an activation object"); + return; + } +// ### look for variableObject in d->frame->scopeChain, replace by object + qWarning("QScriptContext::setActivationObject() not implemented"); } /*! diff --git a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp index 3e32230..4726815 100644 --- a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp +++ b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp @@ -302,10 +302,10 @@ void tst_QScriptContext::returnValue() { QScriptEngine eng; eng.evaluate("123"); - QEXPECT_FAIL("", "Doesn't work", Continue); + QEXPECT_FAIL("", "", Continue); QCOMPARE(eng.currentContext()->returnValue().toNumber(), 123.0); eng.evaluate("\"ciao\""); - QEXPECT_FAIL("", "Doesn't work", Continue); + QEXPECT_FAIL("", "", Continue); QCOMPARE(eng.currentContext()->returnValue().toString(), QString("ciao")); } @@ -473,7 +473,6 @@ void tst_QScriptContext::pushAndPopContext() QCOMPARE(ctx->argument(0).isUndefined(), true); QVERIFY(!ctx->argument(-1).isValid()); QCOMPARE(ctx->argumentsObject().isObject(), true); - QEXPECT_FAIL("", "activationObject not yet implemented", Continue); QCOMPARE(ctx->activationObject().isObject(), true); QCOMPARE(ctx->callee().isValid(), false); QCOMPARE(ctx->thisObject().strictlyEquals(eng.globalObject()), true); @@ -499,10 +498,8 @@ void tst_QScriptContext::pushAndPopContext() { QScriptContext *ctx3 = eng.pushContext(); ctx3->activationObject().setProperty("foo", QScriptValue(&eng, 123)); - QEXPECT_FAIL("", "activationObject not yet implemented", Continue); QVERIFY(eng.evaluate("foo").strictlyEquals(QScriptValue(&eng, 123))); eng.evaluate("var bar = 'ciao'"); - QEXPECT_FAIL("", "activationObject not yet implemented", Continue); QVERIFY(ctx3->activationObject().property("bar", QScriptValue::ResolveLocal).strictlyEquals(QScriptValue(&eng, "ciao"))); eng.popContext(); } @@ -704,7 +701,6 @@ void tst_QScriptContext::getSetActivationObject() { QScriptEngine eng; QScriptContext *ctx = eng.currentContext(); - QEXPECT_FAIL("", "", Abort); QVERIFY(ctx->activationObject().equals(eng.globalObject())); ctx->setActivationObject(QScriptValue()); @@ -713,6 +709,7 @@ void tst_QScriptContext::getSetActivationObject() QScriptValue obj = eng.newObject(); ctx->setActivationObject(obj); + QEXPECT_FAIL("", "", Abort); QVERIFY(ctx->activationObject().equals(obj)); { @@ -729,8 +726,12 @@ void tst_QScriptContext::getSetActivationObject() { QScriptValue ret = eng.evaluate("get_activationObject(1, 2, 3)"); QVERIFY(ret.isObject()); - QVERIFY(ret.property("arguments").isObject()); - QCOMPARE(ret.property("arguments").property("length").toInt32(), 3); + QScriptValue arguments = ret.property("arguments"); + QVERIFY(arguments.isObject()); + QCOMPARE(arguments.property("length").toInt32(), 3); + QCOMPARE(arguments.property("0").toInt32(), 1); + QCOMPARE(arguments.property("1").toInt32(), 1); + QCOMPARE(arguments.property("2").toInt32(), 1); } } diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp index 74368c5..9067005 100644 --- a/tests/auto/qscriptengine/tst_qscriptengine.cpp +++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp @@ -163,7 +163,6 @@ void tst_QScriptEngine::currentContext() QVERIFY(!globalCtx->callee().isValid()); QCOMPARE(globalCtx->state(), QScriptContext::NormalState); QVERIFY(globalCtx->thisObject().strictlyEquals(eng.globalObject())); - QEXPECT_FAIL("", "", Continue); QVERIFY(globalCtx->activationObject().strictlyEquals(eng.globalObject())); QVERIFY(globalCtx->argumentsObject().isObject()); } @@ -183,14 +182,12 @@ void tst_QScriptEngine::pushPopContext() QCOMPARE(ctx->backtrace().size(), 2); QCOMPARE(ctx->engine(), &eng); QCOMPARE(ctx->state(), QScriptContext::NormalState); - QEXPECT_FAIL("", "activationObject not implemented", Continue); QVERIFY(ctx->activationObject().isObject()); QVERIFY(ctx->argumentsObject().isObject()); QScriptContext *ctx2 = eng.pushContext(); QVERIFY(ctx2 != 0); QCOMPARE(ctx2->parentContext(), ctx); - QEXPECT_FAIL("", "activationObject not implemented", Continue); QVERIFY(!ctx2->activationObject().strictlyEquals(ctx->activationObject())); QVERIFY(!ctx2->argumentsObject().strictlyEquals(ctx->argumentsObject())); @@ -890,7 +887,6 @@ void tst_QScriptEngine::getSetGlobalObject() QCOMPARE(glob.isObject(), true); QVERIFY(!glob.isFunction()); QVERIFY(eng.currentContext()->thisObject().strictlyEquals(glob)); - QEXPECT_FAIL("", "Activation object for global context", Continue); QVERIFY(eng.currentContext()->activationObject().strictlyEquals(glob)); QCOMPARE(glob.toString(), QString::fromLatin1("[object global]")); // prototype should be Object.prototype @@ -902,7 +898,6 @@ void tst_QScriptEngine::getSetGlobalObject() eng.setGlobalObject(obj); QVERIFY(eng.globalObject().strictlyEquals(obj)); QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj)); - QEXPECT_FAIL("", "this-object for global context", Continue); QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj)); QVERIFY(eng.evaluate("this").strictlyEquals(obj)); QCOMPARE(eng.globalObject().toString(), QString::fromLatin1("[object Object]")); @@ -913,13 +908,11 @@ void tst_QScriptEngine::getSetGlobalObject() eng.setGlobalObject(obj); QVERIFY(eng.globalObject().strictlyEquals(obj)); QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj)); - QEXPECT_FAIL("", "", Continue); QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj)); eng.collectGarbage(); QVERIFY(eng.globalObject().strictlyEquals(obj)); QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj)); - QEXPECT_FAIL("", "", Continue); QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj)); } -- cgit v0.12 ision on KURL, since that only looks at the text of the document's URL. Do base our decision on the securityOrigin(), which knows more about the document's actual origin. 2009-04-14 Eric Carlson Reviewed by Alexey Proskuryakov. Fix