From b0bdbbd22370ba6e16b0e23b962c5a0195261685 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 14 Mar 2013 14:03:04 +0100 Subject: [PATCH] Remove the parent pointer from ExecutionContext It's cleaner to have an explicit stack of contexts in the Engine, esp. as the global context can get pushed onto the stack several times. This avoids an ugly hack in eval() where we created a 'copy' of the global context. Change-Id: I3936443fba6c1829a60a8e0e9a106ec75293274f Reviewed-by: Simon Hausmann --- src/v4/qv4context.cpp | 14 ++---- src/v4/qv4context.h | 3 +- src/v4/qv4engine.cpp | 96 +++++++++++++++++++++++++++--------- src/v4/qv4engine.h | 10 ++++ src/v4/qv4functionobject.cpp | 6 +-- src/v4/qv4globalobject.cpp | 7 +-- src/v4/qv4mm.cpp | 5 +- 7 files changed, 95 insertions(+), 46 deletions(-) diff --git a/src/v4/qv4context.cpp b/src/v4/qv4context.cpp index f50740e96f..5cb1d104e3 100644 --- a/src/v4/qv4context.cpp +++ b/src/v4/qv4context.cpp @@ -176,7 +176,6 @@ unsigned int ExecutionContext::variableCount() const void ExecutionContext::init(ExecutionEngine *eng) { engine = eng; - parent = 0; outer = 0; thisObject = eng->globalObject; @@ -197,12 +196,11 @@ void ExecutionContext::init(ExecutionEngine *eng) void ExecutionContext::init(ExecutionContext *p, Object *with) { engine = p->engine; - parent = p; outer = p; thisObject = p->thisObject; function = 0; - lookups = parent->lookups; + lookups = p->lookups; arguments = 0; argumentCount = 0; @@ -218,12 +216,11 @@ void ExecutionContext::init(ExecutionContext *p, Object *with) void ExecutionContext::initForCatch(ExecutionContext *p, String *exceptionVarName, const Value &exceptionValue) { engine = p->engine; - parent = p; outer = p; thisObject = p->thisObject; function = 0; - lookups = parent->lookups; + lookups = p->lookups; arguments = 0; argumentCount = 0; locals = 0; @@ -523,13 +520,10 @@ void ExecutionContext::throwURIError(Value msg) throwError(Value::fromObject(engine->newURIErrorObject(this, msg))); } -void ExecutionContext::initCallContext(ExecutionContext *parent) +void ExecutionContext::initCallContext(ExecutionEngine *engine) { - engine = parent->engine; - assert(engine->current == parent); - this->parent = parent; + this->engine = engine; outer = function->scope; - engine->current = this; exceptionVarName = 0; exceptionValue = Value::undefinedValue(); diff --git a/src/v4/qv4context.h b/src/v4/qv4context.h index 96a3dbfded..6112387095 100644 --- a/src/v4/qv4context.h +++ b/src/v4/qv4context.h @@ -77,7 +77,6 @@ struct Q_V4_EXPORT DiagnosticMessage struct ExecutionContext { ExecutionEngine *engine; - ExecutionContext *parent; ExecutionContext *outer; Value thisObject; @@ -111,7 +110,7 @@ struct ExecutionContext Value getBindingValue(ExecutionContext *scope, String *name, bool strict) const; bool deleteBinding(ExecutionContext *ctx, String *name); - void initCallContext(ExecutionContext *parent); + void initCallContext(QQmlJS::VM::ExecutionEngine *engine); void wireUpPrototype(); diff --git a/src/v4/qv4engine.cpp b/src/v4/qv4engine.cpp index ed28b15749..57d4a32fec 100644 --- a/src/v4/qv4engine.cpp +++ b/src/v4/qv4engine.cpp @@ -66,6 +66,9 @@ namespace VM { ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) : memoryManager(new QQmlJS::VM::MemoryManager) + , contextStack(0) + , contextStackPosition(0) + , contextStackSize(0) , debugger(0) , globalObject(Value::nullValue()) , globalCode(0) @@ -107,9 +110,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) emptyClass = new InternalClass(this); arrayClass = emptyClass->addMember(id_length); - rootContext = new ExecutionContext(); - rootContext->init(this); - current = rootContext; + initRootContext(); objectPrototype = new (memoryManager) ObjectPrototype(this); stringPrototype = new (memoryManager) StringPrototype(rootContext); @@ -239,49 +240,98 @@ ExecutionEngine::~ExecutionEngine() { delete globalObject.asObject(); delete rootContext; + delete [] contextStack; UnwindHelper::deregisterFunctions(functions); qDeleteAll(functions); delete memoryManager; } +void ExecutionEngine::initRootContext() +{ + ensureContextStackSize(); + rootContext = new ExecutionContext(); + rootContext->init(this); + current = rootContext; + contextStack[0] = rootContext; +} + +void ExecutionEngine::ensureContextStackSize() +{ + if (contextStackPosition < contextStackSize - 1) + return; + + const int stackSize = qMax(32, 2*contextStackSize); + ExecutionContext **newStack = new ExecutionContext *[stackSize]; + if (contextStack) + memcpy(newStack, contextStack, contextStackSize*sizeof(ExecutionContext *)); + memset(newStack + contextStackSize, 0, (stackSize - contextStackSize)*sizeof(ExecutionContext *)); + contextStackSize = stackSize; + contextStack = newStack; +} + ExecutionContext *ExecutionEngine::newWithContext(Object *with) { - ExecutionContext *withCtx = new ExecutionContext(); - withCtx->init(current, with); - current = withCtx; - return withCtx; + ensureContextStackSize(); + assert(contextStack[contextStackPosition + 1] == 0); + + ExecutionContext *ctx = new ExecutionContext(); + ctx->init(current, with); + current = ctx; + + contextStack[++contextStackPosition] = current; + return current; } ExecutionContext *ExecutionEngine::newCatchContext(String *exceptionVarName, const Value &exceptionValue) { - ExecutionContext *catchCtx = new ExecutionContext(); - catchCtx->initForCatch(current, exceptionVarName, exceptionValue); - current = catchCtx; - return catchCtx; + ensureContextStackSize(); + assert(contextStack[contextStackPosition + 1] == 0); + + ExecutionContext *ctx = new ExecutionContext(); + ctx->initForCatch(current, exceptionVarName, exceptionValue); + current = ctx; + + contextStack[++contextStackPosition] = current; + return current; } ExecutionContext *ExecutionEngine::newCallContext(FunctionObject *f, const Value &thisObject, Value *args, int argc) { + ensureContextStackSize(); + assert(contextStack[contextStackPosition + 1] == 0); + uint size = requiredMemoryForExecutionContect(f, argc); - ExecutionContext *ctx = static_cast(malloc(size)); - ctx->function = f; - ctx->thisObject = thisObject; - ctx->arguments = args; - ctx->argumentCount = argc; - ctx->initCallContext(current); - current = ctx; - return ctx; + current = static_cast(malloc(size)); + current->function = f; + current->thisObject = thisObject; + current->arguments = args; + current->argumentCount = argc; + current->initCallContext(this); + + contextStack[++contextStackPosition] = current; + return current; +} + +ExecutionContext *ExecutionEngine::pushGlobalContext() +{ + ensureContextStackSize(); + assert(contextStack[contextStackPosition + 1] == 0); + + current = rootContext; + + contextStack[++contextStackPosition] = current; + return current; } ExecutionContext *ExecutionEngine::popContext() { - ExecutionContext *oldCtx = current; - current = current->parent; - oldCtx->parent = 0; + assert(current == contextStack[contextStackPosition]); if (debugger) - debugger->justLeft(oldCtx); + debugger->justLeft(current); + contextStack[contextStackPosition] = 0; + current = contextStack[--contextStackPosition]; return current; } diff --git a/src/v4/qv4engine.h b/src/v4/qv4engine.h index ebbe33fb9d..adaa159f67 100644 --- a/src/v4/qv4engine.h +++ b/src/v4/qv4engine.h @@ -105,8 +105,14 @@ struct Q_V4_EXPORT ExecutionEngine { MemoryManager *memoryManager; QScopedPointer iselFactory; + + ExecutionContext **contextStack; + int contextStackPosition; + int contextStackSize; + ExecutionContext *current; ExecutionContext *rootContext; + WTF::BumpPointerAllocator bumperPointerAllocator; // Used by Yarr Regex engine. Identifiers *identifierCache; @@ -190,6 +196,7 @@ struct Q_V4_EXPORT ExecutionEngine ExecutionContext *newWithContext(Object *with); ExecutionContext *newCatchContext(String* exceptionVarName, const QQmlJS::VM::Value &exceptionValue); ExecutionContext *newCallContext(FunctionObject *f, const QQmlJS::VM::Value &thisObject, QQmlJS::VM::Value *args, int argc); + ExecutionContext *pushGlobalContext(); ExecutionContext *popContext(); VM::Function *newFunction(const QString &name); @@ -230,6 +237,9 @@ struct Q_V4_EXPORT ExecutionEngine void markObjects(); Value run(VM::Function *function, ExecutionContext *ctx = 0); + + void initRootContext(); + void ensureContextStackSize(); }; template diff --git a/src/v4/qv4functionobject.cpp b/src/v4/qv4functionobject.cpp index 5336862196..e43410efde 100644 --- a/src/v4/qv4functionobject.cpp +++ b/src/v4/qv4functionobject.cpp @@ -370,7 +370,7 @@ Value ScriptFunction::construct(Managed *that, ExecutionContext *context, Value try { result = f->function->code(ctx, f->function->codeData); } catch (Exception &ex) { - ex.partiallyUnwindContext(ctx->parent); + ex.partiallyUnwindContext(context); throw; } ctx->engine->popContext(); @@ -398,7 +398,7 @@ Value ScriptFunction::call(Managed *that, ExecutionContext *context, const Value try { result = f->function->code(ctx, f->function->codeData); } catch (Exception &ex) { - ex.partiallyUnwindContext(ctx->parent); + ex.partiallyUnwindContext(context); throw; } ctx->engine->popContext(); @@ -442,7 +442,7 @@ Value BuiltinFunctionOld::call(Managed *that, ExecutionContext *context, const V try { result = f->code(ctx); } catch (Exception &ex) { - ex.partiallyUnwindContext(ctx->parent); + ex.partiallyUnwindContext(context); throw; } diff --git a/src/v4/qv4globalobject.cpp b/src/v4/qv4globalobject.cpp index 5ba24c9d3a..c0fd2aaa69 100644 --- a/src/v4/qv4globalobject.cpp +++ b/src/v4/qv4globalobject.cpp @@ -370,12 +370,7 @@ Value EvalFunction::evalCall(ExecutionContext *parentContext, Value /*thisObject if (!directCall) { // the context for eval should be the global scope, so we fake a root // context - ctx = new ExecutionContext(); - ctx->init(parentContext->engine); - ctx->activation = engine->globalObject.asObject(); - ctx->strictMode = engine->rootContext->strictMode; - ctx->parent = parentContext; - ctx->engine->current = ctx; + ctx = engine->pushGlobalContext(); } if (!args[0].isString()) diff --git a/src/v4/qv4mm.cpp b/src/v4/qv4mm.cpp index 281347be24..b02df3b974 100644 --- a/src/v4/qv4mm.cpp +++ b/src/v4/qv4mm.cpp @@ -196,8 +196,9 @@ void MemoryManager::mark() { m_d->engine->markObjects(); - for (ExecutionContext *ctxt = engine()->current; ctxt; ctxt = ctxt->parent) - ctxt->mark(); + ExecutionEngine *e = engine(); + for (int i = 0; i <= e->contextStackPosition; ++i) + e->contextStack[i]->mark(); for (QHash::const_iterator it = m_d->protectedObject.begin(); it != m_d->protectedObject.constEnd(); ++it) it.key()->mark();