diff options
Diffstat (limited to 'src/qml/jsruntime/qv4function.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4function.cpp | 179 |
1 files changed, 134 insertions, 45 deletions
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 4c8117527c..7702939e23 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -38,84 +38,173 @@ ****************************************************************************/ #include "qv4function_p.h" +#include "qv4functionobject_p.h" #include "qv4managed_p.h" #include "qv4string_p.h" #include "qv4value_p.h" #include "qv4engine_p.h" #include "qv4lookup_p.h" #include <private/qv4mm_p.h> +#include <private/qv4identifiertable_p.h> +#include <private/qv4functiontable_p.h> +#include <assembler/MacroAssemblerCodeRef.h> +#include <private/qv4vme_moth_p.h> +#include <private/qqmlglobal_p.h> QT_BEGIN_NAMESPACE using namespace QV4; -Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function, - ReturnedValue (*codePtr)(ExecutionEngine *, const uchar *)) - : compiledFunction(function) - , compilationUnit(unit) - , code(codePtr) - , codeData(0) - , hasQmlDependencies(function->hasQmlDependencies()) +ReturnedValue Function::call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context) { + ExecutionEngine *engine = context->engine(); + CppStackFrame frame; + frame.init(engine, this, argv, argc); + frame.setupJSFrame(engine->jsStackTop, Value::undefinedValue(), context->d(), + thisObject ? *thisObject : Value::undefinedValue(), + Value::undefinedValue()); + + frame.push(); + engine->jsStackTop += frame.requiredJSStackFrameSize(); + + ReturnedValue result = Moth::VME::exec(&frame, engine); + + frame.pop(); + + return result; +} + +Function *Function::create(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function) { - Q_UNUSED(engine); + quint16 traceSlotCount = 0; +#if QT_CONFIG(qml_tracing) + traceSlotCount = function->nTraceInfos == CompiledData::Function::NoTracing() + ? 1 + : function->nTraceInfos; +#endif + quint8 *storage = new quint8[sizeof(Function) + traceSlotCount]; + return new(storage) Function(engine, unit, function); +} + +void Function::destroy() +{ + delete[] reinterpret_cast<quint8 *>(this); +} - internalClass = engine->internalClasses[EngineBase::Class_Empty]; - const CompiledData::LEUInt32 *formalsIndices = compiledFunction->formalsTable(); - // iterate backwards, so we get the right ordering for duplicate names +Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function) + : FunctionData(unit) + , compiledFunction(function) + , codeData(function->code()) + , jittedCode(nullptr) + , codeRef(nullptr) + , hasQmlDependencies(function->hasQmlDependencies()) +{ Scope scope(engine); - ScopedString arg(scope); - for (int i = static_cast<int>(compiledFunction->nFormals - 1); i >= 0; --i) { - arg = compilationUnit->runtimeStrings[formalsIndices[i]]; - while (1) { - InternalClass *newClass = internalClass->addMember(arg, Attr_NotConfigurable); - if (newClass != internalClass) { - internalClass = newClass; - break; - } - // duplicate arguments, need some trick to store them - MemoryManager *mm = engine->memoryManager; - arg = mm->alloc<String>(arg->d(), engine->newString(QString(0xfffe))); - } - } - nFormals = compiledFunction->nFormals; + Scoped<InternalClass> ic(scope, engine->internalClasses(EngineBase::Class_CallContext)); - const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable(); + // first locals + const quint32_le *localsIndices = compiledFunction->localsTable(); for (quint32 i = 0; i < compiledFunction->nLocals; ++i) - internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); + ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable); + + const quint32_le *formalsIndices = compiledFunction->formalsTable(); + for (quint32 i = 0; i < compiledFunction->nFormals; ++i) + ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[formalsIndices[i]]), Attr_NotConfigurable); + internalClass = ic->d(); - canUseSimpleCall = compiledFunction->flags & CompiledData::Function::CanUseSimpleCall; + nFormals = compiledFunction->nFormals; + +#if QT_CONFIG(qml_tracing) + if (tracingEnabled()) { + for (uint i = 0; i < function->nTraceInfos; ++i) + *traceInfo(i) = 0; + } +#endif } Function::~Function() { + if (codeRef) { + destroyFunctionTable(this, codeRef); + delete codeRef; + } } void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> ¶meters) { - internalClass = engine->internalClasses[EngineBase::Class_Empty]; + QStringList parameterNames; - // iterate backwards, so we get the right ordering for duplicate names - Scope scope(engine); - ScopedString arg(scope); - for (int i = parameters.size() - 1; i >= 0; --i) { - arg = engine->newString(QString::fromUtf8(parameters.at(i))); - while (1) { - InternalClass *newClass = internalClass->addMember(arg, Attr_NotConfigurable); - if (newClass != internalClass) { - internalClass = newClass; + // Resolve duplicate parameter names: + for (int i = 0, ei = parameters.count(); i != ei; ++i) { + const QByteArray ¶m = parameters.at(i); + int duplicate = -1; + + for (int j = i - 1; j >= 0; --j) { + const QByteArray &prevParam = parameters.at(j); + if (param == prevParam) { + duplicate = j; break; } - // duplicate arguments, need some trick to store them - arg = engine->memoryManager->alloc<String>(arg->d(), engine->newString(QString(0xfffe))); } + + if (duplicate == -1) { + parameterNames.append(QString::fromUtf8(param)); + } else { + const QString &dup = parameterNames[duplicate]; + parameterNames.append(dup); + parameterNames[duplicate] = + QString(0xfffe) + QString::number(duplicate) + dup; + } + } - nFormals = parameters.size(); - const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable(); + internalClass = engine->internalClasses(EngineBase::Class_CallContext); + + // first locals + const quint32_le *localsIndices = compiledFunction->localsTable(); for (quint32 i = 0; i < compiledFunction->nLocals; ++i) - internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); + internalClass = internalClass->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable); - canUseSimpleCall = false; + Scope scope(engine); + ScopedString arg(scope); + for (const QString ¶meterName : parameterNames) { + arg = engine->newIdentifier(parameterName); + internalClass = internalClass->addMember(arg->propertyKey(), Attr_NotConfigurable); + } + nFormals = parameters.size(); +} + +QString Function::prettyName(const Function *function, const void *code) +{ + QString prettyName = function ? function->name()->toQString() : QString(); + if (prettyName.isEmpty()) { + prettyName = QString::number(reinterpret_cast<quintptr>(code), 16); + prettyName.prepend(QLatin1String("QV4::Function(0x")); + prettyName.append(QLatin1Char(')')); + } + return prettyName; +} + +QQmlSourceLocation Function::sourceLocation() const +{ + return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column); +} + +QString Function::traceInfoToString() +{ + QString info = QLatin1String("=== Trace information for ") + name()->toQString() + QLatin1Char(':'); + if (!tracingEnabled()) + return info + QStringLiteral(" disabled. Interpreter call count: %1\n").arg(interpreterCallCount); + if (compiledFunction->nTraceInfos == 0) + return info + QLatin1String(" none.\n"); + + info += QLatin1Char('\n'); + for (uint i = 0, ei = compiledFunction->nTraceInfos; i < ei; ++i) { + auto bits = QString::number(*traceInfo(i), 2); + if (bits.size() < 8) + bits.prepend(QString(8 - bits.size(), '0')); + info += QStringLiteral(" %1: %2\n").arg(QString::number(i), bits); + } + return info; } QT_END_NAMESPACE |