aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2017-06-27 16:06:29 +0200
committerLars Knoll <lars.knoll@qt.io>2017-06-29 08:33:17 +0000
commitdfe826d7f86db99bd6ecf681ec73c2e8c8b25a15 (patch)
treee3a98ece0c3e5599a44bbfd817abe2932d4b9355
parent987734ff5872c397651630a616a002947fec3810 (diff)
Switch over to new JS call setup
Differences: - push parameters on the stack, including space for CallData members - call instructions calculate the argument start - use temp space above the calldata to evaluate arguments - fewer temporaries are needed when a call is done while generating the arguments of another call - when calling the function, the js stack space above the callData is not used, allowing for optimizations in the future - Array and ObjectLiteral use the same mechanism Change-Id: Id100fa06f12cc9d941b0f90b0b81b8270a8e4f5d Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r--src/qml/compiler/qv4bytecodegenerator.cpp9
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h2
-rw-r--r--src/qml/compiler/qv4codegen.cpp121
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp11
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h6
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp12
-rw-r--r--src/qml/jsruntime/qv4context_p.h2
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp38
8 files changed, 88 insertions, 113 deletions
diff --git a/src/qml/compiler/qv4bytecodegenerator.cpp b/src/qml/compiler/qv4bytecodegenerator.cpp
index 8f9b062af6..3a023c9989 100644
--- a/src/qml/compiler/qv4bytecodegenerator.cpp
+++ b/src/qml/compiler/qv4bytecodegenerator.cpp
@@ -63,6 +63,15 @@ unsigned BytecodeGenerator::newTemp()
return t;
}
+unsigned BytecodeGenerator::newTempArray(int n)
+{
+ int t = function->currentTemp;
+ function->currentTemp += n;
+ if (function->tempCount < function->currentTemp)
+ function->tempCount = function->currentTemp;
+ return t;
+}
+
QByteArray BytecodeGenerator::finalize()
{
QByteArray code;
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index a9e2bce159..c7a27727e8 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -193,7 +193,7 @@ public:
}
unsigned newTemp();
-
+ unsigned newTempArray(int n);
QByteArray finalize();
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 7f4a72c2fc..5ade244bd9 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1328,43 +1328,44 @@ bool Codegen::visit(ArrayLiteral *ast)
TempScope scope(this);
int argc = 0;
- Reference _args[16];
- Reference *args = _args;
- if (_variableEnvironment->maxNumberOfArguments > 16)
- args = new Reference[_variableEnvironment->maxNumberOfArguments];
- auto empty = [this](){ return Reference::fromConst(this, Primitive::emptyValue().asReturnedValue()); };
- auto push = [this, &argc, args](const Reference &arg) {
- args[argc] = arg;
- if (arg.type != Reference::Const)
- args[argc].asRValue();
- argc += 1;
+ int args = -1;
+ auto push = [this, &argc, &args](AST::ExpressionNode *arg) {
+ int temp = bytecodeGenerator->newTemp();
+ if (args == -1)
+ args = temp;
+ if (!arg) {
+ Reference::fromTemp(this, temp).store(Reference::fromConst(this, Primitive::emptyValue().asReturnedValue()));
+ } else {
+ TempScope scope(this);
+ Reference::fromTemp(this, temp).store(expression(arg));
+ }
+ ++argc;
};
for (ElementList *it = ast->elements; it; it = it->next) {
+
for (Elision *elision = it->elision; elision; elision = elision->next)
- push(empty());
+ push(0);
- Reference expr = expression(it->expression);
+ push(it->expression);
if (hasError)
return false;
-
- push(expr);
}
for (Elision *elision = ast->elision; elision; elision = elision->next)
- push(empty());
+ push(0);
- for (int i = 0; i < argc; ++i)
- Reference::fromTemp(this, i).store(args[i]);
+ if (args == -1) {
+ Q_ASSERT(argc == 0);
+ args = 0;
+ }
Instruction::CallBuiltinDefineArray call;
call.argc = argc;
- call.args = 0;
+ call.args = args;
call.result = result.asLValue();
bytecodeGenerator->addInstruction(call);
_expr.result = result;
- if (args != _args)
- delete [] args;
return false;
}
@@ -1731,7 +1732,7 @@ bool Codegen::visit(CallExpression *ast)
if (hasError)
return false;
- auto argc = pushArgs(ast->arguments);
+ auto calldata = pushArgs(ast->arguments);
if (hasError)
return false;
@@ -1739,39 +1740,34 @@ bool Codegen::visit(CallExpression *ast)
Instruction::CallProperty call;
call.base = base.base;
call.name = base.nameIndex;
- call.argc = argc;
- call.callData = 0;
+ call.callData = calldata;
call.result = r.asLValue();
bytecodeGenerator->addInstruction(call);
} else if (base.type == Reference::Subscript) {
Instruction::CallElement call;
call.base = base.base;
call.index = base.subscript;
- call.argc = argc;
- call.callData = 0;
+ call.callData = calldata;
call.result = r.asLValue();
bytecodeGenerator->addInstruction(call);
} else if (base.type == Reference::Name) {
if (useFastLookups && base.global) {
Instruction::CallGlobalLookup call;
call.index = registerGlobalGetterLookup(base.nameIndex);
- call.argc = argc;
- call.callData = 0;
+ call.callData = calldata;
call.result = r.asLValue();
bytecodeGenerator->addInstruction(call);
} else {
Instruction::CallActivationProperty call;
call.name = base.nameIndex;
- call.argc = argc;
- call.callData = 0;
+ call.callData = calldata;
call.result = r.asLValue();
bytecodeGenerator->addInstruction(call);
}
} else {
Instruction::CallValue call;
call.dest = base.asRValue();
- call.argc = argc;
- call.callData = 0;
+ call.callData = calldata;
call.result = r.asLValue();
bytecodeGenerator->addInstruction(call);
}
@@ -1781,26 +1777,22 @@ bool Codegen::visit(CallExpression *ast)
int Codegen::pushArgs(ArgumentList *args)
{
- int minNrOfStackEntries = offsetof(QV4::CallData, args)/sizeof(QV4::Value);
int argc = 0;
- Reference _rargs[16];
- Reference *rargs = _rargs;
- if (_variableEnvironment->maxNumberOfArguments > 16)
- rargs = new Reference[_variableEnvironment->maxNumberOfArguments];
+ for (ArgumentList *it = args; it; it = it->next)
+ ++argc;
+ int calldata = bytecodeGenerator->newTempArray(argc + 2); // 2 additional values for CallData
+
+ Reference::fromTemp(this, calldata).store(Reference::fromConst(this, QV4::Encode(argc)));
+ Reference::fromTemp(this, calldata + 1).store(Reference::fromConst(this, QV4::Encode::undefined()));
+
+ argc = 0;
for (ArgumentList *it = args; it; it = it->next) {
- rargs[argc] = expression(it->expression);
- rargs[argc].asRValue();
- if (hasError)
- return -1;
- argc += 1;
+ TempScope scope(this);
+ Reference::fromTemp(this, calldata + 2 + argc).store(expression(it->expression));
+ ++argc;
}
- for (int i = 0; i < argc; ++i)
- Reference::fromTemp(this, minNrOfStackEntries + i).store(rargs[i]);
-
- if (rargs != _rargs)
- delete [] rargs;
- return argc;
+ return calldata;
}
bool Codegen::visit(ConditionalExpression *ast)
@@ -2012,7 +2004,6 @@ bool Codegen::visit(NewExpression *ast)
Instruction::CreateValue create;
create.func = base.asRValue();
- create.argc = 0;
create.callData = 0;
create.result = r.asLValue();
bytecodeGenerator->addInstruction(create);
@@ -2032,14 +2023,13 @@ bool Codegen::visit(NewMemberExpression *ast)
if (hasError)
return false;
- auto argc = pushArgs(ast->arguments);
+ auto calldata = pushArgs(ast->arguments);
if (hasError)
return false;
Instruction::CreateValue create;
create.func = base.asRValue();
- create.argc = argc;
- create.callData = 0;
+ create.callData = calldata;
create.result = r.asRValue();
bytecodeGenerator->addInstruction(create);
_expr.result = r;
@@ -2143,10 +2133,12 @@ bool Codegen::visit(ObjectLiteral *ast)
}
}
- int argc = 0;
- auto push = [this, &argc](const Reference &arg) {
- Reference::fromTemp(this, argc).store(arg);
- argc += 1;
+ int args = -1;
+ auto push = [this, &args](const Reference &arg) {
+ int temp = bytecodeGenerator->newTemp();
+ if (args == -1)
+ args = temp;
+ Reference::fromTemp(this, temp).store(arg);
};
auto undefined = [this](){ return Reference::fromConst(this, Encode::undefined()); };
@@ -2190,11 +2182,14 @@ bool Codegen::visit(ObjectLiteral *ast)
uint arrayGetterSetterCountAndFlags = arrayKeyWithGetterSetter.size();
arrayGetterSetterCountAndFlags |= needSparseArray << 30;
+ if (args == -1)
+ args = 0;
+
Instruction::CallBuiltinDefineObjectLiteral call;
call.internalClassId = classId;
call.arrayValueCount = arrayKeyWithValue.size();
call.arrayGetterSetterCountAndFlags = arrayGetterSetterCountAndFlags;
- call.args = 0;
+ call.args = args;
call.result = result.asLValue();
bytecodeGenerator->addInstruction(call);
@@ -2440,13 +2435,6 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
savedBytecodeGenerator = bytecodeGenerator;
bytecodeGenerator = &bytecode;
- { // reserve space for outgoing call arguments
- Q_ASSERT(function->tempCount == 0);
- int minNrOfStackEntries = offsetof(QV4::CallData, args)/sizeof(QV4::Value);
- function->tempCount = minNrOfStackEntries + _variableEnvironment->maxNumberOfArguments;
- function->currentTemp = function->tempCount;
- }
-
unsigned returnAddress = bytecodeGenerator->newTemp();
if (function->usesArgumentsObject)
_variableEnvironment->enter(QStringLiteral("arguments"), Environment::VariableDeclaration, AST::VariableDeclaration::FunctionScope);
@@ -3405,6 +3393,13 @@ void Codegen::Reference::store(const Reference &r) const
codegen->bytecodeGenerator->addInstruction(move);
return;
}
+ if (r.type == Closure) {
+ Instruction::LoadClosure load;
+ load.value = r.closureId;
+ load.result = b;
+ codegen->bytecodeGenerator->addInstruction(load);
+ return;
+ }
Moth::Param x = r.asRValue();
Q_ASSERT(b != x);
Instruction::Move move;
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 4b0865a7ca..72a0ccc2ac 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -242,8 +242,7 @@ void dumpBytecode(const char *code, int len)
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallProperty)
- d << instr.result << ", " << instr.base<<"."<<instr.name << "(" << instr.callData
- << ", " << instr.argc << ")";
+ d << instr.result << ", " << instr.base<<"."<<instr.name << "(" << instr.callData << ")";
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
@@ -263,7 +262,7 @@ void dumpBytecode(const char *code, int len)
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallActivationProperty)
- d << instr.result << ", " << instr.name << "(" << instr.callData << ", " << instr.argc << ")";
+ d << instr.result << ", " << instr.name << "(" << instr.callData << ")";
MOTH_END_INSTR(CallActivationProperty)
MOTH_BEGIN_INSTR(CallGlobalLookup)
@@ -368,7 +367,7 @@ void dumpBytecode(const char *code, int len)
MOTH_END_INSTR(CallBuiltinConvertThisToObject)
MOTH_BEGIN_INSTR(CreateValue)
- d << instr.result << ", new" << instr.func << "(" << instr.callData << instr.argc << ")";
+ d << instr.result << ", new" << instr.func << "(" << instr.callData << ")";
MOTH_END_INSTR(CreateValue)
MOTH_BEGIN_INSTR(CreateProperty)
@@ -535,8 +534,10 @@ void dumpBytecode(const char *code, int len)
MOTH_BEGIN_INSTR(LoadQmlSingleton)
d << instr.result << instr.name;
MOTH_END_INSTR(LoadQmlSingleton)
- }
+ default:
+ Q_UNREACHABLE();
+ }
}
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index fe6fee5e2d..0daca9bb9d 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -430,7 +430,6 @@ union Instr
};
struct instr_callValue {
MOTH_INSTR_HEADER
- quint32 argc;
quint32 callData;
Param dest;
Param result;
@@ -438,7 +437,6 @@ union Instr
struct instr_callProperty {
MOTH_INSTR_HEADER
int name;
- quint32 argc;
quint32 callData;
Param base;
Param result;
@@ -471,21 +469,18 @@ union Instr
MOTH_INSTR_HEADER
Param base;
Param index;
- quint32 argc;
quint32 callData;
Param result;
};
struct instr_callActivationProperty {
MOTH_INSTR_HEADER
int name;
- quint32 argc;
quint32 callData;
Param result;
};
struct instr_callGlobalLookup {
MOTH_INSTR_HEADER
int index;
- quint32 argc;
quint32 callData;
Param result;
};
@@ -609,7 +604,6 @@ union Instr
};
struct instr_createValue {
MOTH_INSTR_HEADER
- quint32 argc;
quint32 callData;
Param func;
Param result;
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index 89140a1a5e..8f11253cca 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -314,7 +314,7 @@ void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Ex
{
Instruction::CallValue call;
prepareCallArgs(args, call.argc);
- call.callData = callDataStart();
+// call.callData = callDataStart();
call.dest = getParam(value);
call.result = getResultParam(result);
addInstruction(call);
@@ -360,7 +360,7 @@ void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR:
call.base = getParam(base);
call.name = registerString(name);
prepareCallArgs(args, call.argc);
- call.callData = callDataStart();
+// call.callData = callDataStart();
call.result = getResultParam(result);
addInstruction(call);
}
@@ -374,7 +374,7 @@ void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::Ex
call.base = getParam(base);
call.index = getParam(index);
prepareCallArgs(args, call.argc);
- call.callData = callDataStart();
+// call.callData = callDataStart();
call.result = getResultParam(result);
addInstruction(call);
}
@@ -434,7 +434,7 @@ void InstructionSelection::constructValue(IR::Expr *value, IR::ExprList *args, I
{
Instruction::CreateValue create;
create.func = getParam(value);
- prepareCallArgs(args, create.argc);
+// prepareCallArgs(args, create.argc);
create.callData = callDataStart();
create.result = getResultParam(target);
addInstruction(create);
@@ -1028,7 +1028,7 @@ void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args
Instruction::CallGlobalLookup call;
call.index = registerGlobalGetterLookup(*func->id);
prepareCallArgs(args, call.argc);
- call.callData = callDataStart();
+// call.callData = callDataStart();
call.result = getResultParam(result);
addInstruction(call);
return;
@@ -1036,7 +1036,7 @@ void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args
Instruction::CallActivationProperty call;
call.name = registerString(*func->id);
prepareCallArgs(args, call.argc);
- call.callData = callDataStart();
+// call.callData = callDataStart();
call.result = getResultParam(result);
addInstruction(call);
}
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index a854c324d0..5cf134bc70 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -92,6 +92,8 @@ struct CallData
Value thisObject;
Value args[1];
+
+ static constexpr int HeaderSize() { return offsetof(CallData, args)/sizeof(QV4::Value); }
};
Q_STATIC_ASSERT(std::is_standard_layout<CallData>::value);
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 23a76a15bf..14aef11e7f 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -563,32 +563,17 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
MOTH_END_INSTR(InitStackFrame)
MOTH_BEGIN_INSTR(CallValue)
-#if 0 //def DO_TRACE_INSTR
- if (Debugging::Debugger *debugger = context->engine()->debugger) {
- if (QV4::FunctionObject *o = (VALUE(instr.dest)).asFunctionObject()) {
- if (Debugging::FunctionDebugInfo *info = debugger->debugInfo(o)) {
- QString n = debugger->name(o);
- std::cerr << "*** Call to \"" << (n.isNull() ? "<no name>" : qPrintable(n)) << "\" defined @" << info->startLine << ":" << info->startColumn << std::endl;
- }
- }
- }
-#endif // DO_TRACE_INSTR
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = QV4::Primitive::undefinedValue();
STOREVALUE(instr.result, Runtime::method_callValue(engine, VALUE(instr.dest), callData));
+ //### write barrier?
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallProperty)
TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(engine)->toQString().toUtf8().constData());
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
STOREVALUE(instr.result, Runtime::method_callProperty(engine, instr.name, callData));
+ //### write barrier?
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
@@ -621,30 +606,22 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
MOTH_END_INSTR(CallContextObjectProperty)
MOTH_BEGIN_INSTR(CallElement)
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
STOREVALUE(instr.result, Runtime::method_callElement(engine, VALUE(instr.index), callData));
+ //### write barrier?
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallActivationProperty)
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = QV4::Primitive::undefinedValue();
STOREVALUE(instr.result, Runtime::method_callActivationProperty(engine, instr.name, callData));
+ //### write barrier?
MOTH_END_INSTR(CallActivationProperty)
MOTH_BEGIN_INSTR(CallGlobalLookup)
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = QV4::Primitive::undefinedValue();
STOREVALUE(instr.result, Runtime::method_callGlobalLookup(engine, instr.index, callData));
+ //### write barrier?
MOTH_END_INSTR(CallGlobalLookup)
MOTH_BEGIN_INSTR(SetExceptionHandler)
@@ -752,12 +729,9 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
MOTH_END_INSTR(CallBuiltinConvertThisToObject)
MOTH_BEGIN_INSTR(CreateValue)
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = QV4::Primitive::undefinedValue();
STOREVALUE(instr.result, Runtime::method_constructValue(engine, VALUE(instr.func), callData));
+ //### write barrier?
MOTH_END_INSTR(CreateValue)
MOTH_BEGIN_INSTR(CreateProperty)