diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2015-09-25 20:56:51 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2015-09-25 20:56:51 +0200 |
commit | f9ef039ad955db67dc3ab6e9056afc4a325aa9a3 (patch) | |
tree | 4928ff85fb630639e306ea4eb7137a2064a80c8b /src/qml | |
parent | 0238c739f81911f0963cf2c40b27dcfc8e3d38b7 (diff) | |
parent | 52fb4685e95e5b44e54d2d0f8ea27dea866c75e9 (diff) |
Merge remote-tracking branch 'origin/5.6' into dev
Conflicts:
src/qml/debugger/qqmldebug.cpp
Change-Id: I93de5a81b18cdece475870cf7cfba1b9baef2304
Diffstat (limited to 'src/qml')
109 files changed, 1799 insertions, 1602 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 4b1e3601dc..7b0d4240c4 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1590,7 +1590,7 @@ static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::Membe if (member->name->constData()->isUpper()) { bool ok = false; - int value = type->enumValue(*member->name, &ok); + int value = type->enumValue(qmlEngine, *member->name, &ok); if (ok) { member->setEnumValue(value); resolver->clear(); diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 80ffafda72..e36ba76326 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -1163,8 +1163,6 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, if (!type && typeName != QLatin1String("Qt")) return true; - if (type && type->isComposite()) //No enums on composite (or composite singleton) types - return true; int value = 0; bool ok = false; @@ -1182,7 +1180,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, } else { // Otherwise we have to search the whole type if (type) { - value = type->enumValue(QHashedStringRef(enumValue), &ok); + value = type->enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok); } else { QByteArray enumName = enumValue.toUtf8(); const QMetaObject *metaObject = StaticQtMetaObject::get(); @@ -1210,7 +1208,9 @@ int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &e if (scope != QLatin1String("Qt")) { QQmlType *type = 0; imports->resolveType(scope, &type, 0, 0, 0); - return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; + if (!type) + return -1; + return type ? type->enumValue(compiler->enginePrivate(), QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; } const QMetaObject *mo = StaticQtMetaObject::get(); @@ -1719,17 +1719,6 @@ const QQmlImports &QQmlPropertyValidator::imports() const return *compiler->imports(); } -QString QQmlPropertyValidator::bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const -{ - const QmlIR::Object *object = compiler->qmlObjects()->value(objectIndex); - if (!object) - return QString(); - int reverseIndex = object->runtimeFunctionIndices->indexOf(binding->value.compiledScriptIndex); - if (reverseIndex == -1) - return QString(); - return compiler->bindingAsString(object, reverseIndex); -} - typedef QVarLengthArray<const QV4::CompiledData::Binding *, 8> GroupPropertyVector; struct BindingFinder @@ -1998,10 +1987,12 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD if (customParser && !customBindings.isEmpty()) { customParser->clearErrors(); - customParser->compiler = this; + customParser->validator = this; + customParser->engine = enginePrivate; customParser->imports = compiler->imports(); customParser->verifyBindings(qmlUnit, customBindings); - customParser->compiler = 0; + customParser->validator = 0; + customParser->engine = 0; customParser->imports = (QQmlImports*)0; customParserBindingsPerObject->insert(objectIndex, customParserBindings); const QList<QQmlError> parserErrors = customParser->errors(); diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 75987af656..09ef7aad67 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -264,7 +264,7 @@ protected: QHash<int, QHash<int, int> > *objectIndexToIdPerComponent; }; -class QQmlPropertyValidator : public QQmlCompilePass, public QQmlCustomParserCompilerBackend +class QQmlPropertyValidator : public QQmlCompilePass { Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator) public: @@ -272,9 +272,8 @@ public: bool validate(); - // Re-implemented for QQmlCustomParser - virtual const QQmlImports &imports() const; - virtual QString bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const; + const QQmlImports &imports() const; + QQmlEnginePrivate *engine() const { return enginePrivate; } private: bool validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const; diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index c150666a11..32169f3352 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -3504,7 +3504,7 @@ void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) { } #endif -void cleanupBasicBlocks(IR::Function *function) +static void cleanupBasicBlocks(IR::Function *function) { showMeTheCode(function, "Before basic block cleanup"); diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp index 64004fc86a..b308f5aa29 100644 --- a/src/qml/debugger/qqmldebug.cpp +++ b/src/qml/debugger/qqmldebug.cpp @@ -147,6 +147,8 @@ bool QQmlDebuggingEnabler::startTcpDebugServer(int port, StartMode mode, const Q } /*! + * \since 5.6 + * * Enables debugging for QML engines created after calling this function. The debug connector will * connect to a debugger waiting on a local socket at the given \a socketFileName and block the QML * engine until the connection is established if \a mode is \c WaitForClient. If \a mode is not diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp index 8de734fa68..460cb8f203 100644 --- a/src/qml/debugger/qqmldebugconnector.cpp +++ b/src/qml/debugger/qqmldebugconnector.cpp @@ -107,9 +107,9 @@ QQmlDebugConnector *QQmlDebugConnector::instance() if (!QQmlEnginePrivate::qml_debugging_enabled) { if (!params->arguments.isEmpty()) { - qWarning() << QString::fromLatin1( - "QML Debugger: Ignoring \"-qmljsdebugger=%1\". Debugging has not " - "been enabled.").arg(params->arguments); + qWarning().noquote() << QString::fromLatin1( + "QML Debugger: Ignoring \"-qmljsdebugger=%1\". Debugging " + "has not been enabled.").arg(params->arguments); params->arguments.clear(); } return 0; diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc index 54ed3f1e6e..426848f6e6 100644 --- a/src/qml/doc/src/cppintegration/definetypes.qdoc +++ b/src/qml/doc/src/cppintegration/definetypes.qdoc @@ -314,7 +314,7 @@ merged with the original target class when used from within QML. For example: The \c leftMargin property is a new property added to an existing C++ type, \l QLineEdit, without modifying its source code. -The \l qmlRegisterExtendedType() function is for registering extended types. +The \l {QQmlEngine::}{qmlRegisterExtendedType()} function is for registering extended types. Note that it has two forms. \code diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 4910b6a1c6..b217d3fb4c 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -317,7 +317,9 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in { QV4::ExecutionEngine *v4 = d->m_v4Engine; QV4::Scope scope(v4); - QV4::ScopedContext ctx(scope, v4->currentContext()); + QV4::ExecutionContextSaver saver(scope); + + QV4::ExecutionContext *ctx = v4->currentContext; if (ctx->d() != v4->rootContext()->d()) ctx = v4->pushGlobalContext(); QV4::ScopedValue result(scope); @@ -330,8 +332,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in result = script.run(); if (scope.engine->hasException) result = v4->catchException(); - if (ctx->d() != v4->rootContext()->d()) - v4->popContext(); + return QJSValue(v4, result->asReturnedValue()); } @@ -553,7 +554,7 @@ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr) Creates a QJSValue with the given \a value. - \sa fromScriptValue(), newVariant() + \sa fromScriptValue() */ /*! \fn T QJSEngine::fromScriptValue(const QJSValue &value) diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 2f6cf40beb..698b4c325c 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -40,9 +40,7 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(ArgumentsObject); Heap::ArgumentsObject::ArgumentsObject(QV4::CallContext *context) - : Heap::Object(context->d()->strictMode ? context->d()->engine->strictArgumentsObjectClass : context->d()->engine->argumentsObjectClass, - context->d()->engine->objectPrototype()) - , context(context->d()) + : context(context->d()) , fullyCreated(false) { Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable()); @@ -56,20 +54,20 @@ Heap::ArgumentsObject::ArgumentsObject(QV4::CallContext *context) if (context->d()->strictMode) { Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller())); - args->propertyAt(CalleePropertyIndex)->value = v4->thrower(); - args->propertyAt(CalleePropertyIndex)->set = v4->thrower(); - args->propertyAt(CallerPropertyIndex)->value = v4->thrower(); - args->propertyAt(CallerPropertyIndex)->set = v4->thrower(); + *args->propertyData(CalleePropertyIndex + QV4::Object::GetterOffset) = v4->thrower(); + *args->propertyData(CalleePropertyIndex + QV4::Object::SetterOffset) = v4->thrower(); + *args->propertyData(CallerPropertyIndex + QV4::Object::GetterOffset) = v4->thrower(); + *args->propertyData(CallerPropertyIndex + QV4::Object::SetterOffset) = v4->thrower(); args->arrayReserve(context->argc()); args->arrayPut(0, context->args(), context->argc()); args->d()->fullyCreated = true; } else { Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); - args->memberData()->data[CalleePropertyIndex] = context->d()->function->asReturnedValue(); + *args->propertyData(CalleePropertyIndex) = context->d()->function->asReturnedValue(); } Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length())); - args->memberData()->data[LengthPropertyIndex] = Primitive::fromInt32(context->d()->callData->argc); + *args->propertyData(LengthPropertyIndex) = Primitive::fromInt32(context->d()->callData->argc); } void ArgumentsObject::fullyCreate() @@ -84,10 +82,9 @@ void ArgumentsObject::fullyCreate() Scope scope(engine()); Scoped<MemberData> md(scope, d()->mappedArguments); - if (!md || md->size() < numAccessors) - d()->mappedArguments = md->reallocate(engine(), d()->mappedArguments, numAccessors); + d()->mappedArguments = md->allocate(engine(), numAccessors); for (uint i = 0; i < numAccessors; ++i) { - mappedArguments()->data[i] = context()->callData->args[i]; + d()->mappedArguments->data[i] = context()->callData->args[i]; arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor); } arrayPut(numAccessors, context()->callData->args + numAccessors, argCount - numAccessors); @@ -117,13 +114,13 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con map->copy(pd, mapAttrs); setArrayAttributes(index, Attr_Data); pd = arrayData()->getProperty(index); - pd->value = mappedArguments()->data[index]; + pd->value = d()->mappedArguments->data[index]; } - bool strict = engine->currentContext()->strictMode; - engine->currentContext()->strictMode = false; + bool strict = engine->current->strictMode; + engine->current->strictMode = false; bool result = Object::defineOwnProperty2(scope.engine, index, desc, attrs); - engine->currentContext()->strictMode = strict; + engine->current->strictMode = strict; if (isMapped && attrs.isData()) { Q_ASSERT(arrayData()); @@ -140,7 +137,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con } } - if (engine->currentContext()->strictMode && !result) + if (engine->current->strictMode && !result) return engine->throwTypeError(); return result; } diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index aab5e2c156..98a600fab6 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -103,7 +103,6 @@ struct ArgumentsObject: Object { Heap::CallContext *context() const { return d()->context; } bool fullyCreated() const { return d()->fullyCreated; } - Heap::MemberData *mappedArguments() { return d()->mappedArguments; } static bool isNonStrictArgumentsObject(Managed *m) { return m->d()->vtable()->type == Type_ArgumentsObject && diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp index 23c9695cf4..0a3aa414de 100644 --- a/src/qml/jsruntime/qv4arraybuffer.cpp +++ b/src/qml/jsruntime/qv4arraybuffer.cpp @@ -58,7 +58,7 @@ ReturnedValue ArrayBufferCtor::construct(const Managed *m, CallData *callData) if (len != dl) return v4->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length")); - Scoped<ArrayBuffer> a(scope, v4->memoryManager->alloc<ArrayBuffer>(v4, len)); + Scoped<ArrayBuffer> a(scope, v4->newArrayBuffer(len)); if (scope.engine->hasException) return Encode::undefined(); return a.asReturnedValue(); @@ -83,22 +83,20 @@ ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx) } -Heap::ArrayBuffer::ArrayBuffer(ExecutionEngine *e, size_t length) - : Heap::Object(e->emptyClass, e->arrayBufferPrototype()) +Heap::ArrayBuffer::ArrayBuffer(size_t length) { data = QTypedArrayData<char>::allocate(length + 1); if (!data) { data = 0; - e->throwRangeError(QStringLiteral("ArrayBuffer: out of memory")); + internalClass->engine->throwRangeError(QStringLiteral("ArrayBuffer: out of memory")); return; } data->size = int(length); memset(data->data(), 0, length + 1); } -Heap::ArrayBuffer::ArrayBuffer(ExecutionEngine *e, const QByteArray& array) - : Heap::Object(e->emptyClass, e->arrayBufferPrototype()) - , data(const_cast<QByteArray&>(array).data_ptr()) +Heap::ArrayBuffer::ArrayBuffer(const QByteArray& array) + : data(const_cast<QByteArray&>(array).data_ptr()) { data->ref.ref(); } diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h index a7f9e92c80..19fd74465c 100644 --- a/src/qml/jsruntime/qv4arraybuffer_p.h +++ b/src/qml/jsruntime/qv4arraybuffer_p.h @@ -47,8 +47,8 @@ struct ArrayBufferCtor : FunctionObject { }; struct Q_QML_PRIVATE_EXPORT ArrayBuffer : Object { - ArrayBuffer(ExecutionEngine *e, size_t length); - ArrayBuffer(ExecutionEngine *e, const QByteArray& array); + ArrayBuffer(size_t length); + ArrayBuffer(const QByteArray& array); ~ArrayBuffer(); QTypedArrayData<char> *data; @@ -72,6 +72,7 @@ struct Q_QML_PRIVATE_EXPORT ArrayBuffer : Object { V4_OBJECT2(ArrayBuffer, Object) V4_NEEDS_DESTROY + V4_PROTOTYPE(arrayBufferPrototype) QByteArray asByteArray() const; uint byteLength() const { return d()->byteLength(); } diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index da91db6aae..ec0185de64 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -584,7 +584,7 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n) ScopedValue v(scope); for (const SparseArrayNode *it = os->sparse->begin(); it != os->sparse->end(); it = it->nextNode()) { - v = otherObj->getValue(reinterpret_cast<Property *>(os->arrayData + it->value), other->d()->attrs[it->value]); + v = otherObj->getValue(os->arrayData[it->value], other->d()->attrs[it->value]); obj->arraySet(oldSize + it->key(), v); } } else { @@ -607,7 +607,7 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n) return oldSize + n; } -Property *ArrayData::insert(Object *o, uint index, bool isAccessor) +void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor) { if (!isAccessor && o->d()->arrayData->type != Heap::ArrayData::Sparse) { Heap::SimpleArrayData *d = o->d()->arrayData.cast<Heap::SimpleArrayData>(); @@ -622,7 +622,8 @@ Property *ArrayData::insert(Object *o, uint index, bool isAccessor) d->data(i) = Primitive::emptyValue(); d->len = index + 1; } - return reinterpret_cast<Property *>(d->arrayData + d->mappedIndex(index)); + d->arrayData[d->mappedIndex(index)] = *v; + return; } } @@ -632,7 +633,9 @@ Property *ArrayData::insert(Object *o, uint index, bool isAccessor) if (n->value == UINT_MAX) n->value = SparseArrayData::allocate(o, isAccessor); s = o->d()->arrayData.cast<Heap::SparseArrayData>(); - return reinterpret_cast<Property *>(s->arrayData + n->value); + s->arrayData[n->value] = *v; + if (isAccessor) + s->arrayData[n->value + Object::SetterOffset] = v[Object::SetterOffset]; } @@ -769,7 +772,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c break; PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data; - d->data(i) = thisObject->getValue(reinterpret_cast<Property *>(sparse->arrayData() + n->value), a); + d->data(i) = thisObject->getValue(sparse->arrayData()[n->value], a); d->attrs[i] = a.isAccessor() ? Attr_Data : a; n = n->nextNode(); diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 729e657b1a..cca5bf7f20 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -101,7 +101,10 @@ struct ArrayData : public Base { inline ReturnedValue get(uint i) const { return vtable()->get(this, i); } + inline void getProperty(uint index, Property *p, PropertyAttributes *attrs); + inline void setProperty(uint index, const Property *p); inline Property *getProperty(uint index); + inline Value *getValueOrSetter(uint index, PropertyAttributes *attrs); inline PropertyAttributes attributes(uint i) const; bool isEmpty(uint i) const { @@ -205,7 +208,7 @@ struct Q_QML_EXPORT ArrayData : public Managed static void sort(ExecutionEngine *engine, Object *thisObject, const Value &comparefn, uint dataLen); static uint append(Object *obj, ArrayObject *otherObj, uint n); - static Property *insert(Object *o, uint index, bool isAccessor = false); + static void insert(Object *o, uint index, const Value *v, bool isAccessor = false); }; struct Q_QML_EXPORT SimpleArrayData : public ArrayData @@ -270,6 +273,25 @@ inline SparseArrayData::~SparseArrayData() delete sparse; } +void ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs) +{ + Property *pd = getProperty(index); + Q_ASSERT(pd); + *attrs = attributes(index); + p->value = pd->value; + if (attrs->isAccessor()) + p->set = pd->set; +} + +void ArrayData::setProperty(uint index, const Property *p) +{ + Property *pd = getProperty(index); + Q_ASSERT(pd); + pd->value = p->value; + if (attributes(index).isAccessor()) + pd->set = p->set; +} + inline Property *ArrayData::getProperty(uint index) { if (isSparse()) @@ -284,6 +306,19 @@ inline PropertyAttributes ArrayData::attributes(uint i) const return static_cast<const SimpleArrayData *>(this)->attributes(i); } +Value *ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs) +{ + Property *p = getProperty(index); + if (!p) { + *attrs = Attr_Invalid; + return 0; + } + + *attrs = attributes(index); + return attrs->isAccessor() ? &p->set : &p->value; +} + + } diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index f50c5ab017..403beacf39 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -83,21 +83,31 @@ Heap::CallContext *ExecutionContext::newCallContext(const FunctionObject *functi return c; } -Heap::WithContext *ExecutionContext::newWithContext(Object *with) +Heap::WithContext *ExecutionContext::newWithContext(Heap::Object *with) { - return d()->engine->memoryManager->alloc<WithContext>(d()->engine, with); + return d()->engine->memoryManager->alloc<WithContext>(d(), with); } -Heap::CatchContext *ExecutionContext::newCatchContext(String *exceptionVarName, const Value &exceptionValue) +Heap::CatchContext *ExecutionContext::newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue) { - return d()->engine->memoryManager->alloc<CatchContext>(d()->engine, exceptionVarName, exceptionValue); + Scope scope(this); + ScopedValue e(scope, exceptionValue); + return d()->engine->memoryManager->alloc<CatchContext>(d(), exceptionVarName, e); } Heap::QmlContext *ExecutionContext::newQmlContext(QmlContextWrapper *qml) { - return d()->engine->memoryManager->alloc<QmlContext>(this, qml); + Heap::QmlContext *c = d()->engine->memoryManager->alloc<QmlContext>(this, qml); + return c; } +Heap::QmlContext *ExecutionContext::newQmlContext(QQmlContextData *context, QObject *scopeObject) +{ + Scope scope(this); + Scoped<QmlContextWrapper> qml(scope, QmlContextWrapper::qmlScope(scope.engine, context, scopeObject)); + Heap::QmlContext *c = d()->engine->memoryManager->alloc<QmlContext>(this, qml); + return c; +} void ExecutionContext::createMutableBinding(String *name, bool deletable) { @@ -142,38 +152,38 @@ Heap::GlobalContext::GlobalContext(ExecutionEngine *eng) global = eng->globalObject->d(); } -Heap::WithContext::WithContext(ExecutionEngine *engine, QV4::Object *with) - : Heap::ExecutionContext(engine, Heap::ExecutionContext::Type_WithContext) +Heap::WithContext::WithContext(ExecutionContext *outerContext, Object *with) + : Heap::ExecutionContext(outerContext->engine, Heap::ExecutionContext::Type_WithContext) { - callData = parent->callData; - outer = parent; - lookups = parent->lookups; - compilationUnit = parent->compilationUnit; + outer = outerContext; + callData = outer->callData; + lookups = outer->lookups; + compilationUnit = outer->compilationUnit; - withObject = with ? with->d() : 0; + withObject = with; } -Heap::CatchContext::CatchContext(ExecutionEngine *engine, QV4::String *exceptionVarName, const Value &exceptionValue) - : Heap::ExecutionContext(engine, Heap::ExecutionContext::Type_CatchContext) +Heap::CatchContext::CatchContext(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue) + : Heap::ExecutionContext(outerContext->engine, Heap::ExecutionContext::Type_CatchContext) { - strictMode = parent->strictMode; - callData = parent->callData; - outer = parent; - lookups = parent->lookups; - compilationUnit = parent->compilationUnit; + outer = outerContext; + strictMode = outer->strictMode; + callData = outer->callData; + lookups = outer->lookups; + compilationUnit = outer->compilationUnit; - this->exceptionVarName = exceptionVarName->d(); + this->exceptionVarName = exceptionVarName; this->exceptionValue = exceptionValue; } -Heap::QmlContext::QmlContext(QV4::ExecutionContext *outer, QV4::QmlContextWrapper *qml) - : Heap::ExecutionContext(outer->engine(), Heap::ExecutionContext::Type_QmlContext) +Heap::QmlContext::QmlContext(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml) + : Heap::ExecutionContext(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext) { + outer = outerContext->d(); strictMode = false; - callData = parent->callData; - this->outer = outer->d(); - lookups = parent->lookups; - compilationUnit = parent->compilationUnit; + callData = outer->callData; + lookups = outer->lookups; + compilationUnit = outer->compilationUnit; this->qml = qml->d(); } @@ -362,7 +372,7 @@ void ExecutionContext::setProperty(String *name, const Value &value) if (activation) { uint member = activation->internalClass()->find(name); if (member < UINT_MAX) { - activation->putValue(activation->propertyAt(member), activation->internalClass()->propertyData[member], value); + activation->putValue(member, value); return; } } @@ -538,7 +548,7 @@ Heap::FunctionObject *ExecutionContext::getFunctionObject() const { Scope scope(d()->engine); ScopedContext it(scope, this->d()); - for (; it; it = it->d()->parent) { + for (; it; it = it->d()->outer) { if (const CallContext *callCtx = it->asCallContext()) return callCtx->d()->function; else if (it->asCatchContext() || it->asWithContext()) @@ -560,3 +570,8 @@ QQmlContextData *QmlContext::qmlContext() const { return d()->qml->context; } + +void QmlContext::takeContextOwnership() { + d()->qml->ownsContext = true; +} + diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 2667bbe0b2..2807d1e29c 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -89,7 +89,6 @@ struct ExecutionContext : Base { CallData *callData; ExecutionEngine *engine; - Pointer<ExecutionContext> parent; Pointer<ExecutionContext> outer; Lookup *lookups; CompiledData::CompilationUnit *compilationUnit; @@ -99,6 +98,18 @@ struct ExecutionContext : Base { int lineNumber; }; +inline +ExecutionContext::ExecutionContext(ExecutionEngine *engine, ContextType t) + : engine(engine) + , outer(0) + , lookups(0) + , compilationUnit(0) + , type(t) + , strictMode(false) + , lineNumber(-1) +{} + + struct CallContext : ExecutionContext { CallContext(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext) : ExecutionContext(engine, t) @@ -119,20 +130,20 @@ struct GlobalContext : ExecutionContext { }; struct CatchContext : ExecutionContext { - CatchContext(ExecutionEngine *engine, QV4::String *exceptionVarName, const Value &exceptionValue); + CatchContext(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue); Pointer<String> exceptionVarName; Value exceptionValue; }; struct WithContext : ExecutionContext { - WithContext(ExecutionEngine *engine, QV4::Object *with); + WithContext(ExecutionContext *outerContext, Object *with); Pointer<Object> withObject; }; struct QmlContextWrapper; struct QmlContext : ExecutionContext { - QmlContext(QV4::ExecutionContext *outer, QV4::QmlContextWrapper *qml); + QmlContext(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml); Pointer<QmlContextWrapper> qml; }; @@ -150,9 +161,10 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ExecutionEngine *engine() const { return d()->engine; } Heap::CallContext *newCallContext(const FunctionObject *f, CallData *callData); - Heap::WithContext *newWithContext(Object *with); - Heap::CatchContext *newCatchContext(String *exceptionVarName, const Value &exceptionValue); + Heap::WithContext *newWithContext(Heap::Object *with); + Heap::CatchContext *newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue); Heap::QmlContext *newQmlContext(QmlContextWrapper *qml); + Heap::QmlContext *newQmlContext(QQmlContextData *context, QObject *scopeObject); void createMutableBinding(String *name, bool deletable); @@ -224,6 +236,8 @@ struct QmlContext : public ExecutionContext QObject *qmlScope() const; QQmlContextData *qmlContext() const; + + void takeContextOwnership(); }; inline CallContext *ExecutionContext::asCallContext() diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp index a741d61d10..8901834e76 100644 --- a/src/qml/jsruntime/qv4dataview.cpp +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -62,7 +62,7 @@ ReturnedValue DataViewCtor::construct(const Managed *m, CallData *callData) if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength) return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range")); - Scoped<DataView> a(scope, scope.engine->memoryManager->alloc<DataView>(scope.engine)); + Scoped<DataView> a(scope, scope.engine->memoryManager->allocObject<DataView>()); a->d()->buffer = buffer->d(); a->d()->byteLength = byteLength; a->d()->byteOffset = byteOffset; @@ -76,15 +76,6 @@ ReturnedValue DataViewCtor::call(const Managed *that, CallData *callData) } -Heap::DataView::DataView(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->dataViewPrototype()), - buffer(0), - byteLength(0), - byteOffset(0) -{ -} - - void DataView::markObjects(Heap::Base *that, ExecutionEngine *e) { DataView::Data *v = static_cast<DataView::Data *>(that); @@ -103,22 +94,30 @@ void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor) defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); defineDefaultProperty(QStringLiteral("getInt8"), method_getChar<signed char>, 0); - defineDefaultProperty(QStringLiteral("getUInt8"), method_getChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("getUint8"), method_getChar<unsigned char>, 0); defineDefaultProperty(QStringLiteral("getInt16"), method_get<short>, 0); - defineDefaultProperty(QStringLiteral("getUInt16"), method_get<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("getUint16"), method_get<unsigned short>, 0); defineDefaultProperty(QStringLiteral("getInt32"), method_get<int>, 0); - defineDefaultProperty(QStringLiteral("getUInt32"), method_get<unsigned int>, 0); + defineDefaultProperty(QStringLiteral("getUint32"), method_get<unsigned int>, 0); defineDefaultProperty(QStringLiteral("getFloat32"), method_getFloat<float>, 0); defineDefaultProperty(QStringLiteral("getFloat64"), method_getFloat<double>, 0); defineDefaultProperty(QStringLiteral("setInt8"), method_setChar<signed char>, 0); - defineDefaultProperty(QStringLiteral("setUInt8"), method_setChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("setUint8"), method_setChar<unsigned char>, 0); defineDefaultProperty(QStringLiteral("setInt16"), method_set<short>, 0); - defineDefaultProperty(QStringLiteral("setUInt16"), method_set<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("setUint16"), method_set<unsigned short>, 0); defineDefaultProperty(QStringLiteral("setInt32"), method_set<int>, 0); - defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 0); + defineDefaultProperty(QStringLiteral("setUint32"), method_set<unsigned int>, 0); defineDefaultProperty(QStringLiteral("setFloat32"), method_setFloat<float>, 0); defineDefaultProperty(QStringLiteral("setFloat64"), method_setFloat<double>, 0); + + // For backword compatibility + defineDefaultProperty(QStringLiteral("getUInt8"), method_getChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("getUInt16"), method_get<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("getUInt32"), method_get<unsigned int>, 0); + defineDefaultProperty(QStringLiteral("setUInt8"), method_setChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("setUInt16"), method_set<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 0); } ReturnedValue DataViewPrototype::method_get_buffer(CallContext *ctx) diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h index e98239396a..37a8363645 100644 --- a/src/qml/jsruntime/qv4dataview_p.h +++ b/src/qml/jsruntime/qv4dataview_p.h @@ -47,7 +47,7 @@ struct DataViewCtor : FunctionObject { }; struct DataView : Object { - DataView(ExecutionEngine *e); + DataView() {} Pointer<ArrayBuffer> buffer; uint byteLength; uint byteOffset; @@ -66,6 +66,7 @@ struct DataViewCtor: FunctionObject struct DataView : Object { V4_OBJECT2(DataView, Object) + V4_PROTOTYPE(dataViewPrototype) static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 3f45751695..a6e1f47d91 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -628,8 +628,7 @@ static double getLocalTZA() DEFINE_OBJECT_VTABLE(DateObject); -Heap::DateObject::DateObject(QV4::ExecutionEngine *engine, const QDateTime &date) - : Heap::Object(engine->emptyClass, engine->datePrototype()) +Heap::DateObject::DateObject(const QDateTime &date) { this->date = date.isValid() ? date.toMSecsSinceEpoch() : qSNaN(); } diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index 7a6413e820..a324e216e4 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -46,18 +46,16 @@ namespace QV4 { namespace Heap { struct DateObject : Object { - DateObject(InternalClass *ic, QV4::Object *prototype) - : Object(ic, prototype) + DateObject() { date = qSNaN(); } - DateObject(QV4::ExecutionEngine *engine, const Value &date) - : Object(engine->emptyClass, engine->datePrototype()) + DateObject(const Value &date) { this->date = date.toNumber(); } - DateObject(QV4::ExecutionEngine *engine, const QDateTime &date); + DateObject(const QDateTime &date); double date; }; @@ -71,6 +69,7 @@ struct DateCtor : FunctionObject { struct DateObject: Object { V4_OBJECT2(DateObject, Object) Q_MANAGED_TYPE(DateObject) + V4_PROTOTYPE(datePrototype) double date() const { return d()->date; } diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index 6efc3793ce..79fd58f700 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -66,17 +66,16 @@ void Debugger::JavaScriptJob::run() { Scope scope(engine); - ExecutionContextSaver saver(scope, engine->currentContext()); + ExecutionContextSaver saver(scope); + ExecutionContext *ctx = engine->currentContext; if (frameNr > 0) { - Value *savedContexts = scope.alloc(frameNr); for (int i = 0; i < frameNr; ++i) { - savedContexts[i] = engine->currentContext(); - engine->popContext(); + ctx = engine->parentContext(ctx); } + engine->pushContext(ctx); } - ScopedContext ctx(scope, engine->currentContext()); QV4::Script script(ctx, this->script); script.strictMode = ctx->d()->strictMode; // In order for property lookups in QML to work, we need to disable fast v4 lookups. That @@ -151,7 +150,7 @@ void Debugger::resume(Speed speed) if (!m_returnedValue.isUndefined()) m_returnedValue.set(m_engine, Encode::undefined()); - m_currentContext.set(m_engine, m_engine->currentContext()); + m_currentContext.set(m_engine, *m_engine->currentContext); m_stepping = speed; m_runningCondition.wakeAll(); } @@ -181,7 +180,7 @@ Debugger::ExecutionState Debugger::currentExecutionState() const { ExecutionState state; state.fileName = getFunction()->sourceFile(); - state.lineNumber = engine()->currentContext()->lineNumber; + state.lineNumber = engine()->current->lineNumber; return state; } @@ -206,7 +205,7 @@ void Debugger::maybeBreakAtInstruction() switch (m_stepping) { case StepOver: - if (m_currentContext.asManaged()->d() != m_engine->currentContext()) + if (m_currentContext.asManaged()->d() != m_engine->current) break; // fall through case StepIn: @@ -222,7 +221,7 @@ void Debugger::maybeBreakAtInstruction() pauseAndWait(PauseRequest); } else if (m_haveBreakPoints) { if (Function *f = getFunction()) { - const int lineNumber = engine()->currentContext()->lineNumber; + const int lineNumber = engine()->current->lineNumber; if (reallyHitTheBreakPoint(f->sourceFile(), lineNumber)) pauseAndWait(BreakPoint); } @@ -236,7 +235,7 @@ void Debugger::enteringFunction() QMutexLocker locker(&m_lock); if (m_stepping == StepIn) { - m_currentContext.set(m_engine, m_engine->currentContext()); + m_currentContext.set(m_engine, *m_engine->currentContext); } } @@ -248,8 +247,8 @@ void Debugger::leavingFunction(const ReturnedValue &retVal) QMutexLocker locker(&m_lock); - if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->currentContext()) { - m_currentContext.set(m_engine, m_engine->currentContext()->parent); + if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->current) { + m_currentContext.set(m_engine, *m_engine->parentContext(m_engine->currentContext)); m_stepping = StepOver; m_returnedValue.set(m_engine, retVal); } @@ -270,7 +269,7 @@ void Debugger::aboutToThrow() Function *Debugger::getFunction() const { Scope scope(m_engine); - ScopedContext context(scope, m_engine->currentContext()); + ExecutionContext *context = m_engine->currentContext; ScopedFunctionObject function(scope, context->getFunctionObject()); if (function) return function->function(); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index caf07e8b0b..6fe14da850 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -200,6 +200,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) , memoryManager(new QV4::MemoryManager(this)) , executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) + , currentContext(0) , bumperPointerAllocator(new WTF::BumpPointerAllocator) , jsStack(new WTF::PageAllocation) , debugger(0) @@ -297,10 +298,10 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer")); jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex")); - jsObjects[ObjectProto] = memoryManager->alloc<ObjectPrototype>(emptyClass, (QV4::Object *)0); + jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(emptyClass); arrayClass = emptyClass->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); - jsObjects[ArrayProto] = memoryManager->alloc<ArrayPrototype>(arrayClass, objectPrototype()); + jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(arrayClass, objectPrototype()); InternalClass *argsClass = emptyClass->addMember(id_length(), Attr_NotEnumerable); argumentsObjectClass = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable); @@ -311,15 +312,17 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) Q_ASSERT(globalObject->d()->vtable()); initRootContext(); - jsObjects[StringProto] = memoryManager->alloc<StringPrototype>(emptyClass, objectPrototype()); - jsObjects[NumberProto] = memoryManager->alloc<NumberPrototype>(emptyClass, objectPrototype()); - jsObjects[BooleanProto] = memoryManager->alloc<BooleanPrototype>(emptyClass, objectPrototype()); - jsObjects[DateProto] = memoryManager->alloc<DatePrototype>(emptyClass, objectPrototype()); + stringClass = emptyClass->addMember(id_length(), Attr_ReadOnly); + Q_ASSERT(stringClass->find(id_length()) == Heap::StringObject::LengthPropertyIndex); + jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(stringClass, objectPrototype()); + jsObjects[NumberProto] = memoryManager->allocObject<NumberPrototype>(emptyClass, objectPrototype()); + jsObjects[BooleanProto] = memoryManager->allocObject<BooleanPrototype>(emptyClass, objectPrototype()); + jsObjects[DateProto] = memoryManager->allocObject<DatePrototype>(emptyClass, objectPrototype()); uint index; InternalClass *functionProtoClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - jsObjects[FunctionProto] = memoryManager->alloc<FunctionPrototype>(functionProtoClass, objectPrototype()); + jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(functionProtoClass, objectPrototype()); functionClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); simpleScriptFunctionClass = functionClass->addMember(id_name(), Attr_ReadOnly, &index); @@ -329,42 +332,72 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) protoClass = emptyClass->addMember(id_constructor(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor); - jsObjects[RegExpProto] = memoryManager->alloc<RegExpPrototype>(this); + Scope scope(this); + ScopedString str(scope); + regExpObjectClass = emptyClass->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index); + Q_ASSERT(index == RegExpObject::Index_LastIndex); + regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index); + Q_ASSERT(index == RegExpObject::Index_Source); + regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index); + Q_ASSERT(index == RegExpObject::Index_Global); + regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index); + Q_ASSERT(index == RegExpObject::Index_IgnoreCase); + regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index); + Q_ASSERT(index == RegExpObject::Index_Multiline); + + jsObjects[RegExpProto] = memoryManager->allocObject<RegExpPrototype>(regExpObjectClass, objectPrototype()); 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); - jsObjects[ErrorProto] = memoryManager->alloc<ErrorPrototype>(emptyClass, objectPrototype()); - jsObjects[EvalErrorProto] = memoryManager->alloc<EvalErrorPrototype>(emptyClass, errorPrototype()); - jsObjects[RangeErrorProto] = memoryManager->alloc<RangeErrorPrototype>(emptyClass, errorPrototype()); - jsObjects[ReferenceErrorProto] = memoryManager->alloc<ReferenceErrorPrototype>(emptyClass, errorPrototype()); - jsObjects[SyntaxErrorProto] = memoryManager->alloc<SyntaxErrorPrototype>(emptyClass, errorPrototype()); - jsObjects[TypeErrorProto] = memoryManager->alloc<TypeErrorPrototype>(emptyClass, errorPrototype()); - jsObjects[URIErrorProto] = memoryManager->alloc<URIErrorPrototype>(emptyClass, errorPrototype()); - - jsObjects[VariantProto] = memoryManager->alloc<VariantPrototype>(emptyClass, objectPrototype()); + errorClass = emptyClass->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorObject::Index_Stack); + errorClass = errorClass->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorObject::Index_FileName); + errorClass = errorClass->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorObject::Index_LineNumber); + errorClassWithMessage = errorClass->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorObject::Index_Message); + errorProtoClass = emptyClass->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorPrototype::Index_Constructor); + errorProtoClass = errorProtoClass->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorPrototype::Index_Message); + errorProtoClass = errorProtoClass->addMember(id_name(), Attr_Data|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorPrototype::Index_Name); + + jsObjects[GetStack_Function] = BuiltinFunction::create(rootContext(), str = newIdentifier(QStringLiteral("stack")), ErrorObject::method_get_stack); + getStackFunction()->defineReadonlyProperty(id_length(), Primitive::fromInt32(0)); + + jsObjects[ErrorProto] = memoryManager->allocObject<ErrorPrototype>(errorProtoClass, objectPrototype()); + jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(errorProtoClass, errorPrototype()); + jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(errorProtoClass, errorPrototype()); + jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(errorProtoClass, errorPrototype()); + jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(errorProtoClass, errorPrototype()); + jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(errorProtoClass, errorPrototype()); + jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(errorProtoClass, errorPrototype()); + + jsObjects[VariantProto] = memoryManager->allocObject<VariantPrototype>(emptyClass, objectPrototype()); Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d()); - Scope scope(this); - jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->alloc<SequencePrototype>(arrayClass, arrayPrototype())); - - ScopedContext global(scope, rootContext()); - jsObjects[Object_Ctor] = memoryManager->alloc<ObjectCtor>(global); - jsObjects[String_Ctor] = memoryManager->alloc<StringCtor>(global); - jsObjects[Number_Ctor] = memoryManager->alloc<NumberCtor>(global); - jsObjects[Boolean_Ctor] = memoryManager->alloc<BooleanCtor>(global); - jsObjects[Array_Ctor] = memoryManager->alloc<ArrayCtor>(global); - jsObjects[Function_Ctor] = memoryManager->alloc<FunctionCtor>(global); - jsObjects[Date_Ctor] = memoryManager->alloc<DateCtor>(global); - jsObjects[RegExp_Ctor] = memoryManager->alloc<RegExpCtor>(global); - jsObjects[Error_Ctor] = memoryManager->alloc<ErrorCtor>(global); - jsObjects[EvalError_Ctor] = memoryManager->alloc<EvalErrorCtor>(global); - jsObjects[RangeError_Ctor] = memoryManager->alloc<RangeErrorCtor>(global); - jsObjects[ReferenceError_Ctor] = memoryManager->alloc<ReferenceErrorCtor>(global); - jsObjects[SyntaxError_Ctor] = memoryManager->alloc<SyntaxErrorCtor>(global); - jsObjects[TypeError_Ctor] = memoryManager->alloc<TypeErrorCtor>(global); - jsObjects[URIError_Ctor] = memoryManager->alloc<URIErrorCtor>(global); + jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(arrayClass, arrayPrototype())); + + ExecutionContext *global = rootContext(); + jsObjects[Object_Ctor] = memoryManager->allocObject<ObjectCtor>(global); + jsObjects[String_Ctor] = memoryManager->allocObject<StringCtor>(global); + jsObjects[Number_Ctor] = memoryManager->allocObject<NumberCtor>(global); + jsObjects[Boolean_Ctor] = memoryManager->allocObject<BooleanCtor>(global); + jsObjects[Array_Ctor] = memoryManager->allocObject<ArrayCtor>(global); + jsObjects[Function_Ctor] = memoryManager->allocObject<FunctionCtor>(global); + jsObjects[Date_Ctor] = memoryManager->allocObject<DateCtor>(global); + jsObjects[RegExp_Ctor] = memoryManager->allocObject<RegExpCtor>(global); + jsObjects[Error_Ctor] = memoryManager->allocObject<ErrorCtor>(global); + jsObjects[EvalError_Ctor] = memoryManager->allocObject<EvalErrorCtor>(global); + jsObjects[RangeError_Ctor] = memoryManager->allocObject<RangeErrorCtor>(global); + jsObjects[ReferenceError_Ctor] = memoryManager->allocObject<ReferenceErrorCtor>(global); + jsObjects[SyntaxError_Ctor] = memoryManager->allocObject<SyntaxErrorCtor>(global); + jsObjects[TypeError_Ctor] = memoryManager->allocObject<TypeErrorCtor>(global); + jsObjects[URIError_Ctor] = memoryManager->allocObject<URIErrorCtor>(global); static_cast<ObjectPrototype *>(objectPrototype())->init(this, objectCtor()); static_cast<StringPrototype *>(stringPrototype())->init(this, stringCtor()); @@ -388,18 +421,19 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) // typed arrays - jsObjects[ArrayBuffer_Ctor] = memoryManager->alloc<ArrayBufferCtor>(global); - jsObjects[ArrayBufferProto] = memoryManager->alloc<ArrayBufferPrototype>(emptyClass, objectPrototype()); + jsObjects[ArrayBuffer_Ctor] = memoryManager->allocObject<ArrayBufferCtor>(global); + jsObjects[ArrayBufferProto] = memoryManager->allocObject<ArrayBufferPrototype>(); static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor()); - jsObjects[DataView_Ctor] = memoryManager->alloc<DataViewCtor>(global); - jsObjects[DataViewProto] = memoryManager->alloc<DataViewPrototype>(emptyClass, objectPrototype()); + jsObjects[DataView_Ctor] = memoryManager->allocObject<DataViewCtor>(global); + jsObjects[DataViewProto] = memoryManager->allocObject<DataViewPrototype>(); static_cast<DataViewPrototype *>(dataViewPrototype())->init(this, dataViewCtor()); jsObjects[ValueTypeProto] = (Heap::Base *) 0; + jsObjects[SignalHandlerProto] = (Heap::Base *) 0; for (int i = 0; i < Heap::TypedArray::NTypes; ++i) { - static_cast<Value &>(typedArrayCtors[i]) = memoryManager->alloc<TypedArrayCtor>(global, Heap::TypedArray::Type(i)); - static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->alloc<TypedArrayPrototype>(this, Heap::TypedArray::Type(i)); + static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocObject<TypedArrayCtor>(global, Heap::TypedArray::Type(i)); + static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->allocObject<TypedArrayPrototype>(Heap::TypedArray::Type(i)); typedArrayPrototype[i].as<TypedArrayPrototype>()->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].as<Object>())); } @@ -428,19 +462,18 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor()); globalObject->defineDefaultProperty(QStringLiteral("DataView"), *dataViewCtor()); - ScopedString str(scope); for (int i = 0; i < Heap::TypedArray::NTypes; ++i) globalObject->defineDefaultProperty((str = typedArrayCtors[i].as<FunctionObject>()->name())->toQString(), typedArrayCtors[i]); ScopedObject o(scope); - globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->alloc<MathObject>(this))); - globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->alloc<JsonObject>(this))); + globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->allocObject<MathObject>())); + globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->allocObject<JsonObject>())); globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Primitive::undefinedValue()); globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(std::numeric_limits<double>::quiet_NaN())); globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Primitive::fromDouble(Q_INFINITY)); - jsObjects[Eval_Function] = memoryManager->alloc<EvalFunction>(global); + jsObjects[Eval_Function] = memoryManager->allocObject<EvalFunction>(global); globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction()); globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2); @@ -508,8 +541,11 @@ void ExecutionEngine::initRootContext() r->d()->callData->argc = 0; r->d()->callData->thisObject = globalObject; r->d()->callData->args[0] = Encode::undefined(); + jsObjects[RootContext] = r; + jsObjects[IntegerNull] = Encode((int)0); - jsObjects[RootContect] = r; + currentContext = static_cast<ExecutionContext *>(jsObjects + RootContext); + current = currentContext->d(); } InternalClass *ExecutionEngine::newClass(const InternalClass &other) @@ -517,29 +553,31 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other) return new (classPool) InternalClass(other); } -Heap::ExecutionContext *ExecutionEngine::pushGlobalContext() +ExecutionContext *ExecutionEngine::pushGlobalContext() { - Scope scope(this); - Scoped<GlobalContext> g(scope, memoryManager->alloc<GlobalContext>(this)); - g->d()->callData = rootContext()->d()->callData; + pushContext(rootContext()->d()); - Q_ASSERT(currentContext() == g->d()); - return g->d(); + Q_ASSERT(current == rootContext()->d()); + return currentContext; +} + +ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *context) const +{ + Value *offset = static_cast<Value *>(context) + 1; + Q_ASSERT(offset->isInteger()); + int o = offset->integerValue(); + return o ? context - o : 0; } Heap::Object *ExecutionEngine::newObject() { - Scope scope(this); - ScopedObject object(scope, memoryManager->alloc<Object>(this)); - return object->d(); + return memoryManager->allocObject<Object>(); } Heap::Object *ExecutionEngine::newObject(InternalClass *internalClass, QV4::Object *prototype) { - Scope scope(this); - ScopedObject object(scope, memoryManager->alloc<Object>(internalClass, prototype)); - return object->d(); + return memoryManager->allocObject<Object>(internalClass, prototype); } Heap::String *ExecutionEngine::newString(const QString &s) @@ -555,29 +593,23 @@ Heap::String *ExecutionEngine::newIdentifier(const QString &text) Heap::Object *ExecutionEngine::newStringObject(const String *string) { - Scope scope(this); - Scoped<StringObject> object(scope, memoryManager->alloc<StringObject>(this, string)); - return object->d(); + return memoryManager->allocObject<StringObject>(string); } Heap::Object *ExecutionEngine::newNumberObject(double value) { - Scope scope(this); - Scoped<NumberObject> object(scope, memoryManager->alloc<NumberObject>(this, value)); - return object->d(); + return memoryManager->allocObject<NumberObject>(value); } Heap::Object *ExecutionEngine::newBooleanObject(bool b) { - Scope scope(this); - ScopedObject object(scope, memoryManager->alloc<BooleanObject>(this, b)); - return object->d(); + return memoryManager->allocObject<BooleanObject>(b); } Heap::ArrayObject *ExecutionEngine::newArrayObject(int count) { Scope scope(this); - ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(this)); + ScopedArrayObject object(scope, memoryManager->allocObject<ArrayObject>()); if (count) { if (count < 0x1000) @@ -587,39 +619,60 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(int count) return object->d(); } +Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int length) +{ + Scope scope(this); + ScopedArrayObject a(scope, memoryManager->allocObject<ArrayObject>()); + + if (length) { + size_t size = sizeof(Heap::ArrayData) + (length-1)*sizeof(Value); + Heap::SimpleArrayData *d = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size); + new (d) Heap::SimpleArrayData; + d->alloc = length; + d->type = Heap::ArrayData::Simple; + d->offset = 0; + d->len = length; + memcpy(&d->arrayData, values, length*sizeof(Value)); + a->d()->arrayData = d; + a->setArrayLengthUnchecked(length); + } + return a->d(); +} + Heap::ArrayObject *ExecutionEngine::newArrayObject(const QStringList &list) { Scope scope(this); - ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(this, list)); + ScopedArrayObject object(scope, memoryManager->allocObject<ArrayObject>(list)); return object->d(); } -Heap::ArrayObject *ExecutionEngine::newArrayObject(InternalClass *ic, Object *prototype) +Heap::ArrayObject *ExecutionEngine::newArrayObject(InternalClass *internalClass, Object *prototype) { Scope scope(this); - ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(ic, prototype)); + ScopedArrayObject object(scope, memoryManager->allocObject<ArrayObject>(internalClass, prototype)); return object->d(); } Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(const QByteArray &array) { - Scope scope(this); - Scoped<ArrayBuffer> object(scope, memoryManager->alloc<ArrayBuffer>(this, array)); - return object->d(); + return memoryManager->allocObject<ArrayBuffer>(array); +} + +Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(size_t length) +{ + return memoryManager->allocObject<ArrayBuffer>(length); } Heap::DateObject *ExecutionEngine::newDateObject(const Value &value) { - Scope scope(this); - Scoped<DateObject> object(scope, memoryManager->alloc<DateObject>(this, value)); - return object->d(); + return memoryManager->allocObject<DateObject>(value); } Heap::DateObject *ExecutionEngine::newDateObject(const QDateTime &dt) { Scope scope(this); - Scoped<DateObject> object(scope, memoryManager->alloc<DateObject>(this, dt)); + Scoped<DateObject> object(scope, memoryManager->allocObject<DateObject>(dt)); return object->d(); } @@ -640,97 +693,75 @@ Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int Heap::RegExpObject *ExecutionEngine::newRegExpObject(RegExp *re, bool global) { - Scope scope(this); - Scoped<RegExpObject> object(scope, memoryManager->alloc<RegExpObject>(this, re, global)); - return object->d(); + return memoryManager->allocObject<RegExpObject>(re, global); } Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re) { - Scope scope(this); - Scoped<RegExpObject> object(scope, memoryManager->alloc<RegExpObject>(this, re)); - return object->d(); + return memoryManager->allocObject<RegExpObject>(re); } Heap::Object *ExecutionEngine::newErrorObject(const Value &value) { - Scope scope(this); - ScopedObject object(scope, memoryManager->alloc<ErrorObject>(emptyClass, errorPrototype(), value)); - return object->d(); + return ErrorObject::create<ErrorObject>(this, value); } Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message) { - Scope scope(this); - ScopedString s(scope, newString(message)); - ScopedObject error(scope, memoryManager->alloc<SyntaxErrorObject>(this, s)); - return error->d(); + return ErrorObject::create<SyntaxErrorObject>(this, message); } Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column) { - Scope scope(this); - ScopedObject error(scope, memoryManager->alloc<SyntaxErrorObject>(this, message, fileName, line, column)); - return error->d(); + return ErrorObject::create<SyntaxErrorObject>(this, message, fileName, line, column); } Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message) { - Scope scope(this); - ScopedObject o(scope, memoryManager->alloc<ReferenceErrorObject>(this, message)); - return o->d(); + return ErrorObject::create<ReferenceErrorObject>(this, message); } -Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber, int columnNumber) +Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int line, int column) { - Scope scope(this); - ScopedObject o(scope, memoryManager->alloc<ReferenceErrorObject>(this, message, fileName, lineNumber, columnNumber)); - return o->d(); + return ErrorObject::create<ReferenceErrorObject>(this, message, fileName, line, column); } Heap::Object *ExecutionEngine::newTypeErrorObject(const QString &message) { - Scope scope(this); - ScopedObject o(scope, memoryManager->alloc<TypeErrorObject>(this, message)); - return o->d(); + return ErrorObject::create<TypeErrorObject>(this, message); } Heap::Object *ExecutionEngine::newRangeErrorObject(const QString &message) { - Scope scope(this); - ScopedObject o(scope, memoryManager->alloc<RangeErrorObject>(this, message)); - return o->d(); + return ErrorObject::create<RangeErrorObject>(this, message); } Heap::Object *ExecutionEngine::newURIErrorObject(const Value &message) { - Scope scope(this); - ScopedObject o(scope, memoryManager->alloc<URIErrorObject>(this, message)); - return o->d(); + return ErrorObject::create<URIErrorObject>(this, message); } Heap::Object *ExecutionEngine::newVariantObject(const QVariant &v) { - Scope scope(this); - ScopedObject o(scope, memoryManager->alloc<VariantObject>(this, v)); - return o->d(); + return memoryManager->allocObject<VariantObject>(v); } Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o) { Scope scope(this); - ScopedObject obj(scope, memoryManager->alloc<ForEachIteratorObject>(this, o)); + ScopedObject obj(scope, memoryManager->allocObject<ForEachIteratorObject>(o)); return obj->d(); } Heap::QmlContext *ExecutionEngine::qmlContext() const { - Heap::ExecutionContext *ctx = currentContext(); + Heap::ExecutionContext *ctx = current; + // get the correct context when we're within a builtin function if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer) - ctx = ctx->parent; + ctx = parentContext(currentContext)->d(); if (!ctx->outer) return 0; @@ -745,18 +776,13 @@ Heap::QmlContext *ExecutionEngine::qmlContext() const return static_cast<Heap::QmlContext *>(ctx); } -Heap::QmlContextWrapper *ExecutionEngine::qmlContextObject() const +QObject *ExecutionEngine::qmlScopeObject() const { Heap::QmlContext *ctx = qmlContext(); if (!ctx) return 0; - Q_ASSERT(ctx->qml); - return ctx->qml; -} -QObject *ExecutionEngine::qmlScopeObject() const -{ - return qmlContextObject()->scopeObject; + return ctx->qml->scopeObject; } ReturnedValue ExecutionEngine::qmlSingletonWrapper(String *name) @@ -782,9 +808,11 @@ ReturnedValue ExecutionEngine::qmlSingletonWrapper(String *name) QQmlContextData *ExecutionEngine::callingQmlContext() const { - Heap::QmlContextWrapper *w = qmlContextObject(); + Heap::QmlContext *ctx = qmlContext(); + if (!ctx) + return 0; - return w ? w->context.contextData() : 0; + return ctx->qml->context.contextData(); } QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const @@ -793,7 +821,7 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const ScopedString name(scope); QVector<StackFrame> stack; - ScopedContext c(scope, currentContext()); + ExecutionContext *c = currentContext; ScopedFunctionObject function(scope); while (c && frameLimit) { function = c->getFunctionObject(); @@ -813,7 +841,7 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const stack.append(frame); --frameLimit; } - c = c->d()->parent; + c = parentContext(c); } if (frameLimit && globalCode) { @@ -881,8 +909,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) return src; QUrl base; - Scope scope(this); - ScopedContext c(scope, currentContext()); + ExecutionContext *c = currentContext; while (c) { CallContext *callCtx = c->asCallContext(); if (callCtx && callCtx->d()->function) { @@ -890,7 +917,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) base.setUrl(callCtx->d()->function->function->sourceFile()); break; } - c = c->d()->parent; + c = parentContext(c); } if (base.isEmpty() && globalCode) @@ -920,10 +947,10 @@ void ExecutionEngine::requireArgumentsAccessors(int n) memcpy(argumentsAccessors, oldAccessors, oldSize*sizeof(Property)); delete [] oldAccessors; } - ScopedContext global(scope, scope.engine->rootContext()); + ExecutionContext *global = rootContext(); for (int i = oldSize; i < nArgumentsAccessors; ++i) { - argumentsAccessors[i].value = ScopedValue(scope, memoryManager->alloc<ArgumentsGetterFunction>(global, i)); - argumentsAccessors[i].set = ScopedValue(scope, memoryManager->alloc<ArgumentsSetterFunction>(global, i)); + argumentsAccessors[i].value = ScopedValue(scope, memoryManager->allocObject<ArgumentsGetterFunction>(global, i)); + argumentsAccessors[i].set = ScopedValue(scope, memoryManager->allocObject<ArgumentsSetterFunction>(global, i)); } } } @@ -940,16 +967,6 @@ void ExecutionEngine::markObjects() setter->mark(this); } - Heap::ExecutionContext *c = currentContext(); - while (c) { - Q_ASSERT(c->inUse()); - if (!c->isMarked()) { - c->setMarkBit(); - c->vtable()->markObjects(c, this); - } - c = c->parent; - } - classPool->markObjects(this); for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd(); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 90564a9652..ffcd904013 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -78,7 +78,6 @@ private: friend struct Heap::ExecutionContext; public: Heap::ExecutionContext *current; - Heap::ExecutionContext *currentContext() const { return current; } Value *jsStackTop; quint32 hasException; @@ -88,6 +87,7 @@ public: ExecutableAllocator *regExpAllocator; QScopedPointer<EvalISelFactory> iselFactory; + ExecutionContext *currentContext; Value *jsStackLimit; quintptr cStackLimit; @@ -127,7 +127,8 @@ public: QV8Engine *v8Engine; enum JSObjects { - RootContect, + RootContext, + IntegerNull, // Has to come after the RootContext to make the context stack safe ObjectProto, ArrayProto, StringProto, @@ -148,6 +149,7 @@ public: ArrayBufferProto, DataViewProto, ValueTypeProto, + SignalHandlerProto, Object_Ctor, String_Ctor, @@ -168,13 +170,14 @@ public: DataView_Ctor, Eval_Function, + GetStack_Function, ThrowerObject, NJSObjects }; Value *jsObjects; enum { NTypedArrayTypes = 9 }; // == TypedArray::NValues, avoid header dependency - GlobalContext *rootContext() const { return reinterpret_cast<GlobalContext *>(jsObjects + RootContect); } + GlobalContext *rootContext() const { return reinterpret_cast<GlobalContext *>(jsObjects + RootContext); } FunctionObject *objectCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Object_Ctor); } FunctionObject *stringCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + String_Ctor); } FunctionObject *numberCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Number_Ctor); } @@ -217,22 +220,30 @@ public: Object *typedArrayPrototype; Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); } + Object *signalHandlerPrototype() const { return reinterpret_cast<Object *>(jsObjects + SignalHandlerProto); } InternalClassPool *classPool; InternalClass *emptyClass; InternalClass *arrayClass; + InternalClass *stringClass; InternalClass *functionClass; InternalClass *simpleScriptFunctionClass; InternalClass *protoClass; InternalClass *regExpExecArrayClass; + InternalClass *regExpObjectClass; InternalClass *argumentsObjectClass; InternalClass *strictArgumentsObjectClass; + InternalClass *errorClass; + InternalClass *errorClassWithMessage; + InternalClass *errorProtoClass; + EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); } + FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); } FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); } Property *argumentsAccessors; @@ -347,9 +358,11 @@ public: void enableDebugger(); void enableProfiler(); - Heap::ExecutionContext *pushGlobalContext(); - void pushContext(CallContext *context); - Heap::ExecutionContext *popContext(); + ExecutionContext *pushGlobalContext(); + void pushContext(Heap::ExecutionContext *context); + void pushContext(ExecutionContext *context); + void popContext(); + ExecutionContext *parentContext(ExecutionContext *context) const; Heap::Object *newObject(); Heap::Object *newObject(InternalClass *internalClass, Object *prototype); @@ -362,10 +375,12 @@ public: Heap::Object *newBooleanObject(bool b); Heap::ArrayObject *newArrayObject(int count = 0); + Heap::ArrayObject *newArrayObject(const Value *values, int length); Heap::ArrayObject *newArrayObject(const QStringList &list); Heap::ArrayObject *newArrayObject(InternalClass *ic, Object *prototype); Heap::ArrayBuffer *newArrayBuffer(const QByteArray &array); + Heap::ArrayBuffer *newArrayBuffer(size_t length); Heap::DateObject *newDateObject(const Value &value); Heap::DateObject *newDateObject(const QDateTime &dt); @@ -378,7 +393,7 @@ public: Heap::Object *newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column); Heap::Object *newSyntaxErrorObject(const QString &message); Heap::Object *newReferenceErrorObject(const QString &message); - Heap::Object *newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber, int columnNumber); + Heap::Object *newReferenceErrorObject(const QString &message, const QString &fileName, int line, int column); Heap::Object *newTypeErrorObject(const QString &message); Heap::Object *newRangeErrorObject(const QString &message); Heap::Object *newURIErrorObject(const Value &message); @@ -388,7 +403,6 @@ public: Heap::Object *newForEachIteratorObject(Object *o); Heap::QmlContext *qmlContext() const; - QV4::Heap::QmlContextWrapper *qmlContextObject() const; QObject *qmlScopeObject() const; ReturnedValue qmlSingletonWrapper(String *name); QQmlContextData *callingQmlContext() const; @@ -442,36 +456,33 @@ public: void assertObjectBelongsToEngine(const Heap::Base &baseObject); }; -inline void ExecutionEngine::pushContext(CallContext *context) +inline void ExecutionEngine::pushContext(Heap::ExecutionContext *context) { - Q_ASSERT(current && context && context->d()); - context->d()->parent = current; - current = context->d(); + Q_ASSERT(currentContext && context); + Value *v = jsAlloca(2); + v[0] = Encode(context); + v[1] = Encode((int)(v - static_cast<Value *>(currentContext))); + currentContext = static_cast<ExecutionContext *>(v); + current = currentContext->d(); } -inline Heap::ExecutionContext *ExecutionEngine::popContext() +inline void ExecutionEngine::pushContext(ExecutionContext *context) { - Q_ASSERT(current->parent); - current = current->parent; - Q_ASSERT(current); - return current; + pushContext(context->d()); } -inline -Heap::ExecutionContext::ExecutionContext(ExecutionEngine *engine, ContextType t) - : engine(engine) - , parent(engine->currentContext()) - , outer(0) - , lookups(0) - , compilationUnit(0) - , type(t) - , strictMode(false) - , lineNumber(-1) + +inline void ExecutionEngine::popContext() { - engine->current = this; + Q_ASSERT(jsStackTop > currentContext); + QV4::Value *offset = (currentContext + 1); + Q_ASSERT(offset->isInteger()); + int o = offset->integerValue(); + Q_ASSERT(o); + currentContext -= o; + current = currentContext->d(); } - inline void Heap::Base::mark(QV4::ExecutionEngine *engine) { @@ -487,11 +498,12 @@ void Heap::Base::mark(QV4::ExecutionEngine *engine) inline void Value::mark(ExecutionEngine *e) { - if (!_val) + if (!isManaged()) return; - Managed *m = as<Managed>(); - if (m) - m->d()->mark(e); + + Heap::Base *o = heapObject(); + if (o) + o->mark(e); } diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index a6c2a25b91..87b7a88a2b 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -61,72 +61,49 @@ using namespace QV4; -Heap::ErrorObject::ErrorObject(InternalClass *ic, QV4::Object *prototype) - : Heap::Object(ic, prototype) - , stack(Q_NULLPTR) +Heap::ErrorObject::ErrorObject() { - Scope scope(ic->engine); + Scope scope(internalClass->engine); Scoped<QV4::ErrorObject> e(scope, this); - ScopedString s(scope, scope.engine->newString(QStringLiteral("Error"))); - e->defineDefaultProperty(QStringLiteral("name"), s); -} - -Heap::ErrorObject::ErrorObject(InternalClass *ic, QV4::Object *prototype, const Value &message, ErrorType t) - : Heap::Object(ic, prototype) -{ - errorType = t; + if (internalClass == scope.engine->errorProtoClass) + return; - Scope scope(ic->engine); - Scoped<QV4::ErrorObject> e(scope, this); - - e->defineAccessorProperty(QStringLiteral("stack"), QV4::ErrorObject::method_get_stack, 0); - - if (!message.isUndefined()) - e->defineDefaultProperty(QStringLiteral("message"), message); - ScopedString s(scope); - e->defineDefaultProperty(QStringLiteral("name"), (s = scope.engine->newString(e->className()))); - - e->d()->stackTrace = scope.engine->stackTrace(); - if (!e->d()->stackTrace.isEmpty()) { - e->defineDefaultProperty(QStringLiteral("fileName"), (s = scope.engine->newString(e->d()->stackTrace.at(0).source))); - e->defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(e->d()->stackTrace.at(0).line)); - } + *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); + *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); + *propertyData(QV4::ErrorObject::Index_FileName) = Encode::undefined(); + *propertyData(QV4::ErrorObject::Index_LineNumber) = Encode::undefined(); } -Heap::ErrorObject::ErrorObject(InternalClass *ic, QV4::Object *prototype, const QString &message, ErrorObject::ErrorType t) - : Heap::Object(ic, prototype) +Heap::ErrorObject::ErrorObject(const Value &message, ErrorType t) { errorType = t; - Scope scope(ic->engine); + Scope scope(internalClass->engine); Scoped<QV4::ErrorObject> e(scope, this); - ScopedString s(scope); - - e->defineAccessorProperty(QStringLiteral("stack"), QV4::ErrorObject::method_get_stack, 0); - ScopedValue v(scope, scope.engine->newString(message)); - e->defineDefaultProperty(QStringLiteral("message"), v); - e->defineDefaultProperty(QStringLiteral("name"), (s = scope.engine->newString(e->className()))); + *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); + *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); e->d()->stackTrace = scope.engine->stackTrace(); if (!e->d()->stackTrace.isEmpty()) { - e->defineDefaultProperty(QStringLiteral("fileName"), (s = scope.engine->newString(e->d()->stackTrace.at(0).source))); - e->defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(e->d()->stackTrace.at(0).line)); + *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace.at(0).source); + *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace.at(0).line); } + + if (!message.isUndefined()) + *propertyData(QV4::ErrorObject::Index_Message) = message; } -Heap::ErrorObject::ErrorObject(InternalClass *ic, QV4::Object *prototype, const QString &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t) - : Heap::Object(ic, prototype) +Heap::ErrorObject::ErrorObject(const Value &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t) { errorType = t; - Scope scope(ic->engine); + Scope scope(internalClass->engine); Scoped<QV4::ErrorObject> e(scope, this); - ScopedString s(scope); - e->defineAccessorProperty(QStringLiteral("stack"), QV4::ErrorObject::method_get_stack, 0); - e->defineDefaultProperty(QStringLiteral("name"), (s = scope.engine->newString(e->className()))); + *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); + *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); e->d()->stackTrace = scope.engine->stackTrace(); StackFrame frame; @@ -136,12 +113,33 @@ Heap::ErrorObject::ErrorObject(InternalClass *ic, QV4::Object *prototype, const e->d()->stackTrace.prepend(frame); if (!e->d()->stackTrace.isEmpty()) { - e->defineDefaultProperty(QStringLiteral("fileName"), (s = scope.engine->newString(e->d()->stackTrace.at(0).source))); - e->defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(e->d()->stackTrace.at(0).line)); + *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace.at(0).source); + *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace.at(0).line); } - ScopedValue v(scope, scope.engine->newString(message)); - e->defineDefaultProperty(QStringLiteral("message"), v); + if (!message.isUndefined()) + *propertyData(QV4::ErrorObject::Index_Message) = message; +} + +const char *ErrorObject::className(Heap::ErrorObject::ErrorType t) +{ + switch (t) { + case Heap::ErrorObject::Error: + return "Error"; + case Heap::ErrorObject::EvalError: + return "EvalError"; + case Heap::ErrorObject::RangeError: + return "RangeError"; + case Heap::ErrorObject::ReferenceError: + return "ReferenceError"; + case Heap::ErrorObject::SyntaxError: + return "SyntaxError"; + case Heap::ErrorObject::TypeError: + return "TypeError"; + case Heap::ErrorObject::URIError: + return "URIError"; + } + Q_UNREACHABLE(); } ReturnedValue ErrorObject::method_get_stack(CallContext *ctx) @@ -181,58 +179,43 @@ DEFINE_OBJECT_VTABLE(ErrorObject); DEFINE_OBJECT_VTABLE(SyntaxErrorObject); -Heap::SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const Value &msg) - : Heap::ErrorObject(engine->emptyClass, engine->syntaxErrorPrototype(), msg, SyntaxError) -{ -} - -Heap::SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) - : Heap::ErrorObject(engine->emptyClass, engine->syntaxErrorPrototype(), msg, fileName, lineNumber, columnNumber, SyntaxError) -{ -} - -Heap::EvalErrorObject::EvalErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->evalErrorPrototype(), message, EvalError) -{ -} - -Heap::RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->rangeErrorPrototype(), message, RangeError) +Heap::SyntaxErrorObject::SyntaxErrorObject(const Value &msg) + : Heap::ErrorObject(msg, SyntaxError) { } -Heap::RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const QString &message) - : Heap::ErrorObject(engine->emptyClass, engine->rangeErrorPrototype(), message, RangeError) +Heap::SyntaxErrorObject::SyntaxErrorObject(const Value &msg, const QString &fileName, int lineNumber, int columnNumber) + : Heap::ErrorObject(msg, fileName, lineNumber, columnNumber, SyntaxError) { } -Heap::ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype(), message, ReferenceError) +Heap::EvalErrorObject::EvalErrorObject(const Value &message) + : Heap::ErrorObject(message, EvalError) { } -Heap::ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &message) - : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype(), message, ReferenceError) +Heap::RangeErrorObject::RangeErrorObject(const Value &message) + : Heap::ErrorObject(message, RangeError) { } -Heap::ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) - : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype(), msg, fileName, lineNumber, columnNumber, ReferenceError) +Heap::ReferenceErrorObject::ReferenceErrorObject(const Value &message) + : Heap::ErrorObject(message, ReferenceError) { } -Heap::TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->typeErrorPrototype(), message, TypeError) +Heap::ReferenceErrorObject::ReferenceErrorObject(const Value &msg, const QString &fileName, int lineNumber, int columnNumber) + : Heap::ErrorObject(msg, fileName, lineNumber, columnNumber, ReferenceError) { } -Heap::TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const QString &message) - : Heap::ErrorObject(engine->emptyClass, engine->typeErrorPrototype(), message, TypeError) +Heap::TypeErrorObject::TypeErrorObject(const Value &message) + : Heap::ErrorObject(message, TypeError) { } -Heap::URIErrorObject::URIErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->uRIErrorPrototype(), message, URIError) +Heap::URIErrorObject::URIErrorObject(const Value &message) + : Heap::ErrorObject(message, URIError) { } @@ -258,7 +241,7 @@ ReturnedValue ErrorCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const ErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return Encode(scope.engine->newErrorObject(v)); + return ErrorObject::create<ErrorObject>(scope.engine, v)->asReturnedValue(); } ReturnedValue ErrorCtor::call(const Managed *that, CallData *callData) @@ -275,7 +258,7 @@ ReturnedValue EvalErrorCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const EvalErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return (scope.engine->memoryManager->alloc<EvalErrorObject>(scope.engine, v))->asReturnedValue(); + return ErrorObject::create<EvalErrorObject>(scope.engine, v)->asReturnedValue(); } Heap::RangeErrorCtor::RangeErrorCtor(QV4::ExecutionContext *scope) @@ -287,7 +270,7 @@ ReturnedValue RangeErrorCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const RangeErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return (scope.engine->memoryManager->alloc<RangeErrorObject>(scope.engine, v))->asReturnedValue(); + return ErrorObject::create<RangeErrorObject>(scope.engine, v)->asReturnedValue(); } Heap::ReferenceErrorCtor::ReferenceErrorCtor(QV4::ExecutionContext *scope) @@ -299,7 +282,7 @@ ReturnedValue ReferenceErrorCtor::construct(const Managed *m, CallData *callData { Scope scope(static_cast<const ReferenceErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return (scope.engine->memoryManager->alloc<ReferenceErrorObject>(scope.engine, v))->asReturnedValue(); + return ErrorObject::create<ReferenceErrorObject>(scope.engine, v)->asReturnedValue(); } Heap::SyntaxErrorCtor::SyntaxErrorCtor(QV4::ExecutionContext *scope) @@ -311,7 +294,7 @@ ReturnedValue SyntaxErrorCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const SyntaxErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return (scope.engine->memoryManager->alloc<SyntaxErrorObject>(scope.engine, v))->asReturnedValue(); + return ErrorObject::create<SyntaxErrorObject>(scope.engine, v)->asReturnedValue(); } Heap::TypeErrorCtor::TypeErrorCtor(QV4::ExecutionContext *scope) @@ -323,7 +306,7 @@ ReturnedValue TypeErrorCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const TypeErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return (scope.engine->memoryManager->alloc<TypeErrorObject>(scope.engine, v))->asReturnedValue(); + return ErrorObject::create<TypeErrorObject>(scope.engine, v)->asReturnedValue(); } Heap::URIErrorCtor::URIErrorCtor(QV4::ExecutionContext *scope) @@ -335,19 +318,21 @@ ReturnedValue URIErrorCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const URIErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return (scope.engine->memoryManager->alloc<URIErrorObject>(scope.engine, v))->asReturnedValue(); + return ErrorObject::create<URIErrorObject>(scope.engine, v)->asReturnedValue(); } -void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj) +void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t) { Scope scope(engine); ScopedString s(scope); ScopedObject o(scope); ctor->defineReadonlyProperty(engine->id_prototype(), (o = obj)); ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); - obj->defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - obj->defineDefaultProperty(engine->id_toString(), method_toString, 0); - obj->defineDefaultProperty(QStringLiteral("message"), (s = engine->newString())); + *obj->propertyData(Index_Constructor) = ctor; + *obj->propertyData(Index_Message) = engine->id_empty(); + *obj->propertyData(Index_Name) = engine->newString(QString::fromLatin1(ErrorObject::className(t))); + if (t == Heap::ErrorObject::Error) + obj->defineDefaultProperty(engine->id_toString(), method_toString, 0); } ReturnedValue ErrorPrototype::method_toString(CallContext *ctx) diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index e0fbcb4d8d..7f3babaa79 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -35,6 +35,7 @@ #include "qv4object_p.h" #include "qv4functionobject_p.h" +#include "qv4string_p.h" QT_BEGIN_NAMESPACE @@ -55,10 +56,9 @@ struct ErrorObject : Object { URIError }; - ErrorObject(InternalClass *ic, QV4::Object *prototype); - ErrorObject(InternalClass *ic, QV4::Object *prototype, const Value &message, ErrorType t = Error); - ErrorObject(InternalClass *ic, QV4::Object *prototype, const QString &message, ErrorType t = Error); - ErrorObject(InternalClass *ic, QV4::Object *prototype, const QString &message, const QString &fileName, int line, int column, ErrorType t = Error); + ErrorObject(); + ErrorObject(const Value &message, ErrorType t = Error); + ErrorObject(const Value &message, const QString &fileName, int line, int column, ErrorType t = Error); ErrorType errorType; StackTrace stackTrace; @@ -66,32 +66,29 @@ struct ErrorObject : Object { }; struct EvalErrorObject : ErrorObject { - EvalErrorObject(ExecutionEngine *engine, const Value &message); + EvalErrorObject(const Value &message); }; struct RangeErrorObject : ErrorObject { - RangeErrorObject(ExecutionEngine *engine, const Value &message); - RangeErrorObject(ExecutionEngine *engine, const QString &msg); + RangeErrorObject(const Value &message); }; struct ReferenceErrorObject : ErrorObject { - ReferenceErrorObject(ExecutionEngine *engine, const Value &message); - ReferenceErrorObject(ExecutionEngine *engine, const QString &msg); - ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber); + ReferenceErrorObject(const Value &message); + ReferenceErrorObject(const Value &msg, const QString &fileName, int lineNumber, int columnNumber); }; struct SyntaxErrorObject : ErrorObject { - SyntaxErrorObject(ExecutionEngine *engine, const Value &message); - SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber); + SyntaxErrorObject(const Value &message); + SyntaxErrorObject(const Value &msg, const QString &fileName, int lineNumber, int columnNumber); }; struct TypeErrorObject : ErrorObject { - TypeErrorObject(ExecutionEngine *engine, const Value &message); - TypeErrorObject(ExecutionEngine *engine, const QString &msg); + TypeErrorObject(const Value &message); }; struct URIErrorObject : ErrorObject { - URIErrorObject(ExecutionEngine *engine, const Value &message); + URIErrorObject(const Value &message); }; struct ErrorCtor : Heap::FunctionObject { @@ -130,12 +127,30 @@ struct ErrorObject: Object { IsErrorObject = true }; + enum { + Index_Stack = 0, // Accessor Property + Index_FileName = 2, + Index_LineNumber = 3, + Index_Message = 4 + }; + V4_OBJECT2(ErrorObject, Object) Q_MANAGED_TYPE(ErrorObject) + V4_INTERNALCLASS(errorClass) + V4_PROTOTYPE(errorPrototype) V4_NEEDS_DESTROY + template <typename T> + static Heap::Object *create(ExecutionEngine *e, const Value &message); + template <typename T> + static Heap::Object *create(ExecutionEngine *e, const QString &message); + template <typename T> + static Heap::Object *create(ExecutionEngine *e, const QString &message, const QString &filename, int line, int column); + SyntaxErrorObject *asSyntaxError(); + static const char *className(Heap::ErrorObject::ErrorType t); + static ReturnedValue method_get_stack(CallContext *ctx); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; @@ -147,34 +162,40 @@ inline const ErrorObject *Value::as() const { struct EvalErrorObject: ErrorObject { typedef Heap::EvalErrorObject Data; + V4_PROTOTYPE(evalErrorPrototype) const Data *d() const { return static_cast<const Data *>(ErrorObject::d()); } Data *d() { return static_cast<Data *>(ErrorObject::d()); } }; struct RangeErrorObject: ErrorObject { typedef Heap::RangeErrorObject Data; + V4_PROTOTYPE(rangeErrorPrototype) const Data *d() const { return static_cast<const Data *>(ErrorObject::d()); } Data *d() { return static_cast<Data *>(ErrorObject::d()); } }; struct ReferenceErrorObject: ErrorObject { typedef Heap::ReferenceErrorObject Data; + V4_PROTOTYPE(referenceErrorPrototype) const Data *d() const { return static_cast<const Data *>(ErrorObject::d()); } Data *d() { return static_cast<Data *>(ErrorObject::d()); } }; struct SyntaxErrorObject: ErrorObject { V4_OBJECT2(SyntaxErrorObject, ErrorObject) + V4_PROTOTYPE(syntaxErrorPrototype) }; struct TypeErrorObject: ErrorObject { typedef Heap::TypeErrorObject Data; + V4_PROTOTYPE(typeErrorPrototype) const Data *d() const { return static_cast<const Data *>(ErrorObject::d()); } Data *d() { return static_cast<Data *>(ErrorObject::d()); } }; struct URIErrorObject: ErrorObject { typedef Heap::URIErrorObject Data; + V4_PROTOTYPE(uRIErrorPrototype) const Data *d() const { return static_cast<const Data *>(ErrorObject::d()); } Data *d() { return static_cast<Data *>(ErrorObject::d()); } }; @@ -232,40 +253,45 @@ struct URIErrorCtor: ErrorCtor struct ErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { init(engine, ctor, this); } + enum { + Index_Constructor = 0, + Index_Message = 1, + Index_Name = 2 + }; + void init(ExecutionEngine *engine, Object *ctor) { init(engine, ctor, this, Heap::ErrorObject::Error); } - static void init(ExecutionEngine *engine, Object *ctor, Object *obj); + static void init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t); static ReturnedValue method_toString(CallContext *ctx); }; struct EvalErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this, Heap::ErrorObject::EvalError); } }; struct RangeErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this, Heap::ErrorObject::RangeError); } }; struct ReferenceErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this, Heap::ErrorObject::ReferenceError); } }; struct SyntaxErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this, Heap::ErrorObject::SyntaxError); } }; struct TypeErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this, Heap::ErrorObject::TypeError); } }; struct URIErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this, Heap::ErrorObject::URIError); } }; @@ -274,6 +300,25 @@ inline SyntaxErrorObject *ErrorObject::asSyntaxError() return d()->errorType == QV4::Heap::ErrorObject::SyntaxError ? static_cast<SyntaxErrorObject *>(this) : 0; } + +template <typename T> +Heap::Object *ErrorObject::create(ExecutionEngine *e, const Value &message) { + return e->memoryManager->allocObject<T>(message.isUndefined() ? e->errorClass : e->errorClassWithMessage, T::defaultPrototype(e), message); +} +template <typename T> +Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message) { + Scope scope(e); + ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue()); + return e->memoryManager->allocObject<T>(v->isUndefined() ? e->errorClass : e->errorClassWithMessage, T::defaultPrototype(e), v); +} +template <typename T> +Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message, const QString &filename, int line, int column) { + Scope scope(e); + ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue()); + return e->memoryManager->allocObject<T>(v->isUndefined() ? e->errorClass : e->errorClassWithMessage, T::defaultPrototype(e), v, filename, line, column); +} + + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 98a4490211..66b2125a4f 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -70,14 +70,45 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, arg = mm->alloc<String>(mm, arg->d(), engine->newString(QString(0xfffe))); } } + nFormals = compiledFunction->nFormals; const quint32 *localsIndices = compiledFunction->localsTable(); for (quint32 i = 0; i < compiledFunction->nLocals; ++i) internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); + + activationRequired = compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject)); } Function::~Function() { } +void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> ¶meters) +{ + internalClass = engine->emptyClass; + + // iterate backwards, so we get the right ordering for duplicate names + Scope scope(engine); + ScopedString arg(scope); + for (int i = parameters.size() - 1; i >= 0; --i) { + arg = engine->newString(QString::fromUtf8(parameters.at(i))); + while (1) { + InternalClass *newClass = internalClass->addMember(arg, Attr_NotConfigurable); + if (newClass != internalClass) { + internalClass = newClass; + break; + } + // duplicate arguments, need some trick to store them + arg = engine->memoryManager->alloc<String>(engine->memoryManager, arg->d(), engine->newString(QString(0xfffe))); + } + } + nFormals = parameters.size(); + + const quint32 *localsIndices = compiledFunction->localsTable(); + for (quint32 i = 0; i < compiledFunction->nLocals; ++i) + internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); + + activationRequired = true; +} + QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 10a03bca94..534aa1b750 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -49,11 +49,16 @@ struct Q_QML_EXPORT Function { // first nArguments names in internalClass are the actual arguments InternalClass *internalClass; + uint nFormals; + bool activationRequired; Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function, ReturnedValue (*codePtr)(ExecutionEngine *, const uchar *)); ~Function(); + // used when dynamically assigning signal handlers (QQmlConnection) + void updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> ¶meters); + inline Heap::String *name() { return compilationUnit->runtimeStrings[compiledFunction->nameIndex]; } @@ -64,7 +69,7 @@ struct Q_QML_EXPORT Function { inline bool isNamedExpression() const { return compiledFunction->flags & CompiledData::Function::IsNamedExpression; } inline bool needsActivation() const - { return compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject)); } + { return activationRequired; } }; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 6412e65fa9..a94c3f6db5 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -63,8 +63,7 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(FunctionObject); Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, QV4::String *name, bool createProto) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) - , scope(scope->d()) + : scope(scope->d()) , function(Q_NULLPTR) { Scope s(scope->engine()); @@ -73,8 +72,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, QV4::String * } Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, Function *function, bool createProto) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) - , scope(scope->d()) + : scope(scope->d()) , function(Q_NULLPTR) { Scope s(scope->engine()); @@ -84,8 +82,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, Function *fun } Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const QString &name, bool createProto) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) - , scope(scope->d()) + : scope(scope->d()) , function(Q_NULLPTR) { Scope s(scope->engine()); @@ -95,8 +92,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const QString } Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto) - : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype()) - , scope(scope) + : scope(scope) , function(Q_NULLPTR) { Scope s(scope->engine); @@ -106,8 +102,7 @@ Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const QString &nam } Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const ReturnedValue name) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) - , scope(scope->d()) + : scope(scope->d()) , function(Q_NULLPTR) { Scope s(scope); @@ -117,8 +112,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const Returne } Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValue name) - : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype()) - , scope(scope) + : scope(scope) , function(Q_NULLPTR) { Scope s(scope->engine); @@ -127,15 +121,12 @@ Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValu f->init(n, false); } -Heap::FunctionObject::FunctionObject(InternalClass *ic, QV4::Object *prototype) - : Heap::Object(ic, prototype) - , scope(ic->engine->rootContext()->d()) +Heap::FunctionObject::FunctionObject() + : scope(internalClass->engine->rootContext()->d()) , function(Q_NULLPTR) { - Scope scope(ic->engine); - ScopedObject o(scope, this); - o->ensureMemberIndex(ic->engine, Index_Prototype); - memberData->data[Index_Prototype] = Encode::undefined(); + Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype); + *propertyData(Index_Prototype) = Encode::undefined(); } @@ -150,14 +141,14 @@ void FunctionObject::init(String *n, bool createProto) Scope s(internalClass()->engine); ScopedValue protectThis(s, this); - ensureMemberIndex(s.engine, Heap::FunctionObject::Index_Prototype); + Q_ASSERT(internalClass() && internalClass()->find(s.engine->id_prototype()) == Heap::FunctionObject::Index_Prototype); if (createProto) { ScopedObject proto(s, scope()->engine->newObject(s.engine->protoClass, s.engine->objectPrototype())); - proto->ensureMemberIndex(s.engine, Heap::FunctionObject::Index_ProtoConstructor); - proto->memberData()->data[Heap::FunctionObject::Index_ProtoConstructor] = this->asReturnedValue(); - memberData()->data[Heap::FunctionObject::Index_Prototype] = proto.asReturnedValue(); + Q_ASSERT(s.engine->protoClass->find(s.engine->id_constructor()) == Heap::FunctionObject::Index_ProtoConstructor); + *proto->propertyData(Heap::FunctionObject::Index_ProtoConstructor) = this->asReturnedValue(); + *propertyData(Heap::FunctionObject::Index_Prototype) = proto.asReturnedValue(); } else { - memberData()->data[Heap::FunctionObject::Index_Prototype] = Encode::undefined(); + *propertyData(Heap::FunctionObject::Index_Prototype) = Encode::undefined(); } ScopedValue v(s, n); @@ -202,10 +193,28 @@ Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *sco function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith || function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount || function->isNamedExpression()) - return scope->d()->engine->memoryManager->alloc<ScriptFunction>(scope, function); - return scope->d()->engine->memoryManager->alloc<SimpleScriptFunction>(scope, function, createProto); + return scope->d()->engine->memoryManager->allocObject<ScriptFunction>(scope, function); + return scope->d()->engine->memoryManager->allocObject<SimpleScriptFunction>(scope, function, createProto); } +Heap::FunctionObject *FunctionObject::createQmlFunction(QQmlContextData *qmlContext, QObject *scopeObject, Function *runtimeFunction, const QList<QByteArray> &signalParameters, QString *error) +{ + ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine); + QV4::Scope valueScope(engine); + ExecutionContext *global = valueScope.engine->rootContext(); + QV4::Scoped<QmlContext> wrapperContext(valueScope, global->newQmlContext(qmlContext, scopeObject)); + + if (!signalParameters.isEmpty()) { + if (error) + QQmlPropertyCache::signalParameterStringForJS(engine, signalParameters, error); + runtimeFunction->updateInternalClass(engine, signalParameters); + } + + QV4::ScopedFunctionObject function(valueScope, QV4::FunctionObject::createScriptFunction(wrapperContext, runtimeFunction)); + return function->d(); +} + + bool FunctionObject::isBinding() const { return d()->vtable() == QQmlBindingFunction::staticVTable(); @@ -240,7 +249,7 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) { Scope scope(static_cast<const Object *>(that)->engine()); Scoped<FunctionCtor> f(scope, static_cast<const FunctionCtor *>(that)); - ScopedContext ctx(scope, scope.engine->currentContext()); + QString arguments; QString body; if (callData->argc > 0) { @@ -251,7 +260,7 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) } body = callData->args[callData->argc - 1].toQString(); } - if (ctx->d()->engine->hasException) + if (scope.engine->hasException) return Encode::undefined(); QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1String("}"); @@ -281,7 +290,7 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit = isel->compile(); Function *vmf = compilationUnit->linkToEngine(scope.engine); - ScopedContext global(scope, scope.engine->rootContext()); + ExecutionContext *global = scope.engine->rootContext(); return FunctionObject::createScriptFunction(global, vmf)->asReturnedValue(); } @@ -293,8 +302,7 @@ ReturnedValue FunctionCtor::call(const Managed *that, CallData *callData) DEFINE_OBJECT_VTABLE(FunctionPrototype); -Heap::FunctionPrototype::FunctionPrototype(InternalClass *ic, QV4::Object *prototype) - : Heap::FunctionObject(ic, prototype) +Heap::FunctionPrototype::FunctionPrototype() { } @@ -392,12 +400,12 @@ ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) ScopedValue boundThis(scope, ctx->argument(0)); Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0); if (ctx->argc() > 1) { - boundArgs = MemberData::reallocate(scope.engine, 0, ctx->argc() - 1); + boundArgs = MemberData::allocate(scope.engine, ctx->argc() - 1); boundArgs->d()->size = ctx->argc() - 1; memcpy(boundArgs->data(), ctx->args() + 1, (ctx->argc() - 1)*sizeof(Value)); } - ScopedContext global(scope, scope.engine->rootContext()); + ExecutionContext *global = scope.engine->rootContext(); return BoundFunction::create(global, target, boundThis, boundArgs)->asReturnedValue(); } @@ -416,17 +424,18 @@ ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData) CHECK_STACK_LIMITS(v4); Scope scope(v4); + ExecutionContextSaver ctxSaver(scope); + Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); InternalClass *ic = scope.engine->emptyClass; ScopedObject proto(scope, f->protoForConstructor()); ScopedObject obj(scope, v4->newObject(ic, proto)); - ScopedContext context(scope, v4->currentContext()); callData->thisObject = obj.asReturnedValue(); - Scoped<CallContext> ctx(scope, context->newCallContext(f, callData)); + Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData)); + v4->pushContext(ctx); - ExecutionContextSaver ctxSaver(scope, context); ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); if (f->function()->compiledFunction->hasQmlDependencies()) @@ -448,12 +457,12 @@ ReturnedValue ScriptFunction::call(const Managed *that, CallData *callData) CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); - ScopedContext context(scope, v4->currentContext()); + ExecutionContextSaver ctxSaver(scope); - Scoped<CallContext> ctx(scope, context->newCallContext(f, callData)); + Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); + Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData)); + v4->pushContext(ctx); - ExecutionContextSaver ctxSaver(scope, context); ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); if (f->function()->compiledFunction->hasQmlDependencies()) @@ -465,7 +474,6 @@ ReturnedValue ScriptFunction::call(const Managed *that, CallData *callData) DEFINE_OBJECT_VTABLE(SimpleScriptFunction); Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, Function *function, bool createProto) - : Heap::FunctionObject(function->compilationUnit->engine->simpleScriptFunctionClass, function->compilationUnit->engine->functionPrototype()) { this->scope = scope->d(); @@ -482,9 +490,10 @@ Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, F f->init(name, createProto); f->defineReadonlyProperty(scope->d()->engine->id_length(), Primitive::fromInt32(f->formalParameterCount())); } else { - f->ensureMemberIndex(s.engine, Index_Length); - memberData->data[Index_Name] = function->name(); - memberData->data[Index_Length] = Primitive::fromInt32(f->formalParameterCount()); + Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()) == Index_Length); + Q_ASSERT(internalClass && internalClass->find(s.engine->id_name()) == Index_Name); + *propertyData(Index_Name) = function->name(); + *propertyData(Index_Length) = Primitive::fromInt32(f->formalParameterCount()); } if (scope->d()->strictMode) { @@ -504,14 +513,14 @@ ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *cal CHECK_STACK_LIMITS(v4); Scope scope(v4); + ExecutionContextSaver ctxSaver(scope); + Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); InternalClass *ic = scope.engine->emptyClass; ScopedObject proto(scope, f->protoForConstructor()); callData->thisObject = v4->newObject(ic, proto); - ExecutionContextSaver ctxSaver(scope, v4->currentContext()); - CallContext::Data ctx(v4); #ifndef QT_NO_DEBUG ctx.mm_data = 0; // make sure we don't run into the assertion in setVTable when allocating a context on the stack @@ -526,7 +535,8 @@ ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *cal ctx.locals = scope.alloc(f->varCount()); for (int i = callData->argc; i < (int)f->formalParameterCount(); ++i) callData->args[i] = Encode::undefined(); - Q_ASSERT(v4->currentContext() == &ctx); + v4->pushContext(&ctx); + Q_ASSERT(v4->current == &ctx); ScopedObject result(scope, Q_V4_PROFILE(v4, f->function())); @@ -546,9 +556,9 @@ ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); + ExecutionContextSaver ctxSaver(scope); - ExecutionContextSaver ctxSaver(scope, v4->currentContext()); + Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); CallContext::Data ctx(v4); #ifndef QT_NO_DEBUG @@ -564,7 +574,8 @@ ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData ctx.locals = scope.alloc(f->varCount()); for (int i = callData->argc; i < (int)f->formalParameterCount(); ++i) callData->args[i] = Encode::undefined(); - Q_ASSERT(v4->currentContext() == &ctx); + v4->pushContext(&ctx); + Q_ASSERT(v4->current == &ctx); ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); @@ -607,7 +618,7 @@ ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData) CHECK_STACK_LIMITS(v4); Scope scope(v4); - ExecutionContextSaver ctxSaver(scope, v4->currentContext()); + ExecutionContextSaver ctxSaver(scope); CallContext::Data ctx(v4); #ifndef QT_NO_DEBUG @@ -616,10 +627,10 @@ ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData) ctx.setVtable(CallContext::staticVTable()); ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context? ctx.callData = callData; - Q_ASSERT(v4->currentContext() == &ctx); - Scoped<CallContext> sctx(scope, &ctx); + v4->pushContext(&ctx); + Q_ASSERT(v4->current == &ctx); - return f->d()->code(sctx); + return f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext)); } ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callData) @@ -631,7 +642,7 @@ ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callDa CHECK_STACK_LIMITS(v4); Scope scope(v4); - ExecutionContextSaver ctxSaver(scope, v4->currentContext()); + ExecutionContextSaver ctxSaver(scope); CallContext::Data ctx(v4); #ifndef QT_NO_DEBUG @@ -640,10 +651,10 @@ ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callDa ctx.setVtable(CallContext::staticVTable()); ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context? ctx.callData = callData; - Q_ASSERT(v4->currentContext() == &ctx); - Scoped<CallContext> sctx(scope, &ctx); + v4->pushContext(&ctx); + Q_ASSERT(v4->current == &ctx); - return f->d()->code(sctx, f->d()->index); + return f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index); } DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 2c6a195746..182f06f74e 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -58,10 +58,10 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { FunctionObject(ExecutionContext *scope, const QString &name = QString(), bool createProto = false); FunctionObject(QV4::ExecutionContext *scope, const ReturnedValue name); FunctionObject(ExecutionContext *scope, const ReturnedValue name); - FunctionObject(InternalClass *ic, QV4::Object *prototype); + FunctionObject(); ~FunctionObject(); - unsigned int formalParameterCount() { return function ? function->compiledFunction->nFormals : 0; } + unsigned int formalParameterCount() { return function ? function->nFormals : 0; } unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } bool needsActivation() const { return function ? function->needsActivation() : false; } @@ -74,7 +74,7 @@ struct FunctionCtor : FunctionObject { }; struct FunctionPrototype : FunctionObject { - FunctionPrototype(InternalClass *ic, QV4::Object *prototype); + FunctionPrototype(); }; struct Q_QML_EXPORT BuiltinFunction : FunctionObject { @@ -115,6 +115,8 @@ struct Q_QML_EXPORT FunctionObject: Object { }; V4_OBJECT2(FunctionObject, Object) Q_MANAGED_TYPE(FunctionObject) + V4_INTERNALCLASS(functionClass) + V4_PROTOTYPE(functionPrototype) V4_NEEDS_DESTROY Heap::ExecutionContext *scope() const { return d()->scope; } @@ -134,8 +136,10 @@ struct Q_QML_EXPORT FunctionObject: Object { static ReturnedValue call(const Managed *that, CallData *d); static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true); + static Heap::FunctionObject *createQmlFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, + const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0); - ReturnedValue protoProperty() { return memberData()->data[Heap::FunctionObject::Index_Prototype].asReturnedValue(); } + ReturnedValue protoProperty() { return propertyData(Heap::FunctionObject::Index_Prototype)->asReturnedValue(); } bool needsActivation() const { return d()->needsActivation(); } bool strictMode() const { return d()->function ? d()->function->isStrict() : false; } @@ -178,7 +182,7 @@ struct Q_QML_EXPORT BuiltinFunction: FunctionObject { static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) { - return scope->engine()->memoryManager->alloc<BuiltinFunction>(scope, name, code); + return scope->engine()->memoryManager->allocObject<BuiltinFunction>(scope, name, code); } static ReturnedValue construct(const Managed *, CallData *); @@ -208,6 +212,7 @@ Heap::IndexedBuiltinFunction::IndexedBuiltinFunction(QV4::ExecutionContext *scop struct SimpleScriptFunction: FunctionObject { V4_OBJECT2(SimpleScriptFunction, FunctionObject) + V4_INTERNALCLASS(simpleScriptFunctionClass) static ReturnedValue construct(const Managed *, CallData *callData); static ReturnedValue call(const Managed *that, CallData *callData); @@ -228,7 +233,7 @@ struct BoundFunction: FunctionObject { static Heap::BoundFunction *create(ExecutionContext *scope, FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs) { - return scope->engine()->memoryManager->alloc<BoundFunction>(scope, target, boundThis, boundArgs); + return scope->engine()->memoryManager->allocObject<BoundFunction>(scope, target, boundThis, boundArgs); } Heap::FunctionObject *target() const { return d()->target; } diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index ec7b9b3f7d..110a2c9089 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -339,11 +339,10 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const ExecutionEngine *v4 = engine(); Scope scope(v4); + ExecutionContextSaver ctxSaver(scope); - ScopedContext parentContext(scope, v4->currentContext()); - ExecutionContextSaver ctxSaver(scope, parentContext); - - ScopedContext ctx(scope, parentContext.getPointer()); + ExecutionContext *currentContext = v4->currentContext; + ExecutionContext *ctx = currentContext; if (!directCall) { // the context for eval should be the global scope, so we fake a root @@ -358,10 +357,10 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const bool inheritContext = !ctx->d()->strictMode; Script script(ctx, code, QStringLiteral("eval code")); - script.strictMode = (directCall && parentContext->d()->strictMode); + script.strictMode = (directCall && currentContext->d()->strictMode); script.inheritContext = inheritContext; script.parse(); - if (scope.engine->hasException) + if (v4->hasException) return Encode::undefined(); Function *function = script.function(); diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index 138d76bf4a..a5336ee44f 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -149,6 +149,22 @@ Identifier *IdentifierTable::identifierImpl(const Heap::String *str) return str->identifier; } +Heap::String *IdentifierTable::stringFromIdentifier(Identifier *i) +{ + if (!i) + return 0; + + uint idx = i->hashValue % alloc; + while (1) { + Heap::String *e = entries[idx]; + Q_ASSERT(e); + if (e->identifier == i) + return e; + ++idx; + idx %= alloc; + } +} + Identifier *IdentifierTable::identifier(const QString &s) { return insertString(s)->identifier; diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h index 58f808b4d5..d91ce623c1 100644 --- a/src/qml/jsruntime/qv4identifiertable_p.h +++ b/src/qml/jsruntime/qv4identifiertable_p.h @@ -74,6 +74,8 @@ public: Identifier *identifierImpl(const Heap::String *str); + Heap::String *stringFromIdentifier(Identifier *i); + void mark(ExecutionEngine *e) { for (int i = 0; i < alloc; ++i) { Heap::String *entry = entries[i]; diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 2eb61081c7..90c6738c46 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -49,11 +49,12 @@ QT_BEGIN_NAMESPACE -QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QQmlContextData *context, - const QV4::Value &qmlglobal, const QV4::Value &callback) - : v4(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0), m_context(context) +QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, + QV4::QmlContext *qmlContext, const QV4::Value &callback) + : v4(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0) { - m_qmlglobal.set(engine, qmlglobal); + if (qmlContext) + m_qmlContext.set(engine, *qmlContext); if (callback.as<QV4::FunctionObject>()) m_callbackFunction.set(engine, callback); @@ -142,8 +143,8 @@ void QV4Include::finished() QString code = QString::fromUtf8(data); QmlIR::Document::removeScriptPragmas(code); - QV4::ScopedObject qmlglobal(scope, m_qmlglobal.value()); - QV4::Script script(v4, qmlglobal, code, m_url.toString()); + QV4::Scoped<QV4::QmlContext> qml(scope, m_qmlContext.value()); + QV4::Script script(v4, qml, code, m_url.toString()); script.parse(); if (!scope.engine->hasException) @@ -190,12 +191,10 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) QString localFile = QQmlFile::urlToLocalFileOrQrc(url); QV4::ScopedValue result(scope); - QV4::ScopedObject qmlcontextobject(scope, scope.engine->qmlContextObject()); + QV4::Scoped<QV4::QmlContext> qmlcontext(scope, scope.engine->qmlContext()); if (localFile.isEmpty()) { - QV4Include *i = new QV4Include(url, scope.engine, context, - qmlcontextobject, - callbackFunction); + QV4Include *i = new QV4Include(url, scope.engine, qmlcontext, callbackFunction); result = i->result(); } else { @@ -203,7 +202,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) if (const QQmlPrivate::CachedQmlUnit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url)) { QV4::CompiledData::CompilationUnit *jsUnit = cachedUnit->createCompilationUnit(); - script.reset(new QV4::Script(scope.engine, qmlcontextobject, jsUnit)); + script.reset(new QV4::Script(scope.engine, qmlcontext, jsUnit)); } else { QFile f(localFile); @@ -212,7 +211,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) QString code = QString::fromUtf8(data); QmlIR::Document::removeScriptPragmas(code); - script.reset(new QV4::Script(scope.engine, qmlcontextobject, code, url.toString())); + script.reset(new QV4::Script(scope.engine, qmlcontext, code, url.toString())); } } diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h index 5ef4442b03..3e3cf5e770 100644 --- a/src/qml/jsruntime/qv4include_p.h +++ b/src/qml/jsruntime/qv4include_p.h @@ -76,8 +76,7 @@ private Q_SLOTS: void finished(); private: - QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QQmlContextData *context, - const QV4::Value &qmlglobal, const QV4::Value &callback); + QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &callback); ~QV4Include(); QV4::ReturnedValue result(); @@ -95,8 +94,7 @@ private: QV4::PersistentValue m_callbackFunction; QV4::PersistentValue m_resultObject; - QQmlGuardedContextData m_context; - QV4::PersistentValue m_qmlglobal; + QV4::PersistentValue m_qmlContext; }; QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index a90e8e3689..8f0b1776d7 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -134,21 +134,64 @@ InternalClass::InternalClass(const QV4::InternalClass &other) Q_ASSERT(extensible); } +static void insertHoleIntoPropertyData(Object *object, int idx) +{ + int inlineSize = object->d()->inlineMemberSize; + int icSize = object->internalClass()->size; + int from = qMax(idx, inlineSize); + int to = from + 1; + if (from < icSize) + memmove(object->propertyData(to), object->propertyData(from), icSize - from - 1); + if (from == idx) + return; + if (inlineSize < icSize) + *object->propertyData(inlineSize) = *object->propertyData(inlineSize - 1); + from = idx; + to = from + 1; + if (from < inlineSize - 1) + memmove(object->propertyData(to), object->propertyData(from), inlineSize - from - 1); +} + +static void removeFromPropertyData(Object *object, int idx, bool accessor = false) +{ + int inlineSize = object->d()->inlineMemberSize; + int icSize = object->internalClass()->size; + int delta = (accessor ? 2 : 1); + int to = idx; + int from = to + delta; + if (from < inlineSize) { + memmove(object->propertyData(to), object->d()->propertyData(from), (inlineSize - from)*sizeof(Value)); + to = inlineSize - delta; + from = inlineSize; + } + if (to < inlineSize && from < icSize) { + Q_ASSERT(from >= inlineSize); + memcpy(object->propertyData(to), object->d()->propertyData(from), (inlineSize - to)*sizeof(Value)); + to = inlineSize; + from = inlineSize + delta; + } + if (from < icSize + delta) { + Q_ASSERT(to >= inlineSize && from > to); + memmove(object->propertyData(to), object->d()->propertyData(from), (icSize + delta - to)*sizeof(Value)); + } +} + void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index) { uint idx; - InternalClass *newClass = object->internalClass()->changeMember(string->identifier(), data, &idx); + InternalClass *oldClass = object->internalClass(); + InternalClass *newClass = oldClass->changeMember(string->identifier(), data, &idx); if (index) *index = idx; - if (newClass->size > object->internalClass()->size) { - Q_ASSERT(newClass->size == object->internalClass()->size + 1); - memmove(object->memberData()->data + idx + 2, object->memberData()->data + idx + 1, (object->internalClass()->size - idx - 1)*sizeof(Value)); - } else if (newClass->size < object->internalClass()->size) { - Q_ASSERT(newClass->size == object->internalClass()->size - 1); - memmove(object->memberData()->data + idx + 1, object->memberData()->data + idx + 2, (object->internalClass()->size - idx - 2)*sizeof(Value)); - } object->setInternalClass(newClass); + if (newClass->size > oldClass->size) { + Q_ASSERT(newClass->size == oldClass->size + 1); + insertHoleIntoPropertyData(object, idx + 1); + } else if (newClass->size < oldClass->size) { + Q_ASSERT(newClass->size == oldClass->size - 1); + removeFromPropertyData(object, idx + 1); + } } InternalClassTransition &InternalClass::lookupOrInsertTransition(const InternalClassTransition &t) @@ -286,6 +329,8 @@ void InternalClass::removeMember(Object *object, Identifier *id) Transition temp = { id, 0, -1 }; Transition &t = object->internalClass()->lookupOrInsertTransition(temp); + bool accessor = oldClass->propertyData.at(propIdx).isAccessor(); + if (t.lookup) { object->setInternalClass(t.lookup); } else { @@ -300,8 +345,10 @@ void InternalClass::removeMember(Object *object, Identifier *id) object->setInternalClass(newClass); } - // remove the entry in memberdata - memmove(object->memberData()->data + propIdx, object->memberData()->data + propIdx + 1, (object->internalClass()->size - propIdx)*sizeof(Value)); + Q_ASSERT(object->internalClass()->size == oldClass->size - (accessor ? 2 : 1)); + + // remove the entry in the property data + removeFromPropertyData(object, propIdx, accessor); t.lookup = object->internalClass(); Q_ASSERT(t.lookup); @@ -352,20 +399,26 @@ InternalClass *InternalClass::frozen() if (m_frozen) return m_frozen; - m_frozen = engine->emptyClass; + m_frozen = propertiesFrozen(); + m_frozen = m_frozen->nonExtensible(); + + m_frozen->m_frozen = m_frozen; + m_frozen->m_sealed = m_frozen; + return m_frozen; +} + +InternalClass *InternalClass::propertiesFrozen() const +{ + InternalClass *frozen = engine->emptyClass; for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (attrs.isEmpty()) continue; attrs.setWritable(false); attrs.setConfigurable(false); - m_frozen = m_frozen->addMember(nameMap.at(i), attrs); + frozen = frozen->addMember(nameMap.at(i), attrs); } - m_frozen = m_frozen->nonExtensible(); - - m_frozen->m_frozen = m_frozen; - m_frozen->m_sealed = m_frozen; - return m_frozen; + return frozen; } void InternalClass::destroy() diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 80590fe72e..342870fcd6 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -233,6 +233,7 @@ struct InternalClass : public QQmlJS::Managed { InternalClass *sealed(); InternalClass *frozen(); + InternalClass *propertiesFrozen() const; void destroy(); diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index f703e85399..f4f87f3aea 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -858,10 +858,9 @@ QString Stringify::JA(ArrayObject *a) } -Heap::JsonObject::JsonObject(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->objectPrototype()) +Heap::JsonObject::JsonObject() { - Scope scope(e); + Scope scope(internalClass->engine); ScopedObject o(scope, this); o->defineDefaultProperty(QStringLiteral("parse"), QV4::JsonObject::method_parse, 2); @@ -943,7 +942,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) ReturnedValue JsonObject::fromJsonValue(ExecutionEngine *engine, const QJsonValue &value) { if (value.isString()) - return engine->currentContext()->engine->newString(value.toString())->asReturnedValue(); + return 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 1ad0e2c5de..61d44f206e 100644 --- a/src/qml/jsruntime/qv4jsonobject_p.h +++ b/src/qml/jsruntime/qv4jsonobject_p.h @@ -47,7 +47,7 @@ namespace QV4 { namespace Heap { struct JsonObject : Object { - JsonObject(ExecutionEngine *e); + JsonObject(); }; } diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 443427b024..d97abdb461 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -43,7 +43,7 @@ using namespace QV4; ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttributes *attrs) { ExecutionEngine *engine = o->engine(); - Identifier *name = engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]->identifier; + Identifier *name = engine->current->compilationUnit->runtimeStrings[nameIndex]->identifier; int i = 0; Heap::Object *obj = o->d(); while (i < Size && obj) { @@ -53,7 +53,8 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu if (index != UINT_MAX) { level = i; *attrs = obj->internalClass->propertyData.at(index); - return !attrs->isAccessor() ? obj->memberData->data[index].asReturnedValue() : Object::getValue(thisObject, obj->propertyAt(index), *attrs); + Value *v = obj->propertyData(index); + return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs); } obj = obj->prototype; @@ -65,7 +66,8 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu index = obj->internalClass->find(name); if (index != UINT_MAX) { *attrs = obj->internalClass->propertyData.at(index); - return !attrs->isAccessor() ? obj->memberData->data[index].asReturnedValue() : Object::getValue(thisObject, obj->propertyAt(index), *attrs); + Value *v = obj->propertyData(index); + return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs); } obj = obj->prototype; @@ -77,7 +79,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs { Heap::Object *obj = thisObject->d(); ExecutionEngine *engine = thisObject->engine(); - Identifier *name = engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]->identifier; + Identifier *name = engine->current->compilationUnit->runtimeStrings[nameIndex]->identifier; int i = 0; while (i < Size && obj) { classList[i] = obj->internalClass; @@ -86,7 +88,8 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs if (index != UINT_MAX) { level = i; *attrs = obj->internalClass->propertyData.at(index); - return !attrs->isAccessor() ? obj->memberData->data[index].asReturnedValue() : thisObject->getValue(obj->propertyAt(index), *attrs); + Value *v = obj->propertyData(index); + return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs); } obj = obj->prototype; @@ -98,7 +101,8 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs index = obj->internalClass->find(name); if (index != UINT_MAX) { *attrs = obj->internalClass->propertyData.at(index); - return !attrs->isAccessor() ? obj->memberData->data[index].asReturnedValue() : thisObject->getValue(obj->propertyAt(index), *attrs); + Value *v = obj->propertyData(index); + return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs); } obj = obj->prototype; @@ -165,7 +169,7 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con { uint idx = index.asArrayIndex(); if (idx == UINT_MAX || !object.isObject()) - return indexedGetterGeneric(l, object, index); + return indexedGetterFallback(l, object, index); Object *o = object.objectValue(); if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { @@ -251,7 +255,7 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va Q_ASSERT(object.isString()); proto = engine->stringPrototype(); Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]); if (name->equals(engine->id_length())) { // special case, as the property is on the object itself l->getter = stringLengthGetter; @@ -329,7 +333,7 @@ ReturnedValue Lookup::getterFallback(Lookup *l, ExecutionEngine *engine, const V QV4::ScopedObject o(scope, object.toObject(scope.engine)); if (!o) return Encode::undefined(); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]); return o->get(name); } @@ -340,7 +344,7 @@ ReturnedValue Lookup::getter0(Lookup *l, ExecutionEngine *engine, const Value &o // the internal class won't match Object *o = object.objectValue(); if (l->classList[0] == o->internalClass()) - return o->memberData()->data[l->index].asReturnedValue(); + return o->propertyData(l->index)->asReturnedValue(); } return getterTwoClasses(l, engine, object); } @@ -353,7 +357,7 @@ ReturnedValue Lookup::getter1(Lookup *l, ExecutionEngine *engine, const Value &o Object *o = object.objectValue(); if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) - return o->prototype()->memberData->data[l->index].asReturnedValue(); + return o->prototype()->propertyData(l->index)->asReturnedValue(); } return getterTwoClasses(l, engine, object); } @@ -369,7 +373,7 @@ ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &o if (l->classList[1] == p->internalClass) { p = p->prototype; if (l->classList[2] == p->internalClass) - return p->memberData->data[l->index].asReturnedValue(); + return p->propertyData(l->index)->asReturnedValue(); } } } @@ -384,9 +388,9 @@ ReturnedValue Lookup::getter0getter0(Lookup *l, ExecutionEngine *engine, const V // the internal class won't match Object *o = object.objectValue(); if (l->classList[0] == o->internalClass()) - return o->memberData()->data[l->index].asReturnedValue(); + return o->propertyData(l->index)->asReturnedValue(); if (l->classList[2] == o->internalClass()) - return o->memberData()->data[l->index2].asReturnedValue(); + return o->propertyData(l->index2)->asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); @@ -399,10 +403,10 @@ ReturnedValue Lookup::getter0getter1(Lookup *l, ExecutionEngine *engine, const V // the internal class won't match Object *o = object.objectValue(); if (l->classList[0] == o->internalClass()) - return o->memberData()->data[l->index].asReturnedValue(); + return o->propertyData(l->index)->asReturnedValue(); if (l->classList[2] == o->internalClass() && l->classList[3] == o->prototype()->internalClass) - return o->prototype()->memberData->data[l->index2].asReturnedValue(); + return o->prototype()->propertyData(l->index2)->asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); @@ -416,10 +420,10 @@ ReturnedValue Lookup::getter1getter1(Lookup *l, ExecutionEngine *engine, const V Object *o = object.objectValue(); if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) - return o->prototype()->memberData->data[l->index].asReturnedValue(); + return o->prototype()->propertyData(l->index)->asReturnedValue(); if (l->classList[2] == o->internalClass() && l->classList[3] == o->prototype()->internalClass) - return o->prototype()->memberData->data[l->index2].asReturnedValue(); + return o->prototype()->propertyData(l->index2)->asReturnedValue(); return getterFallback(l, engine, object); } l->getter = getterFallback; @@ -435,7 +439,7 @@ ReturnedValue Lookup::getterAccessor0(Lookup *l, ExecutionEngine *engine, const Object *o = object.objectValue(); if (l->classList[0] == o->internalClass()) { Scope scope(o->engine()); - ScopedFunctionObject getter(scope, o->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -457,7 +461,7 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const if (l->classList[0] == o->internalClass && l->classList[1] == o->prototype->internalClass) { Scope scope(o->internalClass->engine); - ScopedFunctionObject getter(scope, o->prototype->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->prototype->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -482,7 +486,7 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const o = o->prototype; if (l->classList[2] == o->internalClass) { Scope scope(o->internalClass->engine); - ScopedFunctionObject getter(scope, o->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -502,7 +506,7 @@ ReturnedValue Lookup::primitiveGetter0(Lookup *l, ExecutionEngine *engine, const if (object.type() == l->type) { Object *o = l->proto; if (l->classList[0] == o->internalClass()) - return o->memberData()->data[l->index].asReturnedValue(); + return o->propertyData(l->index)->asReturnedValue(); } l->getter = getterGeneric; return getterGeneric(l, engine, object); @@ -514,7 +518,7 @@ ReturnedValue Lookup::primitiveGetter1(Lookup *l, ExecutionEngine *engine, const Object *o = l->proto; if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) - return o->prototype()->memberData->data[l->index].asReturnedValue(); + return o->prototype()->propertyData(l->index)->asReturnedValue(); } l->getter = getterGeneric; return getterGeneric(l, engine, object); @@ -526,7 +530,7 @@ ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engin Object *o = l->proto; if (l->classList[0] == o->internalClass()) { Scope scope(o->engine()); - ScopedFunctionObject getter(scope, o->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -546,7 +550,7 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engin if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) { Scope scope(o->engine()); - ScopedFunctionObject getter(scope, o->prototype()->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -571,7 +575,7 @@ ReturnedValue Lookup::stringLengthGetter(Lookup *l, ExecutionEngine *engine, con ReturnedValue Lookup::arrayLengthGetter(Lookup *l, ExecutionEngine *engine, const Value &object) { if (const ArrayObject *a = object.as<ArrayObject>()) - return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].asReturnedValue(); + return a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->asReturnedValue(); l->getter = getterGeneric; return getterGeneric(l, engine, object); @@ -603,7 +607,7 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine) } } Scope scope(engine); - ScopedString n(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString n(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]); return engine->throwReferenceError(n); } @@ -611,7 +615,7 @@ ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionEngine *engine) { Object *o = engine->globalObject; if (l->classList[0] == o->internalClass()) - return o->memberData()->data[l->index].asReturnedValue(); + return o->propertyData(l->index)->asReturnedValue(); l->globalGetter = globalGetterGeneric; return globalGetterGeneric(l, engine); @@ -622,7 +626,7 @@ ReturnedValue Lookup::globalGetter1(Lookup *l, ExecutionEngine *engine) Object *o = engine->globalObject; if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) - return o->prototype()->memberData->data[l->index].asReturnedValue(); + return o->prototype()->propertyData(l->index)->asReturnedValue(); l->globalGetter = globalGetterGeneric; return globalGetterGeneric(l, engine); @@ -636,7 +640,7 @@ ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionEngine *engine) if (l->classList[1] == o->internalClass) { o = o->prototype; if (l->classList[2] == o->internalClass) { - return o->prototype->memberData->data[l->index].asReturnedValue(); + return o->prototype->propertyData(l->index)->asReturnedValue(); } } } @@ -649,7 +653,7 @@ ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionEngine *engine) Object *o = engine->globalObject; if (l->classList[0] == o->internalClass()) { Scope scope(o->engine()); - ScopedFunctionObject getter(scope, o->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -667,7 +671,7 @@ ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionEngine *engine) if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) { Scope scope(o->engine()); - ScopedFunctionObject getter(scope, o->prototype()->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -688,7 +692,7 @@ ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine) o = o->prototype; if (l->classList[2] == o->internalClass) { Scope scope(o->internalClass->engine); - ScopedFunctionObject getter(scope, o->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -710,7 +714,7 @@ void Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, co o = RuntimeHelpers::convertToObject(scope.engine, object); if (!o) // type error return; - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]); o->put(name, value); return; } @@ -741,7 +745,7 @@ void Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, c QV4::Scope scope(engine); QV4::ScopedObject o(scope, object.toObject(scope.engine)); if (o) { - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]); o->put(name, value); } } @@ -750,7 +754,7 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Va { Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { - o->memberData()->data[l->index] = value; + *o->propertyData(l->index) = value; return; } @@ -762,10 +766,8 @@ void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, co Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { if (!o->prototype()) { - if (!o->memberData() || l->index >= o->memberData()->size) - o->ensureMemberIndex(l->index); - o->memberData()->data[l->index] = value; o->setInternalClass(l->classList[3]); + *o->propertyData(l->index) = value; return; } } @@ -780,10 +782,8 @@ void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, co if (o && o->internalClass() == l->classList[0]) { Heap::Object *p = o->prototype(); if (p && p->internalClass == l->classList[1]) { - if (!o->memberData() || l->index >= o->memberData()->size) - o->ensureMemberIndex(l->index); - o->memberData()->data[l->index] = value; o->setInternalClass(l->classList[3]); + *o->propertyData(l->index) = value; return; } } @@ -800,10 +800,8 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, co if (p && p->internalClass == l->classList[1]) { p = p->prototype; if (p && p->internalClass == l->classList[2]) { - if (!o->memberData() || l->index >= o->memberData()->size) - o->ensureMemberIndex(l->index); - o->memberData()->data[l->index] = value; o->setInternalClass(l->classList[3]); + *o->propertyData(l->index) = value; return; } } @@ -818,11 +816,11 @@ void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, c Object *o = object.as<Object>(); if (o) { if (o->internalClass() == l->classList[0]) { - o->memberData()->data[l->index] = value; + *o->propertyData(l->index) = value; return; } if (o->internalClass() == l->classList[1]) { - o->memberData()->data[l->index2] = value; + *o->propertyData(l->index2) = value; return; } } diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index bb7ee43b4e..e2de36d18e 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -88,29 +88,7 @@ QString Managed::className() const s = "RegExp"; break; case Type_ErrorObject: - switch (static_cast<Heap::ErrorObject *>(d())->errorType) { - case Heap::ErrorObject::Error: - s = "Error"; - break; - case Heap::ErrorObject::EvalError: - s = "EvalError"; - break; - case Heap::ErrorObject::RangeError: - s = "RangeError"; - break; - case Heap::ErrorObject::ReferenceError: - s = "ReferenceError"; - break; - case Heap::ErrorObject::SyntaxError: - s = "SyntaxError"; - break; - case Heap::ErrorObject::TypeError: - s = "TypeError"; - break; - case Heap::ErrorObject::URIError: - s = "URIError"; - break; - } + s = ErrorObject::className(static_cast<Heap::ErrorObject *>(d())->errorType); break; case Type_ArgumentsObject: s = "Arguments"; diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp index c498160c36..f1face007c 100644 --- a/src/qml/jsruntime/qv4mathobject.cpp +++ b/src/qml/jsruntime/qv4mathobject.cpp @@ -47,10 +47,9 @@ DEFINE_OBJECT_VTABLE(MathObject); static const double qt_PI = 2.0 * ::asin(1.0); -Heap::MathObject::MathObject(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->objectPrototype()) +Heap::MathObject::MathObject() { - Scope scope(e); + Scope scope(internalClass->engine); ScopedObject m(scope, this); m->defineReadonlyProperty(QStringLiteral("E"), Primitive::fromDouble(M_E)); diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h index 472b2020b1..ff4fb12ee6 100644 --- a/src/qml/jsruntime/qv4mathobject_p.h +++ b/src/qml/jsruntime/qv4mathobject_p.h @@ -42,7 +42,7 @@ namespace QV4 { namespace Heap { struct MathObject : Object { - MathObject(ExecutionEngine *e); + MathObject(); }; } diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index b3c0863e3e..ee3539c176 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -44,6 +44,7 @@ #include "qv4objectiterator_p.h" #include "qv4identifier_p.h" #include "qv4string_p.h" +#include "qv4identifiertable_p.h" #include <stdint.h> @@ -51,15 +52,25 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(Object); -Heap::Object::Object(InternalClass *internalClass, QV4::Object *prototype) - : internalClass(internalClass), - prototype(prototype ? prototype->d() : 0) +void Object::setInternalClass(InternalClass *ic) { - if (internalClass->size) { - Scope scope(internalClass->engine); - ScopedObject o(scope, this); - o->ensureMemberIndex(internalClass->engine, internalClass->size); - } + d()->internalClass = ic; + ensureMemberData(); +} + +void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const +{ + p->value = *propertyData(index); + *attrs = internalClass()->propertyData.at(index); + if (attrs->isAccessor()) + p->set = *propertyData(index + SetterOffset); +} + +void Object::setProperty(uint index, const Property *p) +{ + *propertyData(index) = p->value; + if (internalClass()->propertyData.at(index).isAccessor()) + *propertyData(index + SetterOffset) = p->set; } bool Object::setPrototype(Object *proto) @@ -81,28 +92,32 @@ void Object::put(ExecutionEngine *engine, const QString &name, const Value &valu put(n, value); } -ReturnedValue Object::getValue(const Value &thisObject, const Property *p, PropertyAttributes attrs) +ReturnedValue Object::getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs) { if (!attrs.isAccessor()) - return p->value.asReturnedValue(); - if (!p->getter()) + return v.asReturnedValue(); + const QV4::FunctionObject *f = v.as<FunctionObject>(); + if (!f) return Encode::undefined(); - Scope scope(p->getter()->internalClass->engine); - ScopedFunctionObject getter(scope, p->getter()); + Scope scope(f->engine()); ScopedCallData callData(scope); callData->thisObject = thisObject; - return getter->call(callData); + return f->call(callData); } -void Object::putValue(Property *pd, PropertyAttributes attrs, const Value &value) +void Object::putValue(uint memberIndex, const Value &value) { - if (internalClass()->engine->hasException) + QV4::InternalClass *ic = internalClass(); + if (ic->engine->hasException) return; + PropertyAttributes attrs = ic->propertyData[memberIndex]; + if (attrs.isAccessor()) { - if (Heap::FunctionObject *set = pd->setter()) { - Scope scope(set->internalClass->engine); + FunctionObject *set = propertyData(memberIndex + SetterOffset)->as<FunctionObject>(); + if (set) { + Scope scope(ic->engine); ScopedFunctionObject setter(scope, set); ScopedCallData callData(scope, 1); callData->args[0] = value; @@ -116,11 +131,11 @@ void Object::putValue(Property *pd, PropertyAttributes attrs, const Value &value if (!attrs.isWritable()) goto reject; - pd->value = value; + *propertyData(memberIndex) = value; return; reject: - if (engine()->currentContext()->strictMode) + if (engine()->current->strictMode) engine()->throwTypeError(); } @@ -137,7 +152,7 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Ca ExecutionEngine *e = engine(); Scope scope(e); ScopedString s(scope, e->newIdentifier(name)); - ScopedContext global(scope, e->rootContext()); + ExecutionContext *global = e->rootContext(); ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code)); function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(s, function); @@ -147,7 +162,7 @@ void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallConte { ExecutionEngine *e = engine(); Scope scope(e); - ScopedContext global(scope, e->rootContext()); + ExecutionContext *global = e->rootContext(); ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code)); function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(name, function); @@ -166,7 +181,7 @@ void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(CallCo ExecutionEngine *v4 = engine(); QV4::Scope scope(v4); ScopedProperty p(scope); - ScopedContext global(scope, scope.engine->rootContext()); + ExecutionContext *global = v4->rootContext(); p->setGetter(ScopedFunctionObject(scope, (getter ? BuiltinFunction::create(global, name, getter) : 0))); p->setSetter(ScopedFunctionObject(scope, (setter ? BuiltinFunction::create(global, name, setter) : 0))); insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); @@ -189,6 +204,12 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e) { Heap::Object *o = static_cast<Heap::Object *>(that); + if (o->inlineMemberSize) { + Value *v = o->propertyData(0); + for (uint i = 0; i < o->inlineMemberSize; ++i) + v[i].mark(e); + } + if (o->memberData) o->memberData->mark(e); if (o->arrayData) @@ -197,9 +218,11 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e) o->prototype->mark(e); } -void Object::ensureMemberIndex(uint idx) +void Object::ensureMemberData() { - d()->memberData = MemberData::reallocate(engine(), d()->memberData, idx); + QV4::InternalClass *ic = internalClass(); + if (ic->size > d()->inlineMemberSize) + d()->memberData = MemberData::reallocate(ic->engine, d()->memberData, ic->size - d()->inlineMemberSize); } void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes) @@ -207,15 +230,11 @@ void Object::insertMember(String *s, const Property *p, PropertyAttributes attri uint idx; InternalClass::addMember(this, s, attributes, &idx); - - ensureMemberIndex(internalClass()->size); - if (attributes.isAccessor()) { - Property *pp = propertyAt(idx); - pp->value = p->value; - pp->set = p->set; + *propertyData(idx + GetterOffset) = p->value; + *propertyData(idx + SetterOffset) = p->set; } else { - d()->memberData->data[idx] = p->value; + *propertyData(idx) = p->value; } } @@ -229,8 +248,11 @@ void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p uint member = internalClass()->find(name); if (member < UINT_MAX) { *attrs = internalClass()->propertyData[member]; - if (p) - p->copy(propertyAt(member), *attrs); + if (p) { + p->value = *propertyData(member); + if (attrs->isAccessor()) + p->set = *propertyData(member + SetterOffset); + } return; } @@ -261,47 +283,44 @@ void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p) } // Section 8.12.2 -Property *Object::__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const +Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs) { Q_ASSERT(name->asArrayIndex() == UINT_MAX); - const Heap::Object *o = d(); + Heap::Object *o = d(); while (o) { uint idx = o->internalClass->find(name); if (idx < UINT_MAX) { - if (attrs) - *attrs = o->internalClass->propertyData[idx]; - return const_cast<Property *>(o->propertyAt(idx)); + *attrs = o->internalClass->propertyData[idx]; + return o->propertyData(attrs->isAccessor() ? idx + SetterOffset : idx); } o = o->prototype; } - if (attrs) - *attrs = Attr_Invalid; + *attrs = Attr_Invalid; return 0; } -Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attrs) const +Value *Object::getValueOrSetter(uint index, PropertyAttributes *attrs) { - const Heap::Object *o = d(); + Heap::Object *o = d(); while (o) { Property *p = o->arrayData ? o->arrayData->getProperty(index) : 0; if (p) { *attrs = o->arrayData->attributes(index); - return p; + return attrs->isAccessor() ? &p->set : &p->value; } if (o->vtable()->type == Type_StringObject) { if (index < static_cast<const Heap::StringObject *>(o)->length()) { // this is an evil hack, but it works, as the method is only ever called from putIndexed, // where we don't use the returned pointer there for non writable attributes *attrs = (Attr_NotWritable|Attr_NotConfigurable); - return reinterpret_cast<Property *>(0x1); + return reinterpret_cast<Value *>(0x1); } } o = o->prototype; } - if (attrs) - *attrs = Attr_Invalid; + *attrs = Attr_Invalid; return 0; } @@ -466,7 +485,7 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value) { Scope scope(static_cast<Object *>(m)->engine()); ScopedObject o(scope, static_cast<Object *>(m)); - ScopedString name(scope, scope.engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, scope.engine->current->compilationUnit->runtimeStrings[l->nameIndex]); InternalClass *c = o->internalClass(); uint idx = c->find(name); @@ -475,12 +494,12 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value) l->classList[0] = o->internalClass(); l->index = idx; l->setter = Lookup::setter0; - o->memberData()->data[idx] = value; + *o->propertyData(idx) = value; return; } if (idx != UINT_MAX) { - o->putValue(o->propertyAt(idx), o->internalClass()->propertyData[idx], value); + o->putValue(idx, value); return; } } @@ -568,13 +587,15 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint * continue; } - Property *p = o->propertyAt(it->memberIndex); + int idx = it->memberIndex; PropertyAttributes a = o->internalClass()->propertyData[it->memberIndex]; ++it->memberIndex; if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { - name->setM(o->engine()->newString(n->string)); + name->setM(o->engine()->identifierTable->stringFromIdentifier(n)); *attrs = a; - pd->copy(p, a); + pd->value = *o->propertyData(idx); + if (a.isAccessor()) + pd->set = *o->propertyData(idx + SetterOffset); return; } } @@ -598,7 +619,7 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) const if (idx < UINT_MAX) { if (hasProperty) *hasProperty = true; - return getValue(o->propertyAt(idx), o->internalClass()->propertyData.at(idx)); + return getValue(*o->propertyData(idx), o->internalClass()->propertyData.at(idx)); } o = o->prototype(); @@ -637,7 +658,7 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const if (pd) { if (hasProperty) *hasProperty = true; - return getValue(pd, attrs); + return getValue(pd->value, attrs); } if (hasProperty) @@ -659,17 +680,17 @@ void Object::internalPut(String *name, const Value &value) name->makeIdentifier(engine()); uint member = internalClass()->find(name); - Property *pd = 0; + Value *v = 0; PropertyAttributes attrs; if (member < UINT_MAX) { - pd = propertyAt(member); attrs = internalClass()->propertyData[member]; + v = propertyData(attrs.isAccessor() ? member + SetterOffset : member); } // clause 1 - if (pd) { + if (v) { if (attrs.isAccessor()) { - if (pd->setter()) + if (v->as<FunctionObject>()) goto cont; goto reject; } else if (!attrs.isWritable()) @@ -685,7 +706,7 @@ void Object::internalPut(String *name, const Value &value) if (!ok) goto reject; } else { - pd->value = value; + *v = value; } return; } else if (!prototype()) { @@ -694,9 +715,9 @@ void Object::internalPut(String *name, const Value &value) } else { // clause 4 Scope scope(engine()); - if ((pd = ScopedObject(scope, prototype())->__getPropertyDescriptor__(name, &attrs))) { + if ((v = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs))) { if (attrs.isAccessor()) { - if (!pd->setter()) + if (!v->as<FunctionObject>()) goto reject; } else if (!isExtensible() || !attrs.isWritable()) { goto reject; @@ -709,11 +730,11 @@ void Object::internalPut(String *name, const Value &value) cont: // Clause 5 - if (pd && attrs.isAccessor()) { - Q_ASSERT(pd->setter() != 0); + if (v && attrs.isAccessor()) { + Q_ASSERT(v->as<FunctionObject>()); Scope scope(engine()); - ScopedFunctionObject setter(scope, pd->setter()); + ScopedFunctionObject setter(scope, *v); ScopedCallData callData(scope, 1); callData->args[0] = value; callData->thisObject = this; @@ -725,7 +746,7 @@ void Object::internalPut(String *name, const Value &value) return; reject: - if (engine()->currentContext()->strictMode) { + if (engine()->current->strictMode) { QString message = QStringLiteral("Cannot assign to read-only property \""); message += name->toQString(); message += QLatin1Char('\"'); @@ -740,26 +761,24 @@ void Object::internalPutIndexed(uint index, const Value &value) PropertyAttributes attrs; - Property *pd = arrayData() ? arrayData()->getProperty(index) : 0; - if (pd) - attrs = arrayData()->attributes(index); + Value *v = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : 0; - if (!pd && isStringObject()) { + if (!v && isStringObject()) { if (index < static_cast<StringObject *>(this)->length()) // not writable goto reject; } // clause 1 - if (pd) { + if (v) { if (attrs.isAccessor()) { - if (pd->setter()) + if (v->as<FunctionObject>()) goto cont; goto reject; } else if (!attrs.isWritable()) goto reject; else - pd->value = value; + *v = value; return; } else if (!prototype()) { if (!isExtensible()) @@ -767,9 +786,9 @@ void Object::internalPutIndexed(uint index, const Value &value) } else { // clause 4 Scope scope(engine()); - if ((pd = ScopedObject(scope, prototype())->__getPropertyDescriptor__(index, &attrs))) { + if ((v = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs))) { if (attrs.isAccessor()) { - if (!pd->setter()) + if (!v->as<FunctionObject>()) goto reject; } else if (!isExtensible() || !attrs.isWritable()) { goto reject; @@ -782,11 +801,11 @@ void Object::internalPutIndexed(uint index, const Value &value) cont: // Clause 5 - if (pd && attrs.isAccessor()) { - Q_ASSERT(pd->setter() != 0); + if (v && attrs.isAccessor()) { + Q_ASSERT(v->as<FunctionObject>()); Scope scope(engine()); - ScopedFunctionObject setter(scope, pd->setter()); + ScopedFunctionObject setter(scope, *v); ScopedCallData callData(scope, 1); callData->args[0] = value; callData->thisObject = this; @@ -798,7 +817,7 @@ void Object::internalPutIndexed(uint index, const Value &value) return; reject: - if (engine()->currentContext()->strictMode) + if (engine()->current->strictMode) engine()->throwTypeError(); } @@ -820,7 +839,7 @@ bool Object::internalDeleteProperty(String *name) InternalClass::removeMember(this, name->identifier()); return true; } - if (engine()->currentContext()->strictMode) + if (engine()->current->strictMode) engine()->throwTypeError(); return false; } @@ -838,7 +857,7 @@ bool Object::internalDeleteIndexedProperty(uint index) if (!ad || ad->vtable()->del(this, index)) return true; - if (engine()->currentContext()->strictMode) + if (engine()->current->strictMode) engine()->throwTypeError(); return false; } @@ -853,17 +872,16 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const Scope scope(engine); name->makeIdentifier(scope.engine); - Property *current; - PropertyAttributes *cattrs; uint memberIndex; if (isArrayObject() && name->equals(engine->id_length())) { Q_ASSERT(Heap::ArrayObject::LengthPropertyIndex == internalClass()->find(engine->id_length())); - Property *lp = propertyAt(Heap::ArrayObject::LengthPropertyIndex); - cattrs = internalClass()->propertyData.constData() + Heap::ArrayObject::LengthPropertyIndex; - if (attrs.isEmpty() || p->isSubset(attrs, lp, *cattrs)) + ScopedProperty lp(scope); + PropertyAttributes cattrs; + getProperty(Heap::ArrayObject::LengthPropertyIndex, lp, &cattrs); + if (attrs.isEmpty() || p->isSubset(attrs, lp, cattrs)) return true; - if (!cattrs->isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable()) + if (!cattrs.isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable()) goto reject; bool succeeded = true; if (attrs.type() == PropertyAttributes::Data) { @@ -876,8 +894,10 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const } succeeded = setArrayLength(l); } - if (attrs.hasWritable() && !attrs.isWritable()) - cattrs->setWritable(false); + if (attrs.hasWritable() && !attrs.isWritable()) { + cattrs.setWritable(false); + InternalClass::changeMember(this, engine->id_length(), cattrs); + } if (!succeeded) goto reject; return true; @@ -885,10 +905,8 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const // Clause 1 memberIndex = internalClass()->find(name); - current = (memberIndex < UINT_MAX) ? propertyAt(memberIndex) : 0; - cattrs = internalClass()->propertyData.constData() + memberIndex; - if (!current) { + if (memberIndex == UINT_MAX) { // clause 3 if (!isExtensible()) goto reject; @@ -902,7 +920,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const return __defineOwnProperty__(engine, memberIndex, name, p, attrs); reject: - if (engine->currentContext()->strictMode) + if (engine->current->strictMode) engine->throwTypeError(); return false; } @@ -918,7 +936,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, const Pr return defineOwnProperty2(engine, index, p, attrs); reject: - if (engine->currentContext()->strictMode) + if (engine->current->strictMode) engine->throwTypeError(); return false; } @@ -954,7 +972,7 @@ bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Prope return __defineOwnProperty__(engine, index, 0, p, attrs); reject: - if (engine->currentContext()->strictMode) + if (engine->current->strictMode) engine->throwTypeError(); return false; } @@ -965,13 +983,14 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * if (attrs.isEmpty()) return true; - Property *current = 0; + Scope scope(engine); + ScopedProperty current(scope); PropertyAttributes cattrs; if (member) { - current = propertyAt(index); + getProperty(index, current, &cattrs); cattrs = internalClass()->propertyData[index]; } else if (arrayData()) { - current = arrayData()->getProperty(index); + arrayData()->getProperty(index, current, &cattrs); cattrs = arrayData()->attributes(index); } @@ -1005,7 +1024,6 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * initSparseArray(); Q_ASSERT(arrayData()); setArrayAttributes(index, cattrs); - current = arrayData()->getProperty(index); } current->setGetter(0); current->setSetter(0); @@ -1016,7 +1034,6 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * if (!member) { // need to convert the array and the slot setArrayAttributes(index, cattrs); - current = arrayData()->getProperty(index); } current->value = Primitive::undefinedValue(); } @@ -1040,12 +1057,14 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * current->merge(cattrs, p, attrs); if (member) { InternalClass::changeMember(this, member, cattrs); + setProperty(index, current); } else { setArrayAttributes(index, cattrs); + arrayData()->setProperty(index, current); } return true; reject: - if (engine->currentContext()->strictMode) + if (engine->current->strictMode) engine->throwTypeError(); return false; } @@ -1135,11 +1154,11 @@ void Object::initSparseArray() DEFINE_OBJECT_VTABLE(ArrayObject); -Heap::ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list) - : Heap::Object(engine->arrayClass, engine->arrayPrototype()) +Heap::ArrayObject::ArrayObject(const QStringList &list) + : Heap::Object() { init(); - Scope scope(engine); + Scope scope(internalClass->engine); ScopedObject a(scope, this); // Converts a QStringList to JS. @@ -1150,19 +1169,19 @@ Heap::ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list) a->arrayReserve(len); ScopedValue v(scope); for (int ii = 0; ii < len; ++ii) - a->arrayPut(ii, (v = engine->newString(list.at(ii)))); + a->arrayPut(ii, (v = scope.engine->newString(list.at(ii)))); a->setArrayLengthUnchecked(len); } ReturnedValue ArrayObject::getLookup(const Managed *m, Lookup *l) { Scope scope(static_cast<const Object *>(m)->engine()); - ScopedString name(scope, scope.engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, scope.engine->current->compilationUnit->runtimeStrings[l->nameIndex]); if (name->equals(scope.engine->id_length())) { // special case, as the property is on the object itself l->getter = Lookup::arrayLengthGetter; const ArrayObject *a = static_cast<const ArrayObject *>(m); - return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].asReturnedValue(); + return a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->asReturnedValue(); } return Object::getLookup(m, l); } @@ -1170,9 +1189,9 @@ ReturnedValue ArrayObject::getLookup(const Managed *m, Lookup *l) uint ArrayObject::getLength(const Managed *m) { const ArrayObject *a = static_cast<const ArrayObject *>(m); - if (a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].isInteger()) - return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].integerValue(); - return Primitive::toUInt32(a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].doubleValue()); + if (a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->isInteger()) + return a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->integerValue(); + return Primitive::toUInt32(a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->doubleValue()); } QStringList ArrayObject::toQStringList() const diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index f129312819..58dab9691f 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -42,17 +42,19 @@ QT_BEGIN_NAMESPACE + namespace QV4 { namespace Heap { struct Object : Base { - inline Object(ExecutionEngine *engine); - Object(InternalClass *internal, QV4::Object *prototype); + inline Object() {} - const Property *propertyAt(uint index) const { return reinterpret_cast<const Property *>(memberData->data + index); } - Property *propertyAt(uint index) { return reinterpret_cast<Property *>(memberData->data + index); } + const Value *propertyData(uint index) const { if (index < inlineMemberSize) return reinterpret_cast<const Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; } + Value *propertyData(uint index) { if (index < inlineMemberSize) return reinterpret_cast<Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; } + uint inlineMemberOffset; + uint inlineMemberSize; InternalClass *internalClass; Pointer<Object> prototype; Pointer<MemberData> memberData; @@ -80,6 +82,13 @@ struct Object : Base { V4_MANAGED_SIZE_TEST \ QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m()); } +#define V4_INTERNALCLASS(c) \ + static QV4::InternalClass *defaultInternalClass(QV4::ExecutionEngine *e) \ + { return e->c; } +#define V4_PROTOTYPE(p) \ + static QV4::Object *defaultPrototype(QV4::ExecutionEngine *e) \ + { return e->p(); } + struct ObjectVTable { VTable vTable; @@ -124,21 +133,26 @@ const QV4::ObjectVTable classname::static_vtbl = \ struct Q_QML_EXPORT Object: Managed { V4_OBJECT2(Object, Object) Q_MANAGED_TYPE(Object) + V4_INTERNALCLASS(emptyClass) + V4_PROTOTYPE(objectPrototype) enum { - IsObject = true + IsObject = true, + GetterOffset = 0, + SetterOffset = 1 }; InternalClass *internalClass() const { return d()->internalClass; } - void setInternalClass(InternalClass *ic) { d()->internalClass = ic; } + void setInternalClass(InternalClass *ic); + + const Value *propertyData(uint index) const { return d()->propertyData(index); } + Value *propertyData(uint index) { return d()->propertyData(index); } - Heap::MemberData *memberData() { return d()->memberData; } - const Heap::MemberData *memberData() const { return d()->memberData; } Heap::ArrayData *arrayData() const { return d()->arrayData; } void setArrayData(ArrayData *a) { d()->arrayData = a->d(); } - const Property *propertyAt(uint index) const { return d()->propertyAt(index); } - Property *propertyAt(uint index) { return d()->propertyAt(index); } + void getProperty(uint index, Property *p, PropertyAttributes *attrs) const; + void setProperty(uint index, const Property *p); const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(d()->vtable()); } Heap::Object *prototype() const { return d()->prototype; } @@ -147,8 +161,8 @@ struct Q_QML_EXPORT Object: Managed { void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0); void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = 0); - Property *__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const; - Property *__getPropertyDescriptor__(uint index, PropertyAttributes *attrs) const; + Value *getValueOrSetter(String *name, PropertyAttributes *attrs); + Value *getValueOrSetter(uint index, PropertyAttributes *attrs); bool hasProperty(String *name) const; bool hasProperty(uint index) const; @@ -167,14 +181,14 @@ struct Q_QML_EXPORT Object: Managed { // void put(ExecutionEngine *engine, const QString &name, const Value &value); - static ReturnedValue getValue(const Value &thisObject, const Property *p, PropertyAttributes attrs); - ReturnedValue getValue(const Property *p, PropertyAttributes attrs) const { + static ReturnedValue getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs); + ReturnedValue getValue(const Value &v, PropertyAttributes attrs) const { Scope scope(this->engine()); ScopedValue t(scope, const_cast<Object *>(this)); - return getValue(t, p, attrs); + return getValue(t, v, attrs); } - void putValue(Property *pd, PropertyAttributes attrs, const Value &value); + void putValue(uint memberIndex, const Value &value); /* The spec default: Writable: true, Enumerable: false, Configurable: true */ void defineDefaultProperty(String *name, const Value &value) { @@ -189,10 +203,6 @@ struct Q_QML_EXPORT Object: Managed { void defineReadonlyProperty(const QString &name, const Value &value); void defineReadonlyProperty(String *name, const Value &value); - void ensureMemberIndex(QV4::ExecutionEngine *e, uint idx) { - d()->memberData = MemberData::reallocate(e, d()->memberData, idx); - } - void insertMember(String *s, const Value &v, PropertyAttributes attributes = Attr_Data) { Scope scope(engine()); ScopedProperty p(scope); @@ -269,7 +279,6 @@ public: return false; } - void ensureMemberIndex(uint idx); inline ReturnedValue get(String *name, bool *hasProperty = 0) const { return vtable()->get(this, name, hasProperty); } @@ -316,6 +325,8 @@ protected: static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); static uint getLength(const Managed *m); + void ensureMemberData(); + private: ReturnedValue internalGet(String *name, bool *hasProperty) const; ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const; @@ -330,39 +341,19 @@ private: namespace Heap { -inline Object::Object(ExecutionEngine *engine) - : internalClass(engine->emptyClass), - prototype(static_cast<Object *>(engine->objectPrototype()->m())) -{ -} - struct BooleanObject : Object { - BooleanObject(InternalClass *ic, QV4::Object *prototype) - : Object(ic, prototype), - b(false) - { - } - - BooleanObject(ExecutionEngine *engine, bool b) - : Object(engine->emptyClass, engine->booleanPrototype()), - b(b) - { - } + BooleanObject() {} + BooleanObject(bool b) + : b(b) + {} bool b; }; struct NumberObject : Object { - NumberObject(InternalClass *ic, QV4::Object *prototype) - : Object(ic, prototype), - value(0) - { - } - - NumberObject(ExecutionEngine *engine, double val) - : Object(engine->emptyClass, engine->numberPrototype()), - value(val) - { - } + NumberObject() {} + NumberObject(double val) + : value(val) + {} double value; }; @@ -371,15 +362,11 @@ struct ArrayObject : Object { LengthPropertyIndex = 0 }; - ArrayObject(ExecutionEngine *engine) - : Heap::Object(engine->arrayClass, engine->arrayPrototype()) - { init(); } - ArrayObject(ExecutionEngine *engine, const QStringList &list); - ArrayObject(InternalClass *ic, QV4::Object *prototype) - : Heap::Object(ic, prototype) + ArrayObject() { init(); } + ArrayObject(const QStringList &list); void init() - { memberData->data[LengthPropertyIndex] = Primitive::fromInt32(0); } + { *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); } }; } @@ -387,6 +374,7 @@ struct ArrayObject : Object { struct BooleanObject: Object { V4_OBJECT2(BooleanObject, Object) Q_MANAGED_TYPE(BooleanObject) + V4_PROTOTYPE(booleanPrototype) bool value() const { return d()->b; } @@ -395,6 +383,7 @@ struct BooleanObject: Object { struct NumberObject: Object { V4_OBJECT2(NumberObject, Object) Q_MANAGED_TYPE(NumberObject) + V4_PROTOTYPE(numberPrototype) double value() const { return d()->value; } }; @@ -402,6 +391,8 @@ struct NumberObject: Object { struct ArrayObject: Object { V4_OBJECT2(ArrayObject, Object) Q_MANAGED_TYPE(ArrayObject) + V4_INTERNALCLASS(arrayClass) + V4_PROTOTYPE(arrayPrototype) void init(ExecutionEngine *engine); @@ -415,7 +406,7 @@ struct ArrayObject: Object { inline void Object::setArrayLengthUnchecked(uint l) { if (isArrayObject()) - memberData()->data[Heap::ArrayObject::LengthPropertyIndex] = Primitive::fromUInt32(l); + *propertyData(Heap::ArrayObject::LengthPropertyIndex) = Primitive::fromUInt32(l); } inline void Object::push_back(const Value &v) @@ -438,10 +429,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a arrayData()->vtable()->reallocate(this, index + 1, false); } setArrayAttributes(index, attributes); - Property *pd = ArrayData::insert(this, index, attributes.isAccessor()); - pd->value = p->value; - if (attributes.isAccessor()) - pd->set = p->set; + ArrayData::insert(this, index, &p->value, attributes.isAccessor()); if (isArrayObject() && index >= getLength()) setArrayLengthUnchecked(index + 1); } @@ -453,8 +441,7 @@ inline void Object::arraySet(uint index, const Value &value) if (index > 0x1000 && index > 2*d()->arrayData->alloc) { initSparseArray(); } - Property *pd = ArrayData::insert(this, index); - pd->value = value; + ArrayData::insert(this, index, &value); if (isArrayObject() && index >= getLength()) setArrayLengthUnchecked(index + 1); } diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index 585f9f5c2e..7f97872092 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -144,7 +144,7 @@ ReturnedValue ObjectIterator::nextPropertyName(Value *value) if (attrs.isEmpty()) return Encode::null(); - *value = object->objectValue()->getValue(p, attrs); + *value = object->objectValue()->getValue(p->value, attrs); if (!!name) return name->asReturnedValue(); @@ -166,7 +166,7 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString(Value *value) if (attrs.isEmpty()) return Encode::null(); - *value = object->objectValue()->getValue(p, attrs); + *value = object->objectValue()->getValue(p->value, attrs); if (!!name) return name->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index bfe04b33aa..e34b641be9 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -67,7 +67,7 @@ struct Q_QML_EXPORT ObjectIterator namespace Heap { struct ForEachIteratorObject : Object { - ForEachIteratorObject(QV4::ExecutionEngine *engine, QV4::Object *o); + ForEachIteratorObject(QV4::Object *o); ObjectIterator it; Value workArea[2]; }; @@ -85,9 +85,8 @@ protected: }; inline -Heap::ForEachIteratorObject::ForEachIteratorObject(QV4::ExecutionEngine *engine, QV4::Object *o) - : Heap::Object(engine) - , it(engine, workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) +Heap::ForEachIteratorObject::ForEachIteratorObject(QV4::Object *o) + : it(internalClass->engine, workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) { } diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 1edf76e2de..df7441ef5d 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -108,7 +108,7 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) defineDefaultProperty(QStringLiteral("__defineGetter__"), method_defineGetter, 2); defineDefaultProperty(QStringLiteral("__defineSetter__"), method_defineSetter, 2); - ScopedContext global(scope, scope.engine->rootContext()); + ExecutionContext *global = v4->rootContext(); ScopedProperty p(scope); p->value = BuiltinFunction::create(global, v4->id___proto__(), method_get_proto); p->set = BuiltinFunction::create(global, v4->id___proto__(), method_set_proto); @@ -141,9 +141,9 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx) if (scope.hasException()) return Encode::undefined(); PropertyAttributes attrs; - Property desc; - O->getOwnProperty(name, &attrs, &desc); - return fromPropertyDescriptor(scope.engine, &desc, attrs); + ScopedProperty desc(scope); + O->getOwnProperty(name, &attrs, desc); + return fromPropertyDescriptor(scope.engine, desc, attrs); } ReturnedValue ObjectPrototype::method_getOwnPropertyNames(CallContext *context) @@ -222,7 +222,7 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx) if (attrs.isEmpty()) break; PropertyAttributes nattrs; - val = o->getValue(pd, attrs); + val = o->getValue(pd->value, attrs); toPropertyDescriptor(scope.engine, val, n, &nattrs); if (scope.engine->hasException) return Encode::undefined(); @@ -630,7 +630,7 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionEngine *engine, const Property *desc, PropertyAttributes attrs) { - if (!desc) + if (attrs.isEmpty()) return Encode::undefined(); Scope scope(engine); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 82e232d28c..ee294b3678 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -228,9 +228,8 @@ static QV4::ReturnedValue LoadProperty(QV4::ExecutionEngine *v4, QObject *object } } -Heap::QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object) - : Heap::Object(engine) - , object(object) +Heap::QObjectWrapper::QObjectWrapper(QObject *object) + : object(object) { } @@ -255,7 +254,7 @@ QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlCont return result; } -ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *n, QObjectWrapper::RevisionMode revisionMode, +ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty, bool includeImports) const { if (QQmlData::wasDeleted(d()->object)) { @@ -264,20 +263,18 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String return QV4::Encode::undefined(); } - QV4::Scope scope(engine()); - QV4::ScopedString name(scope, n); + ExecutionEngine *v4 = engine(); - if (name->equals(scope.engine->id_destroy()) || name->equals(scope.engine->id_toString())) { - int index = name->equals(scope.engine->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod; - ScopedContext global(scope, scope.engine->rootContext()); - QV4::ScopedValue method(scope, QV4::QObjectMethod::create(global, d()->object, index)); + if (name->equals(v4->id_destroy()) || name->equals(v4->id_toString())) { + int index = name->equals(v4->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod; if (hasProperty) *hasProperty = true; - return method->asReturnedValue(); + ExecutionContext *global = v4->rootContext(); + return QV4::QObjectMethod::create(global, d()->object, index); } QQmlPropertyData local; - QQmlPropertyData *result = findProperty(scope.engine, qmlContext, name, revisionMode, &local); + QQmlPropertyData *result = findProperty(v4, qmlContext, name, revisionMode, &local); if (!result) { if (includeImports && name->startsWithUpper()) { @@ -292,10 +289,10 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String if (r.scriptIndex != -1) { return QV4::Encode::undefined(); } else if (r.type) { - return QmlTypeWrapper::create(scope.engine, d()->object, + return QmlTypeWrapper::create(v4, d()->object, r.type, Heap::QmlTypeWrapper::ExcludeEnums); } else if (r.importNamespace) { - return QmlTypeWrapper::create(scope.engine, d()->object, + return QmlTypeWrapper::create(v4, d()->object, qmlContext->imports, r.importNamespace, Heap::QmlTypeWrapper::ExcludeEnums); } Q_ASSERT(!"Unreachable"); @@ -318,13 +315,11 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String if (hasProperty) *hasProperty = true; - return getProperty(scope.engine, d()->object, result); + return getProperty(v4, d()->object, result); } ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired) { - QV4::Scope scope(engine); - QQmlData::flushPendingBinding(object, property->coreIndex); if (property->isFunction() && !property->isVarProperty()) { @@ -333,24 +328,19 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje Q_ASSERT(vmemo); return vmemo->vmeMethod(property->coreIndex); } else if (property->isV4Function()) { - ScopedContext global(scope, scope.engine->qmlContext()); + Scope scope(engine); + ScopedContext global(scope, engine->qmlContext()); return QV4::QObjectMethod::create(global, object, property->coreIndex); } else if (property->isSignalHandler()) { - QV4::Scoped<QV4::QmlSignalHandler> handler(scope, scope.engine->memoryManager->alloc<QV4::QmlSignalHandler>(engine, object, property->coreIndex)); - - QV4::ScopedString connect(scope, engine->newIdentifier(QStringLiteral("connect"))); - QV4::ScopedString disconnect(scope, engine->newIdentifier(QStringLiteral("disconnect"))); - handler->put(connect, QV4::ScopedValue(scope, engine->functionPrototype()->get(connect))); - handler->put(disconnect, QV4::ScopedValue(scope, engine->functionPrototype()->get(disconnect))); - - return handler.asReturnedValue(); + QmlSignalHandler::initProto(engine); + return engine->memoryManager->allocObject<QV4::QmlSignalHandler>(object, property->coreIndex)->asReturnedValue(); } else { - ScopedContext global(scope, scope.engine->rootContext()); + ExecutionContext *global = engine->rootContext(); return QV4::QObjectMethod::create(global, object, property->coreIndex); } } - QQmlEnginePrivate *ep = scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : 0; + QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; if (property->hasAccessors()) { QQmlNotifier *n = 0; @@ -359,6 +349,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje if (ep && ep->propertyCapture && property->accessors->notifier) nptr = &n; + Scope scope(engine); QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(engine, object, *property, nptr)); if (captureRequired) { @@ -390,7 +381,6 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty) { - QV4::Scope scope(engine); if (QQmlData::wasDeleted(object)) { if (hasProperty) *hasProperty = false; @@ -403,6 +393,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC return QV4::Encode::null(); } + QV4::Scope scope(engine); QV4::Scoped<QObjectWrapper> wrapper(scope, wrap(engine, object)); if (!wrapper) { if (hasProperty) @@ -419,11 +410,7 @@ bool QObjectWrapper::setQmlProperty(ExecutionEngine *engine, QQmlContextData *qm return false; QQmlPropertyData local; - QQmlPropertyData *result = 0; - { - result = QQmlPropertyCache::property(engine->jsEngine(), object, name, qmlContext, local); - } - + QQmlPropertyData *result = QQmlPropertyCache::property(engine->jsEngine(), object, name, qmlContext, local); if (!result) return false; @@ -433,8 +420,6 @@ bool QObjectWrapper::setQmlProperty(ExecutionEngine *engine, QQmlContextData *qm return false; } - Scope scope(engine); - ScopedContext ctx(scope, engine->currentContext()); setProperty(engine, object, result, value); return true; } @@ -686,7 +671,7 @@ ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object) { if (engine->jsEngine()) QQmlData::ensurePropertyCache(engine->jsEngine(), object); - return (engine->memoryManager->alloc<QV4::QObjectWrapper>(engine, object))->asReturnedValue(); + return (engine->memoryManager->allocObject<QV4::QObjectWrapper>(object))->asReturnedValue(); } QV4::ReturnedValue QObjectWrapper::get(const Managed *m, String *name, bool *hasProperty) @@ -1037,19 +1022,18 @@ void QObjectWrapper::destroyObject(bool lastCall) if (!h->internalClass) return; // destroyObject already got called - QPointer<QObject> object = h->object; - if (object) { - QQmlData *ddata = QQmlData::get(object, false); + if (h->object) { + QQmlData *ddata = QQmlData::get(h->object, false); if (ddata) { - if (!object->parent() && !ddata->indestructible) { + if (!h->object->parent() && !ddata->indestructible) { if (ddata && ddata->ownContext && ddata->context) ddata->context->emitDestruction(); // This object is notionally destroyed now ddata->isQueuedForDeletion = true; if (lastCall) - delete object; + delete h->object; else - object->deleteLater(); + h->object->deleteLater(); } } } @@ -1061,9 +1045,6 @@ void QObjectWrapper::destroyObject(bool lastCall) DEFINE_OBJECT_VTABLE(QObjectWrapper); -// XXX TODO: Need to review all calls to QQmlEngine *engine() to confirm QObjects work -// correctly in a worker thread - namespace { template<typename A, typename B, typename C, typename D, typename E, @@ -1729,24 +1710,23 @@ QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine) ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, int index) { Scope valueScope(scope); - Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->alloc<QObjectMethod>(scope)); + Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->allocObject<QObjectMethod>(scope)); method->d()->object = object; if (QQmlData *ddata = QQmlData::get(object)) method->d()->propertyCache = ddata->propertyCache; method->d()->index = index; - method->d()->valueTypeWrapper = Primitive::undefinedValue(); return method.asReturnedValue(); } ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index) { Scope valueScope(scope); - Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->alloc<QObjectMethod>(scope)); + Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->allocObject<QObjectMethod>(scope)); method->d()->propertyCache = valueType->d()->propertyCache; method->d()->index = index; - method->d()->valueTypeWrapper = *valueType; + method->d()->valueTypeWrapper = valueType->d(); return method.asReturnedValue(); } @@ -1815,8 +1795,8 @@ ReturnedValue QObjectMethod::call(const Managed *m, CallData *callData) ReturnedValue QObjectMethod::callInternal(CallData *callData) const { - Scope scope(engine()); - ScopedContext context(scope, scope.engine->currentContext()); + ExecutionEngine *v4 = engine(); + ExecutionContext *context = v4->currentContext; if (d()->index == DestroyMethod) return method_destroy(context, callData->args, callData->argc); else if (d()->index == ToStringMethod) @@ -1824,11 +1804,10 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) const QQmlObjectOrGadget object(d()->object.data()); if (!d()->object) { - Scoped<QQmlValueTypeWrapper> wrapper(scope, d()->valueTypeWrapper); - if (!wrapper) + if (!d()->valueTypeWrapper) return Encode::undefined(); - object = QQmlObjectOrGadget(d()->propertyCache.data(), wrapper->d()->gadgetPtr); + object = QQmlObjectOrGadget(d()->propertyCache.data(), d()->valueTypeWrapper->gadgetPtr); } QQmlPropertyData method; @@ -1860,8 +1839,9 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) const } if (method.isV4Function()) { + Scope scope(v4); QV4::ScopedValue rv(scope, QV4::Primitive::undefinedValue()); - QQmlV4Function func(callData, rv, scope.engine); + QQmlV4Function func(callData, rv, v4); QQmlV4Function *funcptr = &func; void *args[] = { 0, &funcptr }; @@ -1871,31 +1851,46 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) const } if (!method.isOverload()) { - return CallPrecise(object, method, scope.engine, callData); + return CallPrecise(object, method, v4, callData); } else { - return CallOverloaded(object, method, scope.engine, callData, d()->propertyCache); + return CallOverloaded(object, method, v4, callData, d()->propertyCache); } } void QObjectMethod::markObjects(Heap::Base *that, ExecutionEngine *e) { QObjectMethod::Data *This = static_cast<QObjectMethod::Data*>(that); - This->valueTypeWrapper.mark(e); + if (This->valueTypeWrapper) + This->valueTypeWrapper->mark(e); FunctionObject::markObjects(that, e); } DEFINE_OBJECT_VTABLE(QObjectMethod); -Heap::QmlSignalHandler::QmlSignalHandler(QV4::ExecutionEngine *engine, QObject *object, int signalIndex) - : Heap::Object(engine) - , object(object) +Heap::QmlSignalHandler::QmlSignalHandler(QObject *object, int signalIndex) + : object(object) , signalIndex(signalIndex) { } DEFINE_OBJECT_VTABLE(QmlSignalHandler); +void QmlSignalHandler::initProto(ExecutionEngine *engine) +{ + if (engine->signalHandlerPrototype()->d()) + return; + + Scope scope(engine); + ScopedObject o(scope, engine->newObject()); + QV4::ScopedString connect(scope, engine->newIdentifier(QStringLiteral("connect"))); + QV4::ScopedString disconnect(scope, engine->newIdentifier(QStringLiteral("disconnect"))); + o->put(connect, QV4::ScopedValue(scope, engine->functionPrototype()->get(connect))); + o->put(disconnect, QV4::ScopedValue(scope, engine->functionPrototype()->get(disconnect))); + + engine->jsObjects[QV4::ExecutionEngine::SignalHandlerProto] = o->d(); +} + void MultiplyWrappedQObjectMap::insert(QObject *key, Heap::Object *value) { QV4::WeakValue v; diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index da24c81f40..1126013806 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -69,8 +69,10 @@ struct QObjectSlotDispatcher; namespace Heap { +struct QQmlValueTypeWrapper; + struct QObjectWrapper : Object { - QObjectWrapper(QV4::ExecutionEngine *engine, QObject *object); + QObjectWrapper(QObject *object); QPointer<QObject> object; }; @@ -80,13 +82,13 @@ struct QObjectMethod : FunctionObject { QQmlRefPointer<QQmlPropertyCache> propertyCache; int index; - Value valueTypeWrapper; + Pointer<QQmlValueTypeWrapper> valueTypeWrapper; const QMetaObject *metaObject(); }; struct QmlSignalHandler : Object { - QmlSignalHandler(QV4::ExecutionEngine *engine, QObject *object, int signalIndex); + QmlSignalHandler(QObject *object, int signalIndex); QPointer<QObject> object; int signalIndex; }; @@ -167,10 +169,13 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject struct QmlSignalHandler : public QV4::Object { V4_OBJECT2(QmlSignalHandler, QV4::Object) + V4_PROTOTYPE(signalHandlerPrototype) V4_NEEDS_DESTROY int signalIndex() const { return d()->signalIndex; } QObject *object() const { return d()->object.data(); } + + static void initProto(ExecutionEngine *v4); }; class MultiplyWrappedQObjectMap : public QObject, diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 329e5d2c56..1839ff17ab 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -62,35 +62,30 @@ Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyn using namespace QV4; DEFINE_OBJECT_VTABLE(RegExpObject); -DEFINE_OBJECT_VTABLE(RegExpPrototype); -Heap::RegExpObject::RegExpObject(InternalClass *ic, QV4::Object *prototype) - : Heap::Object(ic, prototype) +Heap::RegExpObject::RegExpObject() { - Scope scope(ic->engine); + Scope scope(internalClass->engine); Scoped<QV4::RegExpObject> o(scope, this); - o->d()->value = QV4::RegExp::create(ic->engine, QString(), false, false); + o->d()->value = QV4::RegExp::create(scope.engine, QString(), false, false); o->d()->global = false; - o->init(ic->engine); + o->initProperties(); } -Heap::RegExpObject::RegExpObject(QV4::ExecutionEngine *engine, QV4::RegExp *value, bool global) - : Heap::Object(engine->emptyClass, engine->regExpPrototype()) - , value(value->d()) +Heap::RegExpObject::RegExpObject(QV4::RegExp *value, bool global) + : value(value->d()) , global(global) { - Scope scope(engine); + Scope scope(internalClass->engine); Scoped<QV4::RegExpObject> o(scope, this); - o->init(engine); + o->initProperties(); } // Converts a QRegExp to a JS RegExp. // The conversion is not 100% exact since ECMA regexp and QRegExp // have different semantics/flags, but we try to do our best. -Heap::RegExpObject::RegExpObject(QV4::ExecutionEngine *engine, const QRegExp &re) - : Heap::Object(engine->emptyClass, engine->regExpPrototype()) +Heap::RegExpObject::RegExpObject(const QRegExp &re) { - value = 0; global = false; // Convert the pattern to a ECMAScript pattern. @@ -130,26 +125,21 @@ Heap::RegExpObject::RegExpObject(QV4::ExecutionEngine *engine, const QRegExp &re pattern = ecmaPattern; } - Scope scope(engine); + Scope scope(internalClass->engine); Scoped<QV4::RegExpObject> o(scope, this); - o->d()->value = QV4::RegExp::create(engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false); + o->d()->value = QV4::RegExp::create(scope.engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false); - o->init(engine); + o->initProperties(); } -void RegExpObject::init(ExecutionEngine *engine) +void RegExpObject::initProperties() { - Scope scope(engine); - ScopedObject protectThis(scope, this); + *propertyData(Index_LastIndex) = Primitive::fromInt32(0); - ScopedString lastIndex(scope, engine->newIdentifier(QStringLiteral("lastIndex"))); - ScopedValue v(scope, Primitive::fromInt32(0)); - insertMember(lastIndex, v, Attr_NotEnumerable|Attr_NotConfigurable); - if (!this->value()) - return; + Q_ASSERT(value()); - QString p = this->value()->pattern; + QString p = value()->pattern; if (p.isEmpty()) { p = QStringLiteral("(?:)"); } else { @@ -157,10 +147,10 @@ void RegExpObject::init(ExecutionEngine *engine) p.replace('/', QLatin1String("\\/")); } - defineReadonlyProperty(QStringLiteral("source"), (v = engine->newString(p))); - defineReadonlyProperty(QStringLiteral("global"), Primitive::fromBoolean(global())); - defineReadonlyProperty(QStringLiteral("ignoreCase"), Primitive::fromBoolean(this->value()->ignoreCase)); - defineReadonlyProperty(QStringLiteral("multiline"), Primitive::fromBoolean(this->value()->multiLine)); + *propertyData(Index_Source) = engine()->newString(p); + *propertyData(Index_Global) = Primitive::fromBoolean(global()); + *propertyData(Index_IgnoreCase) = Primitive::fromBoolean(value()->ignoreCase); + *propertyData(Index_Multiline) = Primitive::fromBoolean(value()->multiLine); } @@ -172,10 +162,10 @@ void RegExpObject::markObjects(Heap::Base *that, ExecutionEngine *e) Object::markObjects(that, e); } -Property *RegExpObject::lastIndexProperty() +Value *RegExpObject::lastIndexProperty() { Q_ASSERT(0 == internalClass()->find(engine()->id_lastIndex())); - return propertyAt(0); + return propertyData(0); } // Converts a JS RegExp to a QRegExp. @@ -239,17 +229,16 @@ void Heap::RegExpCtor::clearLastMatch() ReturnedValue RegExpCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const Object *>(m)->engine()); - ScopedContext ctx(scope, scope.engine->currentContext()); ScopedValue r(scope, callData->argument(0)); ScopedValue f(scope, callData->argument(1)); Scoped<RegExpObject> re(scope, r); if (re) { if (!f->isUndefined()) - return ctx->engine()->throwTypeError(); + return scope.engine->throwTypeError(); Scoped<RegExp> regexp(scope, re->value()); - return Encode(ctx->d()->engine->newRegExpObject(regexp, re->global())); + return Encode(scope.engine->newRegExpObject(regexp, re->global())); } QString pattern; @@ -274,16 +263,16 @@ ReturnedValue RegExpCtor::construct(const Managed *m, CallData *callData) } else if (str.at(i) == QLatin1Char('m') && !multiLine) { multiLine = true; } else { - return ctx->engine()->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor")); + return scope.engine->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor")); } } } - Scoped<RegExp> regexp(scope, RegExp::create(ctx->d()->engine, pattern, ignoreCase, multiLine)); + Scoped<RegExp> regexp(scope, RegExp::create(scope.engine, pattern, ignoreCase, multiLine)); if (!regexp->isValid()) - return ctx->engine()->throwSyntaxError(QStringLiteral("Invalid regular expression")); + return scope.engine->throwSyntaxError(QStringLiteral("Invalid regular expression")); - return Encode(ctx->d()->engine->newRegExpObject(regexp, global)); + return Encode(scope.engine->newRegExpObject(regexp, global)); } ReturnedValue RegExpCtor::call(const Managed *that, CallData *callData) @@ -354,9 +343,9 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) return Encode::undefined(); QString s = arg->stringValue()->toQString(); - int offset = r->global() ? r->lastIndexProperty()->value.toInt32() : 0; + int offset = r->global() ? r->lastIndexProperty()->toInt32() : 0; if (offset < 0 || offset > s.length()) { - r->lastIndexProperty()->value = Primitive::fromInt32(0); + *r->lastIndexProperty() = Primitive::fromInt32(0); return Encode::null(); } @@ -367,7 +356,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) regExpCtor->d()->clearLastMatch(); if (result == -1) { - r->lastIndexProperty()->value = Primitive::fromInt32(0); + *r->lastIndexProperty() = Primitive::fromInt32(0); return Encode::null(); } @@ -383,8 +372,8 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) array->arrayPut(i, v); } array->setArrayLengthUnchecked(len); - array->memberData()->data[Index_ArrayIndex] = Primitive::fromInt32(result); - array->memberData()->data[Index_ArrayInput] = arg; + *array->propertyData(Index_ArrayIndex) = Primitive::fromInt32(result); + *array->propertyData(Index_ArrayInput) = arg; RegExpCtor::Data *dd = regExpCtor->d(); dd->lastMatch = array; @@ -393,7 +382,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) dd->lastMatchEnd = matchOffsets[1]; if (r->global()) - r->lastIndexProperty()->value = Primitive::fromInt32(matchOffsets[1]); + *r->lastIndexProperty() = Primitive::fromInt32(matchOffsets[1]); return array.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index 29d20614de..4f803df9c8 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -57,9 +57,9 @@ namespace QV4 { namespace Heap { struct RegExpObject : Object { - RegExpObject(InternalClass *ic, QV4::Object *prototype); - RegExpObject(QV4::ExecutionEngine *engine, QV4::RegExp *value, bool global); - RegExpObject(QV4::ExecutionEngine *engine, const QRegExp &re); + RegExpObject(); + RegExpObject(QV4::RegExp *value, bool global); + RegExpObject(const QRegExp &re); Pointer<RegExp> value; bool global; @@ -74,16 +74,13 @@ struct RegExpCtor : FunctionObject { void clearLastMatch(); }; -struct RegExpPrototype : RegExpObject -{ - inline RegExpPrototype(ExecutionEngine *e); -}; - } struct RegExpObject: Object { V4_OBJECT2(RegExpObject, Object) Q_MANAGED_TYPE(RegExpObject) + V4_INTERNALCLASS(regExpObjectClass) + V4_PROTOTYPE(regExpPrototype) // needs to be compatible with the flags in qv4jsir_p.h enum Flags { @@ -93,6 +90,11 @@ struct RegExpObject: Object { }; enum { + Index_LastIndex = 0, + Index_Source = 1, + Index_Global = 2, + Index_IgnoreCase = 3, + Index_Multiline = 4, Index_ArrayIndex = Heap::ArrayObject::LengthPropertyIndex + 1, Index_ArrayInput = Index_ArrayIndex + 1 }; @@ -100,9 +102,9 @@ struct RegExpObject: Object { Heap::RegExp *value() const { return d()->value; } bool global() const { return d()->global; } - void init(ExecutionEngine *engine); + void initProperties(); - Property *lastIndexProperty(); + Value *lastIndexProperty(); QRegExp toQRegExp() const; QString toString() const; QString source() const; @@ -128,8 +130,6 @@ struct RegExpCtor: FunctionObject struct RegExpPrototype: RegExpObject { - V4_OBJECT2(RegExpPrototype, RegExpObject) - void init(ExecutionEngine *engine, Object *ctor); static ReturnedValue method_exec(CallContext *ctx); @@ -145,11 +145,6 @@ struct RegExpPrototype: RegExpObject static ReturnedValue method_get_rightContext(CallContext *ctx); }; -inline Heap::RegExpPrototype::RegExpPrototype(ExecutionEngine *e) - : RegExpObject(e->emptyClass, e->objectPrototype()) -{ -} - } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 9316223696..0d7a1851b8 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -268,10 +268,9 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix) ReturnedValue Runtime::closure(ExecutionEngine *engine, int functionId) { - QV4::Function *clos = engine->currentContext()->compilationUnit->runtimeFunctions[functionId]; + QV4::Function *clos = engine->current->compilationUnit->runtimeFunctions[functionId]; Q_ASSERT(clos); - Scope scope(engine); - return FunctionObject::createScriptFunction(ScopedContext(scope, engine->currentContext()), clos)->asReturnedValue(); + return FunctionObject::createScriptFunction(engine->currentContext, clos)->asReturnedValue(); } ReturnedValue Runtime::deleteElement(ExecutionEngine *engine, const Value &base, const Value &index) @@ -292,7 +291,7 @@ ReturnedValue Runtime::deleteElement(ExecutionEngine *engine, const Value &base, ReturnedValue Runtime::deleteMember(ExecutionEngine *engine, const Value &base, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); return deleteMemberString(engine, base, name); } @@ -308,9 +307,8 @@ ReturnedValue Runtime::deleteMemberString(ExecutionEngine *engine, const Value & ReturnedValue Runtime::deleteName(ExecutionEngine *engine, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); - ScopedContext ctx(scope, engine->currentContext()); - return Encode(ctx->deleteProperty(name)); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); + return Encode(engine->currentContext->deleteProperty(name)); } QV4::ReturnedValue Runtime::instanceof(ExecutionEngine *engine, const Value &left, const Value &right) @@ -566,7 +564,7 @@ QV4::ReturnedValue Runtime::addString(ExecutionEngine *engine, const Value &left void Runtime::setProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); ScopedObject o(scope, object.toObject(engine)); if (!o) return; @@ -663,15 +661,14 @@ ReturnedValue Runtime::foreachNextPropertyName(const Value &foreach_iterator) void Runtime::setActivationProperty(ExecutionEngine *engine, int nameIndex, const Value &value) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); - ScopedContext ctx(scope, engine->currentContext()); - ctx->setProperty(name, value); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); + engine->currentContext->setProperty(name, value); } ReturnedValue Runtime::getProperty(ExecutionEngine *engine, const Value &object, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); ScopedObject o(scope, object); if (o) @@ -691,9 +688,8 @@ ReturnedValue Runtime::getProperty(ExecutionEngine *engine, const Value &object, ReturnedValue Runtime::getActivationProperty(ExecutionEngine *engine, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); - ScopedContext ctx(scope, engine->currentContext()); - return ctx->getProperty(name); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); + return engine->currentContext->getProperty(name); } #endif // V4_BOOTSTRAP @@ -909,12 +905,12 @@ ReturnedValue Runtime::callGlobalLookup(ExecutionEngine *engine, uint index, Cal Scope scope(engine); Q_ASSERT(callData->thisObject.isUndefined()); - Lookup *l = engine->currentContext()->lookups + index; + Lookup *l = engine->current->lookups + index; ScopedFunctionObject o(scope, l->globalGetter(l, engine)); if (!o) return engine->throwTypeError(); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]); if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) return static_cast<EvalFunction *>(o.getPointer())->evalCall(callData, true); @@ -926,11 +922,10 @@ ReturnedValue Runtime::callActivationProperty(ExecutionEngine *engine, int nameI { Q_ASSERT(callData->thisObject.isUndefined()); Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); ScopedObject base(scope); - ScopedContext ctx(scope, engine->currentContext()); - ScopedValue func(scope, ctx->getPropertyAndBase(name, base.getRef())); + ScopedValue func(scope, engine->currentContext->getPropertyAndBase(name, base.getRef())); if (scope.engine->hasException) return Encode::undefined(); @@ -980,7 +975,7 @@ ReturnedValue Runtime::callQmlContextObjectProperty(ExecutionEngine *engine, int ReturnedValue Runtime::callProperty(ExecutionEngine *engine, int nameIndex, CallData *callData) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); ScopedObject baseObject(scope, callData->thisObject); if (!baseObject) { Q_ASSERT(!callData->thisObject.isEmpty()); @@ -1006,7 +1001,7 @@ ReturnedValue Runtime::callProperty(ExecutionEngine *engine, int nameIndex, Call ReturnedValue Runtime::callPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData) { - Lookup *l = engine->currentContext()->lookups + index; + Lookup *l = engine->current->lookups + index; Value v; v = l->getter(l, engine, callData->thisObject); if (!v.isObject()) @@ -1046,7 +1041,7 @@ ReturnedValue Runtime::constructGlobalLookup(ExecutionEngine *engine, uint index Scope scope(engine); Q_ASSERT(callData->thisObject.isUndefined()); - Lookup *l = engine->currentContext()->lookups + index; + Lookup *l = engine->current->lookups + index; ScopedObject f(scope, l->globalGetter(l, engine)); if (!f) return engine->throwTypeError(); @@ -1058,9 +1053,8 @@ ReturnedValue Runtime::constructGlobalLookup(ExecutionEngine *engine, uint index ReturnedValue Runtime::constructActivationProperty(ExecutionEngine *engine, int nameIndex, CallData *callData) { Scope scope(engine); - ScopedContext ctx(scope, engine->currentContext()); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); - ScopedValue func(scope, ctx->getProperty(name)); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); + ScopedValue func(scope, engine->currentContext->getProperty(name)); if (scope.engine->hasException) return Encode::undefined(); @@ -1084,7 +1078,7 @@ ReturnedValue Runtime::constructProperty(ExecutionEngine *engine, int nameIndex, { Scope scope(engine); ScopedObject thisObject(scope, callData->thisObject.toObject(engine)); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); if (scope.engine->hasException) return Encode::undefined(); @@ -1097,7 +1091,7 @@ ReturnedValue Runtime::constructProperty(ExecutionEngine *engine, int nameIndex, ReturnedValue Runtime::constructPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData) { - Lookup *l = engine->currentContext()->lookups + index; + Lookup *l = engine->current->lookups + index; Value v; v = l->getter(l, engine, callData->thisObject); if (!v.isObject()) @@ -1145,9 +1139,8 @@ ReturnedValue Runtime::typeofValue(ExecutionEngine *engine, const Value &value) QV4::ReturnedValue Runtime::typeofName(ExecutionEngine *engine, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); - ScopedContext ctx(scope, engine->currentContext()); - ScopedValue prop(scope, ctx->getProperty(name)); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); + ScopedValue prop(scope, engine->currentContext->getProperty(name)); // typeof doesn't throw. clear any possible exception scope.engine->hasException = false; return Runtime::typeofValue(engine, prop); @@ -1156,7 +1149,7 @@ QV4::ReturnedValue Runtime::typeofName(ExecutionEngine *engine, int nameIndex) QV4::ReturnedValue Runtime::typeofMember(ExecutionEngine *engine, const Value &base, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); ScopedObject obj(scope, base.toObject(engine)); if (scope.engine->hasException) return Encode::undefined(); @@ -1175,14 +1168,6 @@ QV4::ReturnedValue Runtime::typeofElement(ExecutionEngine *engine, const Value & return Runtime::typeofValue(engine, prop); } -void Runtime::pushWithScope(const Value &o, ExecutionEngine *engine) -{ - Scope scope(engine); - ScopedObject obj(scope, o.toObject(engine)); - ScopedContext ctx(scope, engine->currentContext()); - ctx->newWithContext(obj); -} - ReturnedValue Runtime::unwindException(ExecutionEngine *engine) { if (!engine->hasException) @@ -1190,45 +1175,47 @@ ReturnedValue Runtime::unwindException(ExecutionEngine *engine) return engine->catchException(0); } +/* The next three methods are a bit tricky. They can't open up a Scope, as that + * would mess up the pushing of the context. + * + * Instead the push/pop pair acts as a non local scope. + */ +void Runtime::pushWithScope(const Value &o, ExecutionEngine *engine) +{ + engine->pushContext(engine->currentContext->newWithContext(o.toObject(engine))); + Q_ASSERT(engine->jsStackTop = engine->currentContext + 2); +} + void Runtime::pushCatchScope(NoThrowEngine *engine, int exceptionVarNameIndex) { - Scope scope(engine); - ScopedValue v(scope, engine->catchException(0)); - ScopedString exceptionVarName(scope, engine->currentContext()->compilationUnit->runtimeStrings[exceptionVarNameIndex]); - ScopedContext ctx(scope, engine->currentContext()); - ctx->newCatchContext(exceptionVarName, v); + ExecutionContext *c = engine->currentContext; + engine->pushContext(c->newCatchContext(c->d()->compilationUnit->runtimeStrings[exceptionVarNameIndex], engine->catchException(0))); + Q_ASSERT(engine->jsStackTop = engine->currentContext + 2); } void Runtime::popScope(ExecutionEngine *engine) { + Q_ASSERT(engine->jsStackTop = engine->currentContext + 2); engine->popContext(); + engine->jsStackTop -= 2; } void Runtime::declareVar(ExecutionEngine *engine, bool deletable, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); - ScopedContext ctx(scope, engine->currentContext()); - ctx->createMutableBinding(name, deletable); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); + engine->currentContext->createMutableBinding(name, deletable); } ReturnedValue Runtime::arrayLiteral(ExecutionEngine *engine, Value *values, uint length) { - Scope scope(engine); - ScopedArrayObject a(scope, engine->newArrayObject()); - - if (length) { - a->arrayReserve(length); - a->arrayPut(0, values, length); - a->setArrayLengthUnchecked(length); - } - return a.asReturnedValue(); + return engine->newArrayObject(values, length)->asReturnedValue(); } ReturnedValue Runtime::objectLiteral(ExecutionEngine *engine, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags) { Scope scope(engine); - QV4::InternalClass *klass = engine->currentContext()->compilationUnit->runtimeClasses[classId]; + QV4::InternalClass *klass = engine->current->compilationUnit->runtimeClasses[classId]; ScopedObject o(scope, engine->newObject(klass, engine->objectPrototype())); { @@ -1238,7 +1225,7 @@ ReturnedValue Runtime::objectLiteral(ExecutionEngine *engine, const QV4::Value * } for (uint i = 0; i < klass->size; ++i) - o->memberData()->data[i] = *args++; + *o->propertyData(i) = *args++; if (arrayValueCount > 0) { ScopedValue entry(scope); @@ -1269,10 +1256,10 @@ ReturnedValue Runtime::objectLiteral(ExecutionEngine *engine, const QV4::Value * QV4::ReturnedValue Runtime::setupArgumentsObject(ExecutionEngine *engine) { - Q_ASSERT(engine->currentContext()->type == Heap::ExecutionContext::Type_CallContext); - Scope scope(engine); - Scoped<CallContext> c(scope, static_cast<Heap::CallContext *>(engine->currentContext())); - return (engine->memoryManager->alloc<ArgumentsObject>(c))->asReturnedValue(); + Q_ASSERT(engine->current->type == Heap::ExecutionContext::Type_CallContext); + QV4::CallContext *c = static_cast<QV4::CallContext *>(engine->currentContext); + QV4::InternalClass *ic = c->d()->strictMode ? engine->strictArgumentsObjectClass : engine->argumentsObjectClass; + return engine->memoryManager->allocObject<ArgumentsObject>(ic, engine->objectPrototype(), c)->asReturnedValue(); } #endif // V4_BOOTSTRAP @@ -1363,7 +1350,7 @@ ReturnedValue Runtime::getQmlContext(NoThrowEngine *engine) ReturnedValue Runtime::regexpLiteral(ExecutionEngine *engine, int id) { - return engine->currentContext()->compilationUnit->runtimeRegularExpressions[id].asReturnedValue(); + return engine->current->compilationUnit->runtimeRegularExpressions[id].asReturnedValue(); } ReturnedValue Runtime::getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired) @@ -1459,13 +1446,13 @@ ReturnedValue Runtime::getQmlImportedScripts(NoThrowEngine *engine) QV4::ReturnedValue Runtime::getQmlSingleton(QV4::NoThrowEngine *engine, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); return engine->qmlSingletonWrapper(name); } void Runtime::convertThisToObject(ExecutionEngine *engine) { - Value *t = &engine->currentContext()->callData->thisObject; + Value *t = &engine->current->callData->thisObject; if (t->isObject()) return; if (t->isNullOrUndefined()) { diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index e19aeaf882..0c79897015 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -54,18 +54,12 @@ struct ScopedValue; struct Scope { inline Scope(ExecutionContext *ctx) : engine(ctx->d()->engine) -#ifndef QT_NO_DEBUG - , size(0) -#endif { mark = engine->jsStackTop; } explicit Scope(ExecutionEngine *e) : engine(e) -#ifndef QT_NO_DEBUG - , size(0) -#endif { mark = engine->jsStackTop; } @@ -73,6 +67,7 @@ struct Scope { ~Scope() { #ifndef QT_NO_DEBUG Q_ASSERT(engine->jsStackTop >= mark); + Q_ASSERT(engine->currentContext < mark); memset(mark, 0, (engine->jsStackTop - mark)*sizeof(Value)); #endif #ifdef V4_USE_VALGRIND @@ -82,9 +77,6 @@ struct Scope { } Value *alloc(int nValues) { -#ifndef QT_NO_DEBUG - size += nValues; -#endif return engine->jsAlloca(nValues); } @@ -94,9 +86,6 @@ struct Scope { ExecutionEngine *engine; Value *mark; -#ifndef QT_NO_DEBUG - mutable int size; -#endif private: Q_DISABLE_COPY(Scope) @@ -108,18 +97,12 @@ struct ScopedValue { ptr = scope.engine->jsStackTop++; ptr->setRawValue(0); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } ScopedValue(const Scope &scope, const Value &v) { ptr = scope.engine->jsStackTop++; *ptr = v; -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } ScopedValue(const Scope &scope, Heap::Base *o) @@ -129,27 +112,18 @@ struct ScopedValue #if QT_POINTER_SIZE == 4 ptr->setTag(QV4::Value::Managed_Type); #endif -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } ScopedValue(const Scope &scope, Managed *m) { ptr = scope.engine->jsStackTop++; ptr->setRawValue(m->asReturnedValue()); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } ScopedValue(const Scope &scope, const ReturnedValue &v) { ptr = scope.engine->jsStackTop++; ptr->setRawValue(v); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } ScopedValue &operator=(const Value &v) { @@ -213,18 +187,12 @@ struct Scoped #if QT_POINTER_SIZE == 4 ptr->setTag(QV4::Value::Managed_Type); #endif -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, const Value &v) { ptr = scope.engine->jsStackTop++; setPointer(v.as<T>()); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, Heap::Base *o) { @@ -232,69 +200,45 @@ struct Scoped v = o; ptr = scope.engine->jsStackTop++; setPointer(v.as<T>()); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, const ScopedValue &v) { ptr = scope.engine->jsStackTop++; setPointer(v.ptr->as<T>()); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, const Value &v, _Convert) { ptr = scope.engine->jsStackTop++; ptr->setRawValue(value_convert<T>(scope.engine, v)); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, const Value *v) { ptr = scope.engine->jsStackTop++; setPointer(v ? v->as<T>() : 0); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, T *t) { ptr = scope.engine->jsStackTop++; setPointer(t); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, typename T::Data *t) { ptr = scope.engine->jsStackTop++; *ptr = t; -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, const ReturnedValue &v) { ptr = scope.engine->jsStackTop++; setPointer(QV4::Value::fromReturnedValue(v).as<T>()); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, const ReturnedValue &v, _Convert) { ptr = scope.engine->jsStackTop++; ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v))); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped<T> &operator=(Heap::Base *o) { @@ -414,29 +358,18 @@ struct ScopedProperty struct ExecutionContextSaver { ExecutionEngine *engine; - Value *savedContext; + ExecutionContext *savedContext; - ExecutionContextSaver(Scope &scope, ExecutionContext *context) - : engine(context->d()->engine) - , savedContext(scope.alloc(1)) + ExecutionContextSaver(Scope &scope) + : engine(scope.engine) { - savedContext->setM(context->d()); -#if QT_POINTER_SIZE == 4 - savedContext->setTag(QV4::Value::Managed_Type); -#endif - } - ExecutionContextSaver(Scope &scope, Heap::ExecutionContext *context) - : engine(context->engine) - , savedContext(scope.alloc(1)) - { - savedContext->setM(context); -#if QT_POINTER_SIZE == 4 - savedContext->setTag(QV4::Value::Managed_Type); -#endif + savedContext = engine->currentContext; } ~ExecutionContextSaver() { - engine->current = static_cast<Heap::ExecutionContext *>(savedContext->heapObject()); + Q_ASSERT(engine->jsStackTop > engine->currentContext); + engine->currentContext = savedContext; + engine->current = savedContext->d(); } }; diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 7067d10e22..7f2f22780e 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -59,11 +59,15 @@ namespace QV4 { namespace Heap { struct CompilationUnitHolder : Object { - inline CompilationUnitHolder(ExecutionEngine *engine, CompiledData::CompilationUnit *unit); + inline CompilationUnitHolder(CompiledData::CompilationUnit *unit); QQmlRefPointer<CompiledData::CompilationUnit> unit; }; +struct QmlBindingWrapper : FunctionObject { + QmlBindingWrapper(QV4::QmlContext *scope, Function *f); +}; + } struct CompilationUnitHolder : public Object @@ -73,12 +77,17 @@ struct CompilationUnitHolder : public Object }; inline -Heap::CompilationUnitHolder::CompilationUnitHolder(ExecutionEngine *engine, CompiledData::CompilationUnit *unit) - : Heap::Object(engine) - , unit(unit) +Heap::CompilationUnitHolder::CompilationUnitHolder(CompiledData::CompilationUnit *unit) + : unit(unit) { } +struct QmlBindingWrapper : FunctionObject { + V4_OBJECT2(QmlBindingWrapper, FunctionObject) + + static ReturnedValue call(const Managed *that, CallData *callData); +}; + } QT_END_NAMESPACE @@ -88,7 +97,7 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlBindingWrapper); DEFINE_OBJECT_VTABLE(CompilationUnitHolder); -Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::QmlContextWrapper *qml) +Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::QmlContext *scope, Function *f) : Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false) { Q_ASSERT(scope->inUse()); @@ -96,12 +105,6 @@ Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Functio function = f; if (function) function->compilationUnit->addref(); - - Scope s(scope); - Scoped<QV4::QmlBindingWrapper> protectThis(s, this); - - this->scope = scope->newQmlContext(qml); - internalClass->engine->popContext(); } ReturnedValue QmlBindingWrapper::call(const Managed *that, CallData *callData) @@ -113,65 +116,33 @@ ReturnedValue QmlBindingWrapper::call(const Managed *that, CallData *callData) CHECK_STACK_LIMITS(v4); Scope scope(v4); + ExecutionContextSaver ctxSaver(scope); + QV4::Function *f = This->function(); if (!f) return QV4::Encode::undefined(); - ScopedContext context(scope, v4->currentContext()); - Scoped<CallContext> ctx(scope, context->newCallContext(This, callData)); + Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(This, callData)); + v4->pushContext(ctx); - ExecutionContextSaver ctxSaver(scope, context); ScopedValue result(scope, Q_V4_PROFILE(v4, f)); return result->asReturnedValue(); } -static ReturnedValue signalParameterGetter(QV4::CallContext *ctx, uint parameterIndex) -{ - QV4::Scope scope(ctx); - QV4::Scoped<CallContext> signalEmittingContext(scope, ctx->d()->parent.cast<Heap::CallContext>()); - Q_ASSERT(signalEmittingContext && signalEmittingContext->d()->type >= QV4::Heap::ExecutionContext::Type_SimpleCallContext); - return signalEmittingContext->argument(parameterIndex); -} - -Heap::FunctionObject *QmlBindingWrapper::createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, Function *runtimeFunction, const QList<QByteArray> &signalParameters, QString *error) -{ - ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine); - QV4::Scope valueScope(engine); - QV4::Scoped<QmlContextWrapper> qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine, qmlContext, scopeObject)); - ScopedContext global(valueScope, valueScope.engine->rootContext()); - QV4::Scoped<QmlContext> wrapperContext(valueScope, global->newQmlContext(qmlScopeObject)); - engine->popContext(); - - if (!signalParameters.isEmpty()) { - if (error) - QQmlPropertyCache::signalParameterStringForJS(engine, signalParameters, error); - QV4::ScopedProperty p(valueScope); - QV4::ScopedString s(valueScope); - int index = 0; - foreach (const QByteArray ¶m, signalParameters) { - QV4::ScopedFunctionObject g(valueScope, engine->memoryManager->alloc<QV4::IndexedBuiltinFunction>(wrapperContext, index++, signalParameterGetter)); - p->setGetter(g); - p->setSetter(0); - s = engine->newString(QString::fromUtf8(param)); - qmlScopeObject->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable); - } - } - - QV4::ScopedFunctionObject function(valueScope, QV4::FunctionObject::createScriptFunction(wrapperContext, runtimeFunction)); - return function->d(); -} - -Script::Script(ExecutionEngine *v4, Object *qml, CompiledData::CompilationUnit *compilationUnit) +Script::Script(ExecutionEngine *v4, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit) : line(0), column(0), scope(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false) - , qml(v4, qml), vmFunction(0), parseAsBinding(true) + , vmFunction(0), parseAsBinding(true) { + if (qml) + qmlContext.set(v4, *qml); + parsed = true; vmFunction = compilationUnit ? compilationUnit->linkToEngine(v4) : 0; if (vmFunction) { Scope valueScope(v4); - ScopedObject holder(valueScope, v4->memoryManager->alloc<CompilationUnitHolder>(v4, compilationUnit)); + ScopedObject holder(valueScope, v4->memoryManager->allocObject<CompilationUnitHolder>(compilationUnit)); compilationUnitHolder.set(v4, holder); } } @@ -242,7 +213,7 @@ void Script::parse() isel->setUseFastLookups(false); QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = isel->compile(); vmFunction = compilationUnit->linkToEngine(v4); - ScopedObject holder(valueScope, v4->memoryManager->alloc<CompilationUnitHolder>(v4, compilationUnit)); + ScopedObject holder(valueScope, v4->memoryManager->allocObject<CompilationUnitHolder>(compilationUnit)); compilationUnitHolder.set(v4, holder); } @@ -263,10 +234,10 @@ ReturnedValue Script::run() QV4::ExecutionEngine *engine = scope->engine(); QV4::Scope valueScope(engine); - if (qml.isUndefined()) { + if (qmlContext.isUndefined()) { TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction); - ExecutionContextSaver ctxSaver(valueScope, scope); + ExecutionContextSaver ctxSaver(valueScope); ContextStateSaver stateSaver(valueScope, scope); scope->d()->strictMode = vmFunction->isStrict(); scope->d()->lookups = vmFunction->compilationUnit->runtimeLookups; @@ -274,8 +245,8 @@ ReturnedValue Script::run() return Q_V4_PROFILE(engine, vmFunction); } else { - Scoped<QmlContextWrapper> qmlObj(valueScope, qml.value()); - ScopedFunctionObject f(valueScope, engine->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj)); + Scoped<QmlContext> qml(valueScope, qmlContext.value()); + ScopedFunctionObject f(valueScope, engine->memoryManager->allocObject<QmlBindingWrapper>(qml, vmFunction)); ScopedCallData callData(valueScope); callData->thisObject = Primitive::undefinedValue(); return f->call(callData); @@ -352,15 +323,15 @@ ReturnedValue Script::qmlBinding() parse(); ExecutionEngine *v4 = scope->engine(); Scope valueScope(v4); - Scoped<QmlContextWrapper> qmlObj(valueScope, qml.value()); - ScopedObject v(valueScope, v4->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj)); + Scoped<QmlContext> qml(valueScope, qmlContext.value()); + ScopedObject v(valueScope, v4->memoryManager->allocObject<QmlBindingWrapper>(qml, vmFunction)); return v.asReturnedValue(); } -QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject) +QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext) { QV4::Scope scope(engine); - QV4::Script qmlScript(engine, scopeObject, script, QString()); + QV4::Script qmlScript(engine, qmlContext, script, QString()); qmlScript.parse(); QV4::ScopedValue result(scope); diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index fad011f88a..63e8239342 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -36,6 +36,7 @@ #include "qv4global_p.h" #include "qv4engine_p.h" #include "qv4functionobject_p.h" +#include "qv4context_p.h" #include <QQmlError> @@ -85,32 +86,19 @@ struct ContextStateSaver { } }; -namespace Heap { -struct QmlBindingWrapper : Heap::FunctionObject { - QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::QmlContextWrapper *qml); -}; - -} - -struct Q_QML_EXPORT QmlBindingWrapper : FunctionObject { - V4_OBJECT2(QmlBindingWrapper, FunctionObject) - - static ReturnedValue call(const Managed *that, CallData *callData); - - static Heap::FunctionObject *createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, - const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0); -}; - struct Q_QML_EXPORT Script { Script(ExecutionContext *scope, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) : sourceFile(source), line(line), column(column), sourceCode(sourceCode) , scope(scope), strictMode(false), inheritContext(false), parsed(false) , vmFunction(0), parseAsBinding(false) {} - Script(ExecutionEngine *engine, Object *qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) + Script(ExecutionEngine *engine, QmlContext *qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) : sourceFile(source), line(line), column(column), sourceCode(sourceCode) , scope(engine->rootContext()), strictMode(false), inheritContext(true), parsed(false) - , qml(engine, qml), vmFunction(0), parseAsBinding(true) {} - Script(ExecutionEngine *engine, Object *qml, CompiledData::CompilationUnit *compilationUnit); + , vmFunction(0), parseAsBinding(true) { + if (qml) + qmlContext.set(engine, *qml); + } + Script(ExecutionEngine *engine, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit); ~Script(); QString sourceFile; int line; @@ -120,7 +108,7 @@ struct Q_QML_EXPORT Script { bool strictMode; bool inheritContext; bool parsed; - QV4::PersistentValue qml; + QV4::PersistentValue qmlContext; QV4::PersistentValue compilationUnitHolder; Function *vmFunction; bool parseAsBinding; @@ -134,7 +122,7 @@ struct Q_QML_EXPORT Script { static QQmlRefPointer<CompiledData::CompilationUnit> precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors = 0, QQmlJS::Directives *directivesCollector = 0); - static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject); + static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext); }; } diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 23bbcc60e1..36ee848d00 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -207,8 +207,8 @@ namespace Heap { template <typename Container> struct QQmlSequence : Object { - QQmlSequence(QV4::ExecutionEngine *engine, const Container &container); - QQmlSequence(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex); + QQmlSequence(const Container &container); + QQmlSequence(QObject *object, int propertyIndex); mutable Container container; QPointer<QObject> object; @@ -223,6 +223,7 @@ struct QQmlSequence : public QV4::Object { V4_OBJECT2(QQmlSequence<Container>, QV4::Object) Q_MANAGED_TYPE(QmlSequence) + V4_PROTOTYPE(sequencePrototype) V4_NEEDS_DESTROY public: @@ -543,26 +544,24 @@ public: template <typename Container> -Heap::QQmlSequence<Container>::QQmlSequence(QV4::ExecutionEngine *engine, const Container &container) - : Heap::Object(engine->emptyClass, engine->sequencePrototype()) - , container(container) +Heap::QQmlSequence<Container>::QQmlSequence(const Container &container) + : container(container) , propertyIndex(-1) , isReference(false) { - QV4::Scope scope(engine); + QV4::Scope scope(internalClass->engine); QV4::Scoped<QV4::QQmlSequence<Container> > o(scope, this); o->setArrayType(Heap::ArrayData::Custom); o->init(); } template <typename Container> -Heap::QQmlSequence<Container>::QQmlSequence(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex) - : Heap::Object(engine->emptyClass, engine->sequencePrototype()) - , object(object) +Heap::QQmlSequence<Container>::QQmlSequence(QObject *object, int propertyIndex) + : object(object) , propertyIndex(propertyIndex) , isReference(true) { - QV4::Scope scope(engine); + QV4::Scope scope(internalClass->engine); QV4::Scoped<QV4::QQmlSequence<Container> > o(scope, this); o->setArrayType(Heap::ArrayData::Custom); o->loadReference(); @@ -644,7 +643,7 @@ bool SequencePrototype::isSequenceType(int sequenceTypeId) #define NEW_REFERENCE_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \ if (sequenceType == qMetaTypeId<SequenceType>()) { \ - QV4::ScopedObject obj(scope, engine->memoryManager->alloc<QQml##ElementTypeName##List>(engine, object, propertyIndex)); \ + QV4::ScopedObject obj(scope, engine->memoryManager->allocObject<QQml##ElementTypeName##List>(object, propertyIndex)); \ return obj.asReturnedValue(); \ } else @@ -662,7 +661,7 @@ ReturnedValue SequencePrototype::newSequence(QV4::ExecutionEngine *engine, int s #define NEW_COPY_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \ if (sequenceType == qMetaTypeId<SequenceType>()) { \ - QV4::ScopedObject obj(scope, engine->memoryManager->alloc<QQml##ElementTypeName##List>(engine, v.value<SequenceType >())); \ + QV4::ScopedObject obj(scope, engine->memoryManager->allocObject<QQml##ElementTypeName##List>(v.value<SequenceType >())); \ return obj.asReturnedValue(); \ } else diff --git a/src/qml/jsruntime/qv4sparsearray.cpp b/src/qml/jsruntime/qv4sparsearray.cpp index 01f94eeac6..bb1d3aeb69 100644 --- a/src/qml/jsruntime/qv4sparsearray.cpp +++ b/src/qml/jsruntime/qv4sparsearray.cpp @@ -246,15 +246,12 @@ void SparseArray::deleteNode(SparseArrayNode *z) x->setParent(y->parent()); if (root == y) root = x; - else if (y->parent()->left == y) { + else if (y->parent()->left == y) y->parent()->left = x; - if (x) - x->size_left += y->size_left; - } else { + else y->parent()->right = x; - if (x) - x->size_left += y->size_left; - } + if (x && x == y->right) + x->size_left += y->size_left; y->size_left = 0; } if (y->color() != SparseArrayNode::Red) { diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 9fbafa7ded..757ec6c6bf 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -67,25 +67,17 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(StringObject); -Heap::StringObject::StringObject(InternalClass *ic, QV4::Object *prototype) - : Heap::Object(ic, prototype) +Heap::StringObject::StringObject() { Q_ASSERT(vtable() == QV4::StringObject::staticVTable()); - string = ic->engine->newString(); - - Scope scope(ic->engine); - ScopedObject s(scope, this); - s->defineReadonlyProperty(ic->engine->id_length(), Primitive::fromInt32(0)); + string = internalClass->engine->id_empty()->d(); + *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); } -Heap::StringObject::StringObject(ExecutionEngine *engine, const QV4::String *str) - : Heap::Object(engine->emptyClass, engine->stringPrototype()) +Heap::StringObject::StringObject(const QV4::String *str) { string = str->d(); - - Scope scope(engine); - ScopedObject s(scope, this); - s->defineReadonlyProperty(engine->id_length(), Primitive::fromUInt32(length())); + *propertyData(LengthPropertyIndex) = Primitive::fromInt32(length()); } Heap::String *Heap::StringObject::getIndex(uint index) const @@ -98,7 +90,7 @@ Heap::String *Heap::StringObject::getIndex(uint index) const uint Heap::StringObject::length() const { - return string->toQString().length(); + return string->len; } bool StringObject::deleteIndexedProperty(Managed *m, uint index) @@ -109,7 +101,7 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index) Q_ASSERT(!!o); if (index < static_cast<uint>(o->d()->string->toQString().length())) { - if (v4->currentContext()->strictMode) + if (v4->current->strictMode) v4->throwTypeError(); return false; } @@ -511,7 +503,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) offset = qMax(offset + 1, matchOffsets[oldSize + 1]); } if (regExp->global()) - regExp->lastIndexProperty()->value = Primitive::fromUInt32(0); + *regExp->lastIndexProperty() = Primitive::fromUInt32(0); numStringMatches = nMatchOffsets / (regExp->value()->captureCount() * 2); numCaptures = regExp->value()->captureCount(); } else { diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index aa56a79bc3..86d77c726a 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -44,8 +44,12 @@ namespace QV4 { namespace Heap { struct StringObject : Object { - StringObject(InternalClass *ic, QV4::Object *prototype); - StringObject(ExecutionEngine *engine, const QV4::String *string); + enum { + LengthPropertyIndex = 0 + }; + + StringObject(); + StringObject(const QV4::String *string); String *string; Heap::String *getIndex(uint index) const; @@ -61,6 +65,8 @@ struct StringCtor : FunctionObject { struct StringObject: Object { V4_OBJECT2(StringObject, Object) Q_MANAGED_TYPE(StringObject) + V4_INTERNALCLASS(stringClass) + V4_PROTOTYPE(stringPrototype) Heap::String *getIndex(uint index) const { return d()->getIndex(index); diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index f06eeb08b9..b45bbb713c 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -216,11 +216,11 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) if (l != len) scope.engine->throwRangeError(QStringLiteral("Non integer length for typed array.")); uint byteLength = len * operations[that->d()->type].bytesPerElement; - Scoped<ArrayBuffer> buffer(scope, scope.engine->memoryManager->alloc<ArrayBuffer>(scope.engine, byteLength)); + Scoped<ArrayBuffer> buffer(scope, scope.engine->newArrayBuffer(byteLength)); if (scope.engine->hasException) return Encode::undefined(); - Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); array->d()->buffer = buffer->d(); array->d()->byteLength = byteLength; array->d()->byteOffset = 0; @@ -236,11 +236,11 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) uint byteLength = typedArray->d()->byteLength; uint destByteLength = byteLength*destElementSize/srcElementSize; - Scoped<ArrayBuffer> newBuffer(scope, scope.engine->memoryManager->alloc<ArrayBuffer>(scope.engine, destByteLength)); + Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(destByteLength)); if (scope.engine->hasException) return Encode::undefined(); - Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); array->d()->buffer = newBuffer->d(); array->d()->byteLength = destByteLength; array->d()->byteOffset = 0; @@ -290,7 +290,7 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) byteLength = (uint)l; } - Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); array->d()->buffer = buffer->d(); array->d()->byteLength = byteLength; array->d()->byteOffset = byteOffset; @@ -305,11 +305,11 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) return scope.engine->throwTypeError(); uint elementSize = operations[that->d()->type].bytesPerElement; - Scoped<ArrayBuffer> newBuffer(scope, scope.engine->memoryManager->alloc<ArrayBuffer>(scope.engine, l * elementSize)); + Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(l * elementSize)); if (scope.engine->hasException) return Encode::undefined(); - Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); array->d()->buffer = newBuffer->d(); array->d()->byteLength = l * elementSize; array->d()->byteOffset = 0; @@ -335,13 +335,17 @@ ReturnedValue TypedArrayCtor::call(const Managed *that, CallData *callData) return construct(that, callData); } -Heap::TypedArray::TypedArray(ExecutionEngine *e, Type t) - : Heap::Object(e->emptyClass, e->typedArrayPrototype + t), - type(operations + t), +Heap::TypedArray::TypedArray(Type t) + : type(operations + t), arrayType(t) { } +Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type t) +{ + return e->memoryManager->allocObject<TypedArray>(e->emptyClass, e->typedArrayPrototype + t, t); +} + void TypedArray::markObjects(Heap::Base *that, ExecutionEngine *e) { static_cast<TypedArray::Data *>(that)->buffer->mark(e); @@ -383,7 +387,7 @@ void TypedArray::putIndexed(Managed *m, uint index, const Value &value) return; reject: - if (scope.engine->currentContext()->strictMode) + if (scope.engine->current->strictMode) scope.engine->throwTypeError(); } diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index 8e1090dcd2..74ee285da4 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -69,7 +69,7 @@ struct TypedArray : Object { NTypes }; - TypedArray(ExecutionEngine *e, Type t); + TypedArray(Type t); const TypedArrayOperations *type; Pointer<ArrayBuffer> buffer; @@ -85,7 +85,7 @@ struct TypedArrayCtor : FunctionObject { }; struct TypedArrayPrototype : Object { - inline TypedArrayPrototype(ExecutionEngine *e, TypedArray::Type t); + inline TypedArrayPrototype(TypedArray::Type t); TypedArray::Type type; }; @@ -96,6 +96,8 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object { V4_OBJECT2(TypedArray, Object) + static Heap::TypedArray *create(QV4::ExecutionEngine *e, Heap::TypedArray::Type t); + uint byteLength() const { return d()->byteLength; } @@ -142,9 +144,8 @@ struct TypedArrayPrototype : Object }; inline -Heap::TypedArrayPrototype::TypedArrayPrototype(ExecutionEngine *e, TypedArray::Type t) - : Heap::Object(e) - , type(t) +Heap::TypedArrayPrototype::TypedArrayPrototype(TypedArray::Type t) + : type(t) { } diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 6305e6dfbb..14094878d8 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -85,8 +85,8 @@ struct Q_QML_PRIVATE_EXPORT Value Q_ALWAYS_INLINE quint64 val() const { return _val; } Q_ALWAYS_INLINE void setVal(quint64 v) { _val = v; } - Q_ALWAYS_INLINE void setValue(quint32 v) { setTagValue(tag(), v); } - Q_ALWAYS_INLINE void setTag(quint32 t) { setTagValue(t, value()); } + Q_ALWAYS_INLINE void setValue(quint32 v) { memcpy(&_val, &v, 4); } + Q_ALWAYS_INLINE void setTag(quint32 t) { memcpy(4 + (quint8 *)&_val, &t, 4); } #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN static inline int valueOffset() { return 0; } diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index f9e26efe71..4609373cc9 100644 --- a/src/qml/jsruntime/qv4variantobject.cpp +++ b/src/qml/jsruntime/qv4variantobject.cpp @@ -43,12 +43,15 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(VariantObject); -Heap::VariantObject::VariantObject(QV4::ExecutionEngine *engine, const QVariant &value) - : Heap::Object(engine->emptyClass, engine->variantPrototype()) +Heap::VariantObject::VariantObject() +{ +} + +Heap::VariantObject::VariantObject(const QVariant &value) { data = value; if (isScarce()) - engine->scarceResources.insert(this); + internalClass->engine->scarceResources.insert(this); } bool VariantObject::Data::isScarce() const diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h index b19f12bb98..4680912354 100644 --- a/src/qml/jsruntime/qv4variantobject_p.h +++ b/src/qml/jsruntime/qv4variantobject_p.h @@ -60,10 +60,8 @@ namespace Heap { struct VariantObject : Object, public ExecutionEngine::ScarceResourceData { - VariantObject(InternalClass *ic, QV4::Object *prototype) - : Object(ic, prototype) - {} - VariantObject(QV4::ExecutionEngine *engine, const QVariant &value); + VariantObject(); + VariantObject(const QVariant &value); ~VariantObject() { if (isScarce()) node.remove(); @@ -77,6 +75,7 @@ struct VariantObject : Object, public ExecutionEngine::ScarceResourceData struct VariantObject : Object { V4_OBJECT2(VariantObject, Object) + V4_PROTOTYPE(variantPrototype) V4_NEEDS_DESTROY void addVmePropertyReference(); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 0edd7378a7..68f996c4c7 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -375,8 +375,8 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code const uchar *exceptionHandler = 0; QV4::Scope scope(engine); - QV4::ScopedContext context(scope, engine->currentContext()); - engine->currentContext()->lineNumber = -1; + QV4::ExecutionContext *context = engine->currentContext; + engine->current->lineNumber = -1; #ifdef DO_TRACE_INSTR qDebug("Starting VME with context=%p and code=%p", context, code); @@ -650,18 +650,18 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope) Runtime::pushCatchScope(static_cast<QV4::NoThrowEngine*>(engine), instr.name); - context = engine->currentContext(); + context = engine->currentContext; MOTH_END_INSTR(CallBuiltinPushCatchScope) MOTH_BEGIN_INSTR(CallBuiltinPushScope) Runtime::pushWithScope(VALUE(instr.arg), engine); - context = engine->currentContext(); + context = engine->currentContext; CHECK_EXCEPTION; MOTH_END_INSTR(CallBuiltinPushScope) MOTH_BEGIN_INSTR(CallBuiltinPopScope) Runtime::popScope(engine); - context = engine->currentContext(); + context = engine->currentContext; MOTH_END_INSTR(CallBuiltinPopScope) MOTH_BEGIN_INSTR(CallBuiltinForeachIteratorObject) @@ -889,7 +889,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(Ret) MOTH_BEGIN_INSTR(Debug) - engine->currentContext()->lineNumber = instr.lineNumber; + engine->current->lineNumber = instr.lineNumber; QV4::Debugging::Debugger *debugger = context->engine()->debugger; if (debugger && debugger->pauseAtNextOpportunity()) debugger->maybeBreakAtInstruction(); @@ -898,7 +898,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(Debug) MOTH_BEGIN_INSTR(Line) - engine->currentContext()->lineNumber = instr.lineNumber; + engine->current->lineNumber = instr.lineNumber; if (qt_v4IsDebugging) qt_v4CheckForBreak(context, scopes, scopeDepth); MOTH_END_INSTR(Line) diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index b880c9c8d5..0887e43441 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -64,6 +64,8 @@ #include <pthread_np.h> #endif +#define MIN_UNMANAGED_HEAPSIZE_GC_LIMIT (std::size_t)128*1024 + using namespace WTF; QT_BEGIN_NAMESPACE @@ -124,7 +126,7 @@ struct MemoryManager::Data , maxShift(6) , maxChunkSize(32*1024) , unmanagedHeapSize(0) - , unmanagedHeapSizeGCLimit(64 * 1024) + , unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT) , largeItems(0) , totalLargeItemsAllocated(0) { @@ -219,7 +221,8 @@ bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, Exec } // namespace MemoryManager::MemoryManager(ExecutionEngine *engine) - : m_d(new Data) + : engine(engine) + , m_d(new Data) , m_persistentValues(new PersistentValueStorage(engine)) , m_weakValues(new PersistentValueStorage(engine)) { @@ -246,13 +249,12 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize if (m_d->unmanagedHeapSize > m_d->unmanagedHeapSizeGCLimit) { runGC(); - if (m_d->unmanagedHeapSizeGCLimit <= m_d->unmanagedHeapSize) + if (3*m_d->unmanagedHeapSizeGCLimit <= 4*m_d->unmanagedHeapSize) + // more than 75% full, raise limit m_d->unmanagedHeapSizeGCLimit = std::max(m_d->unmanagedHeapSizeGCLimit, m_d->unmanagedHeapSize) * 2; else if (m_d->unmanagedHeapSize * 4 <= m_d->unmanagedHeapSizeGCLimit) - m_d->unmanagedHeapSizeGCLimit /= 2; - else if (m_d->unmanagedHeapSizeGCLimit - m_d->unmanagedHeapSize < 5 * unmanagedSize) - // try preventing running the GC all the time when we're just below the threshold limit and manage to collect just enough to do this one allocation - m_d->unmanagedHeapSizeGCLimit += std::max(std::size_t(8 * 1024), 5 * unmanagedSize); + // less than 25% full, lower limit + m_d->unmanagedHeapSizeGCLimit = qMax(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT, m_d->unmanagedHeapSizeGCLimit/2); didGCRun = true; } @@ -265,7 +267,7 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize // we use malloc for this MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>( - malloc(Q_V4_PROFILE_ALLOC(m_d->engine, size + sizeof(MemoryManager::Data::LargeItem), + malloc(Q_V4_PROFILE_ALLOC(engine, size + sizeof(MemoryManager::Data::LargeItem), Profiling::LargeItem))); memset(item, 0, size + sizeof(MemoryManager::Data::LargeItem)); item->next = m_d->largeItems; @@ -301,7 +303,7 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift); allocSize = roundUpToMultipleOf(WTF::pageSize(), allocSize); PageAllocation allocation = PageAllocation::allocate( - Q_V4_PROFILE_ALLOC(m_d->engine, allocSize, Profiling::HeapPage), + Q_V4_PROFILE_ALLOC(engine, allocSize, Profiling::HeapPage), OSAllocator::JSGCHeapPages); m_d->heapChunks.append(allocation); @@ -335,7 +337,7 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize #ifdef V4_USE_VALGRIND VALGRIND_MEMPOOL_ALLOC(this, m, size); #endif - Q_V4_PROFILE_ALLOC(m_d->engine, size, Profiling::SmallItem); + Q_V4_PROFILE_ALLOC(engine, size, Profiling::SmallItem); ++m_d->allocCount[pos]; ++m_d->totalAlloc; @@ -356,14 +358,14 @@ static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase) void MemoryManager::mark() { - Value *markBase = m_d->engine->jsStackTop; - - m_d->engine->markObjects(); + Value *markBase = engine->jsStackTop; - m_persistentValues->mark(m_d->engine); + engine->markObjects(); collectFromJSStack(); + m_persistentValues->mark(engine); + // Preserve QObject ownership rules within JavaScript: A parent with c++ ownership // keeps all of its children alive in JavaScript. @@ -391,13 +393,13 @@ void MemoryManager::mark() } if (keepAlive) - qobjectWrapper->mark(m_d->engine); + qobjectWrapper->mark(engine); - if (m_d->engine->jsStackTop >= m_d->engine->jsStackLimit) - drainMarkStack(m_d->engine, markBase); + if (engine->jsStackTop >= engine->jsStackLimit) + drainMarkStack(engine, markBase); } - drainMarkStack(m_d->engine, markBase); + drainMarkStack(engine, markBase); } void MemoryManager::sweep(bool lastSweep) @@ -416,7 +418,7 @@ void MemoryManager::sweep(bool lastSweep) (*it) = Primitive::undefinedValue(); } - if (MultiplyWrappedQObjectMap *multiplyWrappedQObjects = m_d->engine->m_multiplyWrappedQObjects) { + if (MultiplyWrappedQObjectMap *multiplyWrappedQObjects = engine->m_multiplyWrappedQObjects) { for (MultiplyWrappedQObjectMap::Iterator it = multiplyWrappedQObjects->begin(); it != multiplyWrappedQObjects->end();) { if (!it.value().isNullOrUndefined()) it = multiplyWrappedQObjects->erase(it); @@ -432,7 +434,7 @@ void MemoryManager::sweep(bool lastSweep) for (int i = 0; i < m_d->heapChunks.size(); ++i) { Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(m_d->heapChunks[i].base()); - chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], m_d->engine, &m_d->unmanagedHeapSize); + chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], engine, &m_d->unmanagedHeapSize); } QVector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin(); @@ -444,7 +446,7 @@ void MemoryManager::sweep(bool lastSweep) // Release that chunk if it could have been spared since the last GC run without any difference. if (chunkIsEmpty[i] && m_d->availableItems[pos] - decrease >= itemsInUse[pos]) { - Q_V4_PROFILE_DEALLOC(m_d->engine, 0, chunkIter->size(), Profiling::HeapPage); + Q_V4_PROFILE_DEALLOC(engine, 0, chunkIter->size(), Profiling::HeapPage); #ifdef V4_USE_VALGRIND VALGRIND_MEMPOOL_FREE(this, header); #endif @@ -476,17 +478,17 @@ void MemoryManager::sweep(bool lastSweep) m->vtable()->destroy(m); *last = i->next; - free(Q_V4_PROFILE_DEALLOC(m_d->engine, i, i->size + sizeof(Data::LargeItem), + free(Q_V4_PROFILE_DEALLOC(engine, i, i->size + sizeof(Data::LargeItem), Profiling::LargeItem)); i = *last; } // some execution contexts are allocated on the stack, make sure we clear their markBit as well if (!lastSweep) { - Heap::ExecutionContext *ctx = engine()->current; + QV4::ExecutionContext *ctx = engine->currentContext; while (ctx) { - ctx->clearMarkBit(); - ctx = ctx->parent; + ctx->d()->clearMarkBit(); + ctx = engine->parentContext(ctx); } } } @@ -520,9 +522,11 @@ void MemoryManager::runGC() int markTime = t.elapsed(); t.restart(); const size_t usedBefore = getUsedMem(); + const size_t largeItemsBefore = getLargeItemsMem(); int chunksBefore = m_d->heapChunks.size(); sweep(); const size_t usedAfter = getUsedMem(); + const size_t largeItemsAfter = getLargeItemsMem(); int sweepTime = t.elapsed(); qDebug() << "========== GC =========="; @@ -533,6 +537,9 @@ void MemoryManager::runGC() qDebug() << "Used memory after GC:" << usedAfter; qDebug() << "Freed up bytes:" << (usedBefore - usedAfter); qDebug() << "Released chunks:" << (chunksBefore - m_d->heapChunks.size()); + qDebug() << "Large item memory before GC:" << largeItemsBefore; + qDebug() << "Large item memory after GC:" << largeItemsAfter; + qDebug() << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter); qDebug() << "======== End GC ========"; } @@ -589,10 +596,7 @@ MemoryManager::~MemoryManager() #endif } -ExecutionEngine *MemoryManager::engine() const -{ - return m_d->engine; -} + void MemoryManager::dumpStats() const { @@ -622,13 +626,13 @@ void MemoryManager::willAllocate(std::size_t size) void MemoryManager::collectFromJSStack() const { - Value *v = m_d->engine->jsStackBase; - Value *top = m_d->engine->jsStackTop; + Value *v = engine->jsStackBase; + Value *top = engine->jsStackTop; while (v < top) { Managed *m = v->as<Managed>(); if (m && m->inUse()) // Skip pointers to already freed objects, they are bogus as well - m->mark(m_d->engine); + m->mark(engine); ++v; } } diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index c01866ff11..c77d5e503d 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -37,6 +37,7 @@ #include <private/qv4global_p.h> #include <private/qv4value_p.h> #include <private/qv4scopedvalue_p.h> +#include <private/qv4object_p.h> //#define DETAILED_MM_STATS @@ -91,10 +92,149 @@ public: return static_cast<typename ManagedType::Data *>(o); } + template <typename ObjectType> + typename ObjectType::Data *allocateObject(InternalClass *ic) + { + const int size = (sizeof(typename ObjectType::Data) + (sizeof(Value) - 1)) & ~(sizeof(Value) - 1); + typename ObjectType::Data *o = allocManaged<ObjectType>(size + ic->size*sizeof(Value)); + o->internalClass = ic; + o->inlineMemberSize = ic->size; + o->inlineMemberOffset = size/sizeof(Value); + return o; + } + + template <typename ObjectType> + typename ObjectType::Data *allocateObject() + { + InternalClass *ic = ObjectType::defaultInternalClass(engine); + const int size = (sizeof(typename ObjectType::Data) + (sizeof(Value) - 1)) & ~(sizeof(Value) - 1); + typename ObjectType::Data *o = allocManaged<ObjectType>(size + ic->size*sizeof(Value)); + Object *prototype = ObjectType::defaultPrototype(engine); + o->internalClass = ic; + o->prototype = prototype->d(); + o->inlineMemberSize = ic->size; + o->inlineMemberOffset = size/sizeof(Value); + return o; + } + + template <typename ManagedType, typename Arg1> + typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1) + { + Scope scope(engine); + Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data), unmanagedSize)); + (void)new (t->d()) typename ManagedType::Data(this, arg1); + return t->d(); + } + + template <typename ObjectType> + typename ObjectType::Data *allocObject(InternalClass *ic) + { + Scope scope(engine); + Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); + (void)new (t->d()) typename ObjectType::Data(); + return t->d(); + } + + template <typename ObjectType> + typename ObjectType::Data *allocObject(InternalClass *ic, Object *prototype) + { + Scope scope(engine); + Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); + t->d()->prototype = prototype->d(); + (void)new (t->d()) typename ObjectType::Data(); + return t->d(); + } + + template <typename ObjectType, typename Arg1> + typename ObjectType::Data *allocObject(InternalClass *ic, Object *prototype, Arg1 arg1) + { + Scope scope(engine); + Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); + t->d()->prototype = prototype->d(); + (void)new (t->d()) typename ObjectType::Data(arg1); + return t->d(); + } + + template <typename ObjectType, typename Arg1, typename Arg2> + typename ObjectType::Data *allocObject(InternalClass *ic, Object *prototype, Arg1 arg1, Arg2 arg2) + { + Scope scope(engine); + Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); + t->d()->prototype = prototype->d(); + (void)new (t->d()) typename ObjectType::Data(arg1, arg2); + return t->d(); + } + + template <typename ObjectType, typename Arg1, typename Arg2, typename Arg3> + typename ObjectType::Data *allocObject(InternalClass *ic, Object *prototype, Arg1 arg1, Arg2 arg2, Arg3 arg3) + { + Scope scope(engine); + Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); + t->d()->prototype = prototype->d(); + (void)new (t->d()) typename ObjectType::Data(arg1, arg2, arg3); + return t->d(); + } + + template <typename ObjectType, typename Arg1, typename Arg2, typename Arg3, typename Arg4> + typename ObjectType::Data *allocObject(InternalClass *ic, Object *prototype, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) + { + Scope scope(engine); + Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); + t->d()->prototype = prototype->d(); + (void)new (t->d()) typename ObjectType::Data(arg1, arg2, arg3, arg4); + return t->d(); + } + + template <typename ObjectType> + typename ObjectType::Data *allocObject() + { + Scope scope(engine); + Scoped<ObjectType> t(scope, allocateObject<ObjectType>()); + (void)new (t->d()) typename ObjectType::Data(); + return t->d(); + } + + template <typename ObjectType, typename Arg1> + typename ObjectType::Data *allocObject(Arg1 arg1) + { + Scope scope(engine); + Scoped<ObjectType> t(scope, allocateObject<ObjectType>()); + (void)new (t->d()) typename ObjectType::Data(arg1); + return t->d(); + } + + template <typename ObjectType, typename Arg1, typename Arg2> + typename ObjectType::Data *allocObject(Arg1 arg1, Arg2 arg2) + { + Scope scope(engine); + Scoped<ObjectType> t(scope, allocateObject<ObjectType>()); + (void)new (t->d()) typename ObjectType::Data(arg1, arg2); + return t->d(); + } + + template <typename ObjectType, typename Arg1, typename Arg2, typename Arg3> + typename ObjectType::Data *allocObject(Arg1 arg1, Arg2 arg2, Arg3 arg3) + { + Scope scope(engine); + Scoped<ObjectType> t(scope, allocateObject<ObjectType>()); + (void)new (t->d()) typename ObjectType::Data(arg1, arg2, arg3); + return t->d(); + } + + template <typename ObjectType, typename Arg1, typename Arg2, typename Arg3, typename Arg4> + typename ObjectType::Data *allocObject(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) + { + Scope scope(engine); + Scoped<ObjectType> t(scope, allocateObject<ObjectType>()); + (void)new (t->d()) typename ObjectType::Data(arg1, arg2, arg3, arg4); + return t->d(); + } + + template <typename ManagedType> typename ManagedType::Data *alloc() { - Scope scope(engine()); + Scope scope(engine); Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data))); (void)new (t->d()) typename ManagedType::Data(); return t->d(); @@ -103,25 +243,16 @@ public: template <typename ManagedType, typename Arg1> typename ManagedType::Data *alloc(Arg1 arg1) { - Scope scope(engine()); + Scope scope(engine); Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data))); (void)new (t->d()) typename ManagedType::Data(arg1); return t->d(); } - template <typename ManagedType, typename Arg1> - typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1) - { - Scope scope(engine()); - Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data), unmanagedSize)); - (void)new (t->d()) typename ManagedType::Data(this, arg1); - return t->d(); - } - template <typename ManagedType, typename Arg1, typename Arg2> typename ManagedType::Data *alloc(Arg1 arg1, Arg2 arg2) { - Scope scope(engine()); + Scope scope(engine); Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data))); (void)new (t->d()) typename ManagedType::Data(arg1, arg2); return t->d(); @@ -130,7 +261,7 @@ public: template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3> typename ManagedType::Data *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3) { - Scope scope(engine()); + Scope scope(engine); Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data))); (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3); return t->d(); @@ -139,7 +270,7 @@ public: template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4> typename ManagedType::Data *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) { - Scope scope(engine()); + Scope scope(engine); Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data))); (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4); return t->d(); @@ -148,7 +279,7 @@ public: template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> typename ManagedType::Data *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) { - Scope scope(engine()); + Scope scope(engine); Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data))); (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4, arg5); return t->d(); @@ -158,8 +289,6 @@ public: void setGCBlocked(bool blockGC); void runGC(); - ExecutionEngine *engine() const; - void dumpStats() const; size_t getUsedMem() const; @@ -182,9 +311,9 @@ private: void mark(); void sweep(bool lastSweep = false); -protected: - QScopedPointer<Data> m_d; public: + QV4::ExecutionEngine *engine; + QScopedPointer<Data> m_d; PersistentValueStorage *m_persistentValues; PersistentValueStorage *m_weakValues; }; diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 3613c17242..f8b737a62a 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -90,7 +90,7 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); if (runtimeFunction) { - m_function.set(v4, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, scopeObject(), runtimeFunction)); + m_function.set(v4, QV4::FunctionObject::createQmlFunction(ctxtdata, scopeObject(), runtimeFunction)); } else { QString code = scriptPrivate->script; createQmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber); diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index ff5f36bd9c..decffaf2fa 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -124,7 +124,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index); QString error; QV4::ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(ctxt->engine); - m_function.set(engine, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, scope, runtimeFunction, signal.parameterNames(), &error)); + m_function.set(engine, QV4::FunctionObject::createQmlFunction(ctxt, scope, runtimeFunction, signal.parameterNames(), &error)); if (!error.isEmpty()) { qmlInfo(scopeObject()) << error; m_function.clear(); diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index d62aada9c6..be482b4639 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -42,7 +42,6 @@ #include "qqml.h" #include "qqmlengine.h" #include "qqmlbinding_p.h" -#include "qqmlglobal_p.h" #include <private/qqmldebugconnector_p.h> #include <private/qqmldebugserviceinterfaces_p.h> #include "qqmlincubator.h" @@ -1060,11 +1059,10 @@ namespace QV4 { namespace Heap { struct QmlIncubatorObject : Object { - QmlIncubatorObject(QV4::ExecutionEngine *engine, QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous); + QmlIncubatorObject(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous); QScopedPointer<QQmlComponentIncubator> incubator; QPointer<QObject> parent; QV4::Value valuemap; - QV4::Value qmlGlobal; QV4::Value statusChanged; }; @@ -1376,14 +1374,12 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) QQmlComponentExtension *e = componentExtension(args->v4engine()); - QV4::Scoped<QV4::QmlIncubatorObject> r(scope, v4->memoryManager->alloc<QV4::QmlIncubatorObject>(args->v4engine(), mode)); + QV4::Scoped<QV4::QmlIncubatorObject> r(scope, v4->memoryManager->allocObject<QV4::QmlIncubatorObject>(mode)); QV4::ScopedObject p(scope, e->incubationProto.value()); r->setPrototype(p); - if (!valuemap->isUndefined()) { + if (!valuemap->isUndefined()) r->d()->valuemap = valuemap; - r->d()->qmlGlobal = args->qmlGlobal(); - } r->d()->parent = parent; QQmlIncubator *incubator = r->d()->incubator.data(); @@ -1481,10 +1477,8 @@ QQmlComponentExtension::~QQmlComponentExtension() { } -QV4::Heap::QmlIncubatorObject::QmlIncubatorObject(ExecutionEngine *engine, QQmlIncubator::IncubationMode m) - : QV4::Heap::Object(engine) - , valuemap(QV4::Primitive::undefinedValue()) - , qmlGlobal(QV4::Primitive::undefinedValue()) +QV4::Heap::QmlIncubatorObject::QmlIncubatorObject(QQmlIncubator::IncubationMode m) + : valuemap(QV4::Primitive::undefinedValue()) , statusChanged(QV4::Primitive::undefinedValue()) { incubator.reset(new QQmlComponentIncubator(this, m)); @@ -1506,7 +1500,6 @@ void QV4::QmlIncubatorObject::markObjects(QV4::Heap::Base *that, QV4::ExecutionE { QmlIncubatorObject::Data *o = static_cast<QmlIncubatorObject::Data *>(that); o->valuemap.mark(e); - o->qmlGlobal.mark(e); o->statusChanged.mark(e); Object::markObjects(that, e); } diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index 99a5fe56ce..0d84c3bb64 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -54,9 +54,8 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlContextWrapper); -Heap::QmlContextWrapper::QmlContextWrapper(QV4::ExecutionEngine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext) - : Heap::Object(engine) - , readOnly(true) +Heap::QmlContextWrapper::QmlContextWrapper(QQmlContextData *context, QObject *scopeObject, bool ownsContext) + : readOnly(true) , ownsContext(ownsContext) , isNullWrapper(false) , context(context) @@ -74,7 +73,7 @@ ReturnedValue QmlContextWrapper::qmlScope(ExecutionEngine *v4, QQmlContextData * { Scope valueScope(v4); - Scoped<QmlContextWrapper> w(valueScope, v4->memoryManager->alloc<QmlContextWrapper>(v4, ctxt, scope)); + Scoped<QmlContextWrapper> w(valueScope, v4->memoryManager->allocObject<QmlContextWrapper>(ctxt, scope)); return w.asReturnedValue(); } @@ -88,7 +87,7 @@ ReturnedValue QmlContextWrapper::urlScope(ExecutionEngine *v4, const QUrl &url) context->isInternal = true; context->isJSContext = true; - Scoped<QmlContextWrapper> w(scope, v4->memoryManager->alloc<QmlContextWrapper>(v4, context, (QObject*)0, true)); + Scoped<QmlContextWrapper> w(scope, v4->memoryManager->allocObject<QmlContextWrapper>(context, (QObject*)0, true)); w->d()->isNullWrapper = true; return w.asReturnedValue(); } @@ -240,7 +239,7 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) uint member = wrapper->internalClass()->find(name); if (member < UINT_MAX) { - wrapper->putValue(wrapper->propertyAt(member), wrapper->internalClass()->propertyData[member], value); + wrapper->putValue(member, value); return; } @@ -248,7 +247,7 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) if (wrapper && wrapper->d()->readOnly) { QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + QLatin1Char('"'); - ScopedString e(scope, v4->currentContext()->engine->newString(error)); + ScopedString e(scope, v4->newString(error)); v4->throwError(e); return; } diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h index 192df9aed6..9dd71b708f 100644 --- a/src/qml/qml/qqmlcontextwrapper_p.h +++ b/src/qml/qml/qqmlcontextwrapper_p.h @@ -66,7 +66,7 @@ struct QmlContextWrapper; namespace Heap { struct QmlContextWrapper : Object { - QmlContextWrapper(ExecutionEngine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext = false); + QmlContextWrapper(QQmlContextData *context, QObject *scopeObject, bool ownsContext = false); ~QmlContextWrapper(); bool readOnly; bool ownsContext; diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index ebca9d2718..517f8d42ed 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -34,6 +34,7 @@ #include "qqmlcustomparser_p.h" #include "qqmlcompiler_p.h" +#include <private/qqmltypecompiler_p.h> #include <QtCore/qdebug.h> @@ -140,7 +141,7 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const type = result.type; } - return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; + return type ? type->enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; } const QMetaObject *mo = StaticQtMetaObject::get(); @@ -159,34 +160,8 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const */ const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const { - return compiler->resolveType(name); -} - -int QQmlCustomParserCompilerBackend::evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const -{ - Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer"); - *ok = false; - - if (scope != QLatin1String("Qt")) { - QQmlType *type = 0; - imports().resolveType(scope, &type, 0, 0, 0); - return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; - } - - const QMetaObject *mo = StaticQtMetaObject::get(); - int i = mo->enumeratorCount(); - while (i--) { - int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok); - if (*ok) - return v; - } - return -1; -} - -const QMetaObject *QQmlCustomParserCompilerBackend::resolveType(const QString &name) const -{ QQmlType *qmltype = 0; - if (!imports().resolveType(name, &qmltype, 0, 0, 0)) + if (!validator->imports().resolveType(name, &qmltype, 0, 0, 0)) return 0; if (!qmltype) return 0; diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h index 88282b1bbc..8bdc73fab1 100644 --- a/src/qml/qml/qqmlcustomparser_p.h +++ b/src/qml/qml/qqmlcustomparser_p.h @@ -55,15 +55,8 @@ QT_BEGIN_NAMESPACE class QQmlCompiledData; - -struct QQmlCustomParserCompilerBackend -{ - virtual ~QQmlCustomParserCompilerBackend() {} - virtual const QQmlImports &imports() const = 0; - - int evaluateEnum(const QString &scope, const QByteArray& enumValue, bool *ok) const; - const QMetaObject *resolveType(const QString& name) const; -}; +class QQmlPropertyValidator; +class QQmlEnginePrivate; class Q_QML_PRIVATE_EXPORT QQmlCustomParser { @@ -75,8 +68,8 @@ public: }; Q_DECLARE_FLAGS(Flags, Flag) - QQmlCustomParser() : compiler(0), m_flags(NoFlag) {} - QQmlCustomParser(Flags f) : compiler(0), m_flags(f) {} + QQmlCustomParser() : engine(0), validator(0), m_flags(NoFlag) {} + QQmlCustomParser(Flags f) : engine(0), validator(0), m_flags(f) {} virtual ~QQmlCustomParser() {} void clearErrors(); @@ -100,7 +93,8 @@ protected: private: QList<QQmlError> exceptions; - const QQmlCustomParserCompilerBackend *compiler; + QQmlEnginePrivate *engine; + const QQmlPropertyValidator *validator; Flags m_flags; QBiPointer<const QQmlImports, QQmlTypeNameCache> imports; friend class QQmlPropertyValidator; diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 332b99ee8f..e9700712e9 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -69,7 +69,7 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, QV4::Function *runtimeFu { expressionFunctionValid = true; QV4::ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(ctxt->engine); - m_function.set(engine, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, me, runtimeFunction)); + m_function.set(engine, QV4::FunctionObject::createQmlFunction(ctxt, me, runtimeFunction)); QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(me); diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 76583846f9..d0d14d9416 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -1659,8 +1659,6 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader, \header \li Platform \li Valid suffixes \row \li Windows \li \c .dll \row \li Unix/Linux \li \c .so - \row \li AIX \li \c .a - \row \li HP-UX \li \c .sl, \c .so (HP-UXi) \row \li OS X \li \c .dylib, \c .bundle, \c .so \endtable @@ -1677,9 +1675,7 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader, << QLatin1String("d.dll") // try a qmake-style debug build first # endif << QLatin1String(".dll")); -#else - -# if defined(Q_OS_DARWIN) +#elif defined(Q_OS_DARWIN) return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, QStringList() @@ -1693,31 +1689,8 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader, << QLatin1String(".so") << QLatin1String(".bundle"), QLatin1String("lib")); -# else // Generic Unix - QStringList validSuffixList; - -# if defined(Q_OS_HPUX) -/* - See "HP-UX Linker and Libraries User's Guide", section "Link-time Differences between PA-RISC and IPF": - "In PA-RISC (PA-32 and PA-64) shared libraries are suffixed with .sl. In IPF (32-bit and 64-bit), - the shared libraries are suffixed with .so. For compatibility, the IPF linker also supports the .sl suffix." - */ - validSuffixList << QLatin1String(".sl"); -# if defined __ia64 - validSuffixList << QLatin1String(".so"); -# endif -# elif defined(Q_OS_AIX) - validSuffixList << QLatin1String(".a") << QLatin1String(".so"); -# elif defined(Q_OS_UNIX) - validSuffixList << QLatin1String(".so"); -# endif - - // Examples of valid library names: - // libfoo.so - - return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, validSuffixList, QLatin1String("lib")); -# endif - +# else // Unix + return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, QStringList() << QLatin1String(".so"), QLatin1String("lib")); #endif } diff --git a/src/qml/qml/qqmlinfo.cpp b/src/qml/qml/qqmlinfo.cpp index b9f96a724c..7a801032d3 100644 --- a/src/qml/qml/qqmlinfo.cpp +++ b/src/qml/qml/qqmlinfo.cpp @@ -109,34 +109,8 @@ QQmlInfo::~QQmlInfo() if (object) { engine = qmlEngine(d->object); - QString typeName; - QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); - if (type) { - typeName = type->qmlTypeName(); - int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); - if (lastSlash != -1) - typeName = typeName.mid(lastSlash+1); - } else { - typeName = QString::fromUtf8(object->metaObject()->className()); - int marker = typeName.indexOf(QLatin1String("_QMLTYPE_")); - if (marker != -1) - typeName = typeName.left(marker); - - marker = typeName.indexOf(QLatin1String("_QML_")); - if (marker != -1) { - typeName = typeName.left(marker); - typeName += QLatin1Char('*'); - type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1())); - if (type) { - typeName = type->qmlTypeName(); - int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); - if (lastSlash != -1) - typeName = typeName.mid(lastSlash+1); - } - } - } - d->buffer.prepend(QLatin1String("QML ") + typeName + QLatin1String(": ")); + d->buffer.prepend(QLatin1String("QML ") + QQmlMetaType::prettyTypeName(object) + QLatin1String(": ")); QQmlData *ddata = QQmlData::get(object, false); if (ddata && ddata->outerContext) { diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 967a7e75d7..5938ebf5d7 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -365,8 +365,8 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObje QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); QV4::Scope scope(v4); - QV4::ScopedObject qmlScopeObject(scope, QV4::QmlContextWrapper::qmlScope(v4, ctxt, scopeObject)); - QV4::Script script(v4, qmlScopeObject, code, filename, line); + QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->rootContext()->newQmlContext(ctxt, scopeObject)); + QV4::Script script(v4, qmlContext, code, filename, line); QV4::ScopedValue result(scope); script.parse(); if (!v4->hasException) @@ -395,8 +395,8 @@ void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject * QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); QV4::Scope scope(v4); - QV4::ScopedObject qmlScopeObject(scope, QV4::QmlContextWrapper::qmlScope(v4, ctxt, qmlScope)); - QV4::Script script(v4, qmlScopeObject, code, filename, line); + QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->rootContext()->newQmlContext(ctxt, qmlScope)); + QV4::Script script(v4, qmlContext, code, filename, line); QV4::ScopedValue result(scope); script.parse(); if (!v4->hasException) diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index d09f4df54c..942f4f79e7 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -45,10 +45,9 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlListWrapper); -Heap::QmlListWrapper::QmlListWrapper(ExecutionEngine *engine) - : Heap::Object(engine) +Heap::QmlListWrapper::QmlListWrapper() { - QV4::Scope scope(engine); + QV4::Scope scope(internalClass->engine); QV4::ScopedObject o(scope, this); o->setArrayType(Heap::ArrayData::Custom); } @@ -64,7 +63,7 @@ ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, QObject *object, i Scope scope(engine); - Scoped<QmlListWrapper> r(scope, engine->memoryManager->alloc<QmlListWrapper>(engine)); + Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocObject<QmlListWrapper>()); r->d()->object = object; r->d()->propertyType = propType; void *args[] = { &r->d()->property, 0 }; @@ -76,7 +75,7 @@ ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, const QQmlListProp { Scope scope(engine); - Scoped<QmlListWrapper> r(scope, engine->memoryManager->alloc<QmlListWrapper>(engine)); + Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocObject<QmlListWrapper>()); r->d()->object = prop.object; r->d()->property = prop; r->d()->propertyType = propType; diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h index ff006d4302..6df3d83b2e 100644 --- a/src/qml/qml/qqmllistwrapper_p.h +++ b/src/qml/qml/qqmllistwrapper_p.h @@ -62,7 +62,7 @@ namespace QV4 { namespace Heap { struct QmlListWrapper : Object { - QmlListWrapper(ExecutionEngine *engine); + QmlListWrapper(); ~QmlListWrapper(); QPointer<QObject> object; QQmlListProperty<QObject> property; diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index 7f49798da6..af7b394a1b 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -806,7 +806,7 @@ QV4::ReturnedValue QQmlLocale::wrap(ExecutionEngine *v4, const QLocale &locale) { QV4::Scope scope(v4); QV4LocaleDataDeletable *d = localeV4Data(scope.engine); - QV4::Scoped<QQmlLocaleData> wrapper(scope, v4->memoryManager->alloc<QQmlLocaleData>(v4)); + QV4::Scoped<QQmlLocaleData> wrapper(scope, v4->memoryManager->allocObject<QQmlLocaleData>()); wrapper->d()->locale = locale; QV4::ScopedObject p(scope, d->prototype.value()); wrapper->setPrototype(p); diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h index cb9fe9bbef..3d2ed307d1 100644 --- a/src/qml/qml/qqmllocale_p.h +++ b/src/qml/qml/qqmllocale_p.h @@ -125,7 +125,7 @@ namespace QV4 { namespace Heap { struct QQmlLocaleData : Object { - inline QQmlLocaleData(ExecutionEngine *engine); + inline QQmlLocaleData() {} QLocale locale; }; @@ -175,11 +175,6 @@ struct QQmlLocaleData : public QV4::Object static QV4::ReturnedValue method_get_pmText(QV4::CallContext *ctx); }; -Heap::QQmlLocaleData::QQmlLocaleData(ExecutionEngine *engine) - : Heap::Object(engine) -{ -} - } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index fbb21f4562..04c001d305 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -38,6 +38,7 @@ #include <private/qqmlcustomparser_p.h> #include <private/qhashedstring_p.h> #include <private/qqmlimport_p.h> +#include <private/qqmlcompiler_p.h> #include <QtCore/qdebug.h> #include <QtCore/qstringlist.h> @@ -217,12 +218,10 @@ public: void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) { QV4::ExecutionEngine *v4 = QV8Engine::getV4(e->handle()); + v4->pushGlobalContext(); if (scriptCallback && scriptApi(e).isUndefined()) { - v4->pushGlobalContext(); setScriptApi(e, scriptCallback(e, e)); - v4->popContext(); } else if (qobjectCallback && !qobjectApi(e)) { - v4->pushGlobalContext(); QObject *o = qobjectCallback(e, e); setQObjectApi(e, o); if (!o) { @@ -230,14 +229,12 @@ void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) } // if this object can use a property cache, create it now QQmlData::ensurePropertyCache(e, o); - v4->popContext(); } else if (!url.isEmpty() && !qobjectApi(e)) { - v4->pushGlobalContext(); QQmlComponent component(e, url, QQmlComponent::PreferSynchronous); QObject *o = component.create(); setQObjectApi(e, o); - v4->popContext(); } + v4->popContext(); } void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e) @@ -477,6 +474,23 @@ QQmlType *QQmlType::superType() const return d->superType; } +int QQmlType::resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const +{ + Q_ASSERT(isComposite()); + *ok = false; + if (!engine) + return -1; + QQmlTypeData *td = engine->typeLoader.getType(sourceUrl()); + if (!td || !td->isComplete()) + return -1; + QQmlCompiledData *cd = td->compiledData(); + const QMetaObject *mo = cd->rootPropertyCache->firstCppMetaObject(); + QQmlType *type = QQmlMetaType::qmlType(mo); + if (!type) + return -1; + return type->enumValue(engine, name, ok); +} + static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd) { @@ -911,9 +925,11 @@ QUrl QQmlType::sourceUrl() const return QUrl(); } -int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const +int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, bool *ok) const { Q_ASSERT(ok); + if (isComposite()) + return resolveCompositeEnumValue(engine, name.toString(), ok); *ok = true; d->initEnums(); @@ -926,9 +942,11 @@ int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const return -1; } -int QQmlType::enumValue(const QHashedCStringRef &name, bool *ok) const +int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name, bool *ok) const { Q_ASSERT(ok); + if (isComposite()) + return resolveCompositeEnumValue(engine, name.toUtf16(), ok); *ok = true; d->initEnums(); @@ -941,9 +959,11 @@ int QQmlType::enumValue(const QHashedCStringRef &name, bool *ok) const return -1; } -int QQmlType::enumValue(const QV4::String *name, bool *ok) const +int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const { Q_ASSERT(ok); + if (isComposite()) + return resolveCompositeEnumValue(engine, name->toQString(), ok); *ok = true; d->initEnums(); @@ -1888,4 +1908,43 @@ const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(const return 0; } +/*! + Returns the pretty QML type name (e.g. 'Item' instead of 'QtQuickItem') for the given object. + */ +QString QQmlMetaType::prettyTypeName(const QObject *object) +{ + QString typeName; + + if (!object) + return typeName; + + const QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); + if (type) { + typeName = type->qmlTypeName(); + const int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); + if (lastSlash != -1) + typeName = typeName.mid(lastSlash + 1); + } else { + typeName = QString::fromUtf8(object->metaObject()->className()); + int marker = typeName.indexOf(QLatin1String("_QMLTYPE_")); + if (marker != -1) + typeName = typeName.left(marker); + + marker = typeName.indexOf(QLatin1String("_QML_")); + if (marker != -1) { + typeName = typeName.left(marker); + typeName += QLatin1Char('*'); + type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1())); + if (type) { + typeName = type->qmlTypeName(); + const int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); + if (lastSlash != -1) + typeName = typeName.mid(lastSlash + 1); + } + } + } + + return typeName; +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 61a6567f1d..40765d461a 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -57,6 +57,7 @@ QT_BEGIN_NAMESPACE class QQmlType; class QQmlEngine; +class QQmlEnginePrivate; class QQmlCustomParser; class QQmlTypePrivate; class QQmlTypeModule; @@ -122,6 +123,8 @@ public: static QStringList typeRegistrationFailures(); static QMutex *typeRegistrationLock(); + + static QString prettyTypeName(const QObject *object); }; struct QQmlMetaTypeData; @@ -204,11 +207,12 @@ public: QUrl sourceUrl() const; - int enumValue(const QHashedStringRef &, bool *ok) const; - int enumValue(const QHashedCStringRef &, bool *ok) const; - int enumValue(const QV4::String *, bool *ok) const; + int enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &, bool *ok) const; + int enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &, bool *ok) const; + int enumValue(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const; private: QQmlType *superType() const; + int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const; friend class QQmlTypePrivate; friend struct QQmlMetaTypeData; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 0e7ce7fb7e..765437b423 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -185,9 +185,10 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI if (subComponentIndex == -1 && compiledData->scripts.count()) { QV4::ScopedObject scripts(scope, v4->newArrayObject(compiledData->scripts.count())); context->importedScripts.set(v4, scripts); + QV4::ScopedValue v(scope); for (int i = 0; i < compiledData->scripts.count(); ++i) { QQmlScriptData *s = compiledData->scripts.at(i); - scripts->putIndexed(i, *s->scriptValueForContext(context).valueRef()); + scripts->putIndexed(i, (v = s->scriptValueForContext(context))); } } else if (sharedState->creationContext) { context->importedScripts = sharedState->creationContext->importedScripts; @@ -988,13 +989,9 @@ void QQmlObjectCreator::registerObjectWithContextById(int objectIndex, QObject * QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext() { - if (!_qmlContext->objectValue()) { - QV4::Scope valueScope(v4); - QV4::Scoped<QV4::QmlContextWrapper> qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(v4, context, _scopeObject)); - QV4::ScopedContext global(valueScope, v4->rootContext()); - _qmlContext->setM(global->newQmlContext(qmlScope)); - v4->popContext(); - } + if (!_qmlContext->objectValue()) + _qmlContext->setM(v4->rootContext()->newQmlContext(context, _scopeObject)); + return _qmlContext->d(); } @@ -1106,6 +1103,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo if (customParser) { QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.constFind(index); if (customParserBindings != compiledData->customParserBindings.constEnd()) { + customParser->engine = QQmlEnginePrivate::get(engine); customParser->imports = compiledData->importCache; QList<const QV4::CompiledData::Binding *> bindings; @@ -1115,6 +1113,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo bindings << obj->bindingTable() + i; customParser->applyBindings(instance, compiledData, bindings); + customParser->engine = 0; customParser->imports = (QQmlTypeNameCache*)0; bindingsToSkip = *customParserBindings; } diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index c1120b4542..d3f7070528 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -50,6 +50,7 @@ #include "qqmlvaluetypeproxybinding_p.h" #include <private/qjsvalue_p.h> #include <private/qv4functionobject_p.h> +#include <private/qv4runtime_p.h> #include <QStringList> #include <private/qmetaobject_p.h> @@ -1350,7 +1351,12 @@ bool QQmlPropertyPrivate::write(QObject *object, if (!ok) { v = value; - if (v.convert(propertyType)) { + if (variantType == QVariant::Double && propertyType == QVariant::String) { + QString number; + QV4::RuntimeHelpers::numberToString(&number, v.toDouble()); + v = number; + ok = true; + } else if (v.convert(propertyType)) { ok = true; } else if (v.isValid() && value.isNull()) { // For historical reasons converting a null QVariant to another type will do the trick diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index eb65f732dd..270c28c399 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2471,12 +2471,10 @@ void QQmlScriptData::initialize(QQmlEngine *engine) addref(); } -QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *parentCtxt) +QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parentCtxt) { if (m_loaded) - return m_value; - - QV4::PersistentValue rv; + return m_value.value(); Q_ASSERT(parentCtxt && parentCtxt->engine); QQmlEnginePrivate *ep = QQmlEnginePrivate::get(parentCtxt->engine); @@ -2526,8 +2524,9 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare } else { scriptsArray = ctxt->importedScripts.valueRef(); } + QV4::ScopedValue v(scope); for (int ii = 0; ii < scripts.count(); ++ii) - scriptsArray->putIndexed(ii, *scripts.at(ii)->scriptData()->scriptValueForContext(ctxt).valueRef()); + scriptsArray->putIndexed(ii, (v = scripts.at(ii)->scriptData()->scriptValueForContext(ctxt))); if (!hasEngine()) initialize(parentCtxt->engine); @@ -2535,13 +2534,13 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare if (!m_program) { if (shared) m_loaded = true; - return QV4::PersistentValue(); + return QV4::Encode::undefined(); } - QV4::Scoped<QV4::QmlContextWrapper> qmlglobal(scope, QV4::QmlContextWrapper::qmlScope(v4, ctxt, 0)); - qmlglobal->takeContextOwnership(); + QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->rootContext()->newQmlContext(ctxt, 0)); + qmlContext->takeContextOwnership(); - m_program->qml.set(scope.engine, qmlglobal); + m_program->qmlContext.set(scope.engine, qmlContext); m_program->run(); if (scope.engine->hasException) { QQmlError error = scope.engine->catchExceptionAsQmlError(); @@ -2549,13 +2548,13 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare ep->warning(error); } - rv.set(scope.engine, qmlglobal); + QV4::ScopedValue retval(scope, qmlContext->d()->qml); if (shared) { - m_value = rv; + m_value.set(scope.engine, retval); m_loaded = true; } - return rv; + return retval->asReturnedValue(); } void QQmlScriptData::clear() diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 5be478fa65..e7b4b8f95b 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -474,7 +474,7 @@ public: QQmlTypeNameCache *importCache; QList<QQmlScriptBlob *> scripts; - QV4::PersistentValue scriptValueForContext(QQmlContextData *parentCtxt); + QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt); protected: virtual void clear(); // From QQmlCleanup diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 1d72b2da0d..d70a4019b2 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -48,12 +48,8 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlTypeWrapper); -Heap::QmlTypeWrapper::QmlTypeWrapper(ExecutionEngine *engine) - : Heap::Object(engine) - , mode(IncludeEnums) - , type(Q_NULLPTR) - , typeNamespace(Q_NULLPTR) - , importNamespace(Q_NULLPTR) +Heap::QmlTypeWrapper::QmlTypeWrapper() + : mode(IncludeEnums) { } @@ -103,7 +99,7 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, Q Q_ASSERT(t); Scope scope(engine); - Scoped<QmlTypeWrapper> w(scope, engine->memoryManager->alloc<QmlTypeWrapper>(engine)); + Scoped<QmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QmlTypeWrapper>()); w->d()->mode = mode; w->d()->object = o; w->d()->type = t; return w.asReturnedValue(); } @@ -117,7 +113,7 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, Q Q_ASSERT(importNamespace); Scope scope(engine); - Scoped<QmlTypeWrapper> w(scope, engine->memoryManager->alloc<QmlTypeWrapper>(engine)); + Scoped<QmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QmlTypeWrapper>()); w->d()->mode = mode; w->d()->object = o; w->d()->typeNamespace = t; w->d()->importNamespace = importNamespace; t->addref(); return w.asReturnedValue(); @@ -182,7 +178,7 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope if (name->startsWithUpper()) { bool ok = false; - int value = type->enumValue(name, &ok); + int value = type->enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); if (ok) return QV4::Primitive::fromInt32(value).asReturnedValue(); diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index 14741a5bad..e67b457c59 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -66,7 +66,7 @@ struct QmlTypeWrapper : Object { ExcludeEnums }; - QmlTypeWrapper(QV4::ExecutionEngine *engine); + QmlTypeWrapper(); ~QmlTypeWrapper(); TypeNameMode mode; QPointer<QObject> object; diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index b0ab85199d..8ddf91ef3c 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -55,7 +55,7 @@ namespace Heap { struct QQmlValueTypeReference : QQmlValueTypeWrapper { - QQmlValueTypeReference(ExecutionEngine *engine); + QQmlValueTypeReference() {} QPointer<QObject> object; int property; }; @@ -77,11 +77,6 @@ DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeReference); using namespace QV4; -Heap::QQmlValueTypeWrapper::QQmlValueTypeWrapper(ExecutionEngine *engine) - : Heap::Object(engine) -{ -} - Heap::QQmlValueTypeWrapper::~QQmlValueTypeWrapper() { if (gadgetPtr) { @@ -107,11 +102,6 @@ QVariant Heap::QQmlValueTypeWrapper::toVariant() const } -Heap::QQmlValueTypeReference::QQmlValueTypeReference(ExecutionEngine *engine) - : Heap::QQmlValueTypeWrapper(engine) -{ -} - bool QQmlValueTypeReference::readReferenceValue() const { if (!d()->object) @@ -164,7 +154,7 @@ bool QQmlValueTypeReference::readReferenceValue() const void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4) { - if (v4->valueTypeWrapperPrototype()->as<Object>()) + if (v4->valueTypeWrapperPrototype()->d()) return; Scope scope(v4); @@ -178,10 +168,9 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *obj Scope scope(engine); initProto(engine); - Scoped<QQmlValueTypeReference> r(scope, engine->memoryManager->alloc<QQmlValueTypeReference>(engine)); - ScopedObject proto(scope, engine->valueTypeWrapperPrototype()); - r->setPrototype(proto); - r->d()->object = object; r->d()->property = property; + Scoped<QQmlValueTypeReference> r(scope, engine->memoryManager->allocObject<QQmlValueTypeReference>()); + r->d()->object = object; + r->d()->property = property; r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); r->d()->valueType = QQmlValueTypeFactory::valueType(typeId); r->d()->gadgetPtr = 0; @@ -193,9 +182,7 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVaria Scope scope(engine); initProto(engine); - Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->alloc<QQmlValueTypeWrapper>(engine)); - ScopedObject proto(scope, engine->valueTypeWrapperPrototype()); - r->setPrototype(proto); + Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocObject<QQmlValueTypeWrapper>()); r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); r->d()->valueType = QQmlValueTypeFactory::valueType(typeId); r->d()->gadgetPtr = 0; @@ -345,12 +332,9 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha if (hasProperty) *hasProperty = true; - if (result->isFunction()) { + if (result->isFunction()) // calling a Q_INVOKABLE function of a value type - Scope scope(v4); - ScopedContext c(scope, v4->rootContext()); - return QV4::QObjectMethod::create(c, r, result->coreIndex); - } + return QV4::QObjectMethod::create(v4->rootContext(), r, result->coreIndex); #define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \ if (result->propType == metatype) { \ diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index 5f0edfb71d..156b4c85d8 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -61,7 +61,7 @@ namespace QV4 { namespace Heap { struct QQmlValueTypeWrapper : Object { - QQmlValueTypeWrapper(ExecutionEngine *engine); + QQmlValueTypeWrapper() {} ~QQmlValueTypeWrapper(); QQmlRefPointer<QQmlPropertyCache> propertyCache; mutable void *gadgetPtr; @@ -76,6 +76,7 @@ struct QQmlValueTypeWrapper : Object { struct Q_QML_EXPORT QQmlValueTypeWrapper : Object { V4_OBJECT2(QQmlValueTypeWrapper, Object) + V4_PROTOTYPE(valueTypeWrapperPrototype) static void destroy(Heap::Base *b); public: diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index 427e751f5d..dcf95b0c69 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -271,8 +271,6 @@ public: QList<QQmlVMEVariantQObjectPtr *> varObjectGuards; QQmlVMEVariantQObjectPtr *getQObjectGuardForProperty(int) const; - - friend class QV8GCCallback; }; QQmlVMEMetaObject *QQmlVMEMetaObject::get(QObject *obj) diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index de7741675b..8666c0db01 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -170,7 +170,7 @@ public: namespace Heap { struct NamedNodeMap : Object { - NamedNodeMap(ExecutionEngine *engine, NodeImpl *data, const QList<NodeImpl *> &list); + NamedNodeMap(NodeImpl *data, const QList<NodeImpl *> &list); ~NamedNodeMap() { if (d) d->release(); @@ -180,7 +180,7 @@ struct NamedNodeMap : Object { }; struct NodeList : Object { - NodeList(ExecutionEngine *engine, NodeImpl *data); + NodeList(NodeImpl *data); ~NodeList() { if (d) d->release(); @@ -189,11 +189,11 @@ struct NodeList : Object { }; struct NodePrototype : Object { - NodePrototype(ExecutionEngine *engine); + NodePrototype(); }; struct Node : Object { - Node(ExecutionEngine *engine, NodeImpl *data); + Node(NodeImpl *data); ~Node() { if (d) d->release(); @@ -217,9 +217,8 @@ public: static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); }; -Heap::NamedNodeMap::NamedNodeMap(ExecutionEngine *engine, NodeImpl *data, const QList<NodeImpl *> &list) - : Heap::Object(engine) - , list(list) +Heap::NamedNodeMap::NamedNodeMap(NodeImpl *data, const QList<NodeImpl *> &list) + : list(list) , d(data) { if (d) @@ -243,9 +242,8 @@ public: }; -Heap::NodeList::NodeList(ExecutionEngine *engine, NodeImpl *data) - : Heap::Object(engine) - , d(data) +Heap::NodeList::NodeList(NodeImpl *data) + : d(data) { if (d) d->addref(); @@ -285,10 +283,9 @@ public: }; -Heap::NodePrototype::NodePrototype(ExecutionEngine *engine) - : Heap::Object(engine) +Heap::NodePrototype::NodePrototype() { - Scope scope(engine); + Scope scope(internalClass->engine); ScopedObject o(scope, this); o->defineAccessorProperty(QStringLiteral("nodeName"), QV4::NodePrototype::method_get_nodeName, 0); @@ -323,9 +320,8 @@ private: Node(const Node &o); }; -Heap::Node::Node(ExecutionEngine *engine, NodeImpl *data) - : Heap::Object(engine) - , d(data) +Heap::Node::Node(NodeImpl *data) + : d(data) { if (d) d->addref(); @@ -584,7 +580,7 @@ ReturnedValue NodePrototype::getProto(ExecutionEngine *v4) Scope scope(v4); QQmlXMLHttpRequestData *d = xhrdata(v4); if (d->nodePrototype.isUndefined()) { - ScopedObject p(scope, v4->memoryManager->alloc<NodePrototype>(v4)); + ScopedObject p(scope, v4->memoryManager->allocObject<NodePrototype>()); d->nodePrototype.set(v4, p); v4->v8Engine->freezeObject(p); } @@ -595,7 +591,7 @@ ReturnedValue Node::create(ExecutionEngine *v4, NodeImpl *data) { Scope scope(v4); - Scoped<Node> instance(scope, v4->memoryManager->alloc<Node>(v4, data)); + Scoped<Node> instance(scope, v4->memoryManager->allocObject<Node>(data)); ScopedObject p(scope); switch (data->type) { @@ -863,7 +859,7 @@ ReturnedValue Document::load(ExecutionEngine *v4, const QByteArray &data) return Encode::null(); } - ScopedObject instance(scope, v4->memoryManager->alloc<Node>(v4, document)); + ScopedObject instance(scope, v4->memoryManager->allocObject<Node>(document)); ScopedObject p(scope); instance->setPrototype((p = Document::prototype(v4))); return instance.asReturnedValue(); @@ -916,7 +912,7 @@ ReturnedValue NamedNodeMap::get(const Managed *m, String *name, bool *hasPropert ReturnedValue NamedNodeMap::create(ExecutionEngine *v4, NodeImpl *data, const QList<NodeImpl *> &list) { - return (v4->memoryManager->alloc<NamedNodeMap>(v4, data, list))->asReturnedValue(); + return (v4->memoryManager->allocObject<NamedNodeMap>(data, list))->asReturnedValue(); } ReturnedValue NodeList::getIndexed(const Managed *m, uint index, bool *hasProperty) @@ -950,7 +946,7 @@ ReturnedValue NodeList::get(const Managed *m, String *name, bool *hasProperty) ReturnedValue NodeList::create(ExecutionEngine *v4, NodeImpl *data) { - return (v4->memoryManager->alloc<NodeList>(v4, data))->asReturnedValue(); + return (v4->memoryManager->allocObject<NodeList>(data))->asReturnedValue(); } ReturnedValue Document::method_documentElement(CallContext *ctx) @@ -1588,7 +1584,7 @@ namespace QV4 { namespace Heap { struct QQmlXMLHttpRequestWrapper : Object { - QQmlXMLHttpRequestWrapper(ExecutionEngine *engine, QQmlXMLHttpRequest *request); + QQmlXMLHttpRequestWrapper(QQmlXMLHttpRequest *request); ~QQmlXMLHttpRequestWrapper() { delete request; } @@ -1609,9 +1605,8 @@ struct QQmlXMLHttpRequestWrapper : public Object V4_NEEDS_DESTROY }; -Heap::QQmlXMLHttpRequestWrapper::QQmlXMLHttpRequestWrapper(ExecutionEngine *engine, QQmlXMLHttpRequest *request) - : Heap::Object(engine) - , request(request) +Heap::QQmlXMLHttpRequestWrapper::QQmlXMLHttpRequestWrapper(QQmlXMLHttpRequest *request) + : request(request) { } @@ -1632,7 +1627,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject return scope.engine->throwTypeError(); QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager()); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->alloc<QQmlXMLHttpRequestWrapper>(scope.engine, r)); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocObject<QQmlXMLHttpRequestWrapper>(r)); ScopedObject proto(scope, ctor->d()->proto); w->setPrototype(proto); return w.asReturnedValue(); @@ -2034,7 +2029,7 @@ void *qt_add_qmlxmlhttprequest(ExecutionEngine *v4) { Scope scope(v4); - Scoped<QQmlXMLHttpRequestCtor> ctor(scope, v4->memoryManager->alloc<QQmlXMLHttpRequestCtor>(v4)); + Scoped<QQmlXMLHttpRequestCtor> ctor(scope, v4->memoryManager->allocObject<QQmlXMLHttpRequestCtor>(v4)); ScopedString s(scope, v4->newString(QStringLiteral("XMLHttpRequest"))); v4->globalObject->defineReadonlyProperty(s, ctor); diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 239bc53f0a..5986fdbdfa 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -80,10 +80,9 @@ struct StaticQtMetaObject : public QObject { return &staticQtMetaObject; } }; -Heap::QtObject::QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine) - : Heap::Object(v4) +Heap::QtObject::QtObject(QQmlEngine *qmlEngine) { - Scope scope(v4); + Scope scope(internalClass->engine); ScopedObject o(scope, this); // Set all the enums from the "Qt" namespace @@ -93,11 +92,11 @@ Heap::QtObject::QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine) for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) { QMetaEnum enumerator = qtMetaObject->enumerator(ii); for (int jj = 0; jj < enumerator.keyCount(); ++jj) { - o->put((str = v4->newString(QString::fromUtf8(enumerator.key(jj)))), (v = QV4::Primitive::fromInt32(enumerator.value(jj)))); + o->put((str = scope.engine->newString(QString::fromUtf8(enumerator.key(jj)))), (v = QV4::Primitive::fromInt32(enumerator.value(jj)))); } } - o->put((str = v4->newString(QStringLiteral("Asynchronous"))), (v = QV4::Primitive::fromInt32(0))); - o->put((str = v4->newString(QStringLiteral("Synchronous"))), (v = QV4::Primitive::fromInt32(1))); + o->put((str = scope.engine->newString(QStringLiteral("Asynchronous"))), (v = QV4::Primitive::fromInt32(0))); + o->put((str = scope.engine->newString(QStringLiteral("Synchronous"))), (v = QV4::Primitive::fromInt32(1))); o->defineDefaultProperty(QStringLiteral("include"), QV4Include::method_include); o->defineDefaultProperty(QStringLiteral("isQtObject"), QV4::QtObject::method_isQtObject); @@ -1262,7 +1261,7 @@ ReturnedValue QtObject::method_binding(CallContext *ctx) if (!f) V4THROW_TYPE("binding(): argument (binding expression) must be a function"); - return (ctx->d()->engine->memoryManager->alloc<QQmlBindingFunction>(f))->asReturnedValue(); + return (ctx->d()->engine->memoryManager->allocObject<QQmlBindingFunction>(f))->asReturnedValue(); } @@ -1315,10 +1314,9 @@ ReturnedValue QtObject::method_get_styleHints(CallContext *ctx) } -QV4::Heap::ConsoleObject::ConsoleObject(ExecutionEngine *v4) - : Heap::Object(v4) +QV4::Heap::ConsoleObject::ConsoleObject() { - QV4::Scope scope(v4); + QV4::Scope scope(internalClass->engine); QV4::ScopedObject o(scope, this); o->defineDefaultProperty(QStringLiteral("debug"), QV4::ConsoleObject::method_log); @@ -1609,10 +1607,10 @@ void QV4::GlobalExtensions::init(QQmlEngine *qmlEngine, Object *globalObject) globalObject->defineDefaultProperty(QStringLiteral("print"), ConsoleObject::method_log); globalObject->defineDefaultProperty(QStringLiteral("gc"), method_gc); - ScopedObject console(scope, v4->memoryManager->alloc<QV4::ConsoleObject>(v4)); + ScopedObject console(scope, v4->memoryManager->allocObject<QV4::ConsoleObject>()); globalObject->defineDefaultProperty(QStringLiteral("console"), console); - ScopedObject qt(scope, v4->memoryManager->alloc<QV4::QtObject>(v4, qmlEngine)); + ScopedObject qt(scope, v4->memoryManager->allocObject<QV4::QtObject>(qmlEngine)); globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt); // string prototype extension @@ -1737,10 +1735,10 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx) int lastDot = path.lastIndexOf(QLatin1Char('.')); int length = lastDot - (lastSlash + 1); context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString(); - } else if (ctx->d()->parent) { - ScopedContext parentCtx(scope, ctx->d()->parent); + } else { + ExecutionContext *parentCtx = scope.engine->parentContext(ctx); // The first non-empty source URL in the call stack determines the translation context. - while (parentCtx && context.isEmpty()) { + while (!!parentCtx && context.isEmpty()) { if (QV4::CompiledData::CompilationUnit *unit = parentCtx->d()->compilationUnit) { QString fileName = unit->fileName(); QUrl url(unit->fileName()); @@ -1753,7 +1751,7 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx) } context = QFileInfo(context).baseName(); } - parentCtx = parentCtx->d()->parent; + parentCtx = scope.engine->parentContext(parentCtx); } } diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index bdd53fe601..bb05376fc0 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -58,13 +58,13 @@ namespace QV4 { namespace Heap { struct QtObject : Object { - QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine); + QtObject(QQmlEngine *qmlEngine); QObject *platform; QObject *application; }; struct ConsoleObject : Object { - ConsoleObject(ExecutionEngine *engine); + ConsoleObject(); }; struct QQmlBindingFunction : FunctionObject { diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 6cb316ce9f..effc37a0eb 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -191,41 +191,47 @@ void QV8Engine::initializeGlobal() m_illegalNames.insert(m_v4Engine->globalObject->internalClass()->nameMap.at(i)->string); } } +} - { -#define FREEZE_SOURCE "(function freeze_recur(obj) { "\ - " if (Qt.isQtObject(obj)) return;"\ - " if (obj != Function.connect && obj != Function.disconnect && "\ - " obj instanceof Object) {"\ - " var properties = Object.getOwnPropertyNames(obj);"\ - " for (var prop in properties) { "\ - " if (prop == \"connect\" || prop == \"disconnect\") {"\ - " Object.freeze(obj[prop]); "\ - " continue;"\ - " }"\ - " freeze_recur(obj[prop]);"\ - " }"\ - " }"\ - " if (obj instanceof Object) {"\ - " Object.freeze(obj);"\ - " }"\ - "})" - - QV4::ScopedFunctionObject result(scope, QV4::Script::evaluate(m_v4Engine, QString::fromUtf8(FREEZE_SOURCE), 0)); - Q_ASSERT(!!result); - m_freezeObject.set(scope.engine, result); -#undef FREEZE_SOURCE +static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object) +{ + if (object->as<QV4::QObjectWrapper>()) + return; + + QV4::Scope scope(v4); + + bool instanceOfObject = false; + QV4::ScopedObject p(scope, object->prototype()); + while (p) { + if (p->d() == v4->objectPrototype()->d()) { + instanceOfObject = true; + break; + } + p = p->prototype(); + } + if (!instanceOfObject) + return; + + QV4::InternalClass *frozen = object->internalClass()->propertiesFrozen(); + if (object->internalClass() == frozen) + return; + object->setInternalClass(frozen); + + QV4::ScopedObject o(scope); + for (uint i = 0; i < frozen->size; ++i) { + if (!frozen->nameMap.at(i)) + continue; + o = *object->propertyData(i); + if (o) + freeze_recursive(v4, o); } } void QV8Engine::freezeObject(const QV4::Value &value) { QV4::Scope scope(m_v4Engine); - QV4::ScopedFunctionObject f(scope, m_freezeObject.value()); - QV4::ScopedCallData callData(scope, 1); - callData->args[0] = value; - callData->thisObject = m_v4Engine->globalObject; - f->call(callData); + QV4::ScopedObject o(scope, value); + freeze_recursive(m_v4Engine, o); } struct QV8EngineRegistrationData diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index 08bbbb8548..552470c88c 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -120,8 +120,6 @@ class QQmlV4Function public: int length() const { return callData->argc; } QV4::ReturnedValue operator[](int idx) { return (idx < callData->argc ? callData->args[idx].asReturnedValue() : QV4::Encode::undefined()); } - QQmlContextData *context() { return e->qmlContextObject()->context.contextData(); } - QV4::ReturnedValue qmlGlobal() { return e->qmlContextObject()->asReturnedValue(); } void setReturnValue(QV4::ReturnedValue rv) { *retVal = rv; } QV4::ExecutionEngine *v4engine() const { return e; } private: @@ -219,8 +217,6 @@ protected: QV4::ExecutionEngine *m_v4Engine; - QV4::PersistentValue m_freezeObject; - void *m_xmlHttpRequestData; QVector<Deletable *> m_extensionData; diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp index a154da8323..df429e5bc1 100644 --- a/src/qml/types/qqmlbind.cpp +++ b/src/qml/types/qqmlbind.cpp @@ -36,6 +36,7 @@ #include <private/qqmlnullablevalue_p.h> #include <private/qqmlproperty_p.h> #include <private/qqmlbinding_p.h> +#include <private/qqmlmetatype_p.h> #include <qqmlengine.h> #include <qqmlcontext.h> @@ -49,6 +50,29 @@ QT_BEGIN_NAMESPACE +namespace { + +void validateProperty(QObject *target, const QString &propertyName, QObject *binding) +{ + if (!target) + return; + + const QMetaObject *mo = target->metaObject(); + const int index = mo->indexOfProperty(propertyName.toUtf8()); + if (index == -1) { + qmlInfo(binding) << "Property '" << propertyName << "' does not exist on " << QQmlMetaType::prettyTypeName(target) << "."; + return; + } + + const QMetaProperty mp = mo->property(index); + if (!mp.isWritable()) { + qmlInfo(binding) << "Property '" << propertyName << "' on " << QQmlMetaType::prettyTypeName(target) << " is read-only."; + return; + } +} + +} + class QQmlBindPrivate : public QObjectPrivate { public: @@ -186,8 +210,10 @@ void QQmlBind::setObject(QObject *obj) d->when = true; } d->obj = obj; - if (d->componentComplete) + if (d->componentComplete) { + validateProperty(d->obj, d->propName, this); d->prop = QQmlProperty(d->obj, d->propName); + } eval(); } @@ -213,8 +239,10 @@ void QQmlBind::setProperty(const QString &p) d->when = true; } d->propName = p; - if (d->componentComplete) + if (d->componentComplete) { + validateProperty(d->obj, d->propName, this); d->prop = QQmlProperty(d->obj, d->propName); + } eval(); } @@ -253,8 +281,10 @@ void QQmlBind::componentComplete() { Q_D(QQmlBind); d->componentComplete = true; - if (!d->prop.isValid()) + if (!d->prop.isValid()) { + validateProperty(d->obj, d->propName, this); d->prop = QQmlProperty(d->obj, d->propName); + } eval(); } diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index bc70e68904..f2de911725 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -64,13 +64,13 @@ struct DelegateModelGroupFunction : FunctionObject { }; struct QQmlDelegateModelGroupChange : Object { - QQmlDelegateModelGroupChange(QV4::ExecutionEngine *engine); + QQmlDelegateModelGroupChange() {} QQmlChangeSet::Change change; }; struct QQmlDelegateModelGroupChangeArray : Object { - QQmlDelegateModelGroupChangeArray(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes); + QQmlDelegateModelGroupChangeArray(const QVector<QQmlChangeSet::Change> &changes); QVector<QQmlChangeSet::Change> changes; }; @@ -83,7 +83,7 @@ struct DelegateModelGroupFunction : QV4::FunctionObject static Heap::DelegateModelGroupFunction *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg)) { - return scope->engine()->memoryManager->alloc<DelegateModelGroupFunction>(scope, flag, code); + return scope->engine()->memoryManager->allocObject<DelegateModelGroupFunction>(scope, flag, code); } static QV4::ReturnedValue call(const QV4::Managed *that, QV4::CallData *callData) @@ -1717,7 +1717,7 @@ void QQmlDelegateModelItemMetaType::initializePrototype() s = v4->newString(QStringLiteral("isUnresolved")); QV4::ScopedFunctionObject f(scope); - QV4::ScopedContext global(scope, scope.engine->rootContext()); + QV4::ExecutionContext *global = scope.engine->rootContext(); p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, 30, QQmlDelegateModelItem::get_member))); p->setSetter(0); proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); @@ -2488,7 +2488,7 @@ QQmlV4Handle QQmlDelegateModelGroup::get(int index) QV8Engine *v8 = model->m_cacheMetaType->v8Engine; QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8); QV4::Scope scope(v4); - QV4::ScopedObject o(scope, v4->memoryManager->alloc<QQmlDelegateModelItemObject>(v4, cacheItem)); + QV4::ScopedObject o(scope, v4->memoryManager->allocObject<QQmlDelegateModelItemObject>(cacheItem)); QV4::ScopedObject p(scope, model->m_cacheMetaType->modelItemProto.value()); o->setPrototype(p); ++cacheItem->scriptRef; @@ -3233,7 +3233,7 @@ struct QQmlDelegateModelGroupChange : QV4::Object V4_OBJECT2(QQmlDelegateModelGroupChange, QV4::Object) static QV4::Heap::QQmlDelegateModelGroupChange *create(QV4::ExecutionEngine *e) { - return e->memoryManager->alloc<QQmlDelegateModelGroupChange>(e); + return e->memoryManager->allocObject<QQmlDelegateModelGroupChange>(); } static QV4::ReturnedValue method_get_index(QV4::CallContext *ctx) { @@ -3261,11 +3261,6 @@ struct QQmlDelegateModelGroupChange : QV4::Object } }; -QV4::Heap::QQmlDelegateModelGroupChange::QQmlDelegateModelGroupChange(QV4::ExecutionEngine *engine) - : QV4::Heap::Object(engine) -{ -} - DEFINE_OBJECT_VTABLE(QQmlDelegateModelGroupChange); struct QQmlDelegateModelGroupChangeArray : public QV4::Object @@ -3275,7 +3270,7 @@ struct QQmlDelegateModelGroupChangeArray : public QV4::Object public: static QV4::Heap::QQmlDelegateModelGroupChangeArray *create(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes) { - return engine->memoryManager->alloc<QQmlDelegateModelGroupChangeArray>(engine, changes); + return engine->memoryManager->allocObject<QQmlDelegateModelGroupChangeArray>(changes); } quint32 count() const { return d()->changes.count(); } @@ -3321,11 +3316,10 @@ public: } }; -QV4::Heap::QQmlDelegateModelGroupChangeArray::QQmlDelegateModelGroupChangeArray(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes) - : QV4::Heap::Object(engine) - , changes(changes) +QV4::Heap::QQmlDelegateModelGroupChangeArray::QQmlDelegateModelGroupChangeArray(const QVector<QQmlChangeSet::Change> &changes) + : changes(changes) { - QV4::Scope scope(engine); + QV4::Scope scope(internalClass->engine); QV4::ScopedObject o(scope, this); o->setArrayType(QV4::Heap::ArrayData::Custom); } diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h index 5c28021c0e..3a19163cbd 100644 --- a/src/qml/types/qqmldelegatemodel_p_p.h +++ b/src/qml/types/qqmldelegatemodel_p_p.h @@ -154,7 +154,7 @@ protected: namespace QV4 { namespace Heap { struct QQmlDelegateModelItemObject : Object { - inline QQmlDelegateModelItemObject(QV4::ExecutionEngine *engine, QQmlDelegateModelItem *item); + inline QQmlDelegateModelItemObject(QQmlDelegateModelItem *item); ~QQmlDelegateModelItemObject(); QQmlDelegateModelItem *item; }; @@ -168,9 +168,8 @@ struct QQmlDelegateModelItemObject : QV4::Object V4_NEEDS_DESTROY }; -QV4::Heap::QQmlDelegateModelItemObject::QQmlDelegateModelItemObject(QV4::ExecutionEngine *engine, QQmlDelegateModelItem *item) - : QV4::Heap::Object(engine) - , item(item) +QV4::Heap::QQmlDelegateModelItemObject::QQmlDelegateModelItemObject(QQmlDelegateModelItem *item) + : item(item) { } diff --git a/src/qml/types/qqmlitemselectionmodel.qdoc b/src/qml/types/qqmlitemselectionmodel.qdoc index 185ffb5fa4..441d219de8 100644 --- a/src/qml/types/qqmlitemselectionmodel.qdoc +++ b/src/qml/types/qqmlitemselectionmodel.qdoc @@ -103,7 +103,7 @@ */ /*! - \qmlmethod QItemSelection selection() + \qmlmethod QItemSelection ItemSelectionModel::selection() */ /*! diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 799f7a0b8a..a4c0f7043f 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -1875,6 +1875,30 @@ QVariant QQmlListModel::data(const QModelIndex &index, int role) const return data(index.row(), role); } +bool QQmlListModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + const int row = index.row(); + if (row >= count() || row < 0) + return false; + + if (m_dynamicRoles) { + const QByteArray property = m_roles.at(role).toUtf8(); + if (m_modelObjects[row]->setValue(property, value)) { + emitItemsChanged(row, 1, QVector<int>() << role); + return true; + } + } else { + const ListLayout::Role &r = m_listModel->getExistingRole(role); + const int roleIndex = m_listModel->setOrCreateProperty(row, r.name, value); + if (roleIndex != -1) { + emitItemsChanged(row, 1, QVector<int>() << role); + return true; + } + } + + return false; +} + QVariant QQmlListModel::data(int index, int role) const { QVariant v; @@ -2252,7 +2276,7 @@ QQmlV4Handle QQmlListModel::get(int index) const result = QV4::QObjectWrapper::wrap(scope.engine, object); } else { QObject *object = m_listModel->getOrCreateModelObject(const_cast<QQmlListModel *>(this), index); - result = scope.engine->memoryManager->alloc<QV4::ModelObject>(scope.engine, object, const_cast<QQmlListModel *>(this), index); + result = scope.engine->memoryManager->allocObject<QV4::ModelObject>(object, const_cast<QQmlListModel *>(this), index); } } diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h index b5a5ef3265..21de392234 100644 --- a/src/qml/types/qqmllistmodel_p.h +++ b/src/qml/types/qqmllistmodel_p.h @@ -71,6 +71,7 @@ public: QModelIndex index(int row, int column, const QModelIndex &parent) const; int rowCount(const QModelIndex &parent) const; QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); QHash<int,QByteArray> roleNames() const; QVariant data(int index, int role) const; diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h index bd0f028e7a..d7e0defaec 100644 --- a/src/qml/types/qqmllistmodel_p_p.h +++ b/src/qml/types/qqmllistmodel_p_p.h @@ -155,8 +155,8 @@ namespace QV4 { namespace Heap { struct ModelObject : public QObjectWrapper { - ModelObject(QV4::ExecutionEngine *engine, QObject *object, QQmlListModel *model, int elementIndex) - : QObjectWrapper(engine, object) + ModelObject(QObject *object, QQmlListModel *model, int elementIndex) + : QObjectWrapper(object) , m_model(model) , m_elementIndex(elementIndex) {} diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp index 0aa5dc4ef6..03915ab414 100644 --- a/src/qml/types/qquickworkerscript.cpp +++ b/src/qml/types/qquickworkerscript.cpp @@ -165,7 +165,7 @@ public: QUrl source; bool initialized; QQuickWorkerScript *owner; - QV4::PersistentValue object; + QV4::PersistentValue qmlContext; }; QHash<int, WorkerScript *> workers; @@ -221,7 +221,7 @@ void QQuickWorkerScriptEnginePrivate::WorkerEngine::init() "})" QV4::Scope scope(m_v4Engine); - QV4::ScopedContext globalContext(scope, scope.engine->rootContext()); + QV4::ExecutionContext *globalContext = scope.engine->rootContext(); onmessage.set(scope.engine, QV4::Script(globalContext, QString::fromUtf8(CALL_ONMESSAGE_SCRIPT)).run()); // do not use QStringLiteral here, MSVC2012 cannot apply this cleanly to the macro Q_ASSERT(!scope.engine->hasException); QV4::Script createsendscript(globalContext, QString::fromUtf8(SEND_MESSAGE_CREATE_SCRIPT)); // do not use QStringLiteral here, MSVC2012 cannot apply this cleanly to the macro @@ -291,7 +291,6 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::method_sendMessage(QV4::Call return QV4::Encode::undefined(); } -// Requires handle scope and context scope QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::getWorker(WorkerScript *script) { if (!script->initialized) { @@ -300,9 +299,7 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::getWorker(WorkerScript *scri QV4::ExecutionEngine *v4 = QV8Engine::getV4(workerEngine); QV4::Scope scope(v4); - script->object.set(v4, QV4::QmlContextWrapper::urlScope(v4, script->source)); - - QV4::Scoped<QV4::QmlContextWrapper> w(scope, script->object.value()); + QV4::Scoped<QV4::QmlContextWrapper> w(scope, QV4::QmlContextWrapper::urlScope(v4, script->source)); Q_ASSERT(!!w); w->setReadOnly(false); @@ -312,9 +309,11 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::getWorker(WorkerScript *scri w->QV4::Object::put(QV4::ScopedString(scope, v4->newString(QStringLiteral("WorkerScript"))), api); w->setReadOnly(true); + + script->qmlContext.set(v4, v4->rootContext()->newQmlContext(w)); } - return script->object.value(); + return script->qmlContext.value(); } bool QQuickWorkerScriptEnginePrivate::event(QEvent *event) @@ -354,10 +353,12 @@ void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &d QV4::ScopedFunctionObject f(scope, workerEngine->onmessage.value()); QV4::ScopedValue value(scope, QV4::Serialize::deserialize(data, v4)); + QV4::Scoped<QV4::QmlContext> qmlContext(scope, script->qmlContext.value()); + Q_ASSERT(!!qmlContext); QV4::ScopedCallData callData(scope, 2); callData->thisObject = workerEngine->global(); - callData->args[0] = script->object.value(); + callData->args[0] = qmlContext->d()->qml; // ### callData->args[1] = value; f->call(callData); if (scope.hasException()) { @@ -382,13 +383,12 @@ void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url) return; script->source = url; - QV4::ScopedObject activation(scope, getWorker(script)); - if (!activation) - return; + QV4::Scoped<QV4::QmlContext> qmlContext(scope, getWorker(script)); + Q_ASSERT(!!qmlContext); if (const QQmlPrivate::CachedQmlUnit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url)) { QV4::CompiledData::CompilationUnit *jsUnit = cachedUnit->createCompilationUnit(); - program.reset(new QV4::Script(v4, activation, jsUnit)); + program.reset(new QV4::Script(v4, qmlContext, jsUnit)); } else { QFile f(fileName); if (!f.open(QIODevice::ReadOnly)) { @@ -400,7 +400,7 @@ void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url) QString sourceCode = QString::fromUtf8(data); QmlIR::Document::removeScriptPragmas(sourceCode); - program.reset(new QV4::Script(v4, activation, sourceCode, url.toString())); + program.reset(new QV4::Script(v4, qmlContext, sourceCode, url.toString())); program->parse(); } diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index f83798488c..29398ff98c 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -221,9 +221,9 @@ public: const QByteArray &propertyName = it.key(); QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName))); - QV4::ScopedContext global(scope, v4->rootContext()); - QV4::ScopedFunctionObject g(scope, v4->memoryManager->alloc<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::get_property)); - QV4::ScopedFunctionObject s(scope, v4->memoryManager->alloc<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::set_property)); + QV4::ExecutionContext *global = v4->rootContext(); + QV4::ScopedFunctionObject g(scope, v4->memoryManager->allocObject<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::get_property)); + QV4::ScopedFunctionObject s(scope, v4->memoryManager->allocObject<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::set_property)); p->setGetter(g); p->setSetter(s); proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable); @@ -428,7 +428,7 @@ public: } QV4::Scope scope(v4); QV4::ScopedObject proto(scope, type->prototype.value()); - QV4::ScopedObject o(scope, proto->engine()->memoryManager->alloc<QQmlDelegateModelItemObject>(proto->engine(), this)); + QV4::ScopedObject o(scope, proto->engine()->memoryManager->allocObject<QQmlDelegateModelItemObject>(this)); o->setPrototype(proto); ++scriptRef; return o.asReturnedValue(); @@ -606,7 +606,7 @@ public: { QQmlAdaptorModelEngineData *data = engineData(v4); QV4::Scope scope(v4); - QV4::ScopedObject o(scope, v4->memoryManager->alloc<QQmlDelegateModelItemObject>(v4, this)); + QV4::ScopedObject o(scope, v4->memoryManager->allocObject<QQmlDelegateModelItemObject>(this)); QV4::ScopedObject p(scope, data->listItemProto.value()); o->setPrototype(p); ++scriptRef; diff --git a/src/qml/util/qqmllistcompositor_p.h b/src/qml/util/qqmllistcompositor_p.h index 8e10cb1546..2ddbc5d5a1 100644 --- a/src/qml/util/qqmllistcompositor_p.h +++ b/src/qml/util/qqmllistcompositor_p.h @@ -166,7 +166,7 @@ public: struct Change { inline Change() {} - inline Change(iterator it, int count, uint flags, int moveId = -1); + inline Change(const iterator &it, int count, uint flags, int moveId = -1); int count; uint flags; int moveId; @@ -188,14 +188,14 @@ public: struct Insert : public Change { Insert() {} - Insert(iterator it, int count, uint flags, int moveId = -1) + Insert(const iterator &it, int count, uint flags, int moveId = -1) : Change(it, count, flags, moveId) {} }; struct Remove : public Change { Remove() {} - Remove(iterator it, int count, uint flags, int moveId = -1) + Remove(const iterator &it, int count, uint flags, int moveId = -1) : Change(it, count, flags, moveId) {} }; @@ -224,14 +224,14 @@ public: void setFlags(iterator from, int count, Group group, uint flags, QVector<Insert> *inserts = 0); void setFlags(Group fromGroup, int from, int count, uint flags, QVector<Insert> *inserts = 0) { setFlags(fromGroup, from, count, fromGroup, flags, inserts); } - void setFlags(iterator from, int count, uint flags, QVector<Insert> *inserts = 0) { + void setFlags(const iterator from, int count, uint flags, QVector<Insert> *inserts = 0) { setFlags(from, count, from.group, flags, inserts); } void clearFlags(Group fromGroup, int from, int count, Group group, uint flags, QVector<Remove> *removals = 0); void clearFlags(iterator from, int count, Group group, uint flags, QVector<Remove> *removals = 0); void clearFlags(Group fromGroup, int from, int count, uint flags, QVector<Remove> *removals = 0) { clearFlags(fromGroup, from, count, fromGroup, flags, removals); } - void clearFlags(iterator from, int count, uint flags, QVector<Remove> *removals = 0) { + void clearFlags(const iterator &from, int count, uint flags, QVector<Remove> *removals = 0) { clearFlags(from, count, from.group, flags, removals); } bool verifyMoveTo(Group fromGroup, int from, Group toGroup, int to, int count, Group group) const; @@ -347,7 +347,7 @@ inline QQmlListCompositor::insert_iterator::insert_iterator( Range *range, int offset, Group group, int groupCount) : iterator(range, offset, group, groupCount) {} -inline QQmlListCompositor::Change::Change(iterator it, int count, uint flags, int moveId) +inline QQmlListCompositor::Change::Change(const iterator &it, int count, uint flags, int moveId) : count(count), flags(flags), moveId(moveId) { for (int i = 0; i < MaximumGroupCount; ++i) diff --git a/src/qml/util/qqmlpropertymap.cpp b/src/qml/util/qqmlpropertymap.cpp index 2e95ab7cb5..28f3c8f215 100644 --- a/src/qml/util/qqmlpropertymap.cpp +++ b/src/qml/util/qqmlpropertymap.cpp @@ -172,8 +172,7 @@ int QQmlPropertyMapMetaObject::createProperty(const char *name, const char *valu modify or clear its associated value. \note When deriving a class from QQmlPropertyMap, use the - \l {QQmlPropertyMap::QQmlPropertyMap(DerivedType *derived, QObject *parent)} - {protected two-argument constructor} + \l {QQmlPropertyMap::QQmlPropertyMap(DerivedType *derived, QObject *parent)} {protected two-argument constructor} which ensures that the class is correctly registered with the Qt \l {Meta-Object System}. */ |