summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/script/api/qscriptcontext.cpp26
-rw-r--r--tests/auto/qscriptcontext/tst_qscriptcontext.cpp33
2 files changed, 49 insertions, 10 deletions
diff --git a/src/script/api/qscriptcontext.cpp b/src/script/api/qscriptcontext.cpp
index d68b913..99b8989 100644
--- a/src/script/api/qscriptcontext.cpp
+++ b/src/script/api/qscriptcontext.cpp
@@ -330,20 +330,36 @@ QScriptValue QScriptContext::argumentsObject() const
*/
bool QScriptContext::isCalledAsConstructor() const
{
- const JSC::CallFrame *frame = reinterpret_cast<const JSC::CallFrame *>(this);
- //look up for the QScriptActivationObject and its calledAsConstructor flag.
+ JSC::CallFrame *frame = reinterpret_cast<JSC::CallFrame *>(const_cast<QScriptContext *>(this));
+
+ //For native functions, look up for the QScriptActivationObject and its calledAsConstructor flag.
JSC::ScopeChainNode *node = frame->scopeChain();
JSC::ScopeChainIterator it(node);
for (it = node->begin(); it != node->end(); ++it) {
- if (!(*it)->isVariableObject()) {
+ if ((*it)->isVariableObject()) {
if ((*it)->inherits(&QScript::QScriptActivationObject::info)) {
return static_cast<QScript::QScriptActivationObject *>(*it)->d_ptr()->calledAsConstructor;
}
//not a native function
- //### we have no way to know if is is or not a constructor
- return false;
+ break;
}
}
+
+ //Not a native function, try to look up in the bytecode if we where called from op_construct
+ JSC::Instruction* returnPC = frame->returnPC();
+
+ if (!returnPC)
+ return false;
+
+ JSC::CallFrame *callerFrame = reinterpret_cast<JSC::CallFrame *>(parentContext());
+ if (!callerFrame)
+ return false;
+
+ if (returnPC[-JSC::op_construct_length].u.opcode == frame->interpreter()->getOpcode(JSC::op_construct)) {
+ //We are maybe called from the op_construct opcode which has 6 opperands.
+ //But we need to check we are not called from op_call with 4 opperands (by checking the argc operand)
+ return returnPC[-4].u.operand == frame->argumentCount();
+ }
return false;
}
diff --git a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp
index 4726815..7a363ac 100644
--- a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp
+++ b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp
@@ -764,15 +764,21 @@ static QScriptValue storeCalledAsConstructorV2(QScriptContext *ctx, QScriptEngin
return eng->undefinedValue();
}
+static QScriptValue storeCalledAsConstructorV3(QScriptContext *ctx, QScriptEngine *eng)
+{
+ ctx->callee().setProperty("calledAsConstructor", ctx->parentContext()->isCalledAsConstructor());
+ return eng->undefinedValue();
+}
+
void tst_QScriptContext::calledAsConstructor()
{
QScriptEngine eng;
+ QScriptValue fun1 = eng.newFunction(storeCalledAsConstructor);
{
- QScriptValue fun = eng.newFunction(storeCalledAsConstructor);
- fun.call();
- QVERIFY(!fun.property("calledAsConstructor").toBool());
- fun.construct();
- QVERIFY(fun.property("calledAsConstructor").toBool());
+ fun1.call();
+ QVERIFY(!fun1.property("calledAsConstructor").toBool());
+ fun1.construct();
+ QVERIFY(fun1.property("calledAsConstructor").toBool());
}
{
QScriptValue fun = eng.newFunction(storeCalledAsConstructorV2, (void*)0);
@@ -781,6 +787,23 @@ void tst_QScriptContext::calledAsConstructor()
fun.construct();
QVERIFY(fun.property("calledAsConstructor").toBool());
}
+ {
+ eng.globalObject().setProperty("fun1", fun1);
+ eng.evaluate("fun1();");
+ QVERIFY(!fun1.property("calledAsConstructor").toBool());
+ eng.evaluate("new fun1();");
+ QVERIFY(fun1.property("calledAsConstructor").toBool());
+ }
+ {
+ QScriptValue fun3 = eng.newFunction(storeCalledAsConstructorV3);
+ eng.globalObject().setProperty("fun3", fun3);
+ eng.evaluate("function test() { fun3() }");
+ eng.evaluate("test();");
+ QVERIFY(!fun3.property("calledAsConstructor").toBool());
+ eng.evaluate("new test();");
+ QVERIFY(fun3.property("calledAsConstructor").toBool());
+ }
+
}
static QScriptValue argumentsObjectInNative_test1(QScriptContext *ctx, QScriptEngine *)