summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/script/api/qscriptcontext.cpp7
-rw-r--r--src/script/api/qscriptcontextinfo.cpp20
-rw-r--r--tests/auto/qscriptcontext/tst_qscriptcontext.cpp41
-rw-r--r--tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp1
-rw-r--r--tests/auto/qscriptengine/tst_qscriptengine.cpp32
5 files changed, 88 insertions, 13 deletions
diff --git a/src/script/api/qscriptcontext.cpp b/src/script/api/qscriptcontext.cpp
index 669002d..f4b8af6 100644
--- a/src/script/api/qscriptcontext.cpp
+++ b/src/script/api/qscriptcontext.cpp
@@ -273,8 +273,7 @@ QScriptValue QScriptContext::argument(int index) const
if (index >= argumentCount())
return QScriptValue(QScriptValue::UndefinedValue);
JSC::Register* thisRegister = frame->registers() - JSC::RegisterFile::CallFrameHeaderSize - frame->argumentCount();
- if (frame->codeBlock() == 0)
- ++index; // ### off-by-one issue with native functions
+ ++index; //skip the 'this' object
return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(thisRegister[index].jsValue());
}
@@ -370,9 +369,7 @@ bool QScriptContext::isCalledAsConstructor() const
QScriptContext *QScriptContext::parentContext() const
{
const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
- JSC::CallFrame *callerFrame = frame->callerFrame();
- if (callerFrame == (JSC::CallFrame*)(1)) // ### CallFrame::noCaller() is private
- return 0;
+ JSC::CallFrame *callerFrame = frame->callerFrame()->removeHostCallFrameFlag();
return reinterpret_cast<QScriptContext *>(callerFrame);
}
diff --git a/src/script/api/qscriptcontextinfo.cpp b/src/script/api/qscriptcontextinfo.cpp
index 52776e2..20b77f0 100644
--- a/src/script/api/qscriptcontextinfo.cpp
+++ b/src/script/api/qscriptcontextinfo.cpp
@@ -174,8 +174,6 @@ QScriptContextInfoPrivate::QScriptContextInfoPrivate(const QScriptContext *conte
for (size_t i = 0; i < body->parameterCount(); ++i)
parameterNames.append(QScript::qtStringFromJSCUString(params[i].ustring()));
// ### get the function name from the AST
- // ### don't know the PC, since it's not stored in the frame
- // lineNumber = codeBlock->expressionRangeForBytecodeOffset(...);
} else if (callee && callee->isObject(&QScript::QtFunction::info)) {
functionType = QScriptContextInfo::QtFunction;
// ### the slot can be overloaded -- need to get the particular overload from the context
@@ -192,6 +190,24 @@ QScriptContextInfoPrivate::QScriptContextInfoPrivate(const QScriptContext *conte
functionType = QScriptContextInfo::QtPropertyFunction;
functionMetaIndex = static_cast<QScript::QtPropertyFunction*>(callee)->propertyIndex();
}
+
+ // get the lineNumber:
+ QScriptContext *rewindContext = context->engine()->currentContext();
+ if (rewindContext == context) {
+ //ignore native function
+ } else {
+ // rewind the stack from the top in order to find the frame from the caller where the returnPC is stored
+ while (rewindContext && rewindContext->parentContext() != context)
+ rewindContext = rewindContext->parentContext();
+ if (rewindContext) {
+ JSC::Instruction *returnPC = QScriptEnginePrivate::frameForContext(rewindContext)->returnPC();
+ JSC::CodeBlock *codeBlock = frame->codeBlock();
+ if (returnPC && codeBlock) {
+ lineNumber = codeBlock->lineNumberForBytecodeOffset(const_cast<JSC::ExecState *>(frame),
+ returnPC - codeBlock->instructions().begin());
+ }
+ }
+ }
}
/*!
diff --git a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp
index 8dd2fc7..be0b2b7 100644
--- a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp
+++ b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp
@@ -76,6 +76,7 @@ private slots:
void toString();
void calledAsConstructor();
void argumentsObjectInNative();
+ void jsActivationObject();
};
tst_QScriptContext::tst_QScriptContext()
@@ -218,11 +219,17 @@ void tst_QScriptContext::arguments()
{
QScriptValue result = eng.evaluate(prefix+"get_argumentsObject(123)");
+ eng.evaluate("function nestedArg(x,y,z) { var w = get_argumentsObject('ABC' , x+y+z); return w; }");
+ QScriptValue result2 = eng.evaluate("nestedArg(1, 'a', 2)");
QCOMPARE(result.isArray(), false);
QVERIFY(result.isObject());
QCOMPARE(result.property("length").toUInt32(), quint32(1));
QCOMPARE(result.property("0").isNumber(), true);
QCOMPARE(result.property("0").toNumber(), 123.0);
+ QVERIFY(result2.isObject());
+ QCOMPARE(result2.property("length").toUInt32(), quint32(2));
+ QCOMPARE(result2.property("0").toString(), QString::fromLatin1("ABC"));
+ QCOMPARE(result2.property("1").toString(), QString::fromLatin1("1a2"));
}
{
@@ -784,7 +791,6 @@ void tst_QScriptContext::toString()
" return parentContextToString();\n"
"}; foo(1, 2, 3)", "script.qs");
QVERIFY(ret.isString());
- QEXPECT_FAIL("", "", Continue);
QCOMPARE(ret.toString(), QString::fromLatin1("foo (first=1, second=2, third=3) at script.qs:2"));
}
@@ -842,7 +848,7 @@ void tst_QScriptContext::calledAsConstructor()
}
-static QScriptValue argumentsObjectInNative_test1(QScriptContext *ctx, QScriptEngine *)
+static QScriptValue argumentsObjectInNative_test1(QScriptContext *ctx, QScriptEngine *eng)
{
#define VERIFY(statement) \
do {\
@@ -854,6 +860,10 @@ static QScriptValue argumentsObjectInNative_test1(QScriptContext *ctx, QScriptEn
VERIFY(obj.isObject());
VERIFY(obj.property(0).toUInt32() == 123);
VERIFY(obj.property(1).toString() == QString::fromLatin1("456"));
+
+ obj.setProperty(0, "abc");
+ VERIFY(eng->evaluate("arguments[0]").toString() == QString::fromLatin1("abc") );
+
return QString::fromLatin1("success");
#undef VERIFY
}
@@ -870,9 +880,6 @@ void tst_QScriptContext::argumentsObjectInNative()
QVERIFY(!eng.hasUncaughtException());
QCOMPARE(result.toString(), QString::fromLatin1("success"));
}
-
-
-
{
QScriptEngine eng;
QScriptValue fun = eng.newFunction(argumentsObjectInNative_test1);
@@ -881,7 +888,31 @@ void tst_QScriptContext::argumentsObjectInNative()
QVERIFY(!eng.hasUncaughtException());
QCOMPARE(result.toString(), QString::fromLatin1("success"));
}
+}
+static QScriptValue get_jsActivationObject(QScriptContext *ctx, QScriptEngine *)
+{
+ return ctx->parentContext()->parentContext()->activationObject();
+}
+
+void tst_QScriptContext::jsActivationObject()
+{
+ QScriptEngine eng;
+ eng.globalObject().setProperty("get_jsActivationObject", eng.newFunction(get_jsActivationObject));
+ eng.evaluate("function f1() { var w = get_jsActivationObject('arg1'); return w; }");
+ eng.evaluate("function f2(x,y,z) { var v1 = 42;\n"
+ // "function foo() {};\n" //this would avoid JSC to optimize
+ "var v2 = f1(); return v2; }");
+ eng.evaluate("function f3() { var v1 = 'nothing'; return f2(1,2,3); }");
+ QScriptValue result1 = eng.evaluate("f2('hello', 'useless', 'world')");
+ QScriptValue result2 = eng.evaluate("f3()");
+ QVERIFY(result1.isObject());
+ QEXPECT_FAIL("", "JSC optimize away the activation object", Abort);
+ QCOMPARE(result1.property("v1").toInt32() , 42);
+ QCOMPARE(result1.property("arguments").property(1).toString() , QString::fromLatin1("useless"));
+ QVERIFY(result2.isObject());
+ QCOMPARE(result2.property("v1").toInt32() , 42);
+ QCOMPARE(result2.property("arguments").property(1).toString() , QString::fromLatin1("2"));
}
QTEST_MAIN(tst_QScriptContext)
diff --git a/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp b/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp
index 0877717..921cbd8 100644
--- a/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp
+++ b/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp
@@ -185,7 +185,6 @@ void tst_QScriptContextInfo::scriptFunction()
QCOMPARE(info.functionType(), QScriptContextInfo::ScriptFunction);
QVERIFY(info.scriptId() != -1);
QCOMPARE(info.fileName(), fileName);
- QEXPECT_FAIL("", "lineNumber doesn't work", Continue);
QCOMPARE(info.lineNumber(), lineNumber + 1);
QEXPECT_FAIL("", "columnNumber doesn't work", Continue);
QCOMPARE(info.columnNumber(), 2);
diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp
index 7fc50d4..ff3a21d 100644
--- a/tests/auto/qscriptengine/tst_qscriptengine.cpp
+++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp
@@ -3934,6 +3934,38 @@ void tst_QScriptEngine::nativeFunctionScopes()
QCOMPARE(ret.toInt32(), 123);
}
}
+
+ //from http://doc.trolltech.com/latest/qtscript.html#nested-functions-and-the-scope-chain
+ {
+ QScriptEngine eng;
+ eng.evaluate("function counter() { var count = 0; return function() { return count++; } }\n"
+ "var c1 = counter(); var c2 = counter(); ");
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ {
+ QScriptEngine eng;
+ eng.globalObject().setProperty("counter", eng.newFunction(counter));
+ eng.evaluate("var c1 = counter(); var c2 = counter(); ");
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ {
+ QScriptEngine eng;
+ eng.globalObject().setProperty("counter", eng.newFunction(counter_hybrid));
+ eng.evaluate("var c1 = counter(); var c2 = counter(); ");
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
+ QVERIFY(!eng.hasUncaughtException());
+ }
}
static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; }