diff options
author | Lars Knoll <lars.knoll@qt.io> | 2017-06-27 16:06:29 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2017-06-29 08:33:17 +0000 |
commit | dfe826d7f86db99bd6ecf681ec73c2e8c8b25a15 (patch) | |
tree | e3a98ece0c3e5599a44bbfd817abe2932d4b9355 | |
parent | 987734ff5872c397651630a616a002947fec3810 (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.cpp | 9 | ||||
-rw-r--r-- | src/qml/compiler/qv4bytecodegenerator_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 121 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth.cpp | 11 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 12 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4context_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 38 |
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) |