aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2017-10-19 15:21:08 +0200
committerLars Knoll <lars.knoll@qt.io>2017-11-07 07:24:21 +0000
commit957de0c8fb109ad6938d7a8673164cc94f346ecc (patch)
tree4cf7161218a31cbf63e55792c0d4df5bd9ad223f /src/qml/jsruntime
parentc8547312d3faf1bd357fe03f4717585e23da7680 (diff)
Refactor Call/Construct instructions
Give them a pointer to argc and argv instead of a pointer to a full callData. Like this we can construct the callData at the end of the JS stack and avoid the need to create an additional copy in VME::exec(). This also opens up the option of completely avoiding all copies for calls into runtime methods. Also make sure that the calldata we pass into other functions is always at the top of the JS stack. Change-Id: I3d0eb49f7bfd7adb9ddabb213422087c66e5a520 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp12
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp14
-rw-r--r--src/qml/jsruntime/qv4global_p.h6
-rw-r--r--src/qml/jsruntime/qv4jscall_p.h18
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp3
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp9
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp93
7 files changed, 96 insertions, 59 deletions
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 5abfe3f8ae..0cf4515cc9 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -791,10 +791,10 @@ ReturnedValue ArrayPrototype::method_every(const BuiltinFunction *b, CallData *c
if (!callback)
THROW_TYPE_ERROR();
- JSCall jsCall(scope, callback, 3);
- jsCall->thisObject = callData->argument(1);
ScopedValue r(scope);
ScopedValue v(scope);
+ JSCall jsCall(scope, callback, 3);
+ jsCall->thisObject = callData->argument(1);
bool ok = true;
for (uint k = 0; ok && k < len; ++k) {
@@ -825,10 +825,10 @@ ReturnedValue ArrayPrototype::method_some(const BuiltinFunction *b, CallData *ca
if (!callback)
THROW_TYPE_ERROR();
- JSCall jsCall(scope, callback, 3);
- jsCall->thisObject = callData->argument(1);
ScopedValue v(scope);
ScopedValue result(scope);
+ JSCall jsCall(scope, callback, 3);
+ jsCall->thisObject = callData->argument(1);
for (uint k = 0; k < len; ++k) {
bool exists;
@@ -859,10 +859,10 @@ ReturnedValue ArrayPrototype::method_forEach(const BuiltinFunction *b, CallData
if (!callback)
THROW_TYPE_ERROR();
+ ScopedValue v(scope);
JSCall jsCall(scope, callback, 3);
jsCall->thisObject = callData->argument(1);
- ScopedValue v(scope);
for (uint k = 0; k < len; ++k) {
bool exists;
v = instance->getIndexed(k, &exists);
@@ -894,11 +894,11 @@ ReturnedValue ArrayPrototype::method_map(const BuiltinFunction *b, CallData *cal
a->arrayReserve(len);
a->setArrayLengthUnchecked(len);
+ ScopedValue v(scope);
ScopedValue mapped(scope);
JSCall jsCall(scope, callback, 3);
jsCall->thisObject = callData->argument(1);
- ScopedValue v(scope);
for (uint k = 0; k < len; ++k) {
bool exists;
v = instance->getIndexed(k, &exists);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 36c5c4441a..716678d2f8 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -305,6 +305,7 @@ ReturnedValue FunctionPrototype::method_apply(const BuiltinFunction *b, CallData
return v4->throwTypeError();
} else {
callData->setArgc(0);
+ v4->jsStackTop = callData->args;
}
return o->call(callData);
@@ -312,16 +313,19 @@ ReturnedValue FunctionPrototype::method_apply(const BuiltinFunction *b, CallData
ReturnedValue FunctionPrototype::method_call(const BuiltinFunction *b, CallData *callData)
{
- if (!callData->thisObject.isFunctionObject()) {
- ExecutionEngine *e = b->engine();
- return e->throwTypeError();
- }
+ ExecutionEngine *engine = b->engine();
+ if (!callData->thisObject.isFunctionObject())
+ return engine->throwTypeError();
+
+ Q_ASSERT(engine->jsStackTop == callData->args + callData->argc());
+
callData->function = callData->thisObject;
callData->thisObject = callData->argc() ? callData->args[0] : Primitive::undefinedValue();
if (callData->argc()) {
callData->setArgc(callData->argc() - 1);
for (int i = 0, ei = callData->argc(); i < ei; ++i)
callData->args[i] = callData->args[i + 1];
+ --engine->jsStackTop;
}
return static_cast<FunctionObject &>(callData->function).call(callData);
}
@@ -354,12 +358,12 @@ ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData)
const ScriptFunction *f = static_cast<const ScriptFunction *>(that);
InternalClass *ic = f->classForConstructor();
+ callData->context = f->scope();
callData->thisObject = v4->memoryManager->allocObject<Object>(ic);
QV4::Function *v4Function = f->function();
Q_ASSERT(v4Function);
- callData->context = f->scope();
ReturnedValue result = v4Function->call(callData);
if (Q_UNLIKELY(v4->hasException))
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 4c5e3c4e5e..6bdeda3313 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -248,12 +248,6 @@ struct IdentifierTable;
class RegExpCache;
class MultiplyWrappedQObjectMap;
-namespace Global {
- enum {
- ReservedArgumentCount = 6
- };
-}
-
enum PropertyFlag {
Attr_Data = 0,
Attr_Accessor = 0x1,
diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h
index 8fd6119102..18dfdc102b 100644
--- a/src/qml/jsruntime/qv4jscall_p.h
+++ b/src/qml/jsruntime/qv4jscall_p.h
@@ -63,24 +63,36 @@ namespace QV4 {
struct JSCall {
JSCall(const Scope &scope, std::nullptr_t, int argc = 0)
{
- int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + qMax(argc , int(QV4::Global::ReservedArgumentCount));
+ int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc;
ptr = reinterpret_cast<CallData *>(scope.alloc(size));
ptr->setArgc(argc);
}
JSCall(const Scope &scope, const FunctionObject *function, int argc = 0)
{
- int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + qMax(argc , int(QV4::Global::ReservedArgumentCount));
+ int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc;
ptr = reinterpret_cast<CallData *>(scope.alloc(size));
ptr->setArgc(argc);
ptr->function = *function;
}
JSCall(const Scope &scope, Heap::FunctionObject *function, int argc = 0)
{
- int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + qMax(argc , int(QV4::Global::ReservedArgumentCount));
+ int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc;
ptr = reinterpret_cast<CallData *>(scope.alloc(size));
ptr->setArgc(argc);
ptr->function = function;
}
+ JSCall(const Scope &scope, Value *argv, int argc, Value *thisObject = 0)
+ {
+ int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc;
+ ptr = reinterpret_cast<CallData *>(scope.engine->jsStackTop);
+ scope.engine->jsStackTop += size;
+ ptr->function = Encode::undefined();
+ ptr->context = Encode::undefined();
+ ptr->accumulator = Encode::undefined();
+ ptr->thisObject = thisObject ? thisObject->asReturnedValue() : Encode::undefined();
+ ptr->setArgc(argc);
+ memcpy(ptr->args, argv, argc*sizeof(Value));
+ }
CallData *operator->() {
return ptr;
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 97b0c5259f..7bc2315610 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -426,10 +426,11 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeH
qSwap(meth1, meth2);
Scope scope(engine);
+ ScopedValue conv(scope, object->get(meth1));
+
JSCall jsCall(scope, nullptr, 0);
jsCall->thisObject = *object;
- ScopedValue conv(scope, object->get(meth1));
if (FunctionObject *o = conv->as<FunctionObject>()) {
jsCall->function = o;
jsCall->accumulator = jsCall.call();
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 9e03913730..b1ce0b0115 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -405,14 +405,17 @@ ReturnedValue StringPrototype::method_match(const BuiltinFunction *b, CallData *
if (callData->thisObject.isNullOrUndefined())
return v4->throwTypeError();
- Scope scope(v4);
- callData->thisObject = callData->thisObject.toString(scope.engine);
+ callData->thisObject = callData->thisObject.toString(v4);
if (v4->hasException)
return Encode::undefined();
+ Q_ASSERT(v4->jsStackTop == callData->args + callData->argc());
if (!callData->argc())
callData->args[0] = Encode::undefined();
callData->setArgc(1);
+ v4->jsStackTop = callData->args + 1;
+
+ Scope scope(v4);
if (!callData->args[0].as<RegExpObject>()) {
// convert args[0] to a regexp
@@ -579,10 +582,10 @@ ReturnedValue StringPrototype::method_replace(const BuiltinFunction *b, CallData
ScopedFunctionObject searchCallback(scope, replaceValue);
if (!!searchCallback) {
result.reserve(string.length() + 10*numStringMatches);
+ ScopedValue entry(scope);
JSCall jsCall(scope, searchCallback, numCaptures + 2);
jsCall->thisObject = Primitive::undefinedValue();
int lastEnd = 0;
- ScopedValue entry(scope);
for (int i = 0; i < numStringMatches; ++i) {
for (int k = 0; k < numCaptures; ++k) {
int idx = (i * numCaptures + k) * 2;
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index b3b9842ba9..3e9f329c9a 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -54,6 +54,7 @@
#include <private/qv4regexpobject_p.h>
#include <private/qv4string_p.h>
#include <private/qv4profiling_p.h>
+#include <private/qv4jscall_p.h>
#include <private/qqmljavascriptexpression_p.h>
#include <iostream>
@@ -509,14 +510,15 @@ QV4::ReturnedValue VME::exec(CallData *callData, QV4::Function *function)
Value *jsStackTop = engine->jsStackTop;
- Q_ASSERT(engine->jsStackTop >= callData->args + callData->argc() - 1);
- Value *stack = engine->jsStackTop;
- engine->jsStackTop += sizeof(CallData)/sizeof(Value) - 1 + qMax(callData->argc(), int(function->compiledFunction->nRegisters));
- memcpy(stack, callData, sizeof(CallData) - sizeof(Value) + callData->argc()*sizeof(Value));
- // clear out remaining arguments and local registers
- callData = reinterpret_cast<CallData *>(stack);
- for (Value *v = callData->args + callData->argc(); v < engine->jsStackTop; ++v)
- *v = Encode::undefined();
+ Q_ASSERT(engine->jsStackTop == callData->args + callData->argc());
+ Value *stack = reinterpret_cast<Value *>(callData);
+ int stackSpaceToAdd = int(function->compiledFunction->nRegisters) - callData->argc();
+ if (stackSpaceToAdd > 0) {
+ // clear out remaining arguments and local registers
+ for (int i = 0; i < stackSpaceToAdd; ++i)
+ engine->jsStackTop[i] = Encode::undefined();
+ engine->jsStackTop += stackSpaceToAdd;
+ }
CppStackFrame frame;
frame.parent = engine->currentStackFrame;
@@ -743,60 +745,78 @@ QV4::ReturnedValue VME::exec(CallData *callData, QV4::Function *function)
MOTH_BEGIN_INSTR(CallValue)
STORE_IP();
STORE_ACC();
- QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData);
- Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop);
- acc = Runtime::method_callValue(engine, accumulator, cData);
+ {
+ Scope scope(engine);
+ JSCall cData(scope, stack + argv, argc);
+ Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop);
+ acc = Runtime::method_callValue(engine, accumulator, cData);
+ }
CHECK_EXCEPTION;
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallProperty)
STORE_IP();
- QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData);
- Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop);
- cData->thisObject = STACK_VALUE(base);
- acc = Runtime::method_callProperty(engine, name, cData);
+ {
+ Scope scope(engine);
+ JSCall cData(scope, stack + argv, argc, stack + base);
+ Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop);
+ acc = Runtime::method_callProperty(engine, name, cData);
+ }
CHECK_EXCEPTION;
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
STORE_IP();
- QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData);
- Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop);
- cData->thisObject = STACK_VALUE(base);
- acc = Runtime::method_callPropertyLookup(engine, lookupIndex, cData);
+ {
+ Scope scope(engine);
+ JSCall cData(scope, stack + argv, argc, stack + base);
+ Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop);
+ acc = Runtime::method_callPropertyLookup(engine, lookupIndex, cData);
+ }
CHECK_EXCEPTION;
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallElement)
STORE_IP();
- QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData);
- Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop);
- cData->thisObject = STACK_VALUE(base);
- acc = Runtime::method_callElement(engine, STACK_VALUE(index), cData);
+ {
+ Scope scope(engine);
+ JSCall cData(scope, stack + argv, argc, stack + base);
+ Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop);
+ acc = Runtime::method_callElement(engine, STACK_VALUE(index), cData);
+ }
CHECK_EXCEPTION;
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallName)
STORE_IP();
- QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData);
- Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop);
- acc = Runtime::method_callName(engine, name, cData);
+ {
+ Scope scope(engine);
+ JSCall cData(scope, stack + argv, argc);
+ Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop);
+ acc = Runtime::method_callName(engine, name, cData);
+ }
CHECK_EXCEPTION;
MOTH_END_INSTR(CallName)
MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
STORE_IP();
- QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData);
- Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop);
- acc = Runtime::method_callPossiblyDirectEval(engine, cData);
+ {
+ Scope scope(engine);
+ JSCall cData(scope, stack + argv, argc);
+ Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop);
+ acc = Runtime::method_callPossiblyDirectEval(engine, cData);
+ }
CHECK_EXCEPTION;
MOTH_END_INSTR(CallPossiblyDirectEval)
MOTH_BEGIN_INSTR(CallGlobalLookup)
STORE_IP();
- QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData);
- Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop);
- acc = Runtime::method_callGlobalLookup(engine, index, cData);
+ {
+ Scope scope(engine);
+ JSCall cData(scope, stack + argv, argc);
+ Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop);
+ acc = Runtime::method_callGlobalLookup(engine, index, cData);
+ }
CHECK_EXCEPTION;
MOTH_END_INSTR(CallGlobalLookup)
@@ -943,9 +963,12 @@ QV4::ReturnedValue VME::exec(CallData *callData, QV4::Function *function)
MOTH_BEGIN_INSTR(Construct)
STORE_IP();
- QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData);
- Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop);
- acc = Runtime::method_construct(engine, STACK_VALUE(func), cData);
+ {
+ Scope scope(engine);
+ JSCall cData(scope, stack + argv, argc);
+ Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop);
+ acc = Runtime::method_construct(engine, STACK_VALUE(func), cData);
+ }
CHECK_EXCEPTION;
MOTH_END_INSTR(Construct)