diff options
author | Lars Knoll <lars.knoll@digia.com> | 2013-03-13 17:05:34 -0400 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2013-03-13 22:49:01 +0100 |
commit | 8ef0ca287f79a24c8e3b5f0f8101bec4b628f453 (patch) | |
tree | 93aff47edf1ce73cec480ab047f20daa9defb204 /src | |
parent | b0aa50d80397032c661b5ee26a36a52f28dc60ca (diff) |
Cleanup and unify context creation
* Always create contexts on the heap. When embedding native methods
we can't create contexts on the stack anymore without running the
risk of them being used in some scope chain.
* Unify context creation for call contexts, share the code
* Add a hack for indirect calls to eval and create a new 'fake'
global context there, so we don't mess up the context stack (it
broke badly when unwinding exceptions before).
Change-Id: I5804224dc26582f24ec79518639ceb13a8a3e967
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/v4/qmljs_environment.cpp | 29 | ||||
-rw-r--r-- | src/v4/qmljs_environment.h | 2 | ||||
-rw-r--r-- | src/v4/qmljs_runtime.cpp | 8 | ||||
-rw-r--r-- | src/v4/qv4functionobject.cpp | 32 | ||||
-rw-r--r-- | src/v4/qv4globalobject.cpp | 43 |
5 files changed, 49 insertions, 65 deletions
diff --git a/src/v4/qmljs_environment.cpp b/src/v4/qmljs_environment.cpp index 09e8783902..8398796085 100644 --- a/src/v4/qmljs_environment.cpp +++ b/src/v4/qmljs_environment.cpp @@ -186,13 +186,30 @@ ExecutionContext *ExecutionContext::createCatchScope(String *exceptionVarName, c return catchCtx; } +ExecutionContext *ExecutionContext::createCallScope(FunctionObject *f, const Value &thisObject, Value *args, int argc) +{ + 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(this); + engine->current = ctx; + return ctx; +} + + ExecutionContext *ExecutionContext::popScope() { assert(engine->current == this); - assert(withObject != 0 || exceptionVarName != 0); engine->current = parent; parent = 0; + + if (engine->debugger) + engine->debugger->justLeft(this); + return engine->current; } @@ -570,6 +587,7 @@ void ExecutionContext::throwURIError(Value msg) void ExecutionContext::initCallContext(ExecutionContext *parent) { engine = parent->engine; + assert(engine->current == parent); this->parent = parent; outer = function->scope; engine->current = this; @@ -614,15 +632,6 @@ void ExecutionContext::initCallContext(ExecutionContext *parent) engine->debugger->aboutToCall(function, this); } -void ExecutionContext::leaveCallContext() -{ - engine->current = parent; - parent = 0; - - if (engine->debugger) - engine->debugger->justLeft(this); -} - void ExecutionContext::wireUpPrototype() { assert(thisObject.isObject()); diff --git a/src/v4/qmljs_environment.h b/src/v4/qmljs_environment.h index 453ca9705e..c726c317b5 100644 --- a/src/v4/qmljs_environment.h +++ b/src/v4/qmljs_environment.h @@ -114,10 +114,10 @@ struct ExecutionContext ExecutionContext *createWithScope(Object *with); ExecutionContext *createCatchScope(String* exceptionVarName, const QQmlJS::VM::Value &exceptionValue); + ExecutionContext *createCallScope(FunctionObject *f, const QQmlJS::VM::Value &thisObject, QQmlJS::VM::Value *args, int argc); ExecutionContext *popScope(); void initCallContext(ExecutionContext *parent); - void leaveCallContext(); void wireUpPrototype(); diff --git a/src/v4/qmljs_runtime.cpp b/src/v4/qmljs_runtime.cpp index ca9c5b365e..1ecf7d4b77 100644 --- a/src/v4/qmljs_runtime.cpp +++ b/src/v4/qmljs_runtime.cpp @@ -141,12 +141,8 @@ void Exception::partiallyUnwindContext(ExecutionContext *catchingContext) if (!throwingContext) return; ExecutionContext *context = throwingContext; - while (context != catchingContext) { - ExecutionContext *parent = context->parent; - if (!context->withObject) - context->leaveCallContext(); - context = parent; - } + while (context != catchingContext) + context = context->popScope(); throwingContext = context; } diff --git a/src/v4/qv4functionobject.cpp b/src/v4/qv4functionobject.cpp index 93f6363ca5..857272ed44 100644 --- a/src/v4/qv4functionobject.cpp +++ b/src/v4/qv4functionobject.cpp @@ -364,15 +364,8 @@ Value ScriptFunction::construct(Managed *that, ExecutionContext *context, Value if (proto.isObject()) obj->prototype = proto.objectValue(); - uint size = requiredMemoryForExecutionContect(f, argc); - ExecutionContext *ctx = static_cast<ExecutionContext *>(f->needsActivation ? malloc(size) : alloca(size)); + ExecutionContext *ctx = context->createCallScope(f, Value::fromObject(obj), args, argc); - ctx->thisObject = Value::fromObject(obj); - ctx->function = f; - ctx->arguments = args; - ctx->argumentCount = argc; - - ctx->initCallContext(context); Value result = Value::undefinedValue(); try { result = f->function->code(ctx, f->function->codeData); @@ -380,7 +373,7 @@ Value ScriptFunction::construct(Managed *that, ExecutionContext *context, Value ex.partiallyUnwindContext(ctx->parent); throw; } - ctx->leaveCallContext(); + ctx->popScope(); if (result.isObject()) return result; @@ -391,10 +384,8 @@ Value ScriptFunction::call(Managed *that, ExecutionContext *context, const Value { ScriptFunction *f = static_cast<ScriptFunction *>(that); assert(f->function->code); - uint size = requiredMemoryForExecutionContect(f, argc); - ExecutionContext *ctx = static_cast<ExecutionContext *>(f->needsActivation ? malloc(size) : alloca(size)); + ExecutionContext *ctx = context->createCallScope(f, thisObject, args, argc); - ctx->thisObject = thisObject; if (!f->strictMode && !thisObject.isObject()) { if (thisObject.isUndefined() || thisObject.isNull()) { ctx->thisObject = context->engine->globalObject; @@ -403,11 +394,6 @@ Value ScriptFunction::call(Managed *that, ExecutionContext *context, const Value } } - ctx->function = f; - ctx->arguments = args; - ctx->argumentCount = argc; - - ctx->initCallContext(context); Value result = Value::undefinedValue(); try { result = f->function->code(ctx, f->function->codeData); @@ -415,7 +401,7 @@ Value ScriptFunction::call(Managed *that, ExecutionContext *context, const Value ex.partiallyUnwindContext(ctx->parent); throw; } - ctx->leaveCallContext(); + ctx->popScope(); return result; } @@ -441,8 +427,7 @@ Value BuiltinFunctionOld::construct(Managed *, ExecutionContext *ctx, Value *, i Value BuiltinFunctionOld::call(Managed *that, ExecutionContext *context, const Value &thisObject, Value *args, int argc) { BuiltinFunctionOld *f = static_cast<BuiltinFunctionOld *>(that); - uint size = requiredMemoryForExecutionContect(f, argc); - ExecutionContext *ctx = static_cast<ExecutionContext *>(f->needsActivation ? malloc(size) : alloca(size)); + ExecutionContext *ctx = context->createCallScope(f, thisObject, args, argc); ctx->thisObject = thisObject; if (!f->strictMode && !thisObject.isObject()) { @@ -453,11 +438,6 @@ Value BuiltinFunctionOld::call(Managed *that, ExecutionContext *context, const V ctx->thisObject = Value::fromObject(thisObject.toObject(context)); } - ctx->function = f; - ctx->arguments = args; - ctx->argumentCount = argc; - - ctx->initCallContext(context); Value result = Value::undefinedValue(); try { result = f->code(ctx); @@ -466,7 +446,7 @@ Value BuiltinFunctionOld::call(Managed *that, ExecutionContext *context, const V throw; } - ctx->leaveCallContext(); + ctx->popScope(); return result; } diff --git a/src/v4/qv4globalobject.cpp b/src/v4/qv4globalobject.cpp index a27e7e86a4..143b54063c 100644 --- a/src/v4/qv4globalobject.cpp +++ b/src/v4/qv4globalobject.cpp @@ -359,17 +359,23 @@ EvalFunction::EvalFunction(ExecutionContext *scope, Object *qmlActivation) this->qmlActivation = qmlActivation; } -Value EvalFunction::evalCall(ExecutionContext *context, Value /*thisObject*/, Value *args, int argc, bool directCall) +Value EvalFunction::evalCall(ExecutionContext *parentContext, Value /*thisObject*/, Value *args, int argc, bool directCall) { if (argc < 1) return Value::undefinedValue(); - ExecutionContext *ctx = context; + ExecutionEngine *engine = parentContext->engine; + ExecutionContext *ctx = parentContext; if (!directCall) { - // the context for eval should be the global scope - while (ctx->parent) - ctx = ctx->parent; + // the context for eval should be the global scope, so we fake a root + // context + ctx = parentContext->engine->newContext(); + 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()) @@ -378,30 +384,22 @@ Value EvalFunction::evalCall(ExecutionContext *context, Value /*thisObject*/, Va const QString code = args[0].stringValue()->toQString(); bool inheritContext = !ctx->strictMode; - QQmlJS::VM::Function *f = parseSource(context, QStringLiteral("eval code"), + QQmlJS::VM::Function *f = parseSource(ctx, QStringLiteral("eval code"), code, QQmlJS::Codegen::EvalCode, - (directCall && context->strictMode), inheritContext); + (directCall && parentContext->strictMode), inheritContext); if (!f) return Value::undefinedValue(); - bool strict = f->isStrict || (directCall && context->strictMode); + bool strict = f->isStrict || (ctx->strictMode); if (qmlActivation) strict = true; - uint size = requiredMemoryForExecutionContect(this, 0); - ExecutionContext *k = static_cast<ExecutionContext *>(malloc(size)); - if (strict) { + ExecutionContext *k = ctx->createCallScope(this, ctx->thisObject, 0, 0); + k->activation = qmlActivation; + k->qmlObject = qmlActivation; ctx = k; - ctx->thisObject = directCall ? context->thisObject : context->engine->globalObject; - ctx->function = this; - ctx->arguments = 0; - ctx->argumentCount = 0; - ctx->initCallContext(context); - - ctx->activation = qmlActivation; - ctx->qmlObject = qmlActivation; } // set the correct strict mode flag on the context @@ -412,15 +410,16 @@ Value EvalFunction::evalCall(ExecutionContext *context, Value /*thisObject*/, Va try { result = f->code(ctx, f->codeData); } catch (Exception &ex) { + ctx->strictMode = cstrict; if (strict) - ex.partiallyUnwindContext(ctx->parent); + ex.partiallyUnwindContext(parentContext); throw; } ctx->strictMode = cstrict; - if (strict) - ctx->leaveCallContext(); + while (engine->current != parentContext) + engine->current->popScope(); return result; } |