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 <simon.hausmann@digia.com>
This commit is contained in:
parent
5aa49a600c
commit
b0bdbbd223
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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<ExecutionContext *>(malloc(size));
|
||||
ctx->function = f;
|
||||
ctx->thisObject = thisObject;
|
||||
ctx->arguments = args;
|
||||
ctx->argumentCount = argc;
|
||||
ctx->initCallContext(current);
|
||||
current = ctx;
|
||||
return ctx;
|
||||
current = static_cast<ExecutionContext *>(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,8 +105,14 @@ struct Q_V4_EXPORT ExecutionEngine
|
|||
{
|
||||
MemoryManager *memoryManager;
|
||||
QScopedPointer<EvalISelFactory> 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 <typename T>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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<Managed *, uint>::const_iterator it = m_d->protectedObject.begin(); it != m_d->protectedObject.constEnd(); ++it)
|
||||
it.key()->mark();
|
||||
|
|
Loading…
Reference in New Issue