aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2013-03-13 17:05:34 -0400
committerSimon Hausmann <simon.hausmann@digia.com>2013-03-13 22:49:01 +0100
commit8ef0ca287f79a24c8e3b5f0f8101bec4b628f453 (patch)
tree93aff47edf1ce73cec480ab047f20daa9defb204 /src
parentb0aa50d80397032c661b5ee26a36a52f28dc60ca (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.cpp29
-rw-r--r--src/v4/qmljs_environment.h2
-rw-r--r--src/v4/qmljs_runtime.cpp8
-rw-r--r--src/v4/qv4functionobject.cpp32
-rw-r--r--src/v4/qv4globalobject.cpp43
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;
}