aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2013-11-15 16:36:13 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-12-04 09:45:33 +0100
commit0fa9cf218bdd3054585f23abfb2b707e26ce987a (patch)
tree346592c0d570d138278c659dbbbbda23ec1d148d
parent608a9600142878574a509964941413bb15c91201 (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.cpp60
-rw-r--r--src/qml/jsruntime/qv4context_p.h1
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp5
-rw-r--r--src/qml/jsruntime/qv4function.cpp33
-rw-r--r--src/qml/jsruntime/qv4function_p.h5
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp26
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h2
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;