diff options
Diffstat (limited to 'src/qml/jsruntime/qv4context.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4context.cpp | 224 |
1 files changed, 90 insertions, 134 deletions
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 3ff864d7b9..6807c835b0 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -54,41 +54,44 @@ using namespace QV4; DEFINE_MANAGED_VTABLE(ExecutionContext); +DEFINE_MANAGED_VTABLE(SimpleCallContext); DEFINE_MANAGED_VTABLE(CallContext); DEFINE_MANAGED_VTABLE(WithContext); DEFINE_MANAGED_VTABLE(CatchContext); DEFINE_MANAGED_VTABLE(GlobalContext); -/* Function *f, int argc */ -#define requiredMemoryForExecutionContect(f, argc) \ - ((sizeof(CallContext::Data) + 7) & ~7) + \ - sizeof(Value) * (f->compiledFunction->nLocals + qMax((uint)argc, f->nFormals)) + sizeof(CallData) - Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData) { - Heap::CallContext *c = engine()->memoryManager->allocManaged<CallContext>( - requiredMemoryForExecutionContect(function, callData->argc)); + uint localsAndFormals = function->compiledFunction->nLocals + sizeof(CallData)/sizeof(Value) - 1 + qMax(static_cast<uint>(callData->argc), function->nFormals); + size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * (localsAndFormals); + + ExecutionEngine *v4 = engine(); + Heap::CallContext *c = v4->memoryManager->allocManaged<CallContext>(requiredMemory); c->init(Heap::ExecutionContext::Type_CallContext); c->v4Function = function; c->strictMode = function->isStrict(); - c->outer = this->d(); - - c->activation = 0; + c->outer.set(v4, this->d()); c->compilationUnit = function->compilationUnit; c->lookups = function->compilationUnit->runtimeLookups; c->constantTable = function->compilationUnit->constants; - c->locals = (Value *)((quintptr(c + 1) + 7) & ~7); const CompiledData::Function *compiledFunction = function->compiledFunction; - int nLocals = compiledFunction->nLocals; + uint nLocals = compiledFunction->nLocals; + c->locals.size = nLocals; + c->locals.alloc = localsAndFormals; +#if QT_POINTER_SIZE == 8 + // memory allocated from the JS heap is 0 initialized, so skip the std::fill() below + Q_ASSERT(Primitive::undefinedValue().asReturnedValue() == 0); +#else if (nLocals) - std::fill(c->locals, c->locals + nLocals, Primitive::undefinedValue()); + std::fill(c->locals.values, c->locals.values + nLocals, Primitive::undefinedValue()); +#endif - c->callData = reinterpret_cast<CallData *>(c->locals + nLocals); - ::memcpy(c->callData, callData, sizeof(CallData) + (callData->argc - 1) * sizeof(Value)); + c->callData = reinterpret_cast<CallData *>(c->locals.values + nLocals); + ::memcpy(c->callData, callData, sizeof(CallData) - sizeof(Value) + static_cast<uint>(callData->argc) * sizeof(Value)); if (callData->argc < static_cast<int>(compiledFunction->nFormals)) std::fill(c->callData->args + c->callData->argc, c->callData->args + compiledFunction->nFormals, Primitive::undefinedValue()); @@ -118,10 +121,10 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) switch (ctx->d()->type) { case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); + Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d()); if (!activation) { if (!c->activation) - c->activation = scope.engine->newObject(); + c->activation.set(scope.engine, scope.engine->newObject()); activation = c->activation; } break; @@ -144,7 +147,7 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) ctx = ctx->d()->outer; } - if (activation->hasProperty(name)) + if (activation->hasOwnProperty(name)) return; ScopedProperty desc(scope); PropertyAttributes attrs(Attr_Data); @@ -155,41 +158,52 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) void Heap::GlobalContext::init(ExecutionEngine *eng) { Heap::ExecutionContext::init(Heap::ExecutionContext::Type_GlobalContext); - global = eng->globalObject->d(); + global.set(eng, eng->globalObject->d()); } void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue) { Heap::ExecutionContext::init(Heap::ExecutionContext::Type_CatchContext); - outer = outerContext; + outer.set(internalClass->engine, outerContext); strictMode = outer->strictMode; callData = outer->callData; lookups = outer->lookups; constantTable = outer->constantTable; compilationUnit = outer->compilationUnit; - this->exceptionVarName = exceptionVarName; - this->exceptionValue = exceptionValue; + this->exceptionVarName.set(internalClass->engine, exceptionVarName); + this->exceptionValue.set(internalClass->engine, exceptionValue); } +void Heap::WithContext::init(ExecutionContext *outerContext, Object *with) +{ + Heap::ExecutionContext::init(Heap::ExecutionContext::Type_WithContext); + outer.set(internalClass->engine, outerContext); + callData = outer->callData; + lookups = outer->lookups; + constantTable = outer->constantTable; + compilationUnit = outer->compilationUnit; -Identifier * const *CallContext::formals() const + withObject.set(internalClass->engine, with); +} + +Identifier * const *SimpleCallContext::formals() const { return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() : 0; } -unsigned int CallContext::formalCount() const +unsigned int SimpleCallContext::formalCount() const { return d()->v4Function ? d()->v4Function->nFormals : 0; } -Identifier * const *CallContext::variables() const +Identifier * const *SimpleCallContext::variables() const { return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() + d()->v4Function->nFormals : 0; } -unsigned int CallContext::variableCount() const +unsigned int SimpleCallContext::variableCount() const { return d()->v4Function ? d()->v4Function->compiledFunction->nLocals : 0; } @@ -202,7 +216,6 @@ bool ExecutionContext::deleteProperty(String *name) Identifier *id = name->identifier(); Scope scope(this); - bool hasWith = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { switch (ctx->d()->type) { @@ -213,7 +226,6 @@ bool ExecutionContext::deleteProperty(String *name) break; } case Heap::ExecutionContext::Type_WithContext: { - hasWith = true; ScopedObject withObject(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); if (withObject->hasProperty(name)) return withObject->deleteProperty(name); @@ -226,14 +238,13 @@ bool ExecutionContext::deleteProperty(String *name) break; } case Heap::ExecutionContext::Type_CallContext: + Q_FALLTHROUGH(); case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - if (c->v4Function && (c->v4Function->needsActivation() || hasWith)) { - uint index = c->v4Function->internalClass->find(id); - if (index < UINT_MAX) - // ### throw in strict mode? - return false; - } + Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d()); + uint index = c->v4Function->internalClass->find(id); + if (index < UINT_MAX) + // ### throw in strict mode? + return false; ScopedObject qml(scope, c->activation); if (qml && qml->hasProperty(name)) return qml->deleteProperty(name); @@ -250,61 +261,6 @@ bool ExecutionContext::deleteProperty(String *name) return true; } -bool CallContext::needsOwnArguments() const -{ - QV4::Function *f = d()->v4Function; - return (f && f->needsActivation()) || (argc() < (f ? static_cast<int>(f->nFormals) : 0)); -} - -void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) -{ - ExecutionContext::Data *ctx = static_cast<ExecutionContext::Data *>(m); - - if (ctx->outer) - ctx->outer->mark(engine); - - switch (ctx->type) { - case Heap::ExecutionContext::Type_CatchContext: { - CatchContext::Data *c = static_cast<CatchContext::Data *>(ctx); - c->exceptionVarName->mark(engine); - c->exceptionValue.mark(engine); - break; - } - case Heap::ExecutionContext::Type_WithContext: { - WithContext::Data *w = static_cast<WithContext::Data *>(ctx); - if (w->withObject) - w->withObject->mark(engine); - break; - } - case Heap::ExecutionContext::Type_GlobalContext: { - GlobalContext::Data *g = static_cast<GlobalContext::Data *>(ctx); - g->global->mark(engine); - break; - } - case Heap::ExecutionContext::Type_SimpleCallContext: - break; - case Heap::ExecutionContext::Type_CallContext: { - QV4::Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx); - Q_ASSERT(c->v4Function); - ctx->callData->thisObject.mark(engine); - for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->v4Function->nFormals); ++arg) - ctx->callData->args[arg].mark(engine); - for (unsigned local = 0, lastLocal = c->v4Function->compiledFunction->nLocals; local < lastLocal; ++local) - c->locals[local].mark(engine); - if (c->activation) - c->activation->mark(engine); - if (c->function) - c->function->mark(engine); - break; - } - case Heap::ExecutionContext::Type_QmlContext: { - QmlContext::Data *g = static_cast<QmlContext::Data *>(ctx); - g->qml->mark(engine); - break; - } - } -} - // Do a standard call with this execution context as the outer scope void ExecutionContext::call(Scope &scope, CallData *callData, Function *function, const FunctionObject *f) { @@ -312,7 +268,7 @@ void ExecutionContext::call(Scope &scope, CallData *callData, Function *function Scoped<CallContext> ctx(scope, newCallContext(function, callData)); if (f) - ctx->d()->function = f->d(); + ctx->d()->function.set(scope.engine, f->d()); scope.engine->pushContext(ctx); scope.result = Q_V4_PROFILE(scope.engine, function); @@ -328,7 +284,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio ExecutionContextSaver ctxSaver(scope); - CallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(); + SimpleCallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(); ctx->strictMode = function->isStrict(); ctx->callData = callData; @@ -336,8 +292,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio ctx->compilationUnit = function->compilationUnit; ctx->lookups = function->compilationUnit->runtimeLookups; ctx->constantTable = function->compilationUnit->constants; - ctx->outer = this->d(); - ctx->locals = scope.alloc(function->compiledFunction->nLocals); + ctx->outer.set(scope.engine, this->d()); for (int i = callData->argc; i < (int)function->nFormals; ++i) callData->args[i] = Encode::undefined(); @@ -366,7 +321,7 @@ void ExecutionContext::setProperty(String *name, const Value &value) case Heap::ExecutionContext::Type_CatchContext: { Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); if (c->exceptionVarName->isEqualTo(name->d())) { - c->exceptionValue = value; + c->exceptionValue.set(scope.engine, value); return; } break; @@ -385,15 +340,16 @@ void ExecutionContext::setProperty(String *name, const Value &value) } case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); + Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d()); if (c->v4Function) { uint index = c->v4Function->internalClass->find(id); if (index < UINT_MAX) { if (index < c->v4Function->nFormals) { c->callData->args[c->v4Function->nFormals - index - 1] = value; } else { + Q_ASSERT(c->type == Heap::ExecutionContext::Type_CallContext); index -= c->v4Function->nFormals; - c->locals[index] = value; + static_cast<Heap::CallContext *>(c)->locals.set(scope.engine, index, value); } return; } @@ -434,13 +390,10 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (name->equals(engine()->id_this())) return thisObject().asReturnedValue(); - bool hasWith = false; - bool hasCatchScope = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { switch (ctx->d()->type) { case Heap::ExecutionContext::Type_CatchContext: { - hasCatchScope = true; Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); if (c->exceptionVarName->isEqualTo(name->d())) return c->exceptionValue.asReturnedValue(); @@ -448,7 +401,6 @@ ReturnedValue ExecutionContext::getProperty(String *name) } case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); - hasWith = true; bool hasProperty = false; v = w->get(name, &hasProperty); if (hasProperty) { @@ -465,19 +417,20 @@ ReturnedValue ExecutionContext::getProperty(String *name) break; } case Heap::ExecutionContext::Type_CallContext: + Q_FALLTHROUGH(); case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { - name->makeIdentifier(); - Identifier *id = name->identifier(); - - uint index = c->v4Function->internalClass->find(id); - if (index < UINT_MAX) { - if (index < c->v4Function->nFormals) - return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); - return c->locals[index - c->v4Function->nFormals].asReturnedValue(); - } + Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d()); + + name->makeIdentifier(); + Identifier *id = name->identifier(); + uint index = c->v4Function->internalClass->find(id); + if (index < UINT_MAX) { + if (index < c->v4Function->nFormals) + return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); + if (c->type == Heap::ExecutionContext::Type_CallContext) + return static_cast<Heap::CallContext *>(c)->locals[index - c->v4Function->nFormals].asReturnedValue(); } + ScopedObject activation(scope, c->activation); if (activation) { bool hasProperty = false; @@ -485,9 +438,12 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (hasProperty) return v->asReturnedValue(); } - if (c->function && c->v4Function->isNamedExpression() - && name->equals(ScopedString(scope, c->v4Function->name()))) - return c->function->asReturnedValue(); + + if (c->v4Function->isNamedExpression() && c->type == Heap::ExecutionContext::Type_CallContext) { + if (name->equals(ScopedString(scope, c->v4Function->name()))) + if (auto func = static_cast<Heap::CallContext *>(c)->function) + return func->asReturnedValue(); + } break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -514,13 +470,10 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) if (name->equals(engine()->id_this())) return thisObject().asReturnedValue(); - bool hasWith = false; - bool hasCatchScope = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { switch (ctx->d()->type) { case Heap::ExecutionContext::Type_CatchContext: { - hasCatchScope = true; Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); if (c->exceptionVarName->isEqualTo(name->d())) return c->exceptionValue.asReturnedValue(); @@ -528,7 +481,6 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) } case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); - hasWith = true; bool hasProperty = false; v = w->get(name, &hasProperty); if (hasProperty) { @@ -546,19 +498,20 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) break; } case Heap::ExecutionContext::Type_CallContext: + Q_FALLTHROUGH(); case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { - name->makeIdentifier(); - Identifier *id = name->identifier(); - - uint index = c->v4Function->internalClass->find(id); - if (index < UINT_MAX) { - if (index < c->v4Function->nFormals) - return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); - return c->locals[index - c->v4Function->nFormals].asReturnedValue(); - } + Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d()); + + name->makeIdentifier(); + Identifier *id = name->identifier(); + uint index = c->v4Function->internalClass->find(id); + if (index < UINT_MAX) { + if (index < c->v4Function->nFormals) + return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); + if (c->type == Heap::ExecutionContext::Type_CallContext) + return static_cast<Heap::CallContext *>(c)->locals[index - c->v4Function->nFormals].asReturnedValue(); } + ScopedObject activation(scope, c->activation); if (activation) { bool hasProperty = false; @@ -566,9 +519,12 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) if (hasProperty) return v->asReturnedValue(); } - if (c->function && c->v4Function->isNamedExpression() - && name->equals(ScopedString(scope, c->v4Function->name()))) - return c->function->asReturnedValue(); + + if (c->v4Function->isNamedExpression() && c->type == Heap::ExecutionContext::Type_CallContext) { + if (name->equals(ScopedString(scope, c->v4Function->name()))) + if (auto func = static_cast<Heap::CallContext *>(c)->function) + return func->asReturnedValue(); + } break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -592,7 +548,7 @@ Function *ExecutionContext::getFunction() const Scope scope(engine()); ScopedContext it(scope, this->d()); for (; it; it = it->d()->outer) { - if (const CallContext *callCtx = it->asCallContext()) + if (const SimpleCallContext *callCtx = it->asSimpleCallContext()) return callCtx->d()->v4Function; else if (it->asCatchContext() || it->asWithContext()) continue; // look in the parent context for a FunctionObject |