diff options
Diffstat (limited to 'src/qml/jsruntime')
54 files changed, 950 insertions, 665 deletions
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index ed010b1230..629c255b48 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -47,21 +47,21 @@ using namespace QV4; DEFINE_MANAGED_VTABLE(ArgumentsObject); ArgumentsObject::ArgumentsObject(CallContext *context) - : Object(context->engine), context(context) + : Object(context->strictMode ? context->engine->strictArgumentsObjectClass : context->engine->argumentsObjectClass) + , context(context) + , fullyCreated(false) { - vtbl = &static_vtbl; type = Type_ArgumentsObject; + flags &= ~SimpleArray; ExecutionEngine *v4 = context->engine; Scope scope(v4); ScopedObject protectThis(scope, this); if (context->strictMode) { - internalClass = v4->strictArgumentsObjectClass; - Property pd = Property::fromAccessor(v4->thrower, v4->thrower); - assert(CalleePropertyIndex == internalClass->find(context->engine->id_callee)); - assert(CallerPropertyIndex == internalClass->find(context->engine->id_caller)); + Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee)); + Q_ASSERT(CallerPropertyIndex == internalClass->find(context->engine->id_caller)); memberData[CalleePropertyIndex] = pd; memberData[CallerPropertyIndex] = pd; @@ -69,31 +69,17 @@ ArgumentsObject::ArgumentsObject(CallContext *context) for (int i = 0; i < context->callData->argc; ++i) arrayData[i].value = context->callData->args[i]; arrayDataLen = context->callData->argc; + fullyCreated = true; } else { - internalClass = engine()->argumentsObjectClass; Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee)); memberData[CalleePropertyIndex].value = context->function->asReturnedValue(); isNonStrictArgumentsObject = true; - - uint numAccessors = qMin((int)context->function->formalParameterCount, context->realArgumentCount); - uint argCount = qMin(context->realArgumentCount, context->callData->argc); - arrayReserve(argCount); - ensureArrayAttributes(); - context->engine->requireArgumentsAccessors(numAccessors); - for (uint i = 0; i < (uint)numAccessors; ++i) { - mappedArguments.append(context->callData->args[i]); - arrayData[i] = context->engine->argumentsAccessors.at(i); - arrayAttributes[i] = Attr_Accessor; - } - for (uint i = numAccessors; i < argCount; ++i) { - arrayData[i] = Property::fromValue(context->callData->args[i]); - arrayAttributes[i] = Attr_Data; - } - arrayDataLen = argCount; } Q_ASSERT(LengthPropertyIndex == internalClass->find(context->engine->id_length)); Property *lp = memberData + ArrayObject::LengthPropertyIndex; lp->value = Primitive::fromInt32(context->realArgumentCount); + + Q_ASSERT(internalClass->vtable == &static_vtbl); } void ArgumentsObject::destroy(Managed *that) @@ -101,8 +87,34 @@ void ArgumentsObject::destroy(Managed *that) static_cast<ArgumentsObject *>(that)->~ArgumentsObject(); } +void ArgumentsObject::fullyCreate() +{ + if (fullyCreated) + return; + + uint numAccessors = qMin((int)context->function->formalParameterCount, context->realArgumentCount); + uint argCount = qMin(context->realArgumentCount, context->callData->argc); + arrayReserve(argCount); + ensureArrayAttributes(); + context->engine->requireArgumentsAccessors(numAccessors); + for (uint i = 0; i < (uint)numAccessors; ++i) { + mappedArguments.append(context->callData->args[i]); + arrayData[i] = context->engine->argumentsAccessors.at(i); + arrayAttributes[i] = Attr_Accessor; + } + for (uint i = numAccessors; i < argCount; ++i) { + arrayData[i] = Property::fromValue(context->callData->args[i]); + arrayAttributes[i] = Attr_Data; + } + arrayDataLen = argCount; + + fullyCreated = true; +} + bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs) { + fullyCreate(); + Scope scope(ctx); uint pidx = propertyIndexFromArrayIndex(index); Property *pd = arrayData + pidx; @@ -143,6 +155,57 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const return result; } +ReturnedValue ArgumentsObject::getIndexed(Managed *m, uint index, bool *hasProperty) +{ + ArgumentsObject *args = static_cast<ArgumentsObject *>(m); + if (args->fullyCreated) + return Object::getIndexed(m, index, hasProperty); + + if (index < static_cast<uint>(args->context->callData->argc)) { + if (hasProperty) + *hasProperty = true; + return args->context->callData->args[index].asReturnedValue(); + } + return Encode::undefined(); +} + +void ArgumentsObject::putIndexed(Managed *m, uint index, const ValueRef value) +{ + ArgumentsObject *args = static_cast<ArgumentsObject *>(m); + if (!args->fullyCreated && index >= static_cast<uint>(args->context->callData->argc)) + args->fullyCreate(); + + if (args->fullyCreated) { + Object::putIndexed(m, index, value); + return; + } + + args->context->callData->args[index] = value; +} + +bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index) +{ + ArgumentsObject *args = static_cast<ArgumentsObject *>(m); + if (!args->fullyCreated) + args->fullyCreate(); + return Object::deleteIndexedProperty(m, index); +} + +PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index) +{ + const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m); + if (args->fullyCreated) + return Object::queryIndexed(m, index); + + uint numAccessors = qMin((int)args->context->function->formalParameterCount, args->context->realArgumentCount); + uint argCount = qMin(args->context->realArgumentCount, args->context->callData->argc); + if (index >= argCount) + return PropertyAttributes(); + if (index >= numAccessors) + return Attr_Data; + return Attr_Accessor; +} + DEFINE_MANAGED_VTABLE(ArgumentsGetterFunction); ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData) @@ -152,7 +215,7 @@ ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData) Scoped<ArgumentsGetterFunction> g(scope, static_cast<ArgumentsGetterFunction *>(getter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); if (!o) - return v4->current->throwTypeError(); + return v4->currentContext()->throwTypeError(); Q_ASSERT(g->index < static_cast<unsigned>(o->context->callData->argc)); return o->context->argument(g->index); @@ -167,7 +230,7 @@ ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData) Scoped<ArgumentsSetterFunction> s(scope, static_cast<ArgumentsSetterFunction *>(setter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); if (!o) - return v4->current->throwTypeError(); + return v4->currentContext()->throwTypeError(); Q_ASSERT(s->index < static_cast<unsigned>(o->context->callData->argc)); o->context->callData->args[s->index] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined(); @@ -177,7 +240,7 @@ ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData) void ArgumentsObject::markObjects(Managed *that, ExecutionEngine *e) { ArgumentsObject *o = static_cast<ArgumentsObject *>(that); - o->context->mark(); + o->context->mark(e); for (int i = 0; i < o->mappedArguments.size(); ++i) o->mappedArguments.at(i).mark(e); diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 7a5b0817a3..d306fae92b 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -54,7 +54,9 @@ struct ArgumentsGetterFunction: FunctionObject uint index; ArgumentsGetterFunction(ExecutionContext *scope, uint index) - : FunctionObject(scope), index(index) { vtbl = &static_vtbl; } + : FunctionObject(scope), index(index) { + setVTable(&static_vtbl); + } static ReturnedValue call(Managed *that, CallData *d); }; @@ -65,7 +67,9 @@ struct ArgumentsSetterFunction: FunctionObject uint index; ArgumentsSetterFunction(ExecutionContext *scope, uint index) - : FunctionObject(scope), index(index) { vtbl = &static_vtbl; } + : FunctionObject(scope), index(index) { + setVTable(&static_vtbl); + } static ReturnedValue call(Managed *that, CallData *callData); }; @@ -74,20 +78,26 @@ struct ArgumentsSetterFunction: FunctionObject struct ArgumentsObject: Object { Q_MANAGED CallContext *context; + bool fullyCreated; QVector<SafeValue> mappedArguments; ArgumentsObject(CallContext *context); ~ArgumentsObject() {} + enum { LengthPropertyIndex = 0, CalleePropertyIndex = 1, CallerPropertyIndex = 2 }; bool defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs); - + static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static void putIndexed(Managed *m, uint index, const ValueRef value); + static bool deleteIndexedProperty(Managed *m, uint index); + static PropertyAttributes queryIndexed(const Managed *m, uint index); static void markObjects(Managed *that, ExecutionEngine *e); -protected: static void destroy(Managed *); + + void fullyCreate(); }; } diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index a0f0345b8b..1628cfe4da 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -51,7 +51,7 @@ DEFINE_MANAGED_VTABLE(ArrayCtor); ArrayCtor::ArrayCtor(ExecutionContext *scope) : FunctionObject(scope, QStringLiteral("Array")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData) @@ -65,7 +65,7 @@ ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData) len = callData->args[0].asArrayLength(&ok); if (!ok) - return v4->current->throwRangeError(callData->args[0]); + return v4->currentContext()->throwRangeError(callData->args[0]); if (len < 0x1000) a->arrayReserve(len); @@ -174,12 +174,22 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx) } ScopedArrayObject elt(scope); + ScopedObject eltAsObj(scope); + ScopedValue entry(scope); for (int i = 0; i < ctx->callData->argc; ++i) { + eltAsObj = ctx->callData->args[i]; elt = ctx->callData->args[i]; - if (elt) + if (elt) { result->arrayConcat(elt.getPointer()); - else + } else if (eltAsObj && eltAsObj->isListType()) { + const uint startIndex = getLength(ctx, result); + for (int i = 0, len = getLength(ctx, eltAsObj); i < len; ++i) { + entry = eltAsObj->getIndexed(i); + result->putIndexed(startIndex + i, entry); + } + } else { result->arraySet(getLength(ctx, result), ctx->callData->args[i]); + } } return result.asReturnedValue(); diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp index a0d0027e5f..f8edfb7850 100644 --- a/src/qml/jsruntime/qv4booleanobject.cpp +++ b/src/qml/jsruntime/qv4booleanobject.cpp @@ -49,7 +49,7 @@ DEFINE_MANAGED_VTABLE(BooleanObject); BooleanCtor::BooleanCtor(ExecutionContext *scope) : FunctionObject(scope, QStringLiteral("Boolean")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue BooleanCtor::construct(Managed *m, CallData *callData) diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h index 56c00f99ed..8d6adc0fb2 100644 --- a/src/qml/jsruntime/qv4booleanobject_p.h +++ b/src/qml/jsruntime/qv4booleanobject_p.h @@ -39,7 +39,7 @@ ** ****************************************************************************/ #ifndef QV4BOOLEANOBJECT_H -#define QBOOLEANOBJECT_H +#define QV4BOOLEANOBJECT_H #include "qv4object_p.h" #include "qv4functionobject_p.h" diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 97247ad368..05a0e66e09 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -51,19 +51,37 @@ using namespace QV4; +const ManagedVTable ExecutionContext::static_vtbl = +{ + call, + construct, + markObjects, + destroy, + 0 /*collectDeletables*/, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + isEqualTo, + 0, + "ExecutionContext", +}; + CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData) { - CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocContext(requiredMemoryForExecutionContect(function, callData->argc))); - - engine->current = c; - - c->initBaseContext(Type_CallContext, engine, this); + CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(function, callData->argc))); + new (c) CallContext(engine, Type_CallContext); c->function = function; c->realArgumentCount = callData->argc; c->strictMode = function->strictMode; - c->marked = false; c->outer = function->scope; #ifndef QT_NO_DEBUG assert(c->outer->next != (ExecutionContext *)0x1); @@ -92,27 +110,20 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData WithContext *ExecutionContext::newWithContext(ObjectRef with) { - WithContext *w = static_cast<WithContext *>(engine->memoryManager->allocContext(sizeof(WithContext))); - engine->current = w; - w->initWithContext(this, with); + WithContext *w = new (engine->memoryManager) WithContext(engine, with); return w; } CatchContext *ExecutionContext::newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue) { - CatchContext *c = static_cast<CatchContext *>(engine->memoryManager->allocContext(sizeof(CatchContext))); - engine->current = c; - c->initCatchContext(this, exceptionVarName, exceptionValue); + CatchContext *c = new (engine->memoryManager) CatchContext(engine, exceptionVarName, exceptionValue); return c; } CallContext *ExecutionContext::newQmlContext(FunctionObject *f, ObjectRef qml) { - CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocContext(requiredMemoryForExecutionContect(f, 0))); - - engine->current = c; - c->initQmlContext(this, qml, f); - + CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(f, 0))); + new (c) CallContext(engine, qml, f); return c; } @@ -149,7 +160,7 @@ String * const *ExecutionContext::formals() const if (type < Type_SimpleCallContext) return 0; QV4::FunctionObject *f = static_cast<const CallContext *>(this)->function; - return f ? f->formalParameterList : 0; + return (f && f->function) ? f->function->internalClass->nameMap.constData() : 0; } unsigned int ExecutionContext::formalCount() const @@ -165,7 +176,7 @@ String * const *ExecutionContext::variables() const if (type < Type_SimpleCallContext) return 0; QV4::FunctionObject *f = static_cast<const CallContext *>(this)->function; - return f ? f->varList : 0; + return (f && f->function) ? f->function->internalClass->nameMap.constData() + f->function->nArguments : 0; } unsigned int ExecutionContext::variableCount() const @@ -177,53 +188,47 @@ unsigned int ExecutionContext::variableCount() const } -void GlobalContext::initGlobalContext(ExecutionEngine *eng) +GlobalContext::GlobalContext(ExecutionEngine *eng) + : ExecutionContext(eng, Type_GlobalContext) { - initBaseContext(Type_GlobalContext, eng, /*parentContext*/0); - callData = reinterpret_cast<CallData *>(this + 1); - callData->tag = QV4::Value::_Integer_Type; - callData->argc = 0; - callData->thisObject = eng->globalObject; - global = 0; + global = eng->globalObject; } -void WithContext::initWithContext(ExecutionContext *p, ObjectRef with) +WithContext::WithContext(ExecutionEngine *engine, ObjectRef with) + : ExecutionContext(engine, Type_WithContext) { - initBaseContext(Type_WithContext, p->engine, p); - callData = p->callData; - outer = p; - lookups = p->lookups; - compilationUnit = p->compilationUnit; + callData = parent->callData; + outer = parent; + lookups = parent->lookups; + compilationUnit = parent->compilationUnit; withObject = with.getPointer(); } -void CatchContext::initCatchContext(ExecutionContext *p, const StringRef exceptionVarName, const ValueRef exceptionValue) +CatchContext::CatchContext(ExecutionEngine *engine, const StringRef exceptionVarName, const ValueRef exceptionValue) + : ExecutionContext(engine, Type_CatchContext) { - initBaseContext(Type_CatchContext, p->engine, p); - strictMode = p->strictMode; - callData = p->callData; - outer = p; - lookups = p->lookups; - compilationUnit = p->compilationUnit; + strictMode = parent->strictMode; + callData = parent->callData; + outer = parent; + lookups = parent->lookups; + compilationUnit = parent->compilationUnit; this->exceptionVarName = exceptionVarName; this->exceptionValue = exceptionValue; } -void CallContext::initQmlContext(ExecutionContext *parentContext, ObjectRef qml, FunctionObject *function) +CallContext::CallContext(ExecutionEngine *engine, ObjectRef qml, FunctionObject *function) + : ExecutionContext(engine, Type_QmlContext) { - initBaseContext(Type_QmlContext, parentContext->engine, parentContext); - this->function = function; - this->callData = reinterpret_cast<CallData *>(this + 1); - this->callData->tag = QV4::Value::_Integer_Type; - this->callData->argc = 0; - this->callData->thisObject = Primitive::undefinedValue(); + callData = reinterpret_cast<CallData *>(this + 1); + callData->tag = QV4::Value::_Integer_Type; + callData->argc = 0; + callData->thisObject = Primitive::undefinedValue(); strictMode = true; - marked = false; - this->outer = function->scope; + outer = function->scope; #ifndef QT_NO_DEBUG assert(outer->next != (ExecutionContext *)0x1); #endif @@ -259,12 +264,10 @@ bool ExecutionContext::deleteProperty(const StringRef name) CallContext *c = static_cast<CallContext *>(ctx); FunctionObject *f = c->function; if (f->needsActivation || hasWith) { - for (unsigned int i = 0; i < f->varCount; ++i) - if (f->varList[i]->isEqualTo(name)) - return false; - for (int i = (int)f->formalParameterCount - 1; i >= 0; --i) - if (f->formalParameterList[i]->isEqualTo(name)) - return false; + uint index = f->function->internalClass->find(name); + if (index < UINT_MAX) + // ### throw in strict mode? + return false; } if (c->activation && c->activation->__hasProperty__(name)) return c->activation->deleteProperty(name); @@ -285,36 +288,34 @@ bool CallContext::needsOwnArguments() const return function->needsActivation || callData->argc < static_cast<int>(function->formalParameterCount); } -void ExecutionContext::mark() +void ExecutionContext::markObjects(Managed *m, ExecutionEngine *engine) { - if (marked) - return; - marked = true; + ExecutionContext *ctx = static_cast<ExecutionContext *>(m); - if (outer) - outer->mark(); + if (ctx->outer) + ctx->outer->mark(engine); // ### shouldn't need these 3 lines - callData->thisObject.mark(engine); - for (int arg = 0; arg < callData->argc; ++arg) - callData->args[arg].mark(engine); + ctx->callData->thisObject.mark(engine); + for (int arg = 0; arg < ctx->callData->argc; ++arg) + ctx->callData->args[arg].mark(engine); - if (type >= Type_CallContext) { - QV4::CallContext *c = static_cast<CallContext *>(this); + if (ctx->type >= Type_CallContext) { + QV4::CallContext *c = static_cast<CallContext *>(ctx); for (unsigned local = 0, lastLocal = c->variableCount(); local < lastLocal; ++local) c->locals[local].mark(engine); if (c->activation) c->activation->mark(engine); c->function->mark(engine); - } else if (type == Type_WithContext) { - WithContext *w = static_cast<WithContext *>(this); + } else if (ctx->type == Type_WithContext) { + WithContext *w = static_cast<WithContext *>(ctx); w->withObject->mark(engine); - } else if (type == Type_CatchContext) { - CatchContext *c = static_cast<CatchContext *>(this); + } else if (ctx->type == Type_CatchContext) { + CatchContext *c = static_cast<CatchContext *>(ctx); c->exceptionVarName->mark(engine); c->exceptionValue.mark(engine); - } else if (type == Type_GlobalContext) { - GlobalContext *g = static_cast<GlobalContext *>(this); + } else if (ctx->type == Type_GlobalContext) { + GlobalContext *g = static_cast<GlobalContext *>(ctx); g->global->mark(engine); } } @@ -336,24 +337,35 @@ void ExecutionContext::setProperty(const StringRef name, const ValueRef value) ScopedObject activation(scope, (Object *)0); if (ctx->type >= Type_CallContext) { CallContext *c = static_cast<CallContext *>(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->callData->args[i] = *value; + if (c->function->function) { + uint index = c->function->function->internalClass->find(name); + if (index < UINT_MAX) { + if (index < c->function->formalParameterCount) { + c->callData->args[c->function->formalParameterCount - index - 1] = *value; + } else { + index -= c->function->formalParameterCount; + c->locals[index] = *value; + } return; } + } activation = c->activation; } else if (ctx->type == Type_GlobalContext) { activation = static_cast<GlobalContext *>(ctx)->global; } - if (activation && (ctx->type == Type_QmlContext || activation->__hasProperty__(name))) { - activation->put(name, value); - return; + if (activation) { + if (ctx->type == Type_QmlContext) { + activation->put(name, value); + return; + } else { + PropertyAttributes attrs; + Property *p = activation->__getOwnProperty__(name, &attrs); + if (p) { + activation->putValue(p, attrs, value); + return; + } + } } } } @@ -398,13 +410,13 @@ ReturnedValue ExecutionContext::getProperty(const StringRef name) else if (ctx->type >= Type_CallContext) { QV4::CallContext *c = static_cast<CallContext *>(ctx); ScopedFunctionObject f(scope, c->function); - if (f->needsActivation || hasWith || hasCatchScope) { - for (unsigned int i = 0; i < f->varCount; ++i) - if (f->varList[i]->isEqualTo(name)) - return c->locals[i].asReturnedValue(); - for (int i = (int)f->formalParameterCount - 1; i >= 0; --i) - if (f->formalParameterList[i]->isEqualTo(name)) - return c->callData->args[i].asReturnedValue(); + if (f->function && (f->needsActivation || hasWith || hasCatchScope)) { + uint index = f->function->internalClass->find(name); + if (index < UINT_MAX) { + if (index < c->function->formalParameterCount) + return c->callData->args[c->function->formalParameterCount - index - 1].asReturnedValue(); + return c->locals[index - c->function->formalParameterCount].asReturnedValue(); + } } if (c->activation) { bool hasProperty = false; @@ -464,13 +476,13 @@ ReturnedValue ExecutionContext::getPropertyAndBase(const StringRef name, ObjectR else if (ctx->type >= Type_CallContext) { QV4::CallContext *c = static_cast<CallContext *>(ctx); FunctionObject *f = c->function; - if (f->needsActivation || hasWith || hasCatchScope) { - for (unsigned int i = 0; i < f->varCount; ++i) - if (f->varList[i]->isEqualTo(name)) - return c->locals[i].asReturnedValue(); - for (int i = (int)f->formalParameterCount - 1; i >= 0; --i) - if (f->formalParameterList[i]->isEqualTo(name)) - return c->callData->args[i].asReturnedValue(); + if (f->function && (f->needsActivation || hasWith || hasCatchScope)) { + uint index = f->function->internalClass->find(name); + if (index < UINT_MAX) { + if (index < c->function->formalParameterCount) + return c->callData->args[c->function->formalParameterCount - index - 1].asReturnedValue(); + return c->locals[index - c->function->formalParameterCount].asReturnedValue(); + } } if (c->activation) { bool hasProperty = false; diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index ccb5cf98f8..4eb89ad905 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -44,6 +44,7 @@ #include "qv4global_p.h" #include "qv4value_def_p.h" #include "qv4managed_p.h" +#include "qv4engine_p.h" QT_BEGIN_NAMESPACE @@ -66,9 +67,11 @@ struct CallContext; struct CatchContext; struct WithContext; -struct Q_QML_EXPORT ExecutionContext +struct Q_QML_EXPORT ExecutionContext : public Managed { - enum Type { + Q_MANAGED + + enum ContextType { Type_GlobalContext = 0x1, Type_CatchContext = 0x2, Type_WithContext = 0x3, @@ -77,9 +80,24 @@ struct Q_QML_EXPORT ExecutionContext Type_QmlContext = 0x6 }; - Type type; + ExecutionContext(ExecutionEngine *engine, ContextType t) + : Managed(engine->executionContextClass) + { + this->type = t; + strictMode = false; + this->engine = engine; + this->parent = engine->currentContext(); + outer = 0; + lookups = 0; + compilationUnit = 0; + currentEvalCode = 0; + interpreterInstructionPointer = 0; + lineNumber = -1; + engine->current = this; + } + + ContextType type; bool strictMode; - bool marked; CallData *callData; @@ -98,28 +116,14 @@ struct Q_QML_EXPORT ExecutionContext EvalCode *currentEvalCode; const uchar **interpreterInstructionPointer; - char *jitInstructionPointer; - - void initBaseContext(Type type, ExecutionEngine *engine, ExecutionContext *parentContext) - { - this->type = type; - strictMode = false; - marked = false; - this->engine = engine; - parent = parentContext; - outer = 0; - lookups = 0; - compilationUnit = 0; - currentEvalCode = 0; - interpreterInstructionPointer = 0; - jitInstructionPointer = 0; - } + int lineNumber; CallContext *newCallContext(FunctionObject *f, CallData *callData); WithContext *newWithContext(ObjectRef with); CatchContext *newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue); CallContext *newQmlContext(FunctionObject *f, ObjectRef qml); + // formals are in reverse order String * const *formals() const; unsigned int formalCount() const; String * const *variables() const; @@ -130,11 +134,11 @@ struct Q_QML_EXPORT ExecutionContext ReturnedValue throwError(const QV4::ValueRef value); ReturnedValue throwError(const QString &message); ReturnedValue throwSyntaxError(const QString &message); - ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int line, int column); + ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int lineNumber, int column); ReturnedValue throwTypeError(); ReturnedValue throwTypeError(const QString &message); ReturnedValue throwReferenceError(const ValueRef value); - ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int line, int column); + ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column); ReturnedValue throwRangeError(const ValueRef value); ReturnedValue throwRangeError(const QString &message); ReturnedValue throwURIError(const ValueRef msg); @@ -148,26 +152,27 @@ struct Q_QML_EXPORT ExecutionContext // Can only be called from within catch(...), rethrows if no JS exception. ReturnedValue catchException(StackTrace *trace = 0); - void mark(); - inline CallContext *asCallContext(); inline const CallContext *asCallContext() const; + + static void markObjects(Managed *m, ExecutionEngine *e); }; struct CallContext : public ExecutionContext { - FunctionObject *function; - int realArgumentCount; - SafeValue *locals; - Object *activation; - - void initSimpleCallContext(ExecutionEngine *engine, ExecutionContext *parent) { - initBaseContext(Type_SimpleCallContext, engine, parent); + CallContext(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext) + : ExecutionContext(engine, t) + { function = 0; locals = 0; activation = 0; } - void initQmlContext(ExecutionContext *parentContext, ObjectRef qml, QV4::FunctionObject *function); + CallContext(ExecutionEngine *engine, ObjectRef qml, QV4::FunctionObject *function); + + FunctionObject *function; + int realArgumentCount; + SafeValue *locals; + Object *activation; inline ReturnedValue argument(int i); bool needsOwnArguments() const; @@ -175,14 +180,14 @@ struct CallContext : public ExecutionContext struct GlobalContext : public ExecutionContext { - void initGlobalContext(ExecutionEngine *e); + GlobalContext(ExecutionEngine *engine); Object *global; }; struct CatchContext : public ExecutionContext { - void initCatchContext(ExecutionContext *p, const StringRef exceptionVarName, const ValueRef exceptionValue); + CatchContext(ExecutionEngine *engine, const StringRef exceptionVarName, const ValueRef exceptionValue); SafeString exceptionVarName; SafeValue exceptionValue; @@ -190,9 +195,8 @@ struct CatchContext : public ExecutionContext struct WithContext : public ExecutionContext { + WithContext(ExecutionEngine *engine, ObjectRef with); Object *withObject; - - void initWithContext(ExecutionContext *p, ObjectRef with); }; inline CallContext *ExecutionContext::asCallContext() @@ -205,6 +209,37 @@ inline const CallContext *ExecutionContext::asCallContext() const return type >= Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0; } + +inline void ExecutionEngine::pushContext(CallContext *context) +{ + context->parent = current; + current = context; + current->currentEvalCode = 0; +} + +inline ExecutionContext *ExecutionEngine::popContext() +{ + Q_ASSERT(current->parent); + current = current->parent; + return current; +} + +struct ExecutionContextSaver +{ + ExecutionEngine *engine; + ExecutionContext *savedContext; + + ExecutionContextSaver(ExecutionContext *context) + : engine(context->engine) + , savedContext(context) + { + } + ~ExecutionContextSaver() + { + engine->current = savedContext; + } +}; + /* Function *f, int argc */ #define requiredMemoryForExecutionContect(f, argc) \ sizeof(CallContext) + sizeof(Value) * (f->varCount + qMax((uint)argc, f->formalParameterCount)) + sizeof(CallData) diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index b732c8a04a..5d0c8ccf8e 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -646,7 +646,7 @@ DEFINE_MANAGED_VTABLE(DateObject); DateObject::DateObject(ExecutionEngine *engine, const QDateTime &date) : Object(engine->dateClass) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); type = Type_DateObject; value.setDouble(date.isValid() ? date.toMSecsSinceEpoch() : qSNaN()); } @@ -661,7 +661,7 @@ DEFINE_MANAGED_VTABLE(DateCtor); DateCtor::DateCtor(ExecutionContext *scope) : FunctionObject(scope, QStringLiteral("Date")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue DateCtor::construct(Managed *m, CallData *callData) diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index e96cac2f20..9c451dd251 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -55,7 +55,6 @@ struct DateObject: Object { Q_MANAGED SafeValue value; DateObject(ExecutionEngine *engine, const ValueRef date): Object(engine->dateClass) { - vtbl = &static_vtbl; type = Type_DateObject; value = date; } @@ -65,7 +64,7 @@ struct DateObject: Object { protected: DateObject(InternalClass *ic): Object(ic) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); type = Type_DateObject; value = Primitive::fromDouble(qSNaN()); } diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index 95b4100651..4170b6817f 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -185,7 +185,7 @@ void Debugger::resume(Speed speed) if (speed == StepOver) setTemporaryBreakPointOnNextLine(); if (speed == StepOut) - m_temporaryBreakPoints = TemporaryBreakPoint(getFunction(), m_engine->current); + m_temporaryBreakPoints = TemporaryBreakPoint(getFunction(), m_engine->currentContext()); m_stepping = speed; m_runningCondition.wakeAll(); @@ -293,15 +293,16 @@ void Debugger::collectArgumentsInContext(Collector *collector, int frameNr, int if (frameNr < 0) return; - CallContext *ctxt = findScope(findContext(engine->current, frameNr), scopeNr); + CallContext *ctxt = findScope(findContext(engine->currentContext(), frameNr), scopeNr); if (!ctxt) return; Scope scope(engine); ScopedValue v(scope); - for (unsigned i = 0, ei = ctxt->formalCount(); i != ei; ++i) { + int nFormals = ctxt->formalCount(); + for (unsigned i = 0, ei = nFormals; i != ei; ++i) { QString qName; - if (String *name = ctxt->formals()[i]) + if (String *name = ctxt->formals()[nFormals - i - 1]) qName = name->toQString(); v = ctxt->argument(i); collector->collect(qName, v); @@ -339,7 +340,7 @@ void Debugger::collectLocalsInContext(Collector *collector, int frameNr, int sco if (frameNr < 0) return; - CallContext *ctxt = findScope(findContext(engine->current, frameNr), scopeNr); + CallContext *ctxt = findScope(findContext(engine->currentContext(), frameNr), scopeNr); if (!ctxt) return; @@ -386,7 +387,7 @@ bool Debugger::collectThisInContext(Debugger::Collector *collector, int frame) bool myRun() { - ExecutionContext *ctxt = findContext(engine->current, frameNr); + ExecutionContext *ctxt = findContext(engine->currentContext(), frameNr); while (ctxt) { if (CallContext *cCtxt = ctxt->asCallContext()) if (cCtxt->activation) @@ -448,14 +449,14 @@ void Debugger::collectReturnedValue(Collector *collector) const collector->collect(o); } -QVector<ExecutionContext::Type> Debugger::getScopeTypes(int frame) const +QVector<ExecutionContext::ContextType> Debugger::getScopeTypes(int frame) const { - QVector<ExecutionContext::Type> types; + QVector<ExecutionContext::ContextType> types; if (state() != Paused) return types; - CallContext *sctxt = findContext(m_engine->current, frame); + CallContext *sctxt = findContext(m_engine->currentContext(), frame); if (!sctxt || sctxt->type < ExecutionContext::Type_SimpleCallContext) return types; CallContext *ctxt = static_cast<CallContext *>(sctxt); @@ -499,7 +500,7 @@ void Debugger::maybeBreakAtInstruction(const uchar *code, bool breakPointHit) m_pauseRequested = false; pauseAndWait(PauseRequest); } else if (breakPointHit) { - if (m_stepping == StepOver && m_temporaryBreakPoints.context == m_engine->current) + if (m_stepping == StepOver && m_temporaryBreakPoints.context == m_engine->currentContext()) pauseAndWait(Step); else if (reallyHitTheBreakPoint(state.fileName, state.lineNumber)) pauseAndWait(BreakPoint); @@ -527,7 +528,7 @@ void Debugger::leavingFunction(const ReturnedValue &retVal) QMutexLocker locker(&m_lock); if ((m_stepping == StepOut || m_stepping == StepOver) - && temporaryBreakPointInFunction(m_engine->current)) { + && temporaryBreakPointInFunction(m_engine->currentContext())) { clearTemporaryBreakPoints(); m_stepping = NotStepping; m_stopForStepping = true; @@ -551,7 +552,7 @@ void Debugger::aboutToThrow() Function *Debugger::getFunction() const { - ExecutionContext *context = m_engine->current; + ExecutionContext *context = m_engine->currentContext(); if (CallContext *callCtx = context->asCallContext()) return callCtx->function->function; else { @@ -594,7 +595,7 @@ void Debugger::setTemporaryBreakPointOnNextLine() if (pcs.isEmpty()) return; - m_temporaryBreakPoints = TemporaryBreakPoint(function, m_engine->current); + m_temporaryBreakPoints = TemporaryBreakPoint(function, m_engine->currentContext()); m_temporaryBreakPoints.codeOffsets.reserve(pcs.size()); for (QList<qptrdiff>::const_iterator i = pcs.begin(), ei = pcs.end(); i != ei; ++i) { // note: we do set a breakpoint on the current line, because there could be a loop where diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h index 98b549995e..0e19c51935 100644 --- a/src/qml/jsruntime/qv4debugging_p.h +++ b/src/qml/jsruntime/qv4debugging_p.h @@ -163,7 +163,7 @@ public: bool collectThisInContext(Collector *collector, int frame = 0); void collectThrownValue(Collector *collector); void collectReturnedValue(Collector *collector) const; - QVector<ExecutionContext::Type> getScopeTypes(int frame = 0) const; + QVector<ExecutionContext::ContextType> getScopeTypes(int frame = 0) const; public: // compile-time interface void maybeBreakAtInstruction(const uchar *code, bool breakPointHit); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 8cd059dd2b..dc8c0da321 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ #include <qv4engine_p.h> +#include <qv4context_p.h> #include <qv4value_p.h> #include <qv4object_p.h> #include <qv4objectproto_p.h> @@ -52,6 +53,7 @@ #include <qv4mathobject_p.h> #include <qv4numberobject_p.h> #include <qv4regexpobject_p.h> +#include <qv4regexp_p.h> #include <qv4variantobject_p.h> #include <qv4runtime_p.h> #include "qv4mm_p.h" @@ -134,11 +136,13 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory) : memoryManager(new QV4::MemoryManager) , executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) + , current(0) , bumperPointerAllocator(new WTF::BumpPointerAllocator) , jsStack(new WTF::PageAllocation) , debugger(0) , globalObject(0) , globalCode(0) + , v8Engine(0) , m_engineId(engineSerial.fetchAndAddOrdered(1)) , regExpCache(0) , m_multiplyWrappedQObjects(0) @@ -181,6 +185,9 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory) identifierTable = new IdentifierTable(this); emptyClass = new (classPool.allocate(sizeof(InternalClass))) InternalClass(this); + executionContextClass = emptyClass->changeVTable(&ExecutionContext::static_vtbl); + stringClass = emptyClass->changeVTable(&String::static_vtbl); + regExpValueClass = emptyClass->changeVTable(&RegExp::static_vtbl); id_undefined = newIdentifier(QStringLiteral("undefined")); id_null = newIdentifier(QStringLiteral("null")); @@ -213,33 +220,39 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory) id_toString = newIdentifier(QStringLiteral("toString")); id_valueOf = newIdentifier(QStringLiteral("valueOf")); - ObjectPrototype *objectPrototype = new (memoryManager) ObjectPrototype(emptyClass); - objectClass = emptyClass->changePrototype(objectPrototype); + ObjectPrototype *objectPrototype = new (memoryManager) ObjectPrototype(emptyClass->changeVTable(&ObjectPrototype::static_vtbl)); + objectClass = InternalClass::create(this, &Object::static_vtbl, objectPrototype); + Q_ASSERT(objectClass->vtable == &Object::static_vtbl); - arrayClass = objectClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable); + arrayClass = InternalClass::create(this, &ArrayObject::static_vtbl, objectPrototype); + arrayClass = arrayClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable); ArrayPrototype *arrayPrototype = new (memoryManager) ArrayPrototype(arrayClass); arrayClass = arrayClass->changePrototype(arrayPrototype); - InternalClass *argsClass = objectClass->addMember(id_length, Attr_NotEnumerable); + InternalClass *argsClass = InternalClass::create(this, &ArgumentsObject::static_vtbl, objectPrototype); + argsClass = argsClass->addMember(id_length, Attr_NotEnumerable); argumentsObjectClass = argsClass->addMember(id_callee, Attr_Data|Attr_NotEnumerable); strictArgumentsObjectClass = argsClass->addMember(id_callee, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); strictArgumentsObjectClass = strictArgumentsObjectClass->addMember(id_caller, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + Q_ASSERT(argumentsObjectClass->vtable == &ArgumentsObject::static_vtbl); + Q_ASSERT(strictArgumentsObjectClass->vtable == &ArgumentsObject::static_vtbl); + initRootContext(); StringPrototype *stringPrototype = new (memoryManager) StringPrototype(objectClass); - stringClass = emptyClass->changePrototype(stringPrototype); + stringObjectClass = InternalClass::create(this, &String::static_vtbl, stringPrototype); NumberPrototype *numberPrototype = new (memoryManager) NumberPrototype(objectClass); - numberClass = emptyClass->changePrototype(numberPrototype); + numberClass = InternalClass::create(this, &NumberObject::static_vtbl, numberPrototype); BooleanPrototype *booleanPrototype = new (memoryManager) BooleanPrototype(objectClass); - booleanClass = emptyClass->changePrototype(booleanPrototype); + booleanClass = InternalClass::create(this, &BooleanObject::static_vtbl, booleanPrototype); DatePrototype *datePrototype = new (memoryManager) DatePrototype(objectClass); - dateClass = emptyClass->changePrototype(datePrototype); + dateClass = InternalClass::create(this, &DateObject::static_vtbl, datePrototype); - FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(objectClass); - functionClass = emptyClass->changePrototype(functionPrototype); + FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(InternalClass::create(this, &FunctionPrototype::static_vtbl, objectPrototype)); + functionClass = InternalClass::create(this, &FunctionObject::static_vtbl, functionPrototype); uint index; functionWithProtoClass = functionClass->addMember(id_prototype, Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == FunctionObject::Index_Prototype); @@ -247,32 +260,33 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory) Q_ASSERT(index == FunctionObject::Index_ProtoConstructor); RegExpPrototype *regExpPrototype = new (memoryManager) RegExpPrototype(objectClass); - regExpClass = emptyClass->changePrototype(regExpPrototype); + regExpClass = InternalClass::create(this, &RegExpObject::static_vtbl, regExpPrototype); regExpExecArrayClass = arrayClass->addMember(id_index, Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayIndex); regExpExecArrayClass = regExpExecArrayClass->addMember(id_input, Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayInput); ErrorPrototype *errorPrototype = new (memoryManager) ErrorPrototype(objectClass); - errorClass = emptyClass->changePrototype(errorPrototype); + errorClass = InternalClass::create(this, &ErrorObject::static_vtbl, errorPrototype); EvalErrorPrototype *evalErrorPrototype = new (memoryManager) EvalErrorPrototype(errorClass); - evalErrorClass = emptyClass->changePrototype(evalErrorPrototype); + evalErrorClass = InternalClass::create(this, &EvalErrorObject::static_vtbl, evalErrorPrototype); RangeErrorPrototype *rangeErrorPrototype = new (memoryManager) RangeErrorPrototype(errorClass); - rangeErrorClass = emptyClass->changePrototype(rangeErrorPrototype); + rangeErrorClass = InternalClass::create(this, &RangeErrorObject::static_vtbl, rangeErrorPrototype); ReferenceErrorPrototype *referenceErrorPrototype = new (memoryManager) ReferenceErrorPrototype(errorClass); - referenceErrorClass = emptyClass->changePrototype(referenceErrorPrototype); + referenceErrorClass = InternalClass::create(this, &ReferenceErrorObject::static_vtbl, referenceErrorPrototype); SyntaxErrorPrototype *syntaxErrorPrototype = new (memoryManager) SyntaxErrorPrototype(errorClass); - syntaxErrorClass = emptyClass->changePrototype(syntaxErrorPrototype); + syntaxErrorClass = InternalClass::create(this, &SyntaxErrorObject::static_vtbl, syntaxErrorPrototype); TypeErrorPrototype *typeErrorPrototype = new (memoryManager) TypeErrorPrototype(errorClass); - typeErrorClass = emptyClass->changePrototype(typeErrorPrototype); + typeErrorClass = InternalClass::create(this, &TypeErrorObject::static_vtbl, typeErrorPrototype); URIErrorPrototype *uRIErrorPrototype = new (memoryManager) URIErrorPrototype(errorClass); - uriErrorClass = emptyClass->changePrototype(uRIErrorPrototype); + uriErrorClass = InternalClass::create(this, &URIErrorObject::static_vtbl, uRIErrorPrototype); - VariantPrototype *variantPrototype = new (memoryManager) VariantPrototype(objectClass); - variantClass = emptyClass->changePrototype(variantPrototype); + VariantPrototype *variantPrototype = new (memoryManager) VariantPrototype(InternalClass::create(this, &VariantPrototype::static_vtbl, objectPrototype)); + variantClass = InternalClass::create(this, &VariantObject::static_vtbl, variantPrototype); + Q_ASSERT(variantClass->prototype == variantPrototype); + Q_ASSERT(variantPrototype->internalClass->prototype == objectPrototype); - SequencePrototype *sequencePrototype = new (memoryManager) SequencePrototype(arrayClass->changePrototype(arrayPrototype)); - sequenceClass = emptyClass->changePrototype(sequencePrototype); + sequencePrototype = new (memoryManager) SequencePrototype(arrayClass); objectCtor = new (memoryManager) ObjectCtor(rootContext); stringCtor = new (memoryManager) StringCtor(rootContext); @@ -307,7 +321,7 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory) uRIErrorPrototype->init(this, uRIErrorCtor); variantPrototype->init(); - sequencePrototype->init(); + static_cast<SequencePrototype *>(sequencePrototype.managed())->init(); // // set up the global object @@ -315,6 +329,7 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory) globalObject = newObject()->getPointer(); rootContext->global = globalObject; rootContext->callData->thisObject = globalObject; + Q_ASSERT(globalObject->internalClass->vtable); globalObject->defineDefaultProperty(QStringLiteral("Object"), objectCtor); globalObject->defineDefaultProperty(QStringLiteral("String"), stringCtor); @@ -389,10 +404,13 @@ void ExecutionEngine::enableDebugger() void ExecutionEngine::initRootContext() { - rootContext = static_cast<GlobalContext *>(memoryManager->allocContext(sizeof(GlobalContext) + sizeof(CallData))); - current = rootContext; - current->parent = 0; - rootContext->initGlobalContext(this); + rootContext = static_cast<GlobalContext *>(memoryManager->allocManaged(sizeof(GlobalContext) + sizeof(CallData))); + new (rootContext) GlobalContext(this); + rootContext->callData = reinterpret_cast<CallData *>(rootContext + 1); + rootContext->callData->tag = QV4::Value::_Integer_Type; + rootContext->callData->argc = 0; + rootContext->callData->thisObject = globalObject; + rootContext->callData->args[0] = Encode::undefined(); } InternalClass *ExecutionEngine::newClass(const InternalClass &other) @@ -402,14 +420,11 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other) ExecutionContext *ExecutionEngine::pushGlobalContext() { - GlobalContext *g = static_cast<GlobalContext *>(memoryManager->allocContext(sizeof(GlobalContext))); - ExecutionContext *oldNext = g->next; - *g = *rootContext; - g->next = oldNext; - g->parent = current; - current = g; + GlobalContext *g = new (memoryManager) GlobalContext(this); + g->callData = rootContext->callData; - return current; + Q_ASSERT(currentContext() == g); + return g; } Returned<FunctionObject> *ExecutionEngine::newBuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *)) @@ -597,7 +612,7 @@ Returned<Object> *ExecutionEngine::newForEachIteratorObject(ExecutionContext *ct Returned<Object> *ExecutionEngine::qmlContextObject() const { - ExecutionContext *ctx = current; + ExecutionContext *ctx = currentContext(); if (ctx->type == QV4::ExecutionContext::Type_SimpleCallContext && !ctx->outer) ctx = ctx->parent; @@ -627,11 +642,12 @@ namespace { void resolve(StackFrame *frame, ExecutionContext *context, Function *function) { qptrdiff offset; - if (context->interpreterInstructionPointer) + if (context->interpreterInstructionPointer) { offset = *context->interpreterInstructionPointer - 1 - function->codeData; - else - offset = context->jitInstructionPointer - (char*)function->codePtr; - frame->line = function->lineNumberForProgramCounter(offset); + frame->line = function->lineNumberForProgramCounter(offset); + } else { + frame->line = context->lineNumber; + } } }; } @@ -642,7 +658,7 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const QVector<StackFrame> stack; - QV4::ExecutionContext *c = current; + QV4::ExecutionContext *c = currentContext(); while (c && frameLimit) { CallContext *callCtx = c->asCallContext(); if (callCtx && callCtx->function) { @@ -696,7 +712,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) return src; QUrl base; - QV4::ExecutionContext *c = current; + QV4::ExecutionContext *c = currentContext(); while (c) { CallContext *callCtx = c->asCallContext(); if (callCtx && callCtx->function) { @@ -752,9 +768,9 @@ void ExecutionEngine::markObjects() setter->mark(this); } - ExecutionContext *c = current; + ExecutionContext *c = currentContext(); while (c) { - c->mark(); + c->mark(this); c = c->parent; } @@ -794,6 +810,7 @@ void ExecutionEngine::markObjects() syntaxErrorCtor.mark(this); typeErrorCtor.mark(this); uRIErrorCtor.mark(this); + sequencePrototype.mark(this); exceptionValue.mark(this); @@ -814,13 +831,13 @@ namespace { { bool operator()(Function *function, quintptr pc) { - return reinterpret_cast<quintptr>(function->codePtr) < pc - && (reinterpret_cast<quintptr>(function->codePtr) + function->codeSize) < pc; + return reinterpret_cast<quintptr>(function->code) < pc + && (reinterpret_cast<quintptr>(function->code) + function->codeSize) < pc; } bool operator()(quintptr pc, Function *function) { - return pc < reinterpret_cast<quintptr>(function->codePtr); + return pc < reinterpret_cast<quintptr>(function->code); } }; } @@ -887,8 +904,8 @@ ReturnedValue ExecutionEngine::throwException(const ValueRef value) ReturnedValue ExecutionEngine::catchException(ExecutionContext *catchingContext, StackTrace *trace) { Q_ASSERT(hasException); - while (current != catchingContext) - popContext(); + Q_UNUSED(catchingContext); + Q_ASSERT(currentContext() == catchingContext); if (trace) *trace = exceptionStackTrace; exceptionStackTrace.clear(); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index b4972904ee..ecb5f2b4d5 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -44,7 +44,6 @@ #include "qv4global_p.h" #include "private/qv4isel_p.h" #include "qv4util_p.h" -#include "qv4context_p.h" #include "qv4property_p.h" #include <private/qintrusivelist_p.h> @@ -112,11 +111,12 @@ class RegExp; class RegExpCache; struct QmlExtensions; struct Exception; +struct ExecutionContextSaver; #define CHECK_STACK_LIMITS(v4) \ if ((v4->jsStackTop <= v4->jsStackLimit) && (reinterpret_cast<quintptr>(&v4) >= v4->cStackLimit || v4->recheckCStackLimits())) {} \ else \ - return v4->current->throwRangeError(QStringLiteral("Maximum call stack size exceeded.")) + return v4->currentContext()->throwRangeError(QStringLiteral("Maximum call stack size exceeded.")) struct Q_QML_EXPORT ExecutionEngine @@ -126,7 +126,13 @@ struct Q_QML_EXPORT ExecutionEngine ExecutableAllocator *regExpAllocator; QScopedPointer<QQmlJS::EvalISelFactory> iselFactory; +private: + friend struct ExecutionContextSaver; + friend struct ExecutionContext; ExecutionContext *current; +public: + ExecutionContext *currentContext() const { return current; } + GlobalContext *rootContext; SafeValue *jsStackTop; @@ -183,12 +189,16 @@ struct Q_QML_EXPORT ExecutionEngine SafeValue syntaxErrorCtor; SafeValue typeErrorCtor; SafeValue uRIErrorCtor; + SafeValue sequencePrototype; QQmlJS::MemoryPool classPool; InternalClass *emptyClass; + InternalClass *executionContextClass; + InternalClass *stringClass; + InternalClass *objectClass; InternalClass *arrayClass; - InternalClass *stringClass; + InternalClass *stringObjectClass; InternalClass *booleanClass; InternalClass *numberClass; InternalClass *dateClass; @@ -199,6 +209,7 @@ struct Q_QML_EXPORT ExecutionEngine InternalClass *regExpClass; InternalClass *regExpExecArrayClass; + InternalClass *regExpValueClass; InternalClass *errorClass; InternalClass *evalErrorClass; @@ -211,7 +222,6 @@ struct Q_QML_EXPORT ExecutionEngine InternalClass *strictArgumentsObjectClass; InternalClass *variantClass; - InternalClass *sequenceClass; EvalFunction *evalFunction; FunctionObject *thrower; @@ -356,38 +366,10 @@ private: QmlExtensions *m_qmlExtensions; }; -inline void ExecutionEngine::pushContext(CallContext *context) -{ - context->parent = current; - current = context; - current->currentEvalCode = 0; -} - -inline ExecutionContext *ExecutionEngine::popContext() -{ - current = current->parent; - return current; -} - -struct ExecutionContextSaver -{ - ExecutionEngine *engine; - ExecutionContext *savedContext; - - ExecutionContextSaver(ExecutionContext *context) - : engine(context->engine) - , savedContext(context) - { - } - ~ExecutionContextSaver() - { - engine->current = savedContext; - } -}; - inline void Managed::mark(QV4::ExecutionEngine *engine) { + Q_ASSERT(inUse); if (markBit) return; markBit = 1; diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index bac29d19e1..cf5c06dd41 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -77,7 +77,6 @@ ErrorObject::ErrorObject(InternalClass *ic) , stack(0) { type = Type_ErrorObject; - vtbl = &static_vtbl; Scope scope(engine()); ScopedValue protectThis(scope, this); @@ -91,7 +90,6 @@ ErrorObject::ErrorObject(InternalClass *ic, const ValueRef message, ErrorType t) , stack(0) { type = Type_ErrorObject; - vtbl = &static_vtbl; subtype = t; Scope scope(engine()); @@ -116,7 +114,6 @@ ErrorObject::ErrorObject(InternalClass *ic, const QString &message, ErrorObject: , stack(0) { type = Type_ErrorObject; - vtbl = &static_vtbl; subtype = t; Scope scope(engine()); @@ -141,7 +138,6 @@ ErrorObject::ErrorObject(InternalClass *ic, const QString &message, const QStrin , stack(0) { type = Type_ErrorObject; - vtbl = &static_vtbl; subtype = t; Scope scope(engine()); @@ -207,13 +203,11 @@ DEFINE_MANAGED_VTABLE(SyntaxErrorObject); SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const ValueRef msg) : ErrorObject(engine->syntaxErrorClass, msg, SyntaxError) { - vtbl = &static_vtbl; } SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) : ErrorObject(engine->syntaxErrorClass, msg, fileName, lineNumber, columnNumber, SyntaxError) { - vtbl = &static_vtbl; } EvalErrorObject::EvalErrorObject(ExecutionEngine *engine, const ValueRef message) @@ -272,13 +266,13 @@ DEFINE_MANAGED_VTABLE(URIErrorCtor); ErrorCtor::ErrorCtor(ExecutionContext *scope) : FunctionObject(scope, QStringLiteral("Error")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ErrorCtor::ErrorCtor(ExecutionContext *scope, const QString &name) : FunctionObject(scope, name) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue ErrorCtor::construct(Managed *m, CallData *callData) @@ -296,7 +290,7 @@ ReturnedValue ErrorCtor::call(Managed *that, CallData *callData) EvalErrorCtor::EvalErrorCtor(ExecutionContext *scope) : ErrorCtor(scope, QStringLiteral("EvalError")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue EvalErrorCtor::construct(Managed *m, CallData *callData) @@ -309,7 +303,7 @@ ReturnedValue EvalErrorCtor::construct(Managed *m, CallData *callData) RangeErrorCtor::RangeErrorCtor(ExecutionContext *scope) : ErrorCtor(scope, QStringLiteral("RangeError")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue RangeErrorCtor::construct(Managed *m, CallData *callData) @@ -322,7 +316,7 @@ ReturnedValue RangeErrorCtor::construct(Managed *m, CallData *callData) ReferenceErrorCtor::ReferenceErrorCtor(ExecutionContext *scope) : ErrorCtor(scope, QStringLiteral("ReferenceError")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue ReferenceErrorCtor::construct(Managed *m, CallData *callData) @@ -335,7 +329,7 @@ ReturnedValue ReferenceErrorCtor::construct(Managed *m, CallData *callData) SyntaxErrorCtor::SyntaxErrorCtor(ExecutionContext *scope) : ErrorCtor(scope, QStringLiteral("SyntaxError")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue SyntaxErrorCtor::construct(Managed *m, CallData *callData) @@ -348,7 +342,7 @@ ReturnedValue SyntaxErrorCtor::construct(Managed *m, CallData *callData) TypeErrorCtor::TypeErrorCtor(ExecutionContext *scope) : ErrorCtor(scope, QStringLiteral("TypeError")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue TypeErrorCtor::construct(Managed *m, CallData *callData) @@ -361,7 +355,7 @@ ReturnedValue TypeErrorCtor::construct(Managed *m, CallData *callData) URIErrorCtor::URIErrorCtor(ExecutionContext *scope) : ErrorCtor(scope, QStringLiteral("URIError")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue URIErrorCtor::construct(Managed *m, CallData *callData) diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 3f4cb8fc43..def776d3b6 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -184,37 +184,37 @@ struct ErrorPrototype: ErrorObject struct EvalErrorPrototype: ErrorObject { - EvalErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; } + EvalErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); } void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); } }; struct RangeErrorPrototype: ErrorObject { - RangeErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; } + RangeErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); } void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); } }; struct ReferenceErrorPrototype: ErrorObject { - ReferenceErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; } + ReferenceErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); } void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); } }; struct SyntaxErrorPrototype: ErrorObject { - SyntaxErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; } + SyntaxErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); } void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); } }; struct TypeErrorPrototype: ErrorObject { - TypeErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; } + TypeErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); } void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); } }; struct URIErrorPrototype: ErrorObject { - URIErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; } + URIErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); } void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); } }; diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index ebe214ad72..0e90e213c4 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -54,7 +54,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, ReturnedValue (*codePtr)(ExecutionContext *, const uchar *), quint32 _codeSize) : compiledFunction(function) , compilationUnit(unit) - , codePtr(codePtr) + , code(codePtr) , codeData(0) , codeSize(_codeSize) { @@ -62,18 +62,29 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, name = compilationUnit->runtimeStrings[compiledFunction->nameIndex].asString(); - formals.resize(compiledFunction->nFormals); - formals.fill(0); - const quint32 *formalsIndices = compiledFunction->formalsTable(); - for (quint32 i = 0; i < compiledFunction->nFormals; ++i) - formals[i] = compilationUnit->runtimeStrings[formalsIndices[i]].asString(); + nArguments = compiledFunction->nFormals; + internalClass = engine->emptyClass; + const quint32 *formalsIndices = compiledFunction->formalsTable(); + // iterate backwards, so we get the right ordering for duplicate names + for (int i = static_cast<int>(compiledFunction->nFormals - 1); i >= 0; --i) { + String *arg = compilationUnit->runtimeStrings[formalsIndices[i]].asString(); + while (1) { + InternalClass *newClass = internalClass->addMember(arg, Attr_NotConfigurable); + if (newClass != internalClass) { + internalClass = newClass; + break; + } + // duplicate arguments, need some trick to store them + arg = new (engine->memoryManager) String(engine, arg, engine->newString(QString(0xfffe))->getPointer()); + } + } - locals.resize(compiledFunction->nLocals); - locals.fill(0); const quint32 *localsIndices = compiledFunction->localsTable(); - for (quint32 i = 0; i < compiledFunction->nLocals; ++i) - locals[i] = compilationUnit->runtimeStrings[localsIndices[i]].asString(); + for (quint32 i = 0; i < compiledFunction->nLocals; ++i) { + String *local = compilationUnit->runtimeStrings[localsIndices[i]].asString(); + internalClass = internalClass->addMember(local, Attr_NotConfigurable); + } } Function::~Function() @@ -84,10 +95,6 @@ Function::~Function() void Function::mark(ExecutionEngine *e) { name.mark(e); - for (int i = 0; i < formals.size(); ++i) - formals.at(i)->mark(e); - for (int i = 0; i < locals.size(); ++i) - locals.at(i)->mark(e); } namespace QV4 { diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 5d284f1b2b..8d07853b45 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -85,16 +85,14 @@ struct Function { const CompiledData::Function *compiledFunction; CompiledData::CompilationUnit *compilationUnit; - inline ReturnedValue code(ExecutionContext *ctx, const uchar *data) { - return codePtr(ctx, data); - } - ReturnedValue (*codePtr)(ExecutionContext *, const uchar *); + ReturnedValue (*code)(ExecutionContext *, const uchar *); const uchar *codeData; quint32 codeSize; - QVector<String *> formals; - QVector<String *> locals; + // first nArguments names in internalClass are the actual arguments + int nArguments; + InternalClass *internalClass; Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function, ReturnedValue (*codePtr)(ExecutionContext *, const uchar *), quint32 _codeSize); diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index aa1cb89a44..6e5c137e0b 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -55,6 +55,7 @@ #include <private/qqmljsparser_p.h> #include <private/qqmljsast_p.h> #include <private/qqmlcontextwrapper_p.h> +#include <private/qqmlengine_p.h> #include <qv4jsir_p.h> #include <qv4codegen_p.h> #include "private/qlocale_tools_p.h" @@ -75,11 +76,11 @@ DEFINE_MANAGED_VTABLE(FunctionObject); FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto) : Object(createProto ? scope->engine->functionWithProtoClass : scope->engine->functionClass) , scope(scope) - , formalParameterList(0) - , varList(0) , formalParameterCount(0) , varCount(0) , function(0) + , protoCacheClass(0) + , protoCacheIndex(UINT_MAX) { init(name, createProto); } @@ -87,11 +88,11 @@ FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bo FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto) : Object(createProto ? scope->engine->functionWithProtoClass : scope->engine->functionClass) , scope(scope) - , formalParameterList(0) - , varList(0) , formalParameterCount(0) , varCount(0) , function(0) + , protoCacheClass(0) + , protoCacheIndex(UINT_MAX) { // set the name to something here, so that a gc run a few lines below doesn't crash on it this->name = scope->engine->id_undefined; @@ -105,13 +106,10 @@ FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, boo FunctionObject::FunctionObject(InternalClass *ic) : Object(ic) , scope(ic->engine->rootContext) - , formalParameterList(0) - , varList(0) , formalParameterCount(0) , varCount(0) , function(0) { - vtbl = &static_vtbl; name = ic->engine->id_undefined; type = Type_FunctionObject; @@ -127,7 +125,6 @@ FunctionObject::~FunctionObject() void FunctionObject::init(const StringRef n, bool createProto) { - vtbl = &static_vtbl; name = n; Scope s(internalClass->engine); @@ -157,43 +154,13 @@ ReturnedValue FunctionObject::newInstance() return construct(callData); } -bool FunctionObject::hasInstance(Managed *that, const ValueRef value) -{ - Scope scope(that->internalClass->engine); - ScopedFunctionObject f(scope, static_cast<FunctionObject *>(that)); - - ScopedObject v(scope, value); - if (!v) - return false; - - Scoped<Object> o(scope, f->get(scope.engine->id_prototype)); - if (!o) { - scope.engine->current->throwTypeError(); - return false; - } - - while (v) { - v = v->prototype(); - - if (! v) - break; - else if (o.getPointer() == v) - return true; - } - - return false; -} - ReturnedValue FunctionObject::construct(Managed *that, CallData *) { ExecutionEngine *v4 = that->internalClass->engine; Scope scope(v4); Scoped<FunctionObject> f(scope, that, Scoped<FunctionObject>::Cast); - InternalClass *ic = v4->objectClass; - Scoped<Object> proto(scope, f->get(v4->id_prototype)); - if (!!proto) - ic = v4->emptyClass->changePrototype(proto.getPointer()); + InternalClass *ic = f->internalClassForConstructor(); Scoped<Object> obj(scope, v4->newObject(ic)); return obj.asReturnedValue(); } @@ -213,7 +180,7 @@ void FunctionObject::markObjects(Managed *that, ExecutionEngine *e) // formalParameterList[i]->mark(); // for (uint i = 0; i < varCount; ++i) // varList[i]->mark(); - o->scope->mark(); + o->scope->mark(e); if (o->function) o->function->mark(e); @@ -230,13 +197,49 @@ FunctionObject *FunctionObject::creatScriptFunction(ExecutionContext *scope, Fun return new (scope->engine->memoryManager) SimpleScriptFunction(scope, function); } +ReturnedValue FunctionObject::protoProperty() +{ + if (protoCacheClass != internalClass) { + protoCacheClass = internalClass; + protoCacheIndex = internalClass->find(internalClass->engine->id_prototype); + } + if (protoCacheIndex < UINT_MAX) { + if (internalClass->propertyData.at(protoCacheIndex).isData()) { + ReturnedValue v = memberData[protoCacheIndex].value.asReturnedValue(); + if (v != protoValue) { + classForConstructor = 0; + protoValue = v; + } + return v; + } + } + classForConstructor = 0; + return get(internalClass->engine->id_prototype); +} + +InternalClass *FunctionObject::internalClassForConstructor() +{ + // need to call this first to ensure we don't use a wrong class + ReturnedValue proto = protoProperty(); + if (classForConstructor) + return classForConstructor; + + Scope scope(internalClass->engine); + ScopedObject p(scope, proto); + if (p) + classForConstructor = InternalClass::create(scope.engine, &Object::static_vtbl, p.getPointer()); + else + classForConstructor = scope.engine->objectClass; + + return classForConstructor; +} DEFINE_MANAGED_VTABLE(FunctionCtor); FunctionCtor::FunctionCtor(ExecutionContext *scope) : FunctionObject(scope, QStringLiteral("Function")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } // 15.3.2 @@ -244,7 +247,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) { FunctionCtor *f = static_cast<FunctionCtor *>(that); ExecutionEngine *v4 = f->internalClass->engine; - ExecutionContext *ctx = v4->current; + ExecutionContext *ctx = v4->currentContext(); QString arguments; QString body; if (callData->argc > 0) { @@ -268,20 +271,20 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) const bool parsed = parser.parseExpression(); if (!parsed) - return v4->current->throwSyntaxError(QLatin1String("Parse error")); + return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error")); using namespace QQmlJS::AST; FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode()); if (!fe) - return v4->current->throwSyntaxError(QLatin1String("Parse error")); + return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error")); QQmlJS::V4IR::Module module(v4->debugger != 0); - QQmlJS::RuntimeCodegen cg(v4->current, f->strictMode); + QQmlJS::RuntimeCodegen cg(v4->currentContext(), f->strictMode); cg.generateFromFunctionExpression(QString(), function, fe, &module); QV4::Compiler::JSUnitGenerator jsGenerator(&module); - QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module, &jsGenerator)); + QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator)); QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile(); QV4::Function *vmf = compilationUnit->linkToEngine(v4); @@ -348,7 +351,7 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) ScopedCallData callData(scope, len); if (len) { - if (arr->protoHasArray() || arr->hasAccessorProperty) { + if (!(arr->flags & SimpleArray) || arr->protoHasArray() || arr->hasAccessorProperty) { for (quint32 i = 0; i < len; ++i) callData->args[i] = arr->getIndexed(i); } else { @@ -401,7 +404,7 @@ DEFINE_MANAGED_VTABLE(ScriptFunction); ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function) : FunctionObject(scope, function->name, true) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); Scope s(scope); ScopedValue protectThis(s, this); @@ -409,7 +412,7 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function) this->function = function; this->function->compilationUnit->ref(); Q_ASSERT(function); - Q_ASSERT(function->codePtr); + Q_ASSERT(function->code); // global function if (!scope) @@ -419,12 +422,10 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function) needsActivation = function->needsActivation(); strictMode = function->isStrict(); - formalParameterCount = function->formals.size(); - formalParameterList = function->formals.constData(); - defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount)); + formalParameterCount = function->nArguments; + varCount = function->internalClass->size - function->nArguments; - varCount = function->locals.size(); - varList = function->locals.constData(); + defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount)); if (scope->strictMode) { Property pd = Property::fromAccessor(v4->thrower, v4->thrower); @@ -443,13 +444,10 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData) Scope scope(v4); Scoped<ScriptFunction> f(scope, static_cast<ScriptFunction *>(that)); - InternalClass *ic = v4->objectClass; - ScopedObject proto(scope, f->memberData[Index_Prototype].value); - if (proto) - ic = v4->emptyClass->changePrototype(proto.getPointer()); + InternalClass *ic = f->internalClassForConstructor(); ScopedObject obj(scope, v4->newObject(ic)); - ExecutionContext *context = v4->current; + ExecutionContext *context = v4->currentContext(); callData->thisObject = obj.asReturnedValue(); ExecutionContext *ctx = context->newCallContext(f.getPointer(), callData); @@ -471,7 +469,7 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) return Encode::undefined(); CHECK_STACK_LIMITS(v4); - ExecutionContext *context = v4->current; + ExecutionContext *context = v4->currentContext(); Scope scope(context); CallContext *ctx = context->newCallContext(f, callData); @@ -488,7 +486,7 @@ DEFINE_MANAGED_VTABLE(SimpleScriptFunction); SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *function) : FunctionObject(scope, function->name, true) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); Scope s(scope); ScopedValue protectThis(s, this); @@ -496,7 +494,7 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu this->function = function; this->function->compilationUnit->ref(); Q_ASSERT(function); - Q_ASSERT(function->codePtr); + Q_ASSERT(function->code); // global function if (!scope) @@ -506,12 +504,10 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu needsActivation = function->needsActivation(); strictMode = function->isStrict(); - formalParameterCount = function->formals.size(); - formalParameterList = function->formals.constData(); - defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount)); + formalParameterCount = function->nArguments; + varCount = function->internalClass->size - function->nArguments; - varCount = function->locals.size(); - varList = function->locals.constData(); + defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount)); if (scope->strictMode) { Property pd = Property::fromAccessor(v4->thrower, v4->thrower); @@ -530,33 +526,29 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData) Scope scope(v4); Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that)); - InternalClass *ic = v4->objectClass; - Scoped<Object> proto(scope, f->memberData[Index_Prototype].value); - if (!!proto) - ic = v4->emptyClass->changePrototype(proto.getPointer()); + InternalClass *ic = f->internalClassForConstructor(); callData->thisObject = v4->newObject(ic); - ExecutionContext *context = v4->current; + ExecutionContext *context = v4->currentContext(); + ExecutionContextSaver ctxSaver(context); - CallContext ctx; - ctx.initSimpleCallContext(v4, context); + CallContext ctx(v4); ctx.strictMode = f->strictMode; ctx.callData = callData; ctx.function = f.getPointer(); ctx.compilationUnit = f->function->compilationUnit; ctx.lookups = ctx.compilationUnit->runtimeLookups; ctx.outer = f->scope; - ctx.locals = v4->stackPush(f->function->locals.size()); + ctx.locals = v4->stackPush(f->varCount); while (callData->argc < (int)f->formalParameterCount) { callData->args[callData->argc] = Encode::undefined(); ++callData->argc; } - v4->pushContext(&ctx); + Q_ASSERT(v4->currentContext() == &ctx); if (f->function->compiledFunction->hasQmlDependencies()) QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction); - ExecutionContextSaver ctxSaver(context); Scoped<Object> result(scope, f->function->code(&ctx, f->function->codeData)); if (!result) @@ -574,27 +566,26 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData) SimpleScriptFunction *f = static_cast<SimpleScriptFunction *>(that); Scope scope(v4); - ExecutionContext *context = v4->current; + ExecutionContext *context = v4->currentContext(); + ExecutionContextSaver ctxSaver(context); - CallContext ctx; - ctx.initSimpleCallContext(v4, context); + CallContext ctx(v4); ctx.strictMode = f->strictMode; ctx.callData = callData; ctx.function = f; ctx.compilationUnit = f->function->compilationUnit; ctx.lookups = ctx.compilationUnit->runtimeLookups; ctx.outer = f->scope; - ctx.locals = v4->stackPush(f->function->locals.size()); + ctx.locals = v4->stackPush(f->varCount); while (callData->argc < (int)f->formalParameterCount) { callData->args[callData->argc] = Encode::undefined(); ++callData->argc; } - v4->current = &ctx; + Q_ASSERT(v4->currentContext() == &ctx); if (f->function->compiledFunction->hasQmlDependencies()) QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction); - ExecutionContextSaver ctxSaver(context); return f->function->code(&ctx, f->function->codeData); } @@ -607,12 +598,12 @@ BuiltinFunction::BuiltinFunction(ExecutionContext *scope, const StringRef name, : FunctionObject(scope, name) , code(code) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue BuiltinFunction::construct(Managed *f, CallData *) { - return f->internalClass->engine->current->throwTypeError(); + return f->internalClass->engine->currentContext()->throwTypeError(); } ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData) @@ -623,15 +614,14 @@ ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData) return Encode::undefined(); CHECK_STACK_LIMITS(v4); - ExecutionContext *context = v4->current; + ExecutionContext *context = v4->currentContext(); + ExecutionContextSaver ctxSaver(context); - CallContext ctx; - ctx.initSimpleCallContext(v4, context); + CallContext ctx(v4); ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context? ctx.callData = callData; - v4->pushContext(&ctx); + Q_ASSERT(v4->currentContext() == &ctx); - ExecutionContextSaver ctxSaver(context); return f->code(&ctx); } @@ -643,16 +633,14 @@ ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData) return Encode::undefined(); CHECK_STACK_LIMITS(v4); - ExecutionContext *context = v4->current; - Scope scope(v4); + ExecutionContext *context = v4->currentContext(); + ExecutionContextSaver ctxSaver(context); - CallContext ctx; - ctx.initSimpleCallContext(v4, context); + CallContext ctx(v4); ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context? ctx.callData = callData; - v4->pushContext(&ctx); + Q_ASSERT(v4->currentContext() == &ctx); - ExecutionContextSaver ctxSaver(context); return f->code(&ctx, f->index); } @@ -665,7 +653,8 @@ BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObjectRef target, , target(target) , boundArgs(boundArgs) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); + subtype = FunctionObject::BoundFunction; this->boundThis = boundThis; Scope s(scope); @@ -717,12 +706,6 @@ ReturnedValue BoundFunction::construct(Managed *that, CallData *dd) return f->target->construct(callData); } -bool BoundFunction::hasInstance(Managed *that, const ValueRef value) -{ - BoundFunction *f = static_cast<BoundFunction *>(that); - return FunctionObject::hasInstance(f->target, value); -} - void BoundFunction::markObjects(Managed *that, ExecutionEngine *e) { BoundFunction *o = static_cast<BoundFunction *>(that); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 2fc36d862f..96534cb68c 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -97,7 +97,8 @@ struct Q_QML_EXPORT FunctionObject: Object { // Used with Managed::subType enum FunctionType { RegularFunction = 0, - WrappedQtMethod = 1 + WrappedQtMethod = 1, + BoundFunction }; enum { @@ -107,11 +108,13 @@ struct Q_QML_EXPORT FunctionObject: Object { ExecutionContext *scope; SafeString name; - String * const *formalParameterList; - String * const *varList; unsigned int formalParameterCount; unsigned int varCount; Function *function; + InternalClass *protoCacheClass; + uint protoCacheIndex; + ReturnedValue protoValue; + InternalClass *classForConstructor; FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto = false); FunctionObject(ExecutionContext *scope, const QString &name = QString(), bool createProto = false); @@ -124,10 +127,10 @@ struct Q_QML_EXPORT FunctionObject: Object { static ReturnedValue construct(Managed *that, CallData *); static ReturnedValue call(Managed *that, CallData *d); inline ReturnedValue construct(CallData *callData) { - return vtbl->construct(this, callData); + return internalClass->vtable->construct(this, callData); } inline ReturnedValue call(CallData *callData) { - return vtbl->call(this, callData); + return internalClass->vtable->call(this, callData); } static FunctionObject *cast(const Value &v) { @@ -136,11 +139,13 @@ struct Q_QML_EXPORT FunctionObject: Object { static FunctionObject *creatScriptFunction(ExecutionContext *scope, Function *function); + ReturnedValue protoProperty(); + InternalClass *internalClassForConstructor(); + protected: FunctionObject(InternalClass *ic); static void markObjects(Managed *that, ExecutionEngine *e); - static bool hasInstance(Managed *that, const ValueRef value); static void destroy(Managed *that) { static_cast<FunctionObject*>(that)->~FunctionObject(); } }; @@ -192,12 +197,12 @@ struct IndexedBuiltinFunction: FunctionObject , code(code) , index(index) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } static ReturnedValue construct(Managed *m, CallData *) { - return m->engine()->current->throwTypeError(); + return m->engine()->currentContext()->throwTypeError(); } static ReturnedValue call(Managed *that, CallData *callData); @@ -235,7 +240,6 @@ struct BoundFunction: FunctionObject { static void destroy(Managed *); static void markObjects(Managed *that, ExecutionEngine *e); - static bool hasInstance(Managed *that, const ValueRef value); }; } diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 7d7338f19c..1d465df0c0 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -119,6 +119,8 @@ struct Object; struct ObjectPrototype; struct ObjectIterator; struct ExecutionContext; +struct GlobalContext; +struct CallContext; struct ScriptFunction; struct InternalClass; struct Property; diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 82622de5bb..fa8af8ed5d 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -349,7 +349,7 @@ DEFINE_MANAGED_VTABLE(EvalFunction); EvalFunction::EvalFunction(ExecutionContext *scope) : FunctionObject(scope, scope->engine->id_eval) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1)); } @@ -379,15 +379,17 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) if (callData->argc < 1) return Encode::undefined(); - ExecutionContext *parentContext = engine()->current; - ExecutionEngine *engine = parentContext->engine; + ExecutionEngine *v4 = engine(); + ExecutionContext *parentContext = v4->currentContext(); + ExecutionContextSaver ctxSaver(parentContext); + ExecutionContext *ctx = parentContext; Scope scope(ctx); if (!directCall) { // the context for eval should be the global scope, so we fake a root // context - ctx = engine->pushGlobalContext(); + ctx = v4->pushGlobalContext(); } if (!callData->args[0].isString()) @@ -418,7 +420,6 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) return e->call(callData); } - ExecutionContextSaver ctxSaver(parentContext); ContextStateSaver stateSaver(ctx); ExecutionContext::EvalCode evalCode; @@ -437,7 +438,6 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) ReturnedValue EvalFunction::call(Managed *that, CallData *callData) { // indirect call - // ### const_cast return static_cast<EvalFunction *>(that)->evalCall(callData, false); } diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 8f2548064a..d0e0e9413b 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -108,7 +108,7 @@ void QV4Include::callback(const QV4::ValueRef callback, const QV4::ValueRef stat if (!f) return; - QV4::ExecutionContext *ctx = v4->current; + QV4::ExecutionContext *ctx = v4->currentContext(); QV4::ScopedCallData callData(scope, 1); callData->thisObject = v4->globalObject->asReturnedValue(); callData->args[0] = status; @@ -153,7 +153,7 @@ void QV4Include::finished() QV4::ScopedObject qmlglobal(scope, m_qmlglobal.value()); QV4::Script script(v4, qmlglobal, code, m_url.toString()); - QV4::ExecutionContext *ctx = v4->current; + QV4::ExecutionContext *ctx = v4->currentContext(); QV4::ScopedString status(scope, v4->newString(QStringLiteral("status"))); script.parse(); if (!scope.engine->hasException) @@ -220,7 +220,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) QV4::Script script(v4, qmlcontextobject, code, url.toString()); - QV4::ExecutionContext *ctx = v4->current; + QV4::ExecutionContext *ctx = v4->currentContext(); script.parse(); if (!v4->hasException) script.run(); diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index cb799a473c..29ede3d104 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -126,10 +126,21 @@ uint PropertyHash::lookup(const Identifier *identifier) const } } +InternalClass::InternalClass(ExecutionEngine *engine) + : engine(engine) + , prototype(0) + , vtable(&Managed::static_vtbl) + , m_sealed(0) + , m_frozen(0) + , size(0) +{ +} + InternalClass::InternalClass(const QV4::InternalClass &other) : engine(other.engine) , prototype(other.prototype) + , vtable(other.vtable) , propertyTable(other.propertyTable) , nameMap(other.nameMap) , propertyData(other.propertyData) @@ -169,6 +180,12 @@ InternalClass *InternalClass::changeMember(String *string, PropertyAttributes da } +InternalClass *InternalClass::create(ExecutionEngine *engine, const ManagedVTable *vtable, Object *proto) +{ + InternalClass *c = engine->emptyClass->changeVTable(vtable); + return c->changePrototype(proto); +} + InternalClass *InternalClass::changePrototype(Object *proto) { if (prototype == proto) @@ -184,11 +201,41 @@ InternalClass *InternalClass::changePrototype(Object *proto) // create a new class and add it to the tree InternalClass *newClass; - if (this == engine->emptyClass) { + if (!size) { newClass = engine->newClass(*this); newClass->prototype = proto; } else { - newClass = engine->emptyClass->changePrototype(proto); + newClass = engine->emptyClass->changeVTable(vtable); + newClass = newClass->changePrototype(proto); + for (uint i = 0; i < size; ++i) + newClass = newClass->addMember(nameMap.at(i), propertyData.at(i)); + } + + transitions.insert(t, newClass); + return newClass; +} + +InternalClass *InternalClass::changeVTable(const ManagedVTable *vt) +{ + if (vtable == vt) + return this; + + Transition t; + t.vtable = vt; + t.flags = Transition::VTableChange; + + QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t); + if (tit != transitions.constEnd()) + return tit.value(); + + // create a new class and add it to the tree + InternalClass *newClass; + if (this == engine->emptyClass) { + newClass = engine->newClass(*this); + newClass->vtable = vt; + } else { + newClass = engine->emptyClass->changeVTable(vt); + newClass = newClass->changePrototype(prototype); for (uint i = 0; i < size; ++i) newClass = newClass->addMember(nameMap.at(i), propertyData.at(i)); } @@ -250,7 +297,8 @@ void InternalClass::removeMember(Object *object, Identifier *id) } // create a new class and add it to the tree - object->internalClass = engine->emptyClass->changePrototype(prototype); + object->internalClass = engine->emptyClass->changeVTable(vtable); + object->internalClass = object->internalClass->changePrototype(prototype); for (uint i = 0; i < size; ++i) { if (i == propIdx) continue; @@ -283,6 +331,7 @@ InternalClass *InternalClass::sealed() return m_sealed; m_sealed = engine->emptyClass; + m_sealed = m_sealed->changeVTable(vtable); m_sealed = m_sealed->changePrototype(prototype); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); @@ -300,6 +349,7 @@ InternalClass *InternalClass::frozen() return m_frozen; m_frozen = engine->emptyClass; + m_frozen = m_frozen->changeVTable(vtable); m_frozen = m_frozen->changePrototype(prototype); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); @@ -343,7 +393,9 @@ void InternalClass::markObjects() for (QHash<Transition, InternalClass *>::ConstIterator it = transitions.begin(), end = transitions.end(); it != end; ++it) { - if (it.key().flags == Transition::ProtoChange) { + if (it.key().flags == Transition::VTableChange) { + it.value()->markObjects(); + } else if (it.key().flags == Transition::ProtoChange) { Q_ASSERT(it.value()->prototype); it.value()->prototype->mark(engine); } diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 9586637b32..b25b895183 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -53,6 +53,7 @@ struct String; struct ExecutionEngine; struct Object; struct Identifier; +struct ManagedVTable; struct PropertyHashData; struct PropertyHash @@ -198,9 +199,14 @@ struct InternalClassTransition union { Identifier *id; Object *prototype; + const ManagedVTable *vtable; }; int flags; - enum { ProtoChange = 0x100 }; + enum { + // range 0-0xff is reserved for attribute changes + ProtoChange = 0x100, + VTableChange = 0x200 + }; bool operator==(const InternalClassTransition &other) const { return id == other.id && flags == other.flags; } @@ -210,6 +216,8 @@ uint qHash(const QV4::InternalClassTransition &t, uint = 0); struct InternalClass { ExecutionEngine *engine; Object *prototype; + const ManagedVTable *vtable; + PropertyHash propertyTable; // id to valueIndex SharedInternalClassData<String *> nameMap; SharedInternalClassData<PropertyAttributes> propertyData; @@ -222,7 +230,9 @@ struct InternalClass { uint size; + static InternalClass *create(ExecutionEngine *engine, const ManagedVTable *vtable, Object *proto); InternalClass *changePrototype(Object *proto); + InternalClass *changeVTable(const ManagedVTable *vt); InternalClass *addMember(StringRef string, PropertyAttributes data, uint *index = 0); InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0); InternalClass *changeMember(String *string, PropertyAttributes data, uint *index = 0); @@ -238,7 +248,7 @@ struct InternalClass { private: friend struct ExecutionEngine; - InternalClass(ExecutionEngine *engine) : engine(engine), prototype(0), m_sealed(0), m_frozen(0), size(0) {} + InternalClass(ExecutionEngine *engine); InternalClass(const InternalClass &other); }; diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 5aac8c8197..6633435668 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -965,7 +965,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) ReturnedValue JsonObject::fromJsonValue(ExecutionEngine *engine, const QJsonValue &value) { if (value.isString()) - return engine->current->engine->newString(value.toString())->asReturnedValue(); + return engine->currentContext()->engine->newString(value.toString())->asReturnedValue(); else if (value.isDouble()) return Encode(value.toDouble()); else if (value.isBool()) diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h index f63e7726f5..3bcbdeadbf 100644 --- a/src/qml/jsruntime/qv4jsonobject_p.h +++ b/src/qml/jsruntime/qv4jsonobject_p.h @@ -38,8 +38,8 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#ifndef QV4JSONOBJECTS_H -#define QV4SJONOBJECTS_H +#ifndef QV4JSONOBJECT_H +#define QV4JSONOBJECT_H #include "qv4object_p.h" #include <qjsonarray.h> diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index f67b24c040..a870cdac61 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -87,13 +87,13 @@ ReturnedValue Lookup::getterGeneric(QV4::Lookup *l, const ValueRef object) switch (object->type()) { case Value::Undefined_Type: case Value::Null_Type: - return engine->current->throwTypeError(); + return engine->currentContext()->throwTypeError(); case Value::Boolean_Type: proto = engine->booleanClass->prototype; break; case Value::Managed_Type: Q_ASSERT(object->isString()); - proto = engine->stringClass->prototype; + proto = engine->stringObjectClass->prototype; if (l->name->equals(engine->id_length)) { // special case, as the property is on the object itself l->getter = stringLengthGetter; @@ -446,7 +446,7 @@ void Lookup::setterGeneric(Lookup *l, const ValueRef object, const ValueRef valu Scope scope(l->name->engine()); ScopedObject o(scope, object); if (!o) { - o = __qmljs_convert_to_object(scope.engine->current, object); + o = __qmljs_convert_to_object(scope.engine->currentContext(), object); if (!o) // type error return; ScopedString s(scope, l->name); diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index 6455a08037..fef7489110 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -52,7 +52,6 @@ const ManagedVTable Managed::static_vtbl = 0 /*markObjects*/, destroy, 0 /*collectDeletables*/, - hasInstance, 0, 0, 0, @@ -82,7 +81,6 @@ void Managed::operator delete(void *ptr) return; Managed *m = static_cast<Managed *>(ptr); - m->vtbl = 0; m->_data = 0; m->markBit = 0; m->~Managed(); @@ -178,29 +176,30 @@ QString Managed::className() const return QString::fromLatin1(s); } -bool Managed::hasInstance(Managed *m, const ValueRef) +void Managed::setVTable(const ManagedVTable *vt) { - return m->engine()->current->throwTypeError(); + Q_ASSERT(internalClass); + internalClass = internalClass->changeVTable(vt); } ReturnedValue Managed::construct(Managed *m, CallData *) { - return m->engine()->current->throwTypeError(); + return m->engine()->currentContext()->throwTypeError(); } ReturnedValue Managed::call(Managed *m, CallData *) { - return m->engine()->current->throwTypeError(); + return m->engine()->currentContext()->throwTypeError(); } ReturnedValue Managed::getLookup(Managed *m, Lookup *) { - return m->engine()->current->throwTypeError(); + return m->engine()->currentContext()->throwTypeError(); } void Managed::setLookup(Managed *m, Lookup *, const ValueRef) { - m->engine()->current->throwTypeError(); + m->engine()->currentContext()->throwTypeError(); } bool Managed::isEqualTo(Managed *, Managed *) @@ -208,47 +207,42 @@ bool Managed::isEqualTo(Managed *, Managed *) return false; } -bool Managed::hasInstance(const ValueRef v) -{ - return vtbl->hasInstance(this, v); -} - ReturnedValue Managed::get(const StringRef name, bool *hasProperty) { - return vtbl->get(this, name, hasProperty); + return internalClass->vtable->get(this, name, hasProperty); } ReturnedValue Managed::getIndexed(uint index, bool *hasProperty) { - return vtbl->getIndexed(this, index, hasProperty); + return internalClass->vtable->getIndexed(this, index, hasProperty); } void Managed::put(const StringRef name, const ValueRef value) { - vtbl->put(this, name, value); + internalClass->vtable->put(this, name, value); } void Managed::setLookup(Lookup *l, const ValueRef v) { - vtbl->setLookup(this, l, v); + internalClass->vtable->setLookup(this, l, v); } void Managed::putIndexed(uint index, const ValueRef value) { - vtbl->putIndexed(this, index, value); + internalClass->vtable->putIndexed(this, index, value); } PropertyAttributes Managed::query(StringRef name) const { - return vtbl->query(this, name); + return internalClass->vtable->query(this, name); } bool Managed::deleteProperty(const StringRef name) { - return vtbl->deleteProperty(this, name); + return internalClass->vtable->deleteProperty(this, name); } Property *Managed::advanceIterator(ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes) { - return vtbl->advanceIterator(this, it, name, index, attributes); + return internalClass->vtable->advanceIterator(this, it, name, index, attributes); } diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 47ac5e05e4..63972688a7 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -46,6 +46,7 @@ #include <QtCore/QDebug> #include "qv4global_p.h" #include "qv4value_def_p.h" +#include "qv4internalclass_p.h" QT_BEGIN_NAMESPACE @@ -84,7 +85,6 @@ struct ManagedVTable void (*markObjects)(Managed *, ExecutionEngine *e); void (*destroy)(Managed *); void (*collectDeletables)(Managed *, GCDeletable **deletable); - bool (*hasInstance)(Managed *, const ValueRef value); ReturnedValue (*get)(Managed *, const StringRef name, bool *hasProperty); ReturnedValue (*getIndexed)(Managed *, uint index, bool *hasProperty); void (*put)(Managed *, const StringRef name, const ValueRef value); @@ -108,7 +108,6 @@ const QV4::ManagedVTable classname::static_vtbl = \ markObjects, \ destroy, \ 0, \ - hasInstance, \ get, \ getIndexed, \ put, \ @@ -132,7 +131,6 @@ const QV4::ManagedVTable classname::static_vtbl = \ markObjects, \ destroy, \ collectDeletables, \ - hasInstance, \ get, \ getIndexed, \ put, \ @@ -158,11 +156,15 @@ private: protected: Managed(InternalClass *internal) - : _data(0), vtbl(&static_vtbl), internalClass(internal) - { inUse = 1; extensible = 1; } + : internalClass(internal), _data(0) + { + Q_ASSERT(!internalClass || internalClass->vtable); + inUse = 1; extensible = 1; + } public: void *operator new(size_t size, MemoryManager *mm); + void *operator new(size_t, Managed *m) { return m; } void operator delete(void *ptr); void operator delete(void *ptr, MemoryManager *mm); @@ -194,12 +196,12 @@ public: template <typename T> T *as() { // ### FIXME: - if (!this) + if (!this || !internalClass) return 0; #if !defined(QT_NO_QOBJECT_CHECK) reinterpret_cast<T *>(this)->qt_check_for_QMANAGED_macro(*reinterpret_cast<T *>(this)); #endif - return vtbl == &T::static_vtbl ? static_cast<T *>(this) : 0; + return internalClass->vtable == &T::static_vtbl ? static_cast<T *>(this) : 0; } template <typename T> const T *as() const { @@ -209,7 +211,7 @@ public: #if !defined(QT_NO_QOBJECT_CHECK) reinterpret_cast<T *>(this)->qt_check_for_QMANAGED_macro(*reinterpret_cast<T *>(const_cast<Managed *>(this))); #endif - return vtbl == &T::static_vtbl ? static_cast<const T *>(this) : 0; + return internalClass->vtable == &T::static_vtbl ? static_cast<const T *>(this) : 0; } String *asString() { return type == Type_String ? reinterpret_cast<String *>(this) : 0; } @@ -240,7 +242,8 @@ public: *reinterpret_cast<Managed **>(this) = m; } - bool hasInstance(const ValueRef v); + void setVTable(const ManagedVTable *vt); + ReturnedValue construct(CallData *d); ReturnedValue call(CallData *d); ReturnedValue get(const StringRef name, bool *hasProperty = 0); @@ -249,21 +252,20 @@ public: void putIndexed(uint index, const ValueRef value); PropertyAttributes query(StringRef name) const; PropertyAttributes queryIndexed(uint index) const - { return vtbl->queryIndexed(this, index); } + { return internalClass->vtable->queryIndexed(this, index); } bool deleteProperty(const StringRef name); bool deleteIndexedProperty(uint index) - { return vtbl->deleteIndexedProperty(this, index); } + { return internalClass->vtable->deleteIndexedProperty(this, index); } ReturnedValue getLookup(Lookup *l) - { return vtbl->getLookup(this, l); } + { return internalClass->vtable->getLookup(this, l); } void setLookup(Lookup *l, const ValueRef v); bool isEqualTo(Managed *other) - { return vtbl->isEqualTo(this, other); } + { return internalClass->vtable->isEqualTo(this, other); } Property *advanceIterator(ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes); static void destroy(Managed *that) { that->_data = 0; } - static bool hasInstance(Managed *that, const ValueRef value); static ReturnedValue construct(Managed *m, CallData *d); static ReturnedValue call(Managed *m, CallData *); static ReturnedValue getLookup(Managed *m, Lookup *); @@ -276,6 +278,9 @@ public: ReturnedValue asReturnedValue() { return Value::fromManaged(this).asReturnedValue(); } + + InternalClass *internalClass; + enum { SimpleArray = 1 }; @@ -297,11 +302,6 @@ public: }; }; -protected: - const ManagedVTable *vtbl; -public: - InternalClass *internalClass; - private: friend class MemoryManager; friend struct Identifiers; @@ -337,10 +337,10 @@ inline FunctionObject *managed_cast(Managed *m) inline ReturnedValue Managed::construct(CallData *d) { - return vtbl->construct(this, d); + return internalClass->vtable->construct(this, d); } inline ReturnedValue Managed::call(CallData *d) { - return vtbl->call(this, d); + return internalClass->vtable->call(this, d); } } diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h index dca75e6c28..6fe3db3950 100644 --- a/src/qml/jsruntime/qv4mathobject_p.h +++ b/src/qml/jsruntime/qv4mathobject_p.h @@ -39,7 +39,7 @@ ** ****************************************************************************/ #ifndef QV4MATHOBJECT_H -#define QV$MATHOBJECT_H +#define QV4MATHOBJECT_H #include "qv4object_p.h" diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp index 9eb3ae7ec9..f67efaffb9 100644 --- a/src/qml/jsruntime/qv4mm.cpp +++ b/src/qml/jsruntime/qv4mm.cpp @@ -155,6 +155,19 @@ struct MemoryManager::Data QVector<Chunk> heapChunks; + + struct LargeItem { + LargeItem *next; + void *data; + + Managed *managed() { + return reinterpret_cast<Managed *>(&data); + } + }; + + LargeItem *largeItems; + + // statistics: #ifdef DETAILED_MM_STATS QVector<unsigned> allocSizeCounters; @@ -167,6 +180,7 @@ struct MemoryManager::Data , stackTop(0) , totalItems(0) , totalAlloc(0) + , largeItems(0) { memset(smallItems, 0, sizeof(smallItems)); memset(nChunks, 0, sizeof(nChunks)); @@ -200,7 +214,6 @@ bool operator<(const MemoryManager::Data::Chunk &a, const MemoryManager::Data::C MemoryManager::MemoryManager() : m_d(new Data(true)) - , m_contextList(0) , m_persistentValues(0) , m_weakValues(0) { @@ -258,8 +271,14 @@ Managed *MemoryManager::alloc(std::size_t size) size_t pos = size >> 4; - // fits into a small bucket - Q_ASSERT(size < MemoryManager::Data::MaxItemSize); + // doesn't fit into a small bucket + if (size >= MemoryManager::Data::MaxItemSize) { + // we use malloc for this + MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>(malloc(size + sizeof(MemoryManager::Data::LargeItem))); + item->next = m_d->largeItems; + m_d->largeItems = item; + return item->managed(); + } Managed *m = m_d->smallItems[pos]; if (m) @@ -279,11 +298,11 @@ Managed *MemoryManager::alloc(std::size_t size) uint shift = ++m_d->nChunks[pos]; if (shift > 10) shift = 10; - std::size_t allocSize = CHUNK_SIZE*(1 << shift); + std::size_t allocSize = CHUNK_SIZE*(size_t(1) << shift); allocSize = roundUpToMultipleOf(WTF::pageSize(), allocSize); Data::Chunk allocation; allocation.memory = PageAllocation::allocate(allocSize, OSAllocator::JSGCHeapPages); - allocation.chunkSize = size; + allocation.chunkSize = int(size); m_d->heapChunks.append(allocation); std::sort(m_d->heapChunks.begin(), m_d->heapChunks.end()); char *chunk = (char *)allocation.memory.base(); @@ -301,8 +320,9 @@ Managed *MemoryManager::alloc(std::size_t size) } *last = 0; m = m_d->smallItems[pos]; - m_d->availableItems[pos] += allocation.memory.size()/size - 1; - m_d->totalItems += allocation.memory.size()/size - 1; + const size_t increase = allocation.memory.size()/size - 1; + m_d->availableItems[pos] += uint(increase); + m_d->totalItems += int(increase); #ifdef V4_USE_VALGRIND VALGRIND_MAKE_MEM_NOACCESS(allocation.memory, allocation.chunkSize); #endif @@ -404,8 +424,8 @@ void MemoryManager::mark() // now that we marked all roots, start marking recursively and popping from the mark stack while (m_d->engine->jsStackTop > markBase) { Managed *m = m_d->engine->popForGC(); - Q_ASSERT (m->vtbl->markObjects); - m->vtbl->markObjects(m, m_d->engine); + Q_ASSERT (m->internalClass->vtable->markObjects); + m->internalClass->vtable->markObjects(m, m_d->engine); } } @@ -447,18 +467,21 @@ void MemoryManager::sweep(bool lastSweep) for (QVector<Data::Chunk>::iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i) sweep(reinterpret_cast<char*>(i->memory.base()), i->memory.size(), i->chunkSize, &deletable); - ExecutionContext *ctx = m_contextList; - ExecutionContext **n = &m_contextList; - while (ctx) { - ExecutionContext *next = ctx->next; - if (!ctx->marked) { - free(ctx); - *n = next; - } else { - ctx->marked = false; - n = &ctx->next; + Data::LargeItem *i = m_d->largeItems; + Data::LargeItem **last = &m_d->largeItems; + while (i) { + Managed *m = i->managed(); + Q_ASSERT(m->inUse); + if (m->markBit) { + m->markBit = 0; + last = &i->next; + i = i->next; + continue; } - ctx = next; + + *last = i->next; + free(i); + i = *last; } deletable = *firstDeletable; @@ -493,9 +516,9 @@ void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size, #ifdef V4_USE_VALGRIND VALGRIND_ENABLE_ERROR_REPORTING; #endif - if (m->vtbl->collectDeletables) - m->vtbl->collectDeletables(m, deletable); - m->vtbl->destroy(m); + if (m->internalClass->vtable->collectDeletables) + m->internalClass->vtable->collectDeletables(m, deletable); + m->internalClass->vtable->destroy(m); m->setNextFree(*f); #ifdef V4_USE_VALGRIND diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/jsruntime/qv4mm_p.h index f3258519de..7d28319536 100644 --- a/src/qml/jsruntime/qv4mm_p.h +++ b/src/qml/jsruntime/qv4mm_p.h @@ -103,8 +103,6 @@ public: return o; } - ExecutionContext *allocContext(uint size); - bool isGCBlocked() const; void setGCBlocked(bool blockGC); void runGC(); @@ -134,21 +132,11 @@ private: protected: QScopedPointer<Data> m_d; - ExecutionContext *m_contextList; public: PersistentValuePrivate *m_persistentValues; PersistentValuePrivate *m_weakValues; }; -inline ExecutionContext *MemoryManager::allocContext(uint size) -{ - ExecutionContext *newContext = (ExecutionContext *)malloc(size); - newContext->next = m_contextList; - m_contextList = newContext; - return newContext; -} - - } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 039b790aed..a363a06242 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -54,7 +54,7 @@ DEFINE_MANAGED_VTABLE(NumberObject); NumberCtor::NumberCtor(ExecutionContext *scope) : FunctionObject(scope, QStringLiteral("Number")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue NumberCtor::construct(Managed *m, CallData *callData) diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index cca7d2b26a..106525d412 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -74,18 +74,17 @@ Object::Object(ExecutionEngine *engine) , memberDataAlloc(InlinePropertySize), memberData(inlineProperties) , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0) { - vtbl = &static_vtbl; type = Type_Object; flags = SimpleArray; memset(memberData, 0, sizeof(Property)*memberDataAlloc); } -Object::Object(InternalClass *internalClass) - : Managed(internalClass) +Object::Object(InternalClass *ic) + : Managed(ic) , memberDataAlloc(InlinePropertySize), memberData(inlineProperties) , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0) { - vtbl = &static_vtbl; + Q_ASSERT(internalClass->vtable && internalClass->vtable != &Managed::static_vtbl); type = Type_Object; flags = SimpleArray; @@ -169,8 +168,8 @@ void Object::putValue(Property *pd, PropertyAttributes attrs, const ValueRef val return; reject: - if (engine()->current->strictMode) - engine()->current->throwTypeError(); + if (engine()->currentContext()->strictMode) + engine()->currentContext()->throwTypeError(); } void Object::defineDefaultProperty(const StringRef name, ValueRef value) @@ -721,7 +720,7 @@ void Object::internalPut(const StringRef name, const ValueRef value) bool ok; uint l = value->asArrayLength(&ok); if (!ok) { - engine()->current->throwRangeError(value); + engine()->currentContext()->throwRangeError(value); return; } ok = setArrayLength(l); @@ -769,11 +768,11 @@ void Object::internalPut(const StringRef name, const ValueRef value) } reject: - if (engine()->current->strictMode) { + if (engine()->currentContext()->strictMode) { QString message = QStringLiteral("Cannot assign to read-only property \""); message += name->toQString(); message += QLatin1Char('\"'); - engine()->current->throwTypeError(message); + engine()->currentContext()->throwTypeError(message); } } @@ -844,8 +843,8 @@ void Object::internalPutIndexed(uint index, const ValueRef value) return; reject: - if (engine()->current->strictMode) - engine()->current->throwTypeError(); + if (engine()->currentContext()->strictMode) + engine()->currentContext()->throwTypeError(); } // Section 8.12.7 @@ -867,8 +866,8 @@ bool Object::internalDeleteProperty(const StringRef name) memmove(memberData + memberIdx, memberData + memberIdx + 1, (internalClass->size - memberIdx)*sizeof(Property)); return true; } - if (engine()->current->strictMode) - engine()->current->throwTypeError(); + if (engine()->currentContext()->strictMode) + engine()->currentContext()->throwTypeError(); return false; } @@ -897,8 +896,8 @@ bool Object::internalDeleteIndexedProperty(uint index) return true; } - if (engine()->current->strictMode) - engine()->current->throwTypeError(); + if (engine()->currentContext()->strictMode) + engine()->currentContext()->throwTypeError(); return false; } @@ -1133,7 +1132,7 @@ ReturnedValue Object::arrayIndexOf(const ValueRef v, uint fromIndex, uint endInd Scope scope(engine()); ScopedValue value(scope); - if (!(flags & SimpleArray) || o->protoHasArray() || o->arrayAttributes) { + if (!(o->flags & SimpleArray) || o->protoHasArray()) { // lets be safe and slow for (uint i = fromIndex; i < endIndex; ++i) { bool exists; @@ -1262,13 +1261,9 @@ void Object::arraySort(ExecutionContext *context, ObjectRef thisObject, const Va ArrayElementLessThan lessThan(context, thisObject, comparefn); + if (!len) + return; Property *begin = arrayData; - // We deliberately choose qSort over std::sort here, because with - // MSVC in debug builds, std::sort has an ASSERT() that verifies - // that the return values of lessThan are perfectly consistent - // and aborts otherwise. We do not want JavaScript to easily crash - // the entire application and therefore choose qSort, which doesn't - // have this property. std::sort(begin, begin + len, lessThan); } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index daef18d4e2..23f2f682fd 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -280,13 +280,13 @@ public: void ensureMemberIndex(uint idx); inline ReturnedValue get(const StringRef name, bool *hasProperty = 0) - { return vtbl->get(this, name, hasProperty); } + { return internalClass->vtable->get(this, name, hasProperty); } inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) - { return vtbl->getIndexed(this, idx, hasProperty); } + { return internalClass->vtable->getIndexed(this, idx, hasProperty); } inline void put(const StringRef name, const ValueRef v) - { vtbl->put(this, name, v); } + { internalClass->vtable->put(this, name, v); } inline void putIndexed(uint idx, const ValueRef v) - { vtbl->putIndexed(this, idx, v); } + { internalClass->vtable->putIndexed(this, idx, v); } using Managed::get; using Managed::getIndexed; using Managed::put; @@ -331,14 +331,13 @@ struct BooleanObject: Object { SafeValue value; BooleanObject(ExecutionEngine *engine, const ValueRef val) : Object(engine->booleanClass) { - vtbl = &static_vtbl; type = Type_BooleanObject; value = val; } protected: BooleanObject(InternalClass *ic) : Object(ic) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); type = Type_BooleanObject; value = Encode(false); } @@ -349,14 +348,13 @@ struct NumberObject: Object { SafeValue value; NumberObject(ExecutionEngine *engine, const ValueRef val) : Object(engine->numberClass) { - vtbl = &static_vtbl; type = Type_NumberObject; value = val; } protected: NumberObject(InternalClass *ic) : Object(ic) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); type = Type_NumberObject; value = Encode((int)0); } diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index 62595b5176..04fa504991 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -42,6 +42,7 @@ #include "qv4object_p.h" #include "qv4stringobject_p.h" #include "qv4identifier_p.h" +#include "qv4argumentsobject_p.h" using namespace QV4; @@ -56,6 +57,11 @@ ObjectIterator::ObjectIterator(SafeObject *scratch1, SafeObject *scratch2, const object = o; current = o; tmpDynamicProperty.value = Primitive::undefinedValue(); + + if (object && object->isNonStrictArgumentsObject) { + Scope scope(object->engine()); + Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate(); + } } ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags) @@ -69,6 +75,11 @@ ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags) object = o; current = o; tmpDynamicProperty.value = Primitive::undefinedValue(); + + if (object && object->isNonStrictArgumentsObject) { + Scope scope(object->engine()); + Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate(); + } } Property *ObjectIterator::next(StringRef name, uint *index, PropertyAttributes *attrs) diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index 19aedf3766..6c333b328c 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -89,7 +89,7 @@ struct ForEachIteratorObject: Object { ObjectIterator it; ForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o) : Object(ctx->engine), it(workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); type = Type_ForeachIteratorObject; } diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 4369267278..7ca790b970 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -41,6 +41,7 @@ #include "qv4objectproto_p.h" +#include "qv4argumentsobject_p.h" #include "qv4mm_p.h" #include "qv4scopedvalue_p.h" #include <QtCore/qnumeric.h> @@ -76,7 +77,7 @@ DEFINE_MANAGED_VTABLE(ObjectCtor); ObjectCtor::ObjectCtor(ExecutionContext *scope) : FunctionObject(scope, QStringLiteral("Object")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue ObjectCtor::construct(Managed *that, CallData *callData) @@ -91,14 +92,14 @@ ReturnedValue ObjectCtor::construct(Managed *that, CallData *callData) obj->setPrototype(proto.getPointer()); return obj.asReturnedValue(); } - return __qmljs_to_object(v4->current, ValueRef(&callData->args[0])); + return __qmljs_to_object(v4->currentContext(), ValueRef(&callData->args[0])); } ReturnedValue ObjectCtor::call(Managed *m, CallData *callData) { if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) return m->engine()->newObject()->asReturnedValue(); - return __qmljs_to_object(m->engine()->current, ValueRef(&callData->args[0])); + return __qmljs_to_object(m->engine()->currentContext(), ValueRef(&callData->args[0])); } void ObjectPrototype::init(ExecutionEngine *v4, ObjectRef ctor) @@ -156,6 +157,9 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx) if (!O) return ctx->throwTypeError(); + if (O->isNonStrictArgumentsObject) + Scoped<ArgumentsObject>(scope, O)->fullyCreate(); + ScopedValue v(scope, ctx->argument(1)); Scoped<String> name(scope, v->toString(ctx)); if (scope.hasException()) @@ -283,6 +287,9 @@ ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx) if (!o) return ctx->throwTypeError(); + if (o->isNonStrictArgumentsObject) + Scoped<ArgumentsObject>(scope, o)->fullyCreate(); + o->extensible = false; o->internalClass = o->internalClass->frozen(); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index f1b0e0bdc4..61f92a0f5c 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -241,7 +241,7 @@ QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object) : Object(engine) , m_object(object) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); Scope scope(engine); ScopedObject protectThis(scope, this); @@ -331,23 +331,23 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD if (hasProperty) *hasProperty = true; - return getProperty(ctx, result); + return getProperty(m_object, ctx, result); } -ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired) +ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired) { QV4::Scope scope(ctx); if (property->isFunction() && !property->isVarProperty()) { if (property->isVMEFunction()) { - QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object); + QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); return vmemo->vmeMethod(property->coreIndex); } else if (property->isV4Function()) { QV4::Scoped<QV4::Object> qmlcontextobject(scope, ctx->engine->qmlContextObject()); - return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, property->coreIndex, qmlcontextobject); + return QV4::QObjectMethod::create(ctx->engine->rootContext, object, property->coreIndex, qmlcontextobject); } else if (property->isSignalHandler()) { - QV4::Scoped<QV4::QmlSignalHandler> handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, m_object, property->coreIndex)); + QV4::Scoped<QV4::QmlSignalHandler> handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, object, property->coreIndex)); QV4::ScopedString connect(scope, ctx->engine->newIdentifier(QStringLiteral("connect"))); QV4::ScopedString disconnect(scope, ctx->engine->newIdentifier(QStringLiteral("disconnect"))); @@ -356,7 +356,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyDat return handler.asReturnedValue(); } else { - return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, property->coreIndex); + return QV4::QObjectMethod::create(ctx->engine->rootContext, object, property->coreIndex); } } @@ -369,14 +369,14 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyDat if (ep && ep->propertyCapture && property->accessors->notifier) nptr = &n; - QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->engine->v8Engine, m_object, *property, nptr)); + QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->engine->v8Engine, object, *property, nptr)); if (captureRequired) { if (property->accessors->notifier) { if (n) ep->captureProperty(n); } else { - ep->captureProperty(m_object, property->coreIndex, property->notifyIndex); + ep->captureProperty(object, property->coreIndex, property->notifyIndex); } } @@ -384,16 +384,16 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyDat } if (captureRequired && ep && !property->isConstant()) - ep->captureProperty(m_object, property->coreIndex, property->notifyIndex); + ep->captureProperty(object, property->coreIndex, property->notifyIndex); if (property->isVarProperty()) { - QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object); + QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); return vmemo->vmeProperty(property->coreIndex); } else if (property->isDirect()) { - return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, m_object, *property, 0); + return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, object, *property, 0); } else { - return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, m_object, *property, 0); + return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, object, *property, 0); } } @@ -583,7 +583,7 @@ ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object) ddata->jsEngineId == 0 || // No one owns the QObject !ddata->hasTaintedV8Object)) { // Someone else has used the QObject, but it isn't tainted - QV4::ScopedValue rv(scope, create(engine, ddata, object)); + QV4::ScopedValue rv(scope, create(engine, object)); ddata->jsWrapper = rv; ddata->jsEngineId = engine->m_engineId; return rv.asReturnedValue(); @@ -598,14 +598,14 @@ ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object) // If our tainted handle doesn't exist or has been collected, and there isn't // a handle in the ddata, we can assume ownership of the ddata->v8object if (ddata->jsWrapper.isUndefined() && !alternateWrapper) { - QV4::ScopedValue result(scope, create(engine, ddata, object)); + QV4::ScopedValue result(scope, create(engine, object)); ddata->jsWrapper = result; ddata->jsEngineId = engine->m_engineId; return result.asReturnedValue(); } if (!alternateWrapper) { - alternateWrapper = create(engine, ddata, object); + alternateWrapper = create(engine, object); if (!engine->m_multiplyWrappedQObjects) engine->m_multiplyWrappedQObjects = new MultiplyWrappedQObjectMap; engine->m_multiplyWrappedQObjects->insert(object, alternateWrapper.getPointer()); @@ -616,11 +616,11 @@ ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object) } } -ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, int propertyIndex, bool captureRequired) +ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, int propertyIndex, bool captureRequired) { - if (QQmlData::wasDeleted(m_object)) + if (QQmlData::wasDeleted(object)) return QV4::Encode::null(); - QQmlData *ddata = QQmlData::get(m_object, /*create*/false); + QQmlData *ddata = QQmlData::get(object, /*create*/false); if (!ddata) return QV4::Encode::undefined(); @@ -628,7 +628,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, int propertyInd Q_ASSERT(cache); QQmlPropertyData *property = cache->property(propertyIndex); Q_ASSERT(property); // We resolved this property earlier, so it better exist! - return getProperty(ctx, property, captureRequired); + return getProperty(object, ctx, property, captureRequired); } void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const ValueRef value) @@ -655,14 +655,11 @@ bool QObjectWrapper::isEqualTo(Managed *a, Managed *b) return false; } -ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QQmlData *ddata, QObject *object) +ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object) { QQmlEngine *qmlEngine = engine->v8Engine->engine(); - if (!ddata->propertyCache && qmlEngine) { - ddata->propertyCache = QQmlEnginePrivate::get(qmlEngine)->cache(object); - if (ddata->propertyCache) ddata->propertyCache->addref(); - } - + if (qmlEngine) + QQmlData::ensurePropertyCache(qmlEngine, object); return (new (engine->memoryManager) QV4::QObjectWrapper(engine, object))->asReturnedValue(); } @@ -671,7 +668,7 @@ QV4::ReturnedValue QObjectWrapper::get(Managed *m, const StringRef name, bool *h QObjectWrapper *that = static_cast<QObjectWrapper*>(m); ExecutionEngine *v4 = m->engine(); QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4); - return that->getQmlProperty(v4->current, qmlContext, name.getPointer(), IgnoreRevision, hasProperty, /*includeImports*/ true); + return that->getQmlProperty(v4->currentContext(), qmlContext, name.getPointer(), IgnoreRevision, hasProperty, /*includeImports*/ true); } void QObjectWrapper::put(Managed *m, const StringRef name, const ValueRef value) @@ -683,10 +680,10 @@ void QObjectWrapper::put(Managed *m, const StringRef name, const ValueRef value) return; QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4); - if (!setQmlProperty(v4->current, qmlContext, that->m_object, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value)) { + if (!setQmlProperty(v4->currentContext(), qmlContext, that->m_object, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value)) { QString error = QLatin1String("Cannot assign to non-existent property \"") + name->toQString() + QLatin1Char('\"'); - v4->current->throwError(error); + v4->currentContext()->throwError(error); } } @@ -766,7 +763,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase Q_ASSERT(v4); QV4::Scope scope(v4); QV4::ScopedFunctionObject f(scope, This->function.value()); - QV4::ExecutionContext *ctx = v4->current; + QV4::ExecutionContext *ctx = v4->currentContext(); QV4::ScopedCallData callData(scope, argCount); callData->thisObject = This->thisObject.isUndefined() ? v4->globalObject->asReturnedValue() : This->thisObject.value(); @@ -851,7 +848,7 @@ ReturnedValue QObjectWrapper::method_connect(CallContext *ctx) QPair<QObject *, int> signalInfo = extractQtSignal(ctx->callData->thisObject); QObject *signalObject = signalInfo.first; - int signalIndex = signalInfo.second; + int signalIndex = signalInfo.second; // in method range, not signal range! if (signalIndex < 0) V4THROW_ERROR("Function.prototype.connect: this object is not a signal"); @@ -885,6 +882,11 @@ ReturnedValue QObjectWrapper::method_connect(CallContext *ctx) slot->thisObject = thisObject; slot->function = f; + if (QQmlData *ddata = QQmlData::get(signalObject)) { + if (QQmlPropertyCache *propertyCache = ddata->propertyCache) { + QQmlPropertyPrivate::flushSignal(signalObject, propertyCache->methodIndexToSignalIndex(signalIndex)); + } + } QObjectPrivate::connect(signalObject, signalIndex, slot, Qt::AutoConnection); return Encode::undefined(); @@ -1335,7 +1337,7 @@ static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &d if (returnType == QMetaType::UnknownType) { QString typeName = QString::fromLatin1(unknownTypeError); QString error = QString::fromLatin1("Unknown method return type: %1").arg(typeName); - return QV8Engine::getV4(engine)->current->throwError(error); + return QV8Engine::getV4(engine)->currentContext()->throwError(error); } if (data.hasArguments()) { @@ -1349,12 +1351,12 @@ static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &d if (!args) { QString typeName = QString::fromLatin1(unknownTypeError); QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName); - return QV8Engine::getV4(engine)->current->throwError(error); + return QV8Engine::getV4(engine)->currentContext()->throwError(error); } if (args[0] > callArgs->argc) { QString error = QLatin1String("Insufficient arguments"); - return QV8Engine::getV4(engine)->current->throwError(error); + return QV8Engine::getV4(engine)->currentContext()->throwError(error); } return CallMethod(object, data.coreIndex, returnType, args[0], args + 1, engine, callArgs); @@ -1453,7 +1455,7 @@ static QV4::ReturnedValue CallOverloaded(QObject *object, const QQmlPropertyData candidate = RelatedMethod(object, candidate, dummy); } - return QV8Engine::getV4(engine)->current->throwError(error); + return QV8Engine::getV4(engine)->currentContext()->throwError(error); } } @@ -1724,7 +1726,7 @@ QObjectMethod::QObjectMethod(ExecutionContext *scope, QObject *object, int index , m_object(object) , m_index(index) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); subtype = WrappedQtMethod; m_qmlGlobal = qmlGlobal; } @@ -1780,7 +1782,7 @@ ReturnedValue QObjectMethod::call(Managed *m, CallData *callData) ReturnedValue QObjectMethod::callInternal(CallData *callData) { - ExecutionContext *context = engine()->current; + ExecutionContext *context = engine()->currentContext(); if (m_index == DestroyMethod) return method_destroy(context, callData->args, callData->argc); else if (m_index == ToStringMethod) @@ -1845,7 +1847,7 @@ QmlSignalHandler::QmlSignalHandler(ExecutionEngine *engine, QObject *object, int , m_object(object) , m_signalIndex(signalIndex) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } DEFINE_MANAGED_VTABLE(QmlSignalHandler); diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index a73c96d098..07de1933c5 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -94,17 +94,17 @@ struct Q_QML_EXPORT QObjectWrapper : public QV4::Object using Object::get; - ReturnedValue getProperty(ExecutionContext *ctx, int propertyIndex, bool captureRequired); + static ReturnedValue getProperty(QObject *object, ExecutionContext *ctx, int propertyIndex, bool captureRequired); void setProperty(ExecutionContext *ctx, int propertyIndex, const ValueRef value); protected: static bool isEqualTo(Managed *that, Managed *o); private: - ReturnedValue getProperty(ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired = true); + static ReturnedValue getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired = true); static void setProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, const ValueRef value); - static ReturnedValue create(ExecutionEngine *engine, QQmlData *ddata, QObject *object); + static ReturnedValue create(ExecutionEngine *engine, QObject *object); QObjectWrapper(ExecutionEngine *engine, QObject *object); diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index 5ec63061dc..41ff9f9741 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -92,14 +92,13 @@ RegExp* RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ign } RegExp::RegExp(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline) - : Managed(engine->emptyClass) + : Managed(engine->regExpValueClass) , m_pattern(pattern) , m_cache(0) , m_subPatternCount(0) , m_ignoreCase(ignoreCase) , m_multiLine(multiline) { - vtbl = &static_vtbl; type = Type_RegExpObject; if (!engine) diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index a8597229c4..468fb34d76 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -142,7 +142,7 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, const QRegExp &re) void RegExpObject::init(ExecutionEngine *engine) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); type = Type_RegExpObject; Scope scope(engine); @@ -237,12 +237,12 @@ DEFINE_MANAGED_VTABLE(RegExpCtor); RegExpCtor::RegExpCtor(ExecutionContext *scope) : FunctionObject(scope, QStringLiteral("RegExp")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) { - ExecutionContext *ctx = m->engine()->current; + ExecutionContext *ctx = m->engine()->currentContext(); Scope scope(ctx); ScopedValue r(scope, callData->argument(0)); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index a8cabcb374..011607f0ba 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -53,6 +53,7 @@ #include "qv4scopedvalue_p.h" #include <private/qqmlcontextwrapper_p.h> #include "qv4qobjectwrapper_p.h" +#include <private/qv8engine_p.h> #include <QtCore/qmath.h> #include <QtCore/qnumeric.h> @@ -299,12 +300,34 @@ ReturnedValue __qmljs_delete_name(ExecutionContext *ctx, const StringRef name) QV4::ReturnedValue __qmljs_instanceof(ExecutionContext *ctx, const ValueRef left, const ValueRef right) { - Object *o = right->asObject(); - if (!o) + FunctionObject *f = right->asFunctionObject(); + if (!f) return ctx->throwTypeError(); - bool r = o->hasInstance(left); - return Encode(r); + if (f->subtype == FunctionObject::BoundFunction) + f = static_cast<BoundFunction *>(f)->target; + + Scope scope(ctx->engine); + ScopedObject v(scope, left); + if (!v) + return Encode(false); + + Scoped<Object> o(scope, f->protoProperty()); + if (!o) { + scope.engine->currentContext()->throwTypeError(); + return Encode(false); + } + + while (v) { + v = v->prototype(); + + if (! v) + break; + else if (o.getPointer() == v) + return Encode(true); + } + + return Encode(false); } QV4::ReturnedValue __qmljs_in(ExecutionContext *ctx, const ValueRef left, const ValueRef right) @@ -366,7 +389,7 @@ ReturnedValue __qmljs_object_default_value(Object *object, int typeHint) if (typeHint == NUMBER_HINT) qSwap(meth1, meth2); - ExecutionContext *ctx = engine->current; + ExecutionContext *ctx = engine->currentContext(); Scope scope(ctx); ScopedCallData callData(scope, 0); callData->thisObject = object; @@ -966,10 +989,10 @@ ReturnedValue __qmljs_construct_value(ExecutionContext *context, const ValueRef return f->construct(callData); } -ReturnedValue __qmljs_construct_property(ExecutionContext *context, const ValueRef base, const StringRef name, CallDataRef callData) +ReturnedValue __qmljs_construct_property(ExecutionContext *context, const StringRef name, CallDataRef callData) { Scope scope(context); - ScopedObject thisObject(scope, base->toObject(context)); + ScopedObject thisObject(scope, callData->thisObject.toObject(context)); if (scope.engine->hasException) return Encode::undefined(); @@ -980,6 +1003,18 @@ ReturnedValue __qmljs_construct_property(ExecutionContext *context, const ValueR return f->construct(callData); } +ReturnedValue __qmljs_construct_property_lookup(ExecutionContext *context, uint index, CallDataRef callData) +{ + Lookup *l = context->lookups + index; + SafeValue v; + v = l->getter(l, callData->thisObject); + if (!v.isManaged()) + return context->throwTypeError(); + + return v.managed()->construct(callData); +} + + void __qmljs_throw(ExecutionContext *context, const ValueRef value) { if (!value->isEmpty()) @@ -1230,10 +1265,9 @@ ReturnedValue __qmljs_lookup_runtime_regexp(ExecutionContext *ctx, int id) return ctx->compilationUnit->runtimeRegularExpressions[id].asReturnedValue(); } -ReturnedValue __qmljs_get_id_object(NoThrowContext *ctx, int id) +ReturnedValue __qmljs_get_id_array(NoThrowContext *ctx) { - QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine); - return QObjectWrapper::wrap(ctx->engine, context->idValues[id].data()); + return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->idObjectsArray(); } ReturnedValue __qmljs_get_context_object(NoThrowContext *ctx) @@ -1257,7 +1291,19 @@ ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef ctx->throwTypeError(QStringLiteral("Cannot read property of null")); return Encode::undefined(); } - return wrapper->getProperty(ctx, propertyIndex, captureRequired); + return QV4::QObjectWrapper::getProperty(wrapper->object(), ctx, propertyIndex, captureRequired); +} + +QV4::ReturnedValue __qmljs_get_attached_property(ExecutionContext *ctx, int attachedPropertiesId, int propertyIndex) +{ + Scope scope(ctx); + QV4::Scoped<QmlContextWrapper> c(scope, ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()); + QObject *scopeObject = c->getScopeObject(); + QObject *attachedObject = qmlAttachedPropertiesObjectById(attachedPropertiesId, scopeObject); + + QQmlEngine *qmlEngine = ctx->engine->v8Engine->engine(); + QQmlData::ensurePropertyCache(qmlEngine, attachedObject); + return QV4::QObjectWrapper::getProperty(attachedObject, ctx, propertyIndex, /*captureRequired*/true); } void __qmljs_set_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value) @@ -1277,6 +1323,11 @@ ReturnedValue __qmljs_get_imported_scripts(NoThrowContext *ctx) return context->importedScripts.value(); } +QV4::ReturnedValue __qmljs_get_qml_singleton(QV4::NoThrowContext *ctx, const QV4::StringRef name) +{ + return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->qmlSingletonWrapper(name); +} + void __qmljs_builtin_convert_this_to_object(ExecutionContext *ctx) { SafeValue *t = &ctx->callData->thisObject; diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index b5567693e5..9524b2459c 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -125,7 +125,8 @@ QV4::ReturnedValue __qmljs_call_element(ExecutionContext *context, const ValueRe QV4::ReturnedValue __qmljs_call_value(QV4::ExecutionContext *context, const QV4::ValueRef func, CallDataRef callData); QV4::ReturnedValue __qmljs_construct_activation_property(QV4::ExecutionContext *, const QV4::StringRef name, CallDataRef callData); -QV4::ReturnedValue __qmljs_construct_property(QV4::ExecutionContext *context, const QV4::ValueRef base, const QV4::StringRef name, CallDataRef callData); +QV4::ReturnedValue __qmljs_construct_property(QV4::ExecutionContext *context, const QV4::StringRef name, CallDataRef callData); +QV4::ReturnedValue __qmljs_construct_property_lookup(ExecutionContext *context, uint index, CallDataRef callData); QV4::ReturnedValue __qmljs_construct_value(QV4::ExecutionContext *context, const QV4::ValueRef func, CallDataRef callData); QV4::ReturnedValue __qmljs_builtin_typeof(QV4::ExecutionContext *ctx, const QV4::ValueRef val); @@ -170,12 +171,14 @@ QV4::ReturnedValue __qmljs_construct_global_lookup(QV4::ExecutionContext *contex QV4::ReturnedValue __qmljs_get_element(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::ValueRef index); void __qmljs_set_element(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::ValueRef index, const QV4::ValueRef value); -QV4::ReturnedValue __qmljs_get_id_object(NoThrowContext *ctx, int id); +QV4::ReturnedValue __qmljs_get_id_array(NoThrowContext *ctx); QV4::ReturnedValue __qmljs_get_imported_scripts(NoThrowContext *ctx); QV4::ReturnedValue __qmljs_get_context_object(NoThrowContext *ctx); QV4::ReturnedValue __qmljs_get_scope_object(NoThrowContext *ctx); QV4::ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, bool captureRequired); +QV4::ReturnedValue __qmljs_get_attached_property(ExecutionContext *ctx, int attachedPropertiesId, int propertyIndex); void __qmljs_set_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value); +QV4::ReturnedValue __qmljs_get_qml_singleton(NoThrowContext *ctx, const QV4::StringRef name); // For each QV4::ReturnedValue __qmljs_foreach_iterator_object(QV4::ExecutionContext *ctx, const QV4::ValueRef in); diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 17a19b5201..21f45745cb 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -41,7 +41,7 @@ #ifndef QV4SCOPEDVALUE_P_H #define QV4SCOPEDVALUE_P_H -#include "qv4engine_p.h" +#include "qv4context_p.h" #include "qv4value_def_p.h" QT_BEGIN_NAMESPACE @@ -231,7 +231,7 @@ struct Scoped Scoped(const Scope &scope, const Value &v, _Convert) { ptr = scope.engine->jsStackTop++; - ptr->val = value_convert<T>(scope.engine->current, v); + ptr->val = value_convert<T>(scope.engine->currentContext(), v); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -278,7 +278,7 @@ struct Scoped Scoped(const Scope &scope, const ReturnedValue &v, _Convert) { ptr = scope.engine->jsStackTop++; - ptr->val = value_convert<T>(scope.engine->current, QV4::Value::fromReturnedValue(v)); + ptr->val = value_convert<T>(scope.engine->currentContext(), QV4::Value::fromReturnedValue(v)); #ifndef QT_NO_DEBUG ++scope.size; #endif diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 25791cff61..4fd0569627 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -51,6 +51,7 @@ #include <private/qqmljslexer_p.h> #include <private/qqmljsparser_p.h> #include <private/qqmljsast_p.h> +#include <private/qqmlengine_p.h> #include <qv4jsir_p.h> #include <qv4codegen_p.h> @@ -62,27 +63,41 @@ using namespace QV4; QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, ObjectRef qml) : FunctionObject(scope, scope->engine->id_eval) , qml(qml) + , qmlContext(0) { - vtbl = &static_vtbl; + Q_ASSERT(scope->inUse); + + setVTable(&static_vtbl); function = f; function->compilationUnit->ref(); needsActivation = function->needsActivation(); + + Scope s(scope); + ScopedValue protectThis(s, this); + defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1)); - qmlContext = scope->engine->current->newQmlContext(this, qml); + qmlContext = scope->engine->currentContext()->newQmlContext(this, qml); scope->engine->popContext(); } QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml) : FunctionObject(scope, scope->engine->id_eval) , qml(qml) + , qmlContext(0) { - vtbl = &static_vtbl; + Q_ASSERT(scope->inUse); + + setVTable(&static_vtbl); function = 0; needsActivation = false; + + Scope s(scope); + ScopedValue protectThis(s, this); + defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1)); - qmlContext = scope->engine->current->newQmlContext(this, qml); + qmlContext = scope->engine->currentContext()->newQmlContext(this, qml); scope->engine->popContext(); } @@ -110,7 +125,8 @@ void QmlBindingWrapper::markObjects(Managed *m, ExecutionEngine *e) if (wrapper->qml) wrapper->qml->mark(e); FunctionObject::markObjects(m, e); - wrapper->qmlContext->mark(); + if (wrapper->qmlContext) + wrapper->qmlContext->mark(e); } DEFINE_MANAGED_VTABLE(QmlBindingWrapper); @@ -124,7 +140,7 @@ struct CompilationUnitHolder : public QV4::Object , unit(unit) { unit->ref(); - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ~CompilationUnitHolder() { @@ -214,7 +230,7 @@ void Script::parse() return; QV4::Compiler::JSUnitGenerator jsGenerator(&module); - QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module, &jsGenerator)); + QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator)); if (inheritContext) isel->setUseFastLookups(false); QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile(); @@ -226,7 +242,7 @@ void Script::parse() if (!vmFunction) { // ### FIX file/line number Scoped<Object> error(valueScope, v4->newSyntaxErrorObject(QStringLiteral("Syntax error"))); - v4->current->throwError(error); + v4->currentContext()->throwError(error); } } @@ -340,7 +356,7 @@ CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const } Compiler::JSUnitGenerator jsGenerator(&module); - QScopedPointer<QQmlJS::EvalInstructionSelection> isel(engine->iselFactory->create(engine->executableAllocator, &module, &jsGenerator)); + QScopedPointer<QQmlJS::EvalInstructionSelection> isel(engine->iselFactory->create(QQmlEnginePrivate::get(engine), engine->executableAllocator, &module, &jsGenerator)); isel->setUseFastLookups(false); return isel->compile(); } @@ -361,7 +377,7 @@ QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &scr QV4::Scope scope(engine); QV4::Script qmlScript(engine, scopeObject, script, QString()); - QV4::ExecutionContext *ctx = engine->current; + QV4::ExecutionContext *ctx = engine->currentContext(); qmlScript.parse(); QV4::ScopedValue result(scope); if (!scope.engine->hasException) diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 26e4dcb8a2..8b0e31cb71 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -47,6 +47,7 @@ #include <private/qv4arrayobject_p.h> #include <private/qqmlengine_p.h> #include <private/qv4scopedvalue_p.h> +#include <private/qv4internalclass_p.h> #include <algorithm> @@ -167,14 +168,13 @@ class QQmlSequence : public QV4::Object Q_MANAGED public: QQmlSequence(QV4::ExecutionEngine *engine, const Container &container) - : QV4::Object(engine->sequenceClass) + : QV4::Object(InternalClass::create(engine, &static_vtbl, engine->sequencePrototype.asObject())) , m_container(container) , m_object(0) , m_propertyIndex(-1) , m_isReference(false) { type = Type_QmlSequence; - vtbl = &static_vtbl; flags &= ~SimpleArray; QV4::Scope scope(engine); QV4::ScopedObject protectThis(scope, this); @@ -183,13 +183,12 @@ public: } QQmlSequence(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex) - : QV4::Object(engine->sequenceClass) + : QV4::Object(InternalClass::create(engine, &static_vtbl, engine->sequencePrototype.asObject())) , m_object(object) , m_propertyIndex(propertyIndex) , m_isReference(true) { type = Type_QmlSequence; - vtbl = &static_vtbl; flags &= ~SimpleArray; QV4::Scope scope(engine); QV4::ScopedObject protectThis(scope, this); @@ -207,7 +206,7 @@ public: { /* Qt containers have int (rather than uint) allowable indexes. */ if (index > INT_MAX) { - generateWarning(engine()->current, QLatin1String("Index out of range during indexed get")); + generateWarning(engine()->currentContext(), QLatin1String("Index out of range during indexed get")); if (hasProperty) *hasProperty = false; return Encode::undefined(); @@ -238,7 +237,7 @@ public: /* Qt containers have int (rather than uint) allowable indexes. */ if (index > INT_MAX) { - generateWarning(engine()->current, QLatin1String("Index out of range during indexed set")); + generateWarning(engine()->currentContext(), QLatin1String("Index out of range during indexed set")); return; } @@ -276,7 +275,7 @@ public: { /* Qt containers have int (rather than uint) allowable indexes. */ if (index > INT_MAX) { - generateWarning(engine()->current, QLatin1String("Index out of range during indexed query")); + generateWarning(engine()->currentContext(), QLatin1String("Index out of range during indexed query")); return QV4::Attr_Invalid; } if (m_isReference) { diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp index 06a2603280..ee325db4c2 100644 --- a/src/qml/jsruntime/qv4serialize.cpp +++ b/src/qml/jsruntime/qv4serialize.cpp @@ -279,7 +279,7 @@ void Serialize::serialize(QByteArray &data, const QV4::ValueRef v, QV8Engine *en s = properties->getIndexed(ii); serialize(data, s, engine); - QV4::ExecutionContext *ctx = v4->current; + QV4::ExecutionContext *ctx = v4->currentContext(); str = s; val = o->get(str); if (scope.hasException()) diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 0e43d03987..e5633eb06f 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -108,7 +108,6 @@ const ManagedVTable String::static_vtbl = markObjects, destroy, 0 /*collectDeletables*/, - hasInstance, get, getIndexed, put, @@ -150,7 +149,7 @@ ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty) return Primitive::fromInt32(that->_text->size).asReturnedValue(); } PropertyAttributes attrs; - Property *pd = v4->stringClass->prototype->__getPropertyDescriptor__(name, &attrs); + Property *pd = v4->stringObjectClass->prototype->__getPropertyDescriptor__(name, &attrs); if (!pd || attrs.isGeneric()) { if (hasProperty) *hasProperty = false; @@ -158,7 +157,7 @@ ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty) } if (hasProperty) *hasProperty = true; - return v4->stringClass->prototype->getValue(that, pd, attrs); + return v4->stringObjectClass->prototype->getValue(that, pd, attrs); } ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty) @@ -173,7 +172,7 @@ ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty) return Encode(engine->newString(that->toQString().mid(index, 1))); } PropertyAttributes attrs; - Property *pd = engine->stringClass->prototype->__getPropertyDescriptor__(index, &attrs); + Property *pd = engine->stringObjectClass->prototype->__getPropertyDescriptor__(index, &attrs); if (!pd || attrs.isGeneric()) { if (hasProperty) *hasProperty = false; @@ -181,7 +180,7 @@ ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty) } if (hasProperty) *hasProperty = true; - return engine->stringClass->prototype->getValue(that, pd, attrs); + return engine->stringObjectClass->prototype->getValue(that, pd, attrs); } void String::put(Managed *m, const StringRef name, const ValueRef value) @@ -252,24 +251,22 @@ bool String::isEqualTo(Managed *t, Managed *o) String::String(ExecutionEngine *engine, const QString &text) - : Managed(engine ? engine->emptyClass : 0), _text(const_cast<QString &>(text).data_ptr()) + : Managed(engine->stringClass), _text(const_cast<QString &>(text).data_ptr()) , identifier(0), stringHash(UINT_MAX) , largestSubLength(0) { _text->ref.ref(); len = _text->size; - vtbl = &static_vtbl; type = Type_String; subtype = StringType_Unknown; } String::String(ExecutionEngine *engine, String *l, String *r) - : Managed(engine ? engine->emptyClass : 0) + : Managed(engine->stringClass) , left(l), right(r) , stringHash(UINT_MAX), largestSubLength(qMax(l->largestSubLength, r->largestSubLength)) , len(l->len + r->len) { - vtbl = &static_vtbl; type = Type_String; subtype = StringType_Unknown; @@ -360,7 +357,7 @@ void String::createHashValue() const // array indices get their number as hash value bool ok; - stringHash = toArrayIndex(ch, end, &ok); + stringHash = ::toArrayIndex(ch, end, &ok); if (ok) { subtype = (stringHash == UINT_MAX) ? StringType_UInt : StringType_ArrayIndex; return; @@ -382,7 +379,7 @@ uint String::createHashValue(const QChar *ch, int length) // array indices get their number as hash value bool ok; - uint stringHash = toArrayIndex(ch, end, &ok); + uint stringHash = ::toArrayIndex(ch, end, &ok); if (ok) return stringHash; @@ -401,7 +398,7 @@ uint String::createHashValue(const char *ch, int length) // array indices get their number as hash value bool ok; - uint stringHash = toArrayIndex(ch, end, &ok); + uint stringHash = ::toArrayIndex(ch, end, &ok); if (ok) return stringHash; @@ -415,3 +412,9 @@ uint String::createHashValue(const char *ch, int length) return h; } + +uint String::toArrayIndex(const QString &str) +{ + bool ok; + return ::toArrayIndex(str.constData(), str.constData() + str.length(), &ok); +} diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index bb6f1d2279..64e15b04c2 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -63,7 +63,7 @@ struct Q_QML_EXPORT String : public Managed { String() : Managed(0), _text(QStringData::sharedNull()), identifier(0) , stringHash(UINT_MAX), largestSubLength(0), len(0) - { vtbl = &static_vtbl; type = Type_String; subtype = StringType_Unknown; } + { type = Type_String; subtype = StringType_Unknown; } String(ExecutionEngine *engine, const QString &text); String(ExecutionEngine *engine, String *l, String *n); ~String() { @@ -140,6 +140,8 @@ struct Q_QML_EXPORT String : public Managed { return len; } + static uint toArrayIndex(const QString &str); + union { mutable QStringData *_text; mutable String *left; diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index bff8f1f9cd..d468fb6b83 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -80,7 +80,7 @@ DEFINE_MANAGED_VTABLE(StringObject); StringObject::StringObject(InternalClass *ic) : Object(ic) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); type = Type_StringObject; Scope scope(engine()); @@ -94,9 +94,9 @@ StringObject::StringObject(InternalClass *ic) } StringObject::StringObject(ExecutionEngine *engine, const ValueRef val) - : Object(engine->stringClass) + : Object(engine->stringObjectClass) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); type = Type_StringObject; Scope scope(engine); @@ -125,13 +125,13 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index) Scope scope(v4); Scoped<StringObject> o(scope, m->asStringObject()); if (!o) { - v4->current->throwTypeError(); + v4->currentContext()->throwTypeError(); return false; } if (index < static_cast<uint>(o->value.stringValue()->toQString().length())) { - if (v4->current->strictMode) - v4->current->throwTypeError(); + if (v4->currentContext()->strictMode) + v4->currentContext()->throwTypeError(); return false; } return true; @@ -172,7 +172,7 @@ DEFINE_MANAGED_VTABLE(StringCtor); StringCtor::StringCtor(ExecutionContext *scope) : FunctionObject(scope, QStringLiteral("String")) { - vtbl = &static_vtbl; + setVTable(&static_vtbl); } ReturnedValue StringCtor::construct(Managed *m, CallData *callData) @@ -181,7 +181,7 @@ ReturnedValue StringCtor::construct(Managed *m, CallData *callData) Scope scope(v4); ScopedValue value(scope); if (callData->argc) - value = callData->args[0].toString(v4->current); + value = callData->args[0].toString(v4->currentContext()); else value = v4->newString(QString()); return Encode(v4->newStringObject(value)); @@ -193,7 +193,7 @@ ReturnedValue StringCtor::call(Managed *m, CallData *callData) Scope scope(v4); ScopedValue value(scope); if (callData->argc) - value = callData->args[0].toString(v4->current); + value = callData->args[0].toString(v4->currentContext()); else value = v4->newString(QString()); return value.asReturnedValue(); diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index 4ae570c8dc..30f7e8cdb0 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -90,7 +90,7 @@ double Value::toNumberImpl() const if (isString()) return __qmljs_string_to_number(stringValue()->toQString()); { - ExecutionContext *ctx = objectValue()->internalClass->engine->current; + ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext(); Scope scope(ctx); ScopedValue prim(scope, __qmljs_to_primitive(ValueRef::fromRawValue(this), NUMBER_HINT)); return prim->toNumber(); @@ -121,7 +121,7 @@ QString Value::toQStringNoThrow() const if (isString()) return stringValue()->toQString(); { - ExecutionContext *ctx = objectValue()->internalClass->engine->current; + ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext(); Scope scope(ctx); ScopedValue ex(scope); bool caughtException = false; @@ -174,7 +174,7 @@ QString Value::toQString() const if (isString()) return stringValue()->toQString(); { - ExecutionContext *ctx = objectValue()->internalClass->engine->current; + ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext(); Scope scope(ctx); ScopedValue prim(scope, __qmljs_to_primitive(ValueRef::fromRawValue(this), STRING_HINT)); return prim->toQString(); diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index 470e8e206b..dfa4ac5775 100644 --- a/src/qml/jsruntime/qv4variantobject.cpp +++ b/src/qml/jsruntime/qv4variantobject.cpp @@ -56,7 +56,6 @@ VariantObject::VariantObject(InternalClass *ic) , ExecutionEngine::ScarceResourceData(QVariant()) , m_vmePropertyReferenceCount(0) { - vtbl = &static_vtbl; } VariantObject::VariantObject(ExecutionEngine *engine, const QVariant &value) @@ -64,7 +63,6 @@ VariantObject::VariantObject(ExecutionEngine *engine, const QVariant &value) , ExecutionEngine::ScarceResourceData(value) , m_vmePropertyReferenceCount(0) { - vtbl = &static_vtbl; if (isScarce()) engine->scarceResources.insert(this); } diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 72db469ee6..9d6540ebe9 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -320,6 +320,10 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code, STOREVALUE(instr.result, __qmljs_get_qobject_property(context, VALUEPTR(instr.base), instr.propertyIndex, instr.captureRequired)); MOTH_END_INSTR(LoadQObjectProperty) + MOTH_BEGIN_INSTR(LoadAttachedQObjectProperty) + STOREVALUE(instr.result, __qmljs_get_attached_property(context, instr.attachedPropertiesId, instr.propertyIndex)); + MOTH_END_INSTR(LoadAttachedQObjectProperty) + MOTH_BEGIN_INSTR(Push) TRACE(inline, "stack size: %u", instr.value); stackSize = instr.value; @@ -503,10 +507,19 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code, QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); callData->tag = QV4::Value::Integer_Type; callData->argc = instr.argc; - callData->thisObject = QV4::Primitive::undefinedValue(); - STOREVALUE(instr.result, __qmljs_construct_property(context, VALUEPTR(instr.base), runtimeStrings[instr.name], callData)); + callData->thisObject = VALUE(instr.base); + STOREVALUE(instr.result, __qmljs_construct_property(context, runtimeStrings[instr.name], callData)); MOTH_END_INSTR(CreateProperty) + MOTH_BEGIN_INSTR(ConstructPropertyLookup) + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize); + QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); + callData->tag = QV4::Value::Integer_Type; + callData->argc = instr.argc; + callData->thisObject = VALUE(instr.base); + STOREVALUE(instr.result, __qmljs_construct_property_lookup(context, instr.index, callData)); + MOTH_END_INSTR(ConstructPropertyLookup) + MOTH_BEGIN_INSTR(CreateActivationProperty) TRACE(inline, "property name = %s, args = %d, argc = %d", runtimeStrings[instr.name]->toQString().toUtf8().constData(), instr.args, instr.argc); Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize); @@ -648,9 +661,9 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code, VALUE(instr.result) = context->callData->thisObject; MOTH_END_INSTR(LoadThis) - MOTH_BEGIN_INSTR(LoadQmlIdObject) - VALUE(instr.result) = __qmljs_get_id_object(static_cast<QV4::NoThrowContext*>(context), instr.id); - MOTH_END_INSTR(LoadQmlIdObject) + MOTH_BEGIN_INSTR(LoadQmlIdArray) + VALUE(instr.result) = __qmljs_get_id_array(static_cast<QV4::NoThrowContext*>(context)); + MOTH_END_INSTR(LoadQmlIdArray) MOTH_BEGIN_INSTR(LoadQmlImportedScripts) VALUE(instr.result) = __qmljs_get_imported_scripts(static_cast<QV4::NoThrowContext*>(context)); @@ -664,6 +677,10 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code, VALUE(instr.result) = __qmljs_get_scope_object(static_cast<QV4::NoThrowContext*>(context)); MOTH_END_INSTR(LoadScopeObject) + MOTH_BEGIN_INSTR(LoadQmlSingleton) + VALUE(instr.result) = __qmljs_get_qml_singleton(static_cast<QV4::NoThrowContext*>(context), runtimeStrings[instr.name]); + MOTH_END_INSTR(LoadQmlSingleton) + #ifdef MOTH_THREADED_INTERPRETER // nothing to do #else |