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)
|
void ExecutionContext::init(ExecutionEngine *eng)
|
||||||
{
|
{
|
||||||
engine = eng;
|
engine = eng;
|
||||||
parent = 0;
|
|
||||||
outer = 0;
|
outer = 0;
|
||||||
thisObject = eng->globalObject;
|
thisObject = eng->globalObject;
|
||||||
|
|
||||||
|
@ -197,12 +196,11 @@ void ExecutionContext::init(ExecutionEngine *eng)
|
||||||
void ExecutionContext::init(ExecutionContext *p, Object *with)
|
void ExecutionContext::init(ExecutionContext *p, Object *with)
|
||||||
{
|
{
|
||||||
engine = p->engine;
|
engine = p->engine;
|
||||||
parent = p;
|
|
||||||
outer = p;
|
outer = p;
|
||||||
thisObject = p->thisObject;
|
thisObject = p->thisObject;
|
||||||
|
|
||||||
function = 0;
|
function = 0;
|
||||||
lookups = parent->lookups;
|
lookups = p->lookups;
|
||||||
|
|
||||||
arguments = 0;
|
arguments = 0;
|
||||||
argumentCount = 0;
|
argumentCount = 0;
|
||||||
|
@ -218,12 +216,11 @@ void ExecutionContext::init(ExecutionContext *p, Object *with)
|
||||||
void ExecutionContext::initForCatch(ExecutionContext *p, String *exceptionVarName, const Value &exceptionValue)
|
void ExecutionContext::initForCatch(ExecutionContext *p, String *exceptionVarName, const Value &exceptionValue)
|
||||||
{
|
{
|
||||||
engine = p->engine;
|
engine = p->engine;
|
||||||
parent = p;
|
|
||||||
outer = p;
|
outer = p;
|
||||||
thisObject = p->thisObject;
|
thisObject = p->thisObject;
|
||||||
|
|
||||||
function = 0;
|
function = 0;
|
||||||
lookups = parent->lookups;
|
lookups = p->lookups;
|
||||||
arguments = 0;
|
arguments = 0;
|
||||||
argumentCount = 0;
|
argumentCount = 0;
|
||||||
locals = 0;
|
locals = 0;
|
||||||
|
@ -523,13 +520,10 @@ void ExecutionContext::throwURIError(Value msg)
|
||||||
throwError(Value::fromObject(engine->newURIErrorObject(this, msg)));
|
throwError(Value::fromObject(engine->newURIErrorObject(this, msg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecutionContext::initCallContext(ExecutionContext *parent)
|
void ExecutionContext::initCallContext(ExecutionEngine *engine)
|
||||||
{
|
{
|
||||||
engine = parent->engine;
|
this->engine = engine;
|
||||||
assert(engine->current == parent);
|
|
||||||
this->parent = parent;
|
|
||||||
outer = function->scope;
|
outer = function->scope;
|
||||||
engine->current = this;
|
|
||||||
|
|
||||||
exceptionVarName = 0;
|
exceptionVarName = 0;
|
||||||
exceptionValue = Value::undefinedValue();
|
exceptionValue = Value::undefinedValue();
|
||||||
|
|
|
@ -77,7 +77,6 @@ struct Q_V4_EXPORT DiagnosticMessage
|
||||||
struct ExecutionContext
|
struct ExecutionContext
|
||||||
{
|
{
|
||||||
ExecutionEngine *engine;
|
ExecutionEngine *engine;
|
||||||
ExecutionContext *parent;
|
|
||||||
ExecutionContext *outer;
|
ExecutionContext *outer;
|
||||||
Value thisObject;
|
Value thisObject;
|
||||||
|
|
||||||
|
@ -111,7 +110,7 @@ struct ExecutionContext
|
||||||
Value getBindingValue(ExecutionContext *scope, String *name, bool strict) const;
|
Value getBindingValue(ExecutionContext *scope, String *name, bool strict) const;
|
||||||
bool deleteBinding(ExecutionContext *ctx, String *name);
|
bool deleteBinding(ExecutionContext *ctx, String *name);
|
||||||
|
|
||||||
void initCallContext(ExecutionContext *parent);
|
void initCallContext(QQmlJS::VM::ExecutionEngine *engine);
|
||||||
|
|
||||||
void wireUpPrototype();
|
void wireUpPrototype();
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,9 @@ namespace VM {
|
||||||
|
|
||||||
ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
|
ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
|
||||||
: memoryManager(new QQmlJS::VM::MemoryManager)
|
: memoryManager(new QQmlJS::VM::MemoryManager)
|
||||||
|
, contextStack(0)
|
||||||
|
, contextStackPosition(0)
|
||||||
|
, contextStackSize(0)
|
||||||
, debugger(0)
|
, debugger(0)
|
||||||
, globalObject(Value::nullValue())
|
, globalObject(Value::nullValue())
|
||||||
, globalCode(0)
|
, globalCode(0)
|
||||||
|
@ -107,9 +110,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
|
||||||
|
|
||||||
emptyClass = new InternalClass(this);
|
emptyClass = new InternalClass(this);
|
||||||
arrayClass = emptyClass->addMember(id_length);
|
arrayClass = emptyClass->addMember(id_length);
|
||||||
rootContext = new ExecutionContext();
|
initRootContext();
|
||||||
rootContext->init(this);
|
|
||||||
current = rootContext;
|
|
||||||
|
|
||||||
objectPrototype = new (memoryManager) ObjectPrototype(this);
|
objectPrototype = new (memoryManager) ObjectPrototype(this);
|
||||||
stringPrototype = new (memoryManager) StringPrototype(rootContext);
|
stringPrototype = new (memoryManager) StringPrototype(rootContext);
|
||||||
|
@ -239,49 +240,98 @@ ExecutionEngine::~ExecutionEngine()
|
||||||
{
|
{
|
||||||
delete globalObject.asObject();
|
delete globalObject.asObject();
|
||||||
delete rootContext;
|
delete rootContext;
|
||||||
|
delete [] contextStack;
|
||||||
UnwindHelper::deregisterFunctions(functions);
|
UnwindHelper::deregisterFunctions(functions);
|
||||||
qDeleteAll(functions);
|
qDeleteAll(functions);
|
||||||
delete memoryManager;
|
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 *ExecutionEngine::newWithContext(Object *with)
|
||||||
{
|
{
|
||||||
ExecutionContext *withCtx = new ExecutionContext();
|
ensureContextStackSize();
|
||||||
withCtx->init(current, with);
|
assert(contextStack[contextStackPosition + 1] == 0);
|
||||||
current = withCtx;
|
|
||||||
return withCtx;
|
ExecutionContext *ctx = new ExecutionContext();
|
||||||
|
ctx->init(current, with);
|
||||||
|
current = ctx;
|
||||||
|
|
||||||
|
contextStack[++contextStackPosition] = current;
|
||||||
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutionContext *ExecutionEngine::newCatchContext(String *exceptionVarName, const Value &exceptionValue)
|
ExecutionContext *ExecutionEngine::newCatchContext(String *exceptionVarName, const Value &exceptionValue)
|
||||||
{
|
{
|
||||||
ExecutionContext *catchCtx = new ExecutionContext();
|
ensureContextStackSize();
|
||||||
catchCtx->initForCatch(current, exceptionVarName, exceptionValue);
|
assert(contextStack[contextStackPosition + 1] == 0);
|
||||||
current = catchCtx;
|
|
||||||
return catchCtx;
|
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)
|
ExecutionContext *ExecutionEngine::newCallContext(FunctionObject *f, const Value &thisObject, Value *args, int argc)
|
||||||
{
|
{
|
||||||
|
ensureContextStackSize();
|
||||||
|
assert(contextStack[contextStackPosition + 1] == 0);
|
||||||
|
|
||||||
uint size = requiredMemoryForExecutionContect(f, argc);
|
uint size = requiredMemoryForExecutionContect(f, argc);
|
||||||
ExecutionContext *ctx = static_cast<ExecutionContext *>(malloc(size));
|
current = static_cast<ExecutionContext *>(malloc(size));
|
||||||
ctx->function = f;
|
current->function = f;
|
||||||
ctx->thisObject = thisObject;
|
current->thisObject = thisObject;
|
||||||
ctx->arguments = args;
|
current->arguments = args;
|
||||||
ctx->argumentCount = argc;
|
current->argumentCount = argc;
|
||||||
ctx->initCallContext(current);
|
current->initCallContext(this);
|
||||||
current = ctx;
|
|
||||||
return ctx;
|
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 *ExecutionEngine::popContext()
|
||||||
{
|
{
|
||||||
ExecutionContext *oldCtx = current;
|
assert(current == contextStack[contextStackPosition]);
|
||||||
current = current->parent;
|
|
||||||
oldCtx->parent = 0;
|
|
||||||
|
|
||||||
if (debugger)
|
if (debugger)
|
||||||
debugger->justLeft(oldCtx);
|
debugger->justLeft(current);
|
||||||
|
|
||||||
|
contextStack[contextStackPosition] = 0;
|
||||||
|
current = contextStack[--contextStackPosition];
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,8 +105,14 @@ struct Q_V4_EXPORT ExecutionEngine
|
||||||
{
|
{
|
||||||
MemoryManager *memoryManager;
|
MemoryManager *memoryManager;
|
||||||
QScopedPointer<EvalISelFactory> iselFactory;
|
QScopedPointer<EvalISelFactory> iselFactory;
|
||||||
|
|
||||||
|
ExecutionContext **contextStack;
|
||||||
|
int contextStackPosition;
|
||||||
|
int contextStackSize;
|
||||||
|
|
||||||
ExecutionContext *current;
|
ExecutionContext *current;
|
||||||
ExecutionContext *rootContext;
|
ExecutionContext *rootContext;
|
||||||
|
|
||||||
WTF::BumpPointerAllocator bumperPointerAllocator; // Used by Yarr Regex engine.
|
WTF::BumpPointerAllocator bumperPointerAllocator; // Used by Yarr Regex engine.
|
||||||
|
|
||||||
Identifiers *identifierCache;
|
Identifiers *identifierCache;
|
||||||
|
@ -190,6 +196,7 @@ struct Q_V4_EXPORT ExecutionEngine
|
||||||
ExecutionContext *newWithContext(Object *with);
|
ExecutionContext *newWithContext(Object *with);
|
||||||
ExecutionContext *newCatchContext(String* exceptionVarName, const QQmlJS::VM::Value &exceptionValue);
|
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 *newCallContext(FunctionObject *f, const QQmlJS::VM::Value &thisObject, QQmlJS::VM::Value *args, int argc);
|
||||||
|
ExecutionContext *pushGlobalContext();
|
||||||
ExecutionContext *popContext();
|
ExecutionContext *popContext();
|
||||||
|
|
||||||
VM::Function *newFunction(const QString &name);
|
VM::Function *newFunction(const QString &name);
|
||||||
|
@ -230,6 +237,9 @@ struct Q_V4_EXPORT ExecutionEngine
|
||||||
void markObjects();
|
void markObjects();
|
||||||
|
|
||||||
Value run(VM::Function *function, ExecutionContext *ctx = 0);
|
Value run(VM::Function *function, ExecutionContext *ctx = 0);
|
||||||
|
|
||||||
|
void initRootContext();
|
||||||
|
void ensureContextStackSize();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
@ -370,7 +370,7 @@ Value ScriptFunction::construct(Managed *that, ExecutionContext *context, Value
|
||||||
try {
|
try {
|
||||||
result = f->function->code(ctx, f->function->codeData);
|
result = f->function->code(ctx, f->function->codeData);
|
||||||
} catch (Exception &ex) {
|
} catch (Exception &ex) {
|
||||||
ex.partiallyUnwindContext(ctx->parent);
|
ex.partiallyUnwindContext(context);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
ctx->engine->popContext();
|
ctx->engine->popContext();
|
||||||
|
@ -398,7 +398,7 @@ Value ScriptFunction::call(Managed *that, ExecutionContext *context, const Value
|
||||||
try {
|
try {
|
||||||
result = f->function->code(ctx, f->function->codeData);
|
result = f->function->code(ctx, f->function->codeData);
|
||||||
} catch (Exception &ex) {
|
} catch (Exception &ex) {
|
||||||
ex.partiallyUnwindContext(ctx->parent);
|
ex.partiallyUnwindContext(context);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
ctx->engine->popContext();
|
ctx->engine->popContext();
|
||||||
|
@ -442,7 +442,7 @@ Value BuiltinFunctionOld::call(Managed *that, ExecutionContext *context, const V
|
||||||
try {
|
try {
|
||||||
result = f->code(ctx);
|
result = f->code(ctx);
|
||||||
} catch (Exception &ex) {
|
} catch (Exception &ex) {
|
||||||
ex.partiallyUnwindContext(ctx->parent);
|
ex.partiallyUnwindContext(context);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -370,12 +370,7 @@ Value EvalFunction::evalCall(ExecutionContext *parentContext, Value /*thisObject
|
||||||
if (!directCall) {
|
if (!directCall) {
|
||||||
// the context for eval should be the global scope, so we fake a root
|
// the context for eval should be the global scope, so we fake a root
|
||||||
// context
|
// context
|
||||||
ctx = new ExecutionContext();
|
ctx = engine->pushGlobalContext();
|
||||||
ctx->init(parentContext->engine);
|
|
||||||
ctx->activation = engine->globalObject.asObject();
|
|
||||||
ctx->strictMode = engine->rootContext->strictMode;
|
|
||||||
ctx->parent = parentContext;
|
|
||||||
ctx->engine->current = ctx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args[0].isString())
|
if (!args[0].isString())
|
||||||
|
|
|
@ -196,8 +196,9 @@ void MemoryManager::mark()
|
||||||
{
|
{
|
||||||
m_d->engine->markObjects();
|
m_d->engine->markObjects();
|
||||||
|
|
||||||
for (ExecutionContext *ctxt = engine()->current; ctxt; ctxt = ctxt->parent)
|
ExecutionEngine *e = engine();
|
||||||
ctxt->mark();
|
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)
|
for (QHash<Managed *, uint>::const_iterator it = m_d->protectedObject.begin(); it != m_d->protectedObject.constEnd(); ++it)
|
||||||
it.key()->mark();
|
it.key()->mark();
|
||||||
|
|
Loading…
Reference in New Issue