From 8da2e2af2634fbba0920a6296ad470c491ae00f7 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 5 Apr 2013 15:57:26 +0200 Subject: Move activation out of ExecutionContext Have an activation object (for now) in CallContext, and a global object in the GlobalContext. Change-Id: I02b1e6a2e976d914acfcc3d35cd8abda08dfd298 Reviewed-by: Simon Hausmann --- src/v4/qv4context.cpp | 187 ++++++++++++++++++++++++++++---------------------- src/v4/qv4context.h | 5 +- src/v4/qv4engine.cpp | 2 +- src/v4/qv4v8.cpp | 5 +- 4 files changed, 113 insertions(+), 86 deletions(-) diff --git a/src/v4/qv4context.cpp b/src/v4/qv4context.cpp index 0fac836858..1ce278860d 100644 --- a/src/v4/qv4context.cpp +++ b/src/v4/qv4context.cpp @@ -81,8 +81,20 @@ String *DiagnosticMessage::buildFullMessage(ExecutionContext *ctx) const void ExecutionContext::createMutableBinding(String *name, bool deletable) { - if (!activation) - activation = engine->newObject(); + + // find the right context to create the binding on + Object *activation = engine->globalObject.objectValue(); + ExecutionContext *ctx = this; + while (ctx) { + if (ctx->type == Type_CallContext || ctx->type == Type_QmlContext) { + CallContext *c = static_cast(ctx); + if (!c->activation) + c->activation = engine->newObject(); + activation = c->activation; + break; + } + ctx = ctx->outer; + } if (activation->__hasProperty__(this, name)) return; @@ -95,31 +107,6 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) activation->__defineOwnProperty__(this, name, &desc); } -bool ExecutionContext::setMutableBinding(ExecutionContext *scope, String *name, const Value &value) -{ - // ### throw if scope->strict is true, and it would change an immutable binding - if (type == Type_CallContext) { - CallContext *c = static_cast(this); - for (unsigned int i = 0; i < c->function->varCount; ++i) - if (c->function->varList[i]->isEqualTo(name)) { - c->locals[i] = value; - return true; - } - for (int i = (int)c->function->formalParameterCount - 1; i >= 0; --i) - if (c->function->formalParameterList[i]->isEqualTo(name)) { - c->arguments[i] = value; - return true; - } - } - - if (activation && (type == Type_QmlContext || activation->__hasProperty__(scope, name))) { - activation->put(scope, name, value); - return true; - } - - return false; -} - String * const *ExecutionContext::formals() const { return type == Type_CallContext ? static_cast(this)->function->formalParameterList : 0; @@ -150,11 +137,11 @@ void GlobalContext::init(ExecutionEngine *eng) engine = eng; outer = 0; lookups = 0; + global = 0; // ### remove arguments = 0; argumentCount = 0; - activation = 0; } void WithContext::init(ExecutionContext *p, Object *with) @@ -172,7 +159,6 @@ void WithContext::init(ExecutionContext *p, Object *with) // ### remove arguments = 0; argumentCount = 0; - activation = 0; } void CatchContext::init(ExecutionContext *p, String *exceptionVarName, const Value &exceptionValue) @@ -191,7 +177,6 @@ void CatchContext::init(ExecutionContext *p, String *exceptionVarName, const Val // ### remove arguments = 0; argumentCount = 0; - activation = 0; } void CallContext::initCallContext(ExecutionEngine *engine) @@ -231,8 +216,14 @@ void CallContext::initCallContext(ExecutionEngine *engine) ArgumentsObject *args = new (engine->memoryManager) ArgumentsObject(this, function->formalParameterCount, argc); args->prototype = engine->objectPrototype; Value arguments = Value::fromObject(args); - createMutableBinding(engine->id_arguments, false); - setMutableBinding(this, engine->id_arguments, arguments); + activation = engine->newObject(); + PropertyDescriptor desc; + desc.value = Value::fromObject(args); + desc.type = PropertyDescriptor::Data; + desc.configurable = PropertyDescriptor::Disabled; + desc.writable = PropertyDescriptor::Enabled; + desc.enumerable = PropertyDescriptor::Enabled; + activation->__defineOwnProperty__(this, engine->id_arguments, &desc); } if (engine->debugger) @@ -249,16 +240,11 @@ bool ExecutionContext::deleteProperty(String *name) WithContext *w = static_cast(ctx); if (w->withObject->__hasProperty__(this, name)) return w->withObject->deleteProperty(this, name); - } else { - if (ctx->activation && ctx->activation->__hasProperty__(this, name)) - return ctx->activation->deleteProperty(this, name); - } - if (ctx->type == Type_CatchContext) { + } else if (ctx->type == Type_CatchContext) { CatchContext *c = static_cast(ctx); if (c->exceptionVarName->isEqualTo(name)) return false; - } - if (ctx->type == Type_CallContext) { + } else if (ctx->type == Type_CallContext || ctx->type == Type_QmlContext) { CallContext *c = static_cast(ctx); FunctionObject *f = c->function; if (f->needsActivation || hasWith) { @@ -269,8 +255,15 @@ bool ExecutionContext::deleteProperty(String *name) if (f->formalParameterList[i]->isEqualTo(name)) return false; } + if (c->activation && c->activation->__hasProperty__(this, name)) + return c->activation->deleteProperty(this, name); + } else if (ctx->type == Type_GlobalContext) { + GlobalContext *g = static_cast(ctx); + if (g->global->__hasProperty__(this, name)) + return g->global->deleteProperty(this, name); } } + if (strictMode) throwSyntaxError(0); return true; @@ -294,24 +287,24 @@ void ExecutionContext::mark() for (unsigned arg = 0, lastArg = argumentCount; arg < lastArg; ++arg) arguments[arg].mark(); - if (type == Type_CallContext) { + if (type == Type_CallContext || type == Type_QmlContext) { VM::CallContext *c = static_cast(this); for (unsigned local = 0, lastLocal = c->variableCount(); local < lastLocal; ++local) c->locals[local].mark(); c->function->mark(); - } - - if (activation) - activation->mark(); - if (type == Type_WithContext) { + if (c->activation) + c->activation->mark(); + } else if (type == Type_WithContext) { WithContext *w = static_cast(this); w->withObject->mark(); - } - if (type == Type_CatchContext) { + } else if (type == Type_CatchContext) { CatchContext *c = static_cast(this); if (c->exceptionVarName) c->exceptionVarName->mark(); c->exceptionValue.mark(); + } else if (type == Type_GlobalContext) { + GlobalContext *g = static_cast(this); + g->global->mark(); } } @@ -328,8 +321,28 @@ void ExecutionContext::setProperty(String *name, const Value& value) static_cast(ctx)->exceptionValue = value; return; } else { - if (ctx->setMutableBinding(this, name, value)) + Object *activation = 0; + if (ctx->type == Type_CallContext || ctx->type == Type_QmlContext) { + CallContext *c = static_cast(ctx); + for (unsigned int i = 0; i < c->function->varCount; ++i) + if (c->function->varList[i]->isEqualTo(name)) { + c->locals[i] = value; + return; + } + for (int i = (int)c->function->formalParameterCount - 1; i >= 0; --i) + if (c->function->formalParameterList[i]->isEqualTo(name)) { + c->arguments[i] = value; + return; + } + activation = c->activation; + } else if (ctx->type == Type_GlobalContext) { + activation = static_cast(ctx)->global; + } + + if (activation && (ctx->type == Type_QmlContext || activation->__hasProperty__(this, name))) { + activation->put(this, name, value); return; + } } } if (strictMode || name->isEqualTo(engine->id_this)) @@ -358,14 +371,14 @@ Value ExecutionContext::getProperty(String *name) continue; } - if (ctx->type == Type_CatchContext) { + else if (ctx->type == Type_CatchContext) { hasCatchScope = true; CatchContext *c = static_cast(ctx); if (c->exceptionVarName->isEqualTo(name)) return c->exceptionValue; } - if (ctx->type == Type_CallContext) { + else if (ctx->type == Type_CallContext || ctx->type == Type_QmlContext) { VM::CallContext *c = static_cast(ctx); FunctionObject *f = c->function; if (f->needsActivation || hasWith || hasCatchScope) { @@ -376,20 +389,24 @@ Value ExecutionContext::getProperty(String *name) if (f->formalParameterList[i]->isEqualTo(name)) return c->arguments[i]; } + if (c->activation) { + bool hasProperty = false; + Value v = c->activation->get(c, name, &hasProperty); + if (hasProperty) + return v; + } + if (f->function && f->function->isNamedExpression + && name->isEqualTo(f->function->name)) + return Value::fromObject(c->function); } - if (ctx->activation) { + + else if (ctx->type == Type_GlobalContext) { + GlobalContext *g = static_cast(ctx); bool hasProperty = false; - Value v = ctx->activation->get(ctx, name, &hasProperty); + Value v = g->global->get(g, name, &hasProperty); if (hasProperty) return v; } - if (ctx->type == Type_CallContext) { - CallContext *c = static_cast(ctx); - FunctionObject *f = c->function; - if (f->function && f->function->isNamedExpression - && name->isEqualTo(f->function->name)) - return Value::fromObject(c->function); - } } throwReferenceError(Value::fromString(name)); return Value::undefinedValue(); @@ -416,14 +433,14 @@ Value ExecutionContext::getPropertyNoThrow(String *name) continue; } - if (ctx->type == Type_CatchContext) { + else if (ctx->type == Type_CatchContext) { hasCatchScope = true; CatchContext *c = static_cast(ctx); if (c->exceptionVarName->isEqualTo(name)) return c->exceptionValue; } - if (ctx->type == Type_CallContext) { + else if (ctx->type == Type_CallContext || ctx->type == Type_QmlContext) { VM::CallContext *c = static_cast(ctx); FunctionObject *f = c->function; if (f->needsActivation || hasWith || hasCatchScope) { @@ -434,20 +451,24 @@ Value ExecutionContext::getPropertyNoThrow(String *name) if (f->formalParameterList[i]->isEqualTo(name)) return c->arguments[i]; } + if (c->activation) { + bool hasProperty = false; + Value v = c->activation->get(c, name, &hasProperty); + if (hasProperty) + return v; + } + if (f->function && f->function->isNamedExpression + && name->isEqualTo(f->function->name)) + return Value::fromObject(c->function); } - if (ctx->activation) { + + else if (ctx->type == Type_GlobalContext) { + GlobalContext *g = static_cast(ctx); bool hasProperty = false; - Value v = ctx->activation->get(ctx, name, &hasProperty); + Value v = g->global->get(g, name, &hasProperty); if (hasProperty) return v; } - if (ctx->type == Type_CallContext) { - CallContext *c = static_cast(ctx); - FunctionObject *f = c->function; - if (f->function && f->function->isNamedExpression - && name->isEqualTo(f->function->name)) - return Value::fromObject(c->function); - } } return Value::undefinedValue(); } @@ -475,14 +496,14 @@ Value ExecutionContext::getPropertyAndBase(String *name, Object **base) continue; } - if (ctx->type == Type_CatchContext) { + else if (ctx->type == Type_CatchContext) { hasCatchScope = true; CatchContext *c = static_cast(ctx); if (c->exceptionVarName->isEqualTo(name)) return c->exceptionValue; } - if (ctx->type == Type_CallContext) { + else if (ctx->type == Type_CallContext || ctx->type == Type_QmlContext) { VM::CallContext *c = static_cast(ctx); FunctionObject *f = c->function; if (f->needsActivation || hasWith || hasCatchScope) { @@ -493,20 +514,24 @@ Value ExecutionContext::getPropertyAndBase(String *name, Object **base) if (f->formalParameterList[i]->isEqualTo(name)) return c->arguments[i]; } + if (c->activation) { + bool hasProperty = false; + Value v = c->activation->get(c, name, &hasProperty); + if (hasProperty) + return v; + } + if (f->function && f->function->isNamedExpression + && name->isEqualTo(f->function->name)) + return Value::fromObject(c->function); } - if (ctx->activation) { + + else if (ctx->type == Type_GlobalContext) { + GlobalContext *g = static_cast(ctx); bool hasProperty = false; - Value v = ctx->activation->get(ctx, name, &hasProperty); + Value v = g->global->get(g, name, &hasProperty); if (hasProperty) return v; } - if (ctx->type == Type_CallContext) { - CallContext *c = static_cast(ctx); - FunctionObject *f = c->function; - if (f->function && f->function->isNamedExpression - && name->isEqualTo(f->function->name)) - return Value::fromObject(c->function); - } } throwReferenceError(Value::fromString(name)); return Value::undefinedValue(); diff --git a/src/v4/qv4context.h b/src/v4/qv4context.h index 7e6156a6ff..b2d644d39c 100644 --- a/src/v4/qv4context.h +++ b/src/v4/qv4context.h @@ -100,7 +100,6 @@ struct ExecutionContext // ### move to CallContext Value *arguments; unsigned int argumentCount; - Object *activation; String * const *formals() const; unsigned int formalCount() const; @@ -108,7 +107,6 @@ struct ExecutionContext unsigned int variableCount() const; void createMutableBinding(String *name, bool deletable); - bool setMutableBinding(ExecutionContext *scope, String *name, const Value &value); void Q_NORETURN throwError(const Value &value); void Q_NORETURN throwError(const QString &message); @@ -140,11 +138,14 @@ struct CallContext : public ExecutionContext FunctionObject *function; Value *locals; + Object *activation; }; struct GlobalContext : public ExecutionContext { void init(ExecutionEngine *e); + + Object *global; }; struct CatchContext : public ExecutionContext diff --git a/src/v4/qv4engine.cpp b/src/v4/qv4engine.cpp index 105dd6ce59..f22e9a9161 100644 --- a/src/v4/qv4engine.cpp +++ b/src/v4/qv4engine.cpp @@ -199,7 +199,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) // VM::Object *glo = newObject(/*rootContext*/); globalObject = Value::fromObject(glo); - rootContext->activation = glo; + rootContext->global = glo; rootContext->thisObject = Value::fromObject(glo); glo->defineDefaultProperty(rootContext, QStringLiteral("Object"), objectCtor); diff --git a/src/v4/qv4v8.cpp b/src/v4/qv4v8.cpp index 4adc706f77..835c825dfb 100644 --- a/src/v4/qv4v8.cpp +++ b/src/v4/qv4v8.cpp @@ -2108,10 +2108,11 @@ Local Context::GetCallingQmlGlobal() while (ctx && ctx->outer != engine->rootContext) ctx = ctx->outer; - if (!ctx) + assert(ctx); + if (!ctx->type == ExecutionContext::Type_QmlContext) return Local(); - return Local::New(Value::fromVmValue(VM::Value::fromObject(ctx->activation))); + return Local::New(Value::fromVmValue(VM::Value::fromObject(static_cast(ctx)->activation))); } Local Context::GetCallingScriptData() -- cgit v1.2.3