From c0f961cd6b82a523e277f6d8778a20508b15697d Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 3 Aug 2017 20:26:28 +0200 Subject: Change function signatures for call/construct back Change those back again to return a value. This will be required to avoid creation of Scope objects between JS function calls. Change-Id: I05cb5cf8fd0c13dcefa60d213ccd5983fab57ea3 Reviewed-by: Erik Verbruggen --- tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'tests/auto/qml/qqmlecmascript') diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 45f312e934..22251111d5 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -2349,7 +2349,7 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const QV4::ScopedCallData d(scope, 1); d->args[0] = o; d->thisObject = engine->global(); - function->call(scope, d); + function->call(d); if (scope.engine->hasException) { scope.engine->catchException(); return true; @@ -2375,15 +2375,16 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o, if (!function) return false; + QV4::ScopedValue value(scope); QV4::ScopedCallData d(scope, 1); d->args[0] = o; d->thisObject = engine->global(); - function->call(scope, d); + value = function->call(d); if (scope.engine->hasException) { scope.engine->catchException(); return false; } - return QV4::Runtime::method_strictEqual(scope.result, result); + return QV4::Runtime::method_strictEqual(value, result); } static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o, @@ -2407,12 +2408,12 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o QV4::ScopedCallData d(scope, 1); d->args[0] = o; d->thisObject = engine->global(); - function->call(scope, d); + QV4::ScopedValue result(scope, function->call(d)); if (scope.engine->hasException) { scope.engine->catchException(); return QV4::Encode::undefined(); } - return scope.result.asReturnedValue(); + return result->asReturnedValue(); } #define EVALUATE_ERROR(source) evaluate_error(engine, object, source) -- cgit v1.2.3 From 6df6f642ea382169533a0ad106be270b6d4b7d58 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 30 Aug 2017 21:53:03 +0200 Subject: Move CallContext construction into a interpreter instruction This will allow us to further cut down on function call overhead. To make this work, introduce a proper distinction between EvalCode and GlobalCode and use the correct compilation mode in all places. Change-Id: I070621142159b7416026347c9239200c5ed7a56b Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tests/auto/qml/qqmlecmascript') diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 22251111d5..447151a59e 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -2338,7 +2338,7 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const QLatin1String(source) + QLatin1String(" })"); QV4::Scope scope(QV8Engine::getV4(engine)); - QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), functionSource); + QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::EvalCode, functionSource); program.inheritContext = true; QV4::ScopedFunctionObject function(scope, program.run()); @@ -2364,7 +2364,7 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o, QLatin1String(source) + QLatin1String(" })"); QV4::Scope scope(QV8Engine::getV4(engine)); - QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), functionSource); + QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::EvalCode, functionSource); program.inheritContext = true; QV4::ScopedFunctionObject function(scope, program.run()); @@ -2395,7 +2395,7 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o QV4::Scope scope(QV8Engine::getV4(engine)); - QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), functionSource); + QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::EvalCode, functionSource); program.inheritContext = true; QV4::ScopedFunctionObject function(scope, program.run()); -- cgit v1.2.3 From aa8f956e8d742ec25a01dfeb0d7a7ce54b49ed73 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 1 Sep 2017 10:09:45 +0200 Subject: Move ScopedCallData and ScopedStackFrame into a separate file Change-Id: I9ae42aa7a811aa93fe0950725e9d253a0c5e8dba Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'tests/auto/qml/qqmlecmascript') diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 447151a59e..f36e260642 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -43,6 +43,7 @@ #include "../../shared/util.h" #include #include +#include #include #include #include -- cgit v1.2.3 From 74c8fe86755af485f8d0a47799d6d50f00070f05 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 1 Sep 2017 11:48:15 +0200 Subject: Always set the correct FunctionObject when calling JS functions Renamed ScopedCallData to JSCall, enforced passing a JS FunctionObject to it, and added call() and callAsConstructor() methods to it. Change-Id: I30db65c9765c2896b5909fe2105c0934c6dad861 Reviewed-by: Simon Hausmann --- .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'tests/auto/qml/qqmlecmascript') diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index f36e260642..5f6b0a056e 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -2347,10 +2347,10 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const scope.engine->catchException(); return true; } - QV4::ScopedCallData d(scope, 1); - d->args[0] = o; - d->thisObject = engine->global(); - function->call(d); + QV4::JSCall jsCall(scope, function, 1); + jsCall->args[0] = o; + jsCall->thisObject = engine->global(); + jsCall.call(); if (scope.engine->hasException) { scope.engine->catchException(); return true; @@ -2377,10 +2377,10 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o, return false; QV4::ScopedValue value(scope); - QV4::ScopedCallData d(scope, 1); - d->args[0] = o; - d->thisObject = engine->global(); - value = function->call(d); + QV4::JSCall jsCall(scope, function, 1); + jsCall->args[0] = o; + jsCall->thisObject = engine->global(); + value = jsCall.call(); if (scope.engine->hasException) { scope.engine->catchException(); return false; @@ -2406,10 +2406,10 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o } if (!function) return QV4::Encode::undefined(); - QV4::ScopedCallData d(scope, 1); - d->args[0] = o; - d->thisObject = engine->global(); - QV4::ScopedValue result(scope, function->call(d)); + QV4::JSCall jsCall(scope, function, 1); + jsCall->args[0] = o; + jsCall->thisObject = engine->global(); + QV4::ScopedValue result(scope, jsCall.call()); if (scope.engine->hasException) { scope.engine->catchException(); return QV4::Encode::undefined(); -- cgit v1.2.3 From 737275826330cb2988a147be534e3d8e74cb02c6 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 19 Sep 2017 14:22:18 +0200 Subject: Fix delayed loading of arguments in binary expressions Consider the following functions: function f(x) { return x + (++x) } function g(x) { return x + x } In f() it is not correct to delay the load of x on the left-hand side of the + operator, while in g() it is. The reason is that calculating the right-hand side of the + operator in f() will change the value of x. So, if an argument is written to in an expression in a statement, it cannot be delay-loaded. The same is true for member/field accesses, because the accessors can be overwritten and do anything. Change-Id: I5bed4b0d03919edc1c94a82127e2dd705fc1d9b1 Reviewed-by: Lars Knoll Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tests/auto/qml/qqmlecmascript') diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 5f6b0a056e..7583579de6 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -343,6 +343,7 @@ private slots: void freeze_empty_object(); void singleBlockLoops(); void qtbug_60547(); + void delayLoadingArgs(); private: // static void propertyVarWeakRefCallback(v8::Persistent object, void* parameter); @@ -8371,6 +8372,13 @@ void tst_qqmlecmascript::qtbug_60547() QCOMPARE(object->property("counter"), QVariant(int(1))); } +void tst_qqmlecmascript::delayLoadingArgs() +{ + QJSEngine engine; + QJSValue ret = engine.evaluate("(function(x){return x + (x+=2)})(20)"); + QCOMPARE(ret.toInt(), 42); // esp. not 44. +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" -- cgit v1.2.3 From bc2427ce32efbfa3759e2658ba53289428527071 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 17 Oct 2017 15:14:59 +0200 Subject: Never truncate the JS stack Truncating it can lead to all sorts of crazy side effects, especially as we'd be extending it again when leaving the function. When that happens already freed JS objects could suddenly become visible to the GC again. Fix this by copying the CallData to set up a new stack frame. This is not yet ideal, as we're copying too much data, but that can be fixed separately. Change-Id: I02a39ce479475bae326f9eddfe6654fbcf8e6d35 Reviewed-by: Lars Knoll --- tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'tests/auto/qml/qqmlecmascript') diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 899f14b51d..faab61cd3d 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -344,6 +344,7 @@ private slots: void singleBlockLoops(); void qtbug_60547(); void delayLoadingArgs(); + void manyArguments(); private: // static void propertyVarWeakRefCallback(v8::Persistent object, void* parameter); @@ -8375,6 +8376,17 @@ void tst_qqmlecmascript::delayLoadingArgs() QCOMPARE(ret.toInt(), 42); // esp. not 44. } +void tst_qqmlecmascript::manyArguments() +{ + const char *testCase = + "function x() { var sum; for (var i = 0; i < arguments.length; ++i) sum += arguments[i][0]; }" + "x([0],[1],[2],[3],[4],[5],[6],[7],[8],[9], [0],[1],[2],[3],[4],[5],[6],[7],[8],[9], [0],[1],[2],[3],[4],[5],[6],[7],[8],[9])"; + + QJSEngine engine; + engine.evaluate(testCase); +} + + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" -- cgit v1.2.3 From c6c79644dc869259482a011f8b737f709af02fb2 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 20 Oct 2017 15:14:41 +0200 Subject: Rename JSCall to JSCallData As, this is going to change in a simple stack based structure to keep pointers to the data to pass to calls. Change-Id: Ia9aa3f81ee3eeba36affd16aac7b2fe97d59aea9 Reviewed-by: Erik Verbruggen --- tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tests/auto/qml/qqmlecmascript') diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index faab61cd3d..14bf328f5a 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -2349,7 +2349,7 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const scope.engine->catchException(); return true; } - QV4::JSCall jsCall(scope, function, 1); + QV4::JSCallData jsCall(scope, function, 1); jsCall->args[0] = o; jsCall->thisObject = engine->global(); jsCall.call(); @@ -2379,7 +2379,7 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o, return false; QV4::ScopedValue value(scope); - QV4::JSCall jsCall(scope, function, 1); + QV4::JSCallData jsCall(scope, function, 1); jsCall->args[0] = o; jsCall->thisObject = engine->global(); value = jsCall.call(); @@ -2408,7 +2408,7 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o } if (!function) return QV4::Encode::undefined(); - QV4::JSCall jsCall(scope, function, 1); + QV4::JSCallData jsCall(scope, function, 1); jsCall->args[0] = o; jsCall->thisObject = engine->global(); QV4::ScopedValue result(scope, jsCall.call()); -- cgit v1.2.3 From a59d9a7eacea3614462eb910e03351cbb9d34b75 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 20 Oct 2017 16:00:56 +0200 Subject: Get rid of JSCallData::call() Change-Id: I6b99e9a7102b3dcb6a7699f54b6456eba6248699 Reviewed-by: Erik Verbruggen --- .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'tests/auto/qml/qqmlecmascript') diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 14bf328f5a..206d08e4e9 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -2349,10 +2349,10 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const scope.engine->catchException(); return true; } - QV4::JSCallData jsCall(scope, function, 1); - jsCall->args[0] = o; - jsCall->thisObject = engine->global(); - jsCall.call(); + QV4::JSCallData jsCallData(scope, function, 1); + jsCallData->args[0] = o; + jsCallData->thisObject = engine->global(); + function->call(jsCallData); if (scope.engine->hasException) { scope.engine->catchException(); return true; @@ -2379,10 +2379,10 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o, return false; QV4::ScopedValue value(scope); - QV4::JSCallData jsCall(scope, function, 1); - jsCall->args[0] = o; - jsCall->thisObject = engine->global(); - value = jsCall.call(); + QV4::JSCallData jsCallData(scope, function, 1); + jsCallData->args[0] = o; + jsCallData->thisObject = engine->global(); + value = function->call(jsCallData); if (scope.engine->hasException) { scope.engine->catchException(); return false; @@ -2408,10 +2408,10 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o } if (!function) return QV4::Encode::undefined(); - QV4::JSCallData jsCall(scope, function, 1); - jsCall->args[0] = o; - jsCall->thisObject = engine->global(); - QV4::ScopedValue result(scope, jsCall.call()); + QV4::JSCallData jsCallData(scope, function, 1); + jsCallData->args[0] = o; + jsCallData->thisObject = engine->global(); + QV4::ScopedValue result(scope, function->call(jsCallData)); if (scope.engine->hasException) { scope.engine->catchException(); return QV4::Encode::undefined(); -- cgit v1.2.3 From bc5ff76e5afe6356bebb344c9a5d8b304e852f3c Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 20 Oct 2017 16:54:10 +0200 Subject: Simplify JSCallData construction Change-Id: Ic53532edae9a209aa7125af6f00a9d993d74f1a3 Reviewed-by: Erik Verbruggen --- tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tests/auto/qml/qqmlecmascript') diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 206d08e4e9..68da4de37a 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -2349,7 +2349,7 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const scope.engine->catchException(); return true; } - QV4::JSCallData jsCallData(scope, function, 1); + QV4::JSCallData jsCallData(scope, 1); jsCallData->args[0] = o; jsCallData->thisObject = engine->global(); function->call(jsCallData); @@ -2379,7 +2379,7 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o, return false; QV4::ScopedValue value(scope); - QV4::JSCallData jsCallData(scope, function, 1); + QV4::JSCallData jsCallData(scope, 1); jsCallData->args[0] = o; jsCallData->thisObject = engine->global(); value = function->call(jsCallData); @@ -2408,7 +2408,7 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o } if (!function) return QV4::Encode::undefined(); - QV4::JSCallData jsCallData(scope, function, 1); + QV4::JSCallData jsCallData(scope, 1); jsCallData->args[0] = o; jsCallData->thisObject = engine->global(); QV4::ScopedValue result(scope, function->call(jsCallData)); -- cgit v1.2.3 From e72306a6f2aeb2bddbb462c205db8fad2fb5a1a4 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 20 Oct 2017 17:19:25 +0200 Subject: Further cleanup JSCallData Avoid allocations on the JS stack if possible Change-Id: I344cd6dceb6264314f9d22c94db22b22d1d24d14 Reviewed-by: Erik Verbruggen --- tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tests/auto/qml/qqmlecmascript') diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 68da4de37a..a4b7b8089f 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -2351,7 +2351,7 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const } QV4::JSCallData jsCallData(scope, 1); jsCallData->args[0] = o; - jsCallData->thisObject = engine->global(); + *jsCallData->thisObject = engine->global(); function->call(jsCallData); if (scope.engine->hasException) { scope.engine->catchException(); @@ -2381,7 +2381,7 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o, QV4::ScopedValue value(scope); QV4::JSCallData jsCallData(scope, 1); jsCallData->args[0] = o; - jsCallData->thisObject = engine->global(); + *jsCallData->thisObject = engine->global(); value = function->call(jsCallData); if (scope.engine->hasException) { scope.engine->catchException(); @@ -2410,7 +2410,7 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o return QV4::Encode::undefined(); QV4::JSCallData jsCallData(scope, 1); jsCallData->args[0] = o; - jsCallData->thisObject = engine->global(); + *jsCallData->thisObject = engine->global(); QV4::ScopedValue result(scope, function->call(jsCallData)); if (scope.engine->hasException) { scope.engine->catchException(); -- cgit v1.2.3