diff options
author | Lars Knoll <lars.knoll@digia.com> | 2013-11-15 16:36:13 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-12-04 09:45:33 +0100 |
commit | 0fa9cf218bdd3054585f23abfb2b707e26ce987a (patch) | |
tree | 346592c0d570d138278c659dbbbbda23ec1d148d | |
parent | 608a9600142878574a509964941413bb15c91201 (diff) |
Use an internalClass to represent formals and locals in CallContexts
formals and locals in a CallContext where so far accessed through a
linear search in ExecutionContext::getProperty. Fix this by
introducing an internalClass for the Function used by the call
context.
Change-Id: I1141efa12b19d6de4a354bfd6e769c5ffcb8898b
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
-rw-r--r-- | src/qml/jsruntime/qv4context.cpp | 60 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4context_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4debugging.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4function.cpp | 33 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4function_p.h | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 26 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject_p.h | 2 |
7 files changed, 65 insertions, 67 deletions
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index b0fb535361..90e6850161 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -172,7 +172,7 @@ String * const *ExecutionContext::formals() const if (type < Type_SimpleCallContext) return 0; QV4::FunctionObject *f = static_cast<const CallContext *>(this)->function; - return f ? f->formalParameterList : 0; + return (f && f->function) ? f->function->internalClass->nameMap.constData() : 0; } unsigned int ExecutionContext::formalCount() const @@ -188,7 +188,7 @@ String * const *ExecutionContext::variables() const if (type < Type_SimpleCallContext) return 0; QV4::FunctionObject *f = static_cast<const CallContext *>(this)->function; - return f ? f->varList : 0; + return (f && f->function) ? f->function->internalClass->nameMap.constData() + f->function->nArguments : 0; } unsigned int ExecutionContext::variableCount() const @@ -282,12 +282,10 @@ bool ExecutionContext::deleteProperty(const StringRef name) CallContext *c = static_cast<CallContext *>(ctx); FunctionObject *f = c->function; if (f->needsActivation || hasWith) { - for (unsigned int i = 0; i < f->varCount; ++i) - if (f->varList[i]->isEqualTo(name)) - return false; - for (int i = (int)f->formalParameterCount - 1; i >= 0; --i) - if (f->formalParameterList[i]->isEqualTo(name)) - return false; + uint index = f->function->internalClass->find(name); + if (index < UINT_MAX) + // ### throw in strict mode? + return false; } if (c->activation && c->activation->__hasProperty__(name)) return c->activation->deleteProperty(name); @@ -357,16 +355,18 @@ void ExecutionContext::setProperty(const StringRef name, const ValueRef value) ScopedObject activation(scope, (Object *)0); if (ctx->type >= Type_CallContext) { CallContext *c = static_cast<CallContext *>(ctx); - for (unsigned int i = 0; i < c->function->varCount; ++i) - if (c->function->varList[i]->isEqualTo(name)) { - c->locals[i] = *value; - return; - } - for (int i = (int)c->function->formalParameterCount - 1; i >= 0; --i) - if (c->function->formalParameterList[i]->isEqualTo(name)) { - c->callData->args[i] = *value; + if (c->function->function) { + uint index = c->function->function->internalClass->find(name); + if (index < UINT_MAX) { + if (index < c->function->formalParameterCount) { + c->callData->args[c->function->formalParameterCount - index - 1] = *value; + } else { + index -= c->function->formalParameterCount; + c->locals[index] = *value; + } return; } + } activation = c->activation; } else if (ctx->type == Type_GlobalContext) { activation = static_cast<GlobalContext *>(ctx)->global; @@ -419,13 +419,13 @@ ReturnedValue ExecutionContext::getProperty(const StringRef name) else if (ctx->type >= Type_CallContext) { QV4::CallContext *c = static_cast<CallContext *>(ctx); ScopedFunctionObject f(scope, c->function); - if (f->needsActivation || hasWith || hasCatchScope) { - for (unsigned int i = 0; i < f->varCount; ++i) - if (f->varList[i]->isEqualTo(name)) - return c->locals[i].asReturnedValue(); - for (int i = (int)f->formalParameterCount - 1; i >= 0; --i) - if (f->formalParameterList[i]->isEqualTo(name)) - return c->callData->args[i].asReturnedValue(); + if (f->function && (f->needsActivation || hasWith || hasCatchScope)) { + uint index = f->function->internalClass->find(name); + if (index < UINT_MAX) { + if (index < c->function->formalParameterCount) + return c->callData->args[c->function->formalParameterCount - index - 1].asReturnedValue(); + return c->locals[index - c->function->formalParameterCount].asReturnedValue(); + } } if (c->activation) { bool hasProperty = false; @@ -485,13 +485,13 @@ ReturnedValue ExecutionContext::getPropertyAndBase(const StringRef name, ObjectR else if (ctx->type >= Type_CallContext) { QV4::CallContext *c = static_cast<CallContext *>(ctx); FunctionObject *f = c->function; - if (f->needsActivation || hasWith || hasCatchScope) { - for (unsigned int i = 0; i < f->varCount; ++i) - if (f->varList[i]->isEqualTo(name)) - return c->locals[i].asReturnedValue(); - for (int i = (int)f->formalParameterCount - 1; i >= 0; --i) - if (f->formalParameterList[i]->isEqualTo(name)) - return c->callData->args[i].asReturnedValue(); + if (f->function && (f->needsActivation || hasWith || hasCatchScope)) { + uint index = f->function->internalClass->find(name); + if (index < UINT_MAX) { + if (index < c->function->formalParameterCount) + return c->callData->args[c->function->formalParameterCount - index - 1].asReturnedValue(); + return c->locals[index - c->function->formalParameterCount].asReturnedValue(); + } } if (c->activation) { bool hasProperty = false; diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index e7f5ee9a9e..c06c10453b 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -131,6 +131,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed CatchContext *newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue); CallContext *newQmlContext(FunctionObject *f, ObjectRef qml); + // formals are in reverse order String * const *formals() const; unsigned int formalCount() const; String * const *variables() const; diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index 95b4100651..1673428c0b 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -299,9 +299,10 @@ void Debugger::collectArgumentsInContext(Collector *collector, int frameNr, int Scope scope(engine); ScopedValue v(scope); - for (unsigned i = 0, ei = ctxt->formalCount(); i != ei; ++i) { + int nFormals = ctxt->formalCount(); + for (unsigned i = 0, ei = nFormals; i != ei; ++i) { QString qName; - if (String *name = ctxt->formals()[i]) + if (String *name = ctxt->formals()[nFormals - i - 1]) qName = name->toQString(); v = ctxt->argument(i); collector->collect(qName, v); diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 950224386d..0e90e213c4 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -62,18 +62,29 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, name = compilationUnit->runtimeStrings[compiledFunction->nameIndex].asString(); - formals.resize(compiledFunction->nFormals); - formals.fill(0); - const quint32 *formalsIndices = compiledFunction->formalsTable(); - for (quint32 i = 0; i < compiledFunction->nFormals; ++i) - formals[i] = compilationUnit->runtimeStrings[formalsIndices[i]].asString(); + nArguments = compiledFunction->nFormals; + internalClass = engine->emptyClass; + const quint32 *formalsIndices = compiledFunction->formalsTable(); + // iterate backwards, so we get the right ordering for duplicate names + for (int i = static_cast<int>(compiledFunction->nFormals - 1); i >= 0; --i) { + String *arg = compilationUnit->runtimeStrings[formalsIndices[i]].asString(); + while (1) { + InternalClass *newClass = internalClass->addMember(arg, Attr_NotConfigurable); + if (newClass != internalClass) { + internalClass = newClass; + break; + } + // duplicate arguments, need some trick to store them + arg = new (engine->memoryManager) String(engine, arg, engine->newString(QString(0xfffe))->getPointer()); + } + } - locals.resize(compiledFunction->nLocals); - locals.fill(0); const quint32 *localsIndices = compiledFunction->localsTable(); - for (quint32 i = 0; i < compiledFunction->nLocals; ++i) - locals[i] = compilationUnit->runtimeStrings[localsIndices[i]].asString(); + for (quint32 i = 0; i < compiledFunction->nLocals; ++i) { + String *local = compilationUnit->runtimeStrings[localsIndices[i]].asString(); + internalClass = internalClass->addMember(local, Attr_NotConfigurable); + } } Function::~Function() @@ -84,10 +95,6 @@ Function::~Function() void Function::mark(ExecutionEngine *e) { name.mark(e); - for (int i = 0; i < formals.size(); ++i) - formals.at(i)->mark(e); - for (int i = 0; i < locals.size(); ++i) - locals.at(i)->mark(e); } namespace QV4 { diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index a7b569cf7e..8d07853b45 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -90,8 +90,9 @@ struct Function { const uchar *codeData; quint32 codeSize; - QVector<String *> formals; - QVector<String *> locals; + // first nArguments names in internalClass are the actual arguments + int nArguments; + InternalClass *internalClass; Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function, ReturnedValue (*codePtr)(ExecutionContext *, const uchar *), quint32 _codeSize); diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 194320528c..b9859d20e5 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -76,8 +76,6 @@ DEFINE_MANAGED_VTABLE(FunctionObject); FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto) : Object(createProto ? scope->engine->functionWithProtoClass : scope->engine->functionClass) , scope(scope) - , formalParameterList(0) - , varList(0) , formalParameterCount(0) , varCount(0) , function(0) @@ -90,8 +88,6 @@ FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bo FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto) : Object(createProto ? scope->engine->functionWithProtoClass : scope->engine->functionClass) , scope(scope) - , formalParameterList(0) - , varList(0) , formalParameterCount(0) , varCount(0) , function(0) @@ -110,8 +106,6 @@ FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, boo FunctionObject::FunctionObject(InternalClass *ic) : Object(ic) , scope(ic->engine->rootContext) - , formalParameterList(0) - , varList(0) , formalParameterCount(0) , varCount(0) , function(0) @@ -410,12 +404,10 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function) needsActivation = function->needsActivation(); strictMode = function->isStrict(); - formalParameterCount = function->formals.size(); - formalParameterList = function->formals.constData(); - defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount)); + formalParameterCount = function->nArguments; + varCount = function->internalClass->size - function->nArguments; - varCount = function->locals.size(); - varList = function->locals.constData(); + defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount)); if (scope->strictMode) { Property pd = Property::fromAccessor(v4->thrower, v4->thrower); @@ -497,12 +489,10 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu needsActivation = function->needsActivation(); strictMode = function->isStrict(); - formalParameterCount = function->formals.size(); - formalParameterList = function->formals.constData(); - defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount)); + formalParameterCount = function->nArguments; + varCount = function->internalClass->size - function->nArguments; - varCount = function->locals.size(); - varList = function->locals.constData(); + defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount)); if (scope->strictMode) { Property pd = Property::fromAccessor(v4->thrower, v4->thrower); @@ -537,7 +527,7 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData) ctx.compilationUnit = f->function->compilationUnit; ctx.lookups = ctx.compilationUnit->runtimeLookups; ctx.outer = f->scope; - ctx.locals = v4->stackPush(f->function->locals.size()); + ctx.locals = v4->stackPush(f->varCount); while (callData->argc < (int)f->formalParameterCount) { callData->args[callData->argc] = Encode::undefined(); ++callData->argc; @@ -575,7 +565,7 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData) ctx.compilationUnit = f->function->compilationUnit; ctx.lookups = ctx.compilationUnit->runtimeLookups; ctx.outer = f->scope; - ctx.locals = v4->stackPush(f->function->locals.size()); + ctx.locals = v4->stackPush(f->varCount); while (callData->argc < (int)f->formalParameterCount) { callData->args[callData->argc] = Encode::undefined(); ++callData->argc; diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index c4fd49bec5..990989363c 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -108,8 +108,6 @@ struct Q_QML_EXPORT FunctionObject: Object { ExecutionContext *scope; SafeString name; - String * const *formalParameterList; - String * const *varList; unsigned int formalParameterCount; unsigned int varCount; Function *function; |