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();