diff options
Diffstat (limited to 'src/qml/jsruntime')
98 files changed, 4350 insertions, 5241 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index ef44ca6f4d..5ffdebe328 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -10,7 +10,6 @@ SOURCES += \ $$PWD/qv4lookup.cpp \ $$PWD/qv4identifier.cpp \ $$PWD/qv4identifiertable.cpp \ - $$PWD/qv4mm.cpp \ $$PWD/qv4managed.cpp \ $$PWD/qv4internalclass.cpp \ $$PWD/qv4sparsearray.cpp \ @@ -40,7 +39,6 @@ SOURCES += \ $$PWD/qv4sequenceobject.cpp \ $$PWD/qv4include.cpp \ $$PWD/qv4qobjectwrapper.cpp \ - $$PWD/qv4qmlextensions.cpp \ $$PWD/qv4vme_moth.cpp \ $$PWD/qv4profiling.cpp \ $$PWD/qv4arraybuffer.cpp \ @@ -57,7 +55,6 @@ HEADERS += \ $$PWD/qv4lookup_p.h \ $$PWD/qv4identifier_p.h \ $$PWD/qv4identifiertable_p.h \ - $$PWD/qv4mm_p.h \ $$PWD/qv4managed_p.h \ $$PWD/qv4internalclass_p.h \ $$PWD/qv4sparsearray_p.h \ @@ -90,7 +87,6 @@ HEADERS += \ $$PWD/qv4sequenceobject_p.h \ $$PWD/qv4include_p.h \ $$PWD/qv4qobjectwrapper_p.h \ - $$PWD/qv4qmlextensions_p.h \ $$PWD/qv4vme_moth_p.h \ $$PWD/qv4profiling_p.h \ $$PWD/qv4arraybuffer_p.h \ @@ -102,7 +98,7 @@ HEADERS += \ HEADERS += \ $$PWD/qv4runtime_p.h \ - $$PWD/qv4value_inl_p.h \ + $$PWD/qv4value_p.h \ $$PWD/qv4string_p.h \ $$PWD/qv4value_p.h diff --git a/src/qml/jsruntime/qv4alloca_p.h b/src/qml/jsruntime/qv4alloca_p.h index a4537868e2..df40a018ba 100644 --- a/src/qml/jsruntime/qv4alloca_p.h +++ b/src/qml/jsruntime/qv4alloca_p.h @@ -34,6 +34,17 @@ #ifndef QV4_ALLOCA_H #define QV4_ALLOCA_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <qglobal.h> #if defined(Q_OS_WIN) diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 92c77570af..698b4c325c 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -33,18 +33,17 @@ #include <qv4argumentsobject_p.h> #include <qv4alloca_p.h> #include <qv4scopedvalue_p.h> +#include "qv4string_p.h" 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.asObject()) - , context(context->d()) + : context(context->d()) , fullyCreated(false) { - Q_ASSERT(vtable == QV4::ArgumentsObject::staticVTable()); + Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable()); ExecutionEngine *v4 = context->d()->engine; Scope scope(v4); @@ -53,22 +52,22 @@ Heap::ArgumentsObject::ArgumentsObject(QV4::CallContext *context) args->setArrayType(Heap::ArrayData::Complex); 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; + Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); + Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller())); + *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(); + Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); + *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); + Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length())); + *args->propertyData(LengthPropertyIndex) = Primitive::fromInt32(context->d()->callData->argc); } void ArgumentsObject::fullyCreate() @@ -76,17 +75,16 @@ void ArgumentsObject::fullyCreate() if (fullyCreated()) return; - uint numAccessors = qMin((int)context()->function->formalParameterCount(), context()->callData->argc); uint argCount = context()->callData->argc; + uint numAccessors = qMin(context()->function->formalParameterCount(), argCount); ArrayData::realloc(this, Heap::ArrayData::Sparse, argCount, true); context()->engine->requireArgumentsAccessors(numAccessors); Scope scope(engine()); Scoped<MemberData> md(scope, d()->mappedArguments); - if (!md || md->size() < numAccessors) - d()->mappedArguments = md->reallocate(engine(), d()->mappedArguments, numAccessors); - for (uint i = 0; i < (uint)numAccessors; ++i) { - mappedArguments()->data[i] = context()->callData->args[i]; + d()->mappedArguments = md->allocate(engine(), numAccessors); + for (uint i = 0; i < numAccessors; ++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); @@ -116,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()); @@ -139,14 +137,14 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con } } - if (engine->currentContext()->strictMode && !result) + if (engine->current->strictMode && !result) return engine->throwTypeError(); return result; } -ReturnedValue ArgumentsObject::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *hasProperty) { - ArgumentsObject *args = static_cast<ArgumentsObject *>(m); + const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m); if (args->fullyCreated()) return Object::getIndexed(m, index, hasProperty); @@ -199,11 +197,11 @@ PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index) DEFINE_OBJECT_VTABLE(ArgumentsGetterFunction); -ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData) +ReturnedValue ArgumentsGetterFunction::call(const Managed *getter, CallData *callData) { - ExecutionEngine *v4 = static_cast<ArgumentsGetterFunction *>(getter)->engine(); + ExecutionEngine *v4 = static_cast<const ArgumentsGetterFunction *>(getter)->engine(); Scope scope(v4); - Scoped<ArgumentsGetterFunction> g(scope, static_cast<ArgumentsGetterFunction *>(getter)); + Scoped<ArgumentsGetterFunction> g(scope, static_cast<const ArgumentsGetterFunction *>(getter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); if (!o) return v4->throwTypeError(); @@ -214,11 +212,11 @@ ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData) DEFINE_OBJECT_VTABLE(ArgumentsSetterFunction); -ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData) +ReturnedValue ArgumentsSetterFunction::call(const Managed *setter, CallData *callData) { - ExecutionEngine *v4 = static_cast<ArgumentsSetterFunction *>(setter)->engine(); + ExecutionEngine *v4 = static_cast<const ArgumentsSetterFunction *>(setter)->engine(); Scope scope(v4); - Scoped<ArgumentsSetterFunction> s(scope, static_cast<ArgumentsSetterFunction *>(setter)); + Scoped<ArgumentsSetterFunction> s(scope, static_cast<const ArgumentsSetterFunction *>(setter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); if (!o) return v4->throwTypeError(); diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 43cd6d1dee..7a9c4b1d51 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -33,6 +33,17 @@ #ifndef QV4ARGUMENTSOBJECTS_H #define QV4ARGUMENTSOBJECTS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" @@ -59,9 +70,9 @@ struct ArgumentsObject : Object { CallerPropertyIndex = 3 }; ArgumentsObject(QV4::CallContext *context); - CallContext *context; + Pointer<CallContext> context; bool fullyCreated; - MemberData *mappedArguments; + Pointer<MemberData> mappedArguments; }; } @@ -71,7 +82,7 @@ struct ArgumentsGetterFunction: FunctionObject V4_OBJECT2(ArgumentsGetterFunction, FunctionObject) uint index() const { return d()->index; } - static ReturnedValue call(Managed *that, CallData *d); + static ReturnedValue call(const Managed *that, CallData *d); }; inline @@ -86,7 +97,7 @@ struct ArgumentsSetterFunction: FunctionObject V4_OBJECT2(ArgumentsSetterFunction, FunctionObject) uint index() const { return d()->index; } - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; inline @@ -103,15 +114,14 @@ 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 && + return m->d()->vtable()->type == Type_ArgumentsObject && !static_cast<ArgumentsObject *>(m)->context()->strictMode; } bool defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static void putIndexed(Managed *m, uint index, const Value &value); static bool deleteIndexedProperty(Managed *m, uint index); static PropertyAttributes queryIndexed(const Managed *m, uint index); diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp index dc65b5d21a..0a3aa414de 100644 --- a/src/qml/jsruntime/qv4arraybuffer.cpp +++ b/src/qml/jsruntime/qv4arraybuffer.cpp @@ -33,6 +33,7 @@ #include "qv4arraybuffer_p.h" #include "qv4typedarray_p.h" #include "qv4dataview_p.h" +#include "qv4string_p.h" using namespace QV4; @@ -44,9 +45,9 @@ Heap::ArrayBufferCtor::ArrayBufferCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ArrayBufferCtor::construct(Managed *m, CallData *callData) +ReturnedValue ArrayBufferCtor::construct(const Managed *m, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(m)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(m)->engine(); Scope scope(v4); ScopedValue l(scope, callData->argument(0)); @@ -57,14 +58,14 @@ ReturnedValue ArrayBufferCtor::construct(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(); } -ReturnedValue ArrayBufferCtor::call(Managed *that, CallData *callData) +ReturnedValue ArrayBufferCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } @@ -82,22 +83,20 @@ ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx) } -Heap::ArrayBuffer::ArrayBuffer(ExecutionEngine *e, size_t length) - : Heap::Object(e->emptyClass, e->arrayBufferPrototype.asObject()) +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.asObject()) - , data(const_cast<QByteArray&>(array).data_ptr()) +Heap::ArrayBuffer::ArrayBuffer(const QByteArray& array) + : data(const_cast<QByteArray&>(array).data_ptr()) { data->ref.ref(); } @@ -138,10 +137,10 @@ void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); ctor->defineDefaultProperty(QStringLiteral("isView"), ArrayBufferCtor::method_isView, 1); - defineDefaultProperty(engine->id_constructor, (o = ctor)); + defineDefaultProperty(engine->id_constructor(), (o = ctor)); defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); defineDefaultProperty(QStringLiteral("slice"), method_slice, 2); } @@ -172,7 +171,7 @@ ReturnedValue ArrayBufferPrototype::method_slice(CallContext *ctx) double first = (start < 0) ? qMax(a->d()->data->size + start, 0.) : qMin(start, (double)a->d()->data->size); double final = (end < 0) ? qMax(a->d()->data->size + end, 0.) : qMin(end, (double)a->d()->data->size); - ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor)); + ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor())); if (!constructor) return scope.engine->throwTypeError(); diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h index fe3150618d..56f45b5a72 100644 --- a/src/qml/jsruntime/qv4arraybuffer_p.h +++ b/src/qml/jsruntime/qv4arraybuffer_p.h @@ -33,6 +33,17 @@ #ifndef QV4ARRAYBUFFER_H #define QV4ARRAYBUFFER_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" @@ -47,8 +58,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; @@ -61,8 +72,8 @@ struct ArrayBufferCtor: FunctionObject { V4_OBJECT2(ArrayBufferCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); static ReturnedValue method_isView(CallContext *ctx); @@ -72,6 +83,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 afcfa00905..ec0185de64 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -33,13 +33,14 @@ #include "qv4arraydata_p.h" #include "qv4object_p.h" #include "qv4functionobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4runtime_p.h" #include "qv4argumentsobject_p.h" +#include "qv4string_p.h" using namespace QV4; -const QV4::ManagedVTable QV4::ArrayData::static_vtbl = { +const QV4::VTable QV4::ArrayData::static_vtbl = { 0, QV4::ArrayData::IsExecutionContext, QV4::ArrayData::IsString, @@ -90,6 +91,13 @@ const ArrayVTable SparseArrayData::static_vtbl = Q_STATIC_ASSERT(sizeof(Heap::ArrayData) == sizeof(Heap::SimpleArrayData)); Q_STATIC_ASSERT(sizeof(Heap::ArrayData) == sizeof(Heap::SparseArrayData)); +static Q_ALWAYS_INLINE void storeValue(ReturnedValue *target, uint value) +{ + Value v = Value::fromReturnedValue(*target); + v.setValue(value); + *target = v.asReturnedValue(); +} + void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAttributes) { Scope scope(o->engine()); @@ -165,7 +173,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt Heap::SparseArrayData *sparse = static_cast<Heap::SparseArrayData *>(newData->d()); - uint *lastFree; + ReturnedValue *lastFree; if (d && d->type() == Heap::ArrayData::Sparse) { Heap::SparseArrayData *old = static_cast<Heap::SparseArrayData *>(d->d()); sparse->sparse = old->sparse; @@ -180,20 +188,20 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt SparseArrayNode *n = sparse->sparse->insert(i); n->value = i; } else { - *lastFree = i; - sparse->arrayData[i].tag = Value::Empty_Type; - lastFree = &sparse->arrayData[i].uint_32; + storeValue(lastFree, i); + sparse->arrayData[i].setTag(Value::Empty_Type); + lastFree = &sparse->arrayData[i].rawValueRef(); } } } if (toCopy < sparse->alloc) { for (uint i = toCopy; i < sparse->alloc; ++i) { - *lastFree = i; - sparse->arrayData[i].tag = Value::Empty_Type; - lastFree = &sparse->arrayData[i].uint_32; + storeValue(lastFree, i); + sparse->arrayData[i].setTag(Value::Empty_Type); + lastFree = &sparse->arrayData[i].rawValueRef(); } - *lastFree = UINT_MAX; + storeValue(lastFree, UINT_MAX); } // ### Could explicitly free the old data } @@ -230,7 +238,7 @@ ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index) bool SimpleArrayData::put(Object *o, uint index, const Value &value) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Q_ASSERT(index >= dd->len || !dd->attrs || !dd->attrs[index].isAccessor()); // ### honour attributes dd->data(index) = value; @@ -244,7 +252,7 @@ bool SimpleArrayData::put(Object *o, uint index, const Value &value) bool SimpleArrayData::del(Object *o, uint index) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (index >= dd->len) return true; @@ -266,12 +274,12 @@ void SimpleArrayData::setAttribute(Object *o, uint index, PropertyAttributes att void SimpleArrayData::push_front(Object *o, const Value *values, uint n) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Q_ASSERT(!dd->attrs); if (dd->len + n > dd->alloc) { realloc(o, Heap::ArrayData::Simple, dd->len + n, false); Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Simple); - dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } dd->offset = (dd->offset - n) % dd->alloc; dd->len += n; @@ -281,7 +289,7 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n) ReturnedValue SimpleArrayData::pop_front(Object *o) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Q_ASSERT(!dd->attrs); if (!dd->len) return Encode::undefined(); @@ -294,7 +302,7 @@ ReturnedValue SimpleArrayData::pop_front(Object *o) uint SimpleArrayData::truncate(Object *o, uint newLen) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (dd->len < newLen) return newLen; @@ -318,10 +326,10 @@ uint SimpleArrayData::length(const Heap::ArrayData *d) bool SimpleArrayData::putArray(Object *o, uint index, const Value *values, uint n) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (index + n > dd->alloc) { reallocate(o, index + n + 1, false); - dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } for (uint i = dd->len; i < index; ++i) dd->data(i) = Primitive::emptyValue(); @@ -337,13 +345,10 @@ void SparseArrayData::free(Heap::ArrayData *d, uint idx) Value *v = d->arrayData + idx; if (d->attrs && d->attrs[idx].isAccessor()) { // double slot, free both. Order is important, so we have a double slot for allocation again afterwards. - v[1].tag = Value::Empty_Type; - v[1].uint_32 = d->freeList; - v[0].tag = Value::Empty_Type; - v[0].uint_32 = idx + 1; + v[1].setTagValue(Value::Empty_Type, Value::fromReturnedValue(d->freeList).value()); + v[0].setTagValue(Value::Empty_Type, idx + 1); } else { - v->tag = Value::Empty_Type; - v->uint_32 = d->freeList; + v->setTagValue(Value::Empty_Type, Value::fromReturnedValue(d->freeList).value()); } d->freeList = idx; if (d->attrs) @@ -369,35 +374,37 @@ Heap::ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttr uint SparseArrayData::allocate(Object *o, bool doubleSlot) { Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Sparse); - Heap::SparseArrayData *dd = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (doubleSlot) { - uint *last = &dd->freeList; + ReturnedValue *last = &dd->freeList; while (1) { - if (*last == UINT_MAX) { + if (Value::fromReturnedValue(*last).value() == UINT_MAX) { reallocate(o, dd->alloc + 2, true); - dd = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); last = &dd->freeList; - Q_ASSERT(*last != UINT_MAX); + Q_ASSERT(Value::fromReturnedValue(*last).value() != UINT_MAX); } - Q_ASSERT(dd->arrayData[*last].uint_32 != *last); - if (dd->arrayData[*last].uint_32 == (*last + 1)) { + Q_ASSERT(dd->arrayData[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value()); + if (dd->arrayData[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) { // found two slots in a row - uint idx = *last; - *last = dd->arrayData[*last + 1].uint_32; + uint idx = Value::fromReturnedValue(*last).uint_32(); + Value lastV = Value::fromReturnedValue(*last); + lastV.setValue(dd->arrayData[lastV.value() + 1].value()); + *last = lastV.rawValue(); dd->attrs[idx] = Attr_Accessor; return idx; } - last = &dd->arrayData[*last].uint_32; + last = &dd->arrayData[Value::fromReturnedValue(*last).value()].rawValueRef(); } } else { - if (dd->freeList == UINT_MAX) { + if (Value::fromReturnedValue(dd->freeList).value() == UINT_MAX) { reallocate(o, dd->alloc + 1, false); - dd = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } - uint idx = dd->freeList; + uint idx = Value::fromReturnedValue(dd->freeList).value(); Q_ASSERT(idx != UINT_MAX); - dd->freeList = dd->arrayData[idx].uint_32; + dd->freeList = dd->arrayData[idx].uint_32(); if (dd->attrs) dd->attrs[idx] = Attr_Data; return idx; @@ -418,12 +425,12 @@ bool SparseArrayData::put(Object *o, uint index, const Value &value) if (value.isEmpty()) return true; - Heap::SparseArrayData *s = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *s = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *n = s->sparse->insert(index); Q_ASSERT(n->value == UINT_MAX || !s->attrs || !s->attrs[n->value].isAccessor()); if (n->value == UINT_MAX) n->value = allocate(o); - s = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + s = o->d()->arrayData.cast<Heap::SparseArrayData>(); s->arrayData[n->value] = value; if (s->attrs) s->attrs[n->value] = Attr_Data; @@ -432,7 +439,7 @@ bool SparseArrayData::put(Object *o, uint index, const Value &value) bool SparseArrayData::del(Object *o, uint index) { - Heap::SparseArrayData *dd = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *dd = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *n = dd->sparse->findNode(index); if (!n) @@ -452,13 +459,10 @@ bool SparseArrayData::del(Object *o, uint index) if (isAccessor) { // free up both indices - dd->arrayData[pidx + 1].tag = Value::Empty_Type; - dd->arrayData[pidx + 1].uint_32 = dd->freeList; - dd->arrayData[pidx].tag = Value::Undefined_Type; - dd->arrayData[pidx].uint_32 = pidx + 1; + dd->arrayData[pidx + 1].setTagValue(Value::Empty_Type, Value::fromReturnedValue(dd->freeList).value()); + dd->arrayData[pidx].setTagValue(Value::Undefined_Type, pidx + 1); } else { - dd->arrayData[pidx].tag = Value::Empty_Type; - dd->arrayData[pidx].uint_32 = dd->freeList; + dd->arrayData[pidx].setTagValue(Value::Empty_Type, Value::fromReturnedValue(dd->freeList).value()); } dd->freeList = pidx; @@ -468,28 +472,28 @@ bool SparseArrayData::del(Object *o, uint index) void SparseArrayData::setAttribute(Object *o, uint index, PropertyAttributes attrs) { - Heap::SparseArrayData *d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *n = d->sparse->insert(index); if (n->value == UINT_MAX) { n->value = allocate(o, attrs.isAccessor()); - d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + d = o->d()->arrayData.cast<Heap::SparseArrayData>(); } else if (attrs.isAccessor() != d->attrs[n->value].isAccessor()) { // need to convert the slot free(o->arrayData(), n->value); n->value = allocate(o, attrs.isAccessor()); - d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + d = o->d()->arrayData.cast<Heap::SparseArrayData>(); } d->attrs[n->value] = attrs; } void SparseArrayData::push_front(Object *o, const Value *values, uint n) { - Heap::SparseArrayData *d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>(); Q_ASSERT(!d->attrs); for (int i = n - 1; i >= 0; --i) { uint idx = allocate(o); - d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + d = o->d()->arrayData.cast<Heap::SparseArrayData>(); d->arrayData[idx] = values[i]; d->sparse->push_front(idx); } @@ -497,7 +501,7 @@ void SparseArrayData::push_front(Object *o, const Value *values, uint n) ReturnedValue SparseArrayData::pop_front(Object *o) { - Heap::SparseArrayData *d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>(); Q_ASSERT(!d->attrs); uint idx = d->sparse->pop_front(); ReturnedValue v; @@ -512,7 +516,7 @@ ReturnedValue SparseArrayData::pop_front(Object *o) uint SparseArrayData::truncate(Object *o, uint newLen) { - Heap::SparseArrayData *d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *begin = d->sparse->lowerBound(newLen); if (begin != d->sparse->end()) { SparseArrayNode *it = d->sparse->end()->previousNode(); @@ -580,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 { @@ -603,14 +607,14 @@ 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 = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *d = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (index < 0x1000 || index < d->len + (d->len >> 2)) { if (index >= d->alloc) { o->arrayReserve(index + 1); - d = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + d = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } if (index >= d->len) { // mark possible hole in the array @@ -618,17 +622,20 @@ 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; } } o->initSparseArray(); - Heap::SparseArrayData *s = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *s = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *n = s->sparse->insert(index); if (n->value == UINT_MAX) n->value = SparseArrayData::allocate(o, isAccessor); - s = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); - return reinterpret_cast<Property *>(s->arrayData + n->value); + s = o->d()->arrayData.cast<Heap::SparseArrayData>(); + s->arrayData[n->value] = *v; + if (isAccessor) + s->arrayData[n->value + Object::SetterOffset] = v[Object::SetterOffset]; } @@ -737,7 +744,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c if (!arrayData || !arrayData->length()) return; - if (!(comparefn.isUndefined() || comparefn.asObject())) { + if (!(comparefn.isUndefined() || comparefn.as<Object>())) { engine->throwTypeError(); return; } @@ -755,7 +762,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c thisObject->setArrayData(0); ArrayData::realloc(thisObject, Heap::ArrayData::Simple, sparse->sparse()->nEntries(), sparse->attrs() ? true : false); - Heap::SimpleArrayData *d = static_cast<Heap::SimpleArrayData *>(thisObject->d()->arrayData); + Heap::SimpleArrayData *d = thisObject->d()->arrayData.cast<Heap::SimpleArrayData>(); SparseArrayNode *n = sparse->sparse()->begin(); uint i = 0; @@ -765,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(); @@ -795,7 +802,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c } } else { - Heap::SimpleArrayData *d = static_cast<Heap::SimpleArrayData *>(thisObject->d()->arrayData); + Heap::SimpleArrayData *d = thisObject->d()->arrayData.cast<Heap::SimpleArrayData>(); if (len > d->len) len = d->len; diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 915e862bbb..48d2b9dbbf 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -33,6 +33,17 @@ #ifndef QV4ARRAYDATA_H #define QV4ARRAYDATA_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include "qv4managed_p.h" #include "qv4property_p.h" @@ -47,17 +58,17 @@ namespace QV4 { Q_MANAGED_CHECK \ typedef QV4::Heap::DataClass Data; \ static const QV4::ArrayVTable static_vtbl; \ - static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \ + static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \ V4_MANAGED_SIZE_TEST \ - const Data *d() const { return static_cast<const Data *>(m); } \ - Data *d() { return static_cast<Data *>(m); } + const Data *d() const { return static_cast<const Data *>(m()); } \ + Data *d() { return static_cast<Data *>(m()); } struct ArrayData; struct ArrayVTable { - ManagedVTable managedVTable; + VTable vTable; uint type; Heap::ArrayData *(*reallocate)(Object *o, uint n, bool enforceAttributes); ReturnedValue (*get)(const Heap::ArrayData *d, uint index); @@ -86,7 +97,7 @@ struct ArrayData : public Base { PropertyAttributes *attrs; union { uint len; - uint freeList; + ReturnedValue freeList; }; union { uint offset; @@ -96,12 +107,15 @@ struct ArrayData : public Base { bool isSparse() const { return type == Sparse; } - const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(Base::vtable); } + const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(Base::vtable()); } 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 +219,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 @@ -239,8 +253,8 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData V4_ARRAYDATA(SparseArrayData) V4_NEEDS_DESTROY - uint &freeList() { return d()->freeList; } - uint freeList() const { return d()->freeList; } + ReturnedValue &freeList() { return d()->freeList; } + ReturnedValue freeList() const { return d()->freeList; } SparseArray *sparse() const { return d()->sparse; } void setSparse(SparseArray *s) { d()->sparse = s; } @@ -270,6 +284,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 +317,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/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 231eb93dd5..25d3d9329b 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -37,6 +37,7 @@ #include "qv4scopedvalue_p.h" #include "qv4argumentsobject_p.h" #include "qv4runtime_p.h" +#include "qv4string_p.h" using namespace QV4; @@ -47,9 +48,9 @@ Heap::ArrayCtor::ArrayCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData) +ReturnedValue ArrayCtor::construct(const Managed *m, CallData *callData) { - ExecutionEngine *v4 = static_cast<ArrayCtor *>(m)->engine(); + ExecutionEngine *v4 = static_cast<const ArrayCtor *>(m)->engine(); Scope scope(v4); ScopedArrayObject a(scope, v4->newArrayObject()); uint len; @@ -72,7 +73,7 @@ ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData) return a.asReturnedValue(); } -ReturnedValue ArrayCtor::call(Managed *that, CallData *callData) +ReturnedValue ArrayCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } @@ -81,11 +82,11 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); ctor->defineDefaultProperty(QStringLiteral("isArray"), method_isArray, 1); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString, 0); + defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); defineDefaultProperty(QStringLiteral("concat"), method_concat, 1); defineDefaultProperty(QStringLiteral("join"), method_join, 1); @@ -110,7 +111,7 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) ReturnedValue ArrayPrototype::method_isArray(CallContext *ctx) { - bool isArray = ctx->argc() && ctx->args()[0].asArrayObject(); + bool isArray = ctx->argc() && ctx->args()[0].as<ArrayObject>(); return Encode(isArray); } @@ -185,7 +186,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) r4 = arg->toQString(); ScopedObject self(scope, ctx->thisObject()); - ScopedValue length(scope, self->get(ctx->d()->engine->id_length)); + ScopedValue length(scope, self->get(ctx->d()->engine->id_length())); const quint32 r2 = length->isUndefined() ? 0 : length->toUInt32(); if (!r2) @@ -194,7 +195,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) QString R; // ### FIXME - if (ArrayObject *a = self->asArrayObject()) { + if (ArrayObject *a = self->as<ArrayObject>()) { ScopedValue e(scope); for (uint i = 0; i < a->getLength(); ++i) { if (i) @@ -242,7 +243,7 @@ ReturnedValue ArrayPrototype::method_pop(CallContext *ctx) if (!len) { if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); return Encode::undefined(); } @@ -256,7 +257,7 @@ ReturnedValue ArrayPrototype::method_pop(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLength(len - 1); else - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); return result->asReturnedValue(); } @@ -282,7 +283,7 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx) } double newLen = l + ctx->argc(); if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); else { ScopedString str(scope, ctx->d()->engine->newString(QStringLiteral("Array.prototype.push: Overflow"))); return ctx->engine()->throwRangeError(str); @@ -303,7 +304,7 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLengthUnchecked(len); else - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len))); return Encode(len); } @@ -354,7 +355,7 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx) if (!len) { if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); return Encode::undefined(); } @@ -388,7 +389,7 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLengthUnchecked(len - 1); else - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); return result->asReturnedValue(); } @@ -523,7 +524,7 @@ ReturnedValue ArrayPrototype::method_splice(CallContext *ctx) } ctx->d()->strictMode = true; - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount))); return newArray.asReturnedValue(); } @@ -561,7 +562,7 @@ ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLengthUnchecked(newLen); else - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); return Encode(newLen); } @@ -619,7 +620,7 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) return Encode(-1); } else { Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex); - Heap::SimpleArrayData *sa = static_cast<Heap::SimpleArrayData *>(instance->d()->arrayData); + Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>(); if (len > sa->len) len = sa->len; uint idx = fromIndex; diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h index 4e67eb2e31..afd8080fa3 100644 --- a/src/qml/jsruntime/qv4arrayobject_p.h +++ b/src/qml/jsruntime/qv4arrayobject_p.h @@ -33,6 +33,17 @@ #ifndef QV4ARRAYOBJECT_H #define QV4ARRAYOBJECT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" #include <QtCore/qnumeric.h> @@ -53,8 +64,8 @@ struct ArrayCtor: FunctionObject { V4_OBJECT2(ArrayCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct ArrayPrototype: ArrayObject diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp index 9c293e783b..53f8abf3f2 100644 --- a/src/qml/jsruntime/qv4booleanobject.cpp +++ b/src/qml/jsruntime/qv4booleanobject.cpp @@ -32,6 +32,7 @@ ****************************************************************************/ #include "qv4booleanobject_p.h" +#include "qv4string_p.h" using namespace QV4; @@ -43,14 +44,14 @@ Heap::BooleanCtor::BooleanCtor(QV4::ExecutionContext *scope) { } -ReturnedValue BooleanCtor::construct(Managed *m, CallData *callData) +ReturnedValue BooleanCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<BooleanCtor *>(m)->engine()); + Scope scope(static_cast<const BooleanCtor *>(m)->engine()); bool n = callData->argc ? callData->args[0].toBoolean() : false; return Encode(scope.engine->newBooleanObject(n)); } -ReturnedValue BooleanCtor::call(Managed *, CallData *callData) +ReturnedValue BooleanCtor::call(const Managed *, CallData *callData) { bool value = callData->argc ? callData->args[0].toBoolean() : 0; return Encode(value); @@ -60,11 +61,11 @@ void BooleanPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString); - defineDefaultProperty(engine->id_valueOf, method_valueOf); + defineDefaultProperty(engine->id_toString(), method_toString); + defineDefaultProperty(engine->id_valueOf(), method_valueOf); } ReturnedValue BooleanPrototype::method_toString(CallContext *ctx) @@ -73,7 +74,7 @@ ReturnedValue BooleanPrototype::method_toString(CallContext *ctx) if (ctx->thisObject().isBoolean()) { result = ctx->thisObject().booleanValue(); } else { - BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); + const BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); if (!thisObject) return ctx->engine()->throwTypeError(); result = thisObject->value(); @@ -87,7 +88,7 @@ ReturnedValue BooleanPrototype::method_valueOf(CallContext *ctx) if (ctx->thisObject().isBoolean()) return ctx->thisObject().asReturnedValue(); - BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); + const BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); if (!thisObject) return ctx->engine()->throwTypeError(); diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h index 903261bdce..203c8ba4ea 100644 --- a/src/qml/jsruntime/qv4booleanobject_p.h +++ b/src/qml/jsruntime/qv4booleanobject_p.h @@ -33,6 +33,17 @@ #ifndef QV4BOOLEANOBJECT_H #define QV4BOOLEANOBJECT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" #include <QtCore/qnumeric.h> @@ -53,8 +64,8 @@ struct BooleanCtor: FunctionObject { V4_OBJECT2(BooleanCtor, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct BooleanPrototype: BooleanObject diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 9330f10780..007bf92639 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -36,10 +36,12 @@ #include <qv4context_p.h> #include <qv4object_p.h> #include <qv4objectproto_p.h> -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include <qv4argumentsobject_p.h> #include "qv4function_p.h" #include "qv4errorobject_p.h" +#include "qv4string_p.h" +#include "private/qqmlcontextwrapper_p.h" using namespace QV4; @@ -48,8 +50,9 @@ DEFINE_MANAGED_VTABLE(CallContext); DEFINE_MANAGED_VTABLE(WithContext); DEFINE_MANAGED_VTABLE(CatchContext); DEFINE_MANAGED_VTABLE(GlobalContext); +DEFINE_MANAGED_VTABLE(QmlContext); -Heap::CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData) +Heap::CallContext *ExecutionContext::newCallContext(const FunctionObject *function, CallData *callData) { Q_ASSERT(function->function()); @@ -80,39 +83,64 @@ Heap::CallContext *ExecutionContext::newCallContext(FunctionObject *function, Ca 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::CallContext *ExecutionContext::newQmlContext(FunctionObject *f, Object *qml) +Heap::QmlContext *ExecutionContext::newQmlContext(QmlContextWrapper *qml) { - Scope scope(this); - Scoped<CallContext> c(scope, d()->engine->memoryManager->allocManaged<CallContext>(requiredMemoryForExecutionContect(f, 0))); - new (c->d()) Heap::CallContext(d()->engine, qml, f); - return c->d(); + 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) { Scope scope(this); // find the right context to create the binding on - ScopedObject activation(scope, d()->engine->globalObject()); + ScopedObject activation(scope); ScopedContext ctx(scope, this); while (ctx) { - if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - if (!c->activation) - c->activation = scope.engine->newObject(); - activation = c->activation; + if (!activation) { + if (!c->activation) + c->activation = scope.engine->newObject(); + activation = c->activation; + } + break; + } + case Heap::ExecutionContext::Type_QmlContext: { + // this is ugly, as it overrides the inner callcontext, but has to stay as long + // as bindings still get their own callcontext + Heap::QmlContext *qml = static_cast<Heap::QmlContext *>(ctx->d()); + activation = qml->qml; + break; + } + case Heap::ExecutionContext::Type_GlobalContext: { + if (!activation) + activation = scope.engine->globalObject; + break; + } + default: break; } ctx = ctx->d()->outer; @@ -130,57 +158,46 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) Heap::GlobalContext::GlobalContext(ExecutionEngine *eng) : Heap::ExecutionContext(eng, Heap::ExecutionContext::Type_GlobalContext) { - global = eng->globalObject()->d(); + 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; this->exceptionValue = exceptionValue; } -Heap::CallContext::CallContext(ExecutionEngine *engine, QV4::Object *qml, QV4::FunctionObject *function) - : Heap::ExecutionContext(engine, Heap::ExecutionContext::Type_QmlContext) +Heap::QmlContext::QmlContext(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml) + : Heap::ExecutionContext(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext) { - this->function = function->d(); - callData = reinterpret_cast<CallData *>(this + 1); - callData->tag = QV4::Value::_Integer_Type; - callData->argc = 0; - callData->thisObject = Primitive::undefinedValue(); - + outer = outerContext->d(); strictMode = false; - outer = function->scope(); + callData = outer->callData; + lookups = outer->lookups; + compilationUnit = outer->compilationUnit; - activation = qml->d(); - - if (function->function()) { - compilationUnit = function->function()->compilationUnit; - lookups = compilationUnit->runtimeLookups; - } - - locals = (Value *)(this + 1); - if (function->varCount()) - std::fill(locals, locals + function->varCount(), Primitive::undefinedValue()); + this->qml = qml->d(); } + Identifier * const *CallContext::formals() const { return (d()->function && d()->function->function) ? d()->function->function->internalClass->nameMap.constData() : 0; @@ -209,16 +226,28 @@ bool ExecutionContext::deleteProperty(String *name) bool hasWith = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { - if (ctx->d()->type == Heap::ExecutionContext::Type_WithContext) { + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CatchContext: { + Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); + if (c->exceptionVarName->isEqualTo(name->d())) + return false; + break; + } + case Heap::ExecutionContext::Type_WithContext: { hasWith = true; ScopedObject withObject(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); if (withObject->hasProperty(name)) return withObject->deleteProperty(name); - } else if (ctx->d()->type == Heap::ExecutionContext::Type_CatchContext) { - Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); - if (c->exceptionVarName->isEqualTo(name)) - return false; - } else if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { + break; + } + case Heap::ExecutionContext::Type_GlobalContext: { + ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + if (global->hasProperty(name)) + return global->deleteProperty(name); + break; + } + case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); ScopedFunctionObject f(scope, c->function); if (f->needsActivation() || hasWith) { @@ -227,13 +256,14 @@ bool ExecutionContext::deleteProperty(String *name) // ### throw in strict mode? return false; } - ScopedObject activation(scope, c->activation); - if (activation && activation->hasProperty(name)) - return activation->deleteProperty(name); - } else if (ctx->d()->type == Heap::ExecutionContext::Type_GlobalContext) { - ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); - if (global->hasProperty(name)) - return global->deleteProperty(name); + ScopedObject qml(scope, c->activation); + if (qml && qml->hasProperty(name)) + return qml->deleteProperty(name); + break; + } + case Heap::ExecutionContext::Type_QmlContext: + // can't delete properties on qml objects + break; } } @@ -254,7 +284,27 @@ void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) if (ctx->outer) ctx->outer->mark(engine); - if (ctx->type >= Heap::ExecutionContext::Type_CallContext) { + switch (ctx->type) { + case Heap::ExecutionContext::Type_CatchContext: { + CatchContext::Data *c = static_cast<CatchContext::Data *>(ctx); + c->exceptionVarName->mark(engine); + c->exceptionValue.mark(engine); + break; + } + case Heap::ExecutionContext::Type_WithContext: { + WithContext::Data *w = static_cast<WithContext::Data *>(ctx); + if (w->withObject) + w->withObject->mark(engine); + break; + } + case Heap::ExecutionContext::Type_GlobalContext: { + GlobalContext::Data *g = static_cast<GlobalContext::Data *>(ctx); + g->global->mark(engine); + break; + } + case Heap::ExecutionContext::Type_SimpleCallContext: + break; + case Heap::ExecutionContext::Type_CallContext: { QV4::Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx); ctx->callData->thisObject.mark(engine); for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->function->formalParameterCount()); ++arg) @@ -264,17 +314,13 @@ void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) if (c->activation) c->activation->mark(engine); c->function->mark(engine); - } else if (ctx->type == Heap::ExecutionContext::Type_WithContext) { - WithContext::Data *w = static_cast<WithContext::Data *>(ctx); - if (w->withObject) - w->withObject->mark(engine); - } else if (ctx->type == Heap::ExecutionContext::Type_CatchContext) { - CatchContext::Data *c = static_cast<CatchContext::Data *>(ctx); - c->exceptionVarName->mark(engine); - c->exceptionValue.mark(engine); - } else if (ctx->type == Heap::ExecutionContext::Type_GlobalContext) { - GlobalContext::Data *g = static_cast<GlobalContext::Data *>(ctx); - g->global->mark(engine); + break; + } + case Heap::ExecutionContext::Type_QmlContext: { + QmlContext::Data *g = static_cast<QmlContext::Data *>(ctx); + g->qml->mark(engine); + break; + } } } @@ -282,57 +328,71 @@ void ExecutionContext::setProperty(String *name, const Value &value) { Scope scope(this); ScopedContext ctx(scope, this); + ScopedObject activation(scope); + for (; ctx; ctx = ctx->d()->outer) { - if (ctx->d()->type == Heap::ExecutionContext::Type_WithContext) { + activation = (Object *)0; + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CatchContext: { + Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); + if (c->exceptionVarName->isEqualTo(name->d())) { + c->exceptionValue = value; + return; + } + break; + } + case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); if (w->hasProperty(name)) { w->put(name, value); return; } - } else if (ctx->d()->type == Heap::ExecutionContext::Type_CatchContext && static_cast<Heap::CatchContext *>(ctx->d())->exceptionVarName->isEqualTo(name)) { - static_cast<Heap::CatchContext *>(ctx->d())->exceptionValue = value; - return; - } else { - ScopedObject activation(scope, (Object *)0); - if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { - Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - if (c->function->function) { - uint index = c->function->function->internalClass->find(name); - if (index < UINT_MAX) { - if (index < c->function->formalParameterCount()) { - c->callData->args[c->function->formalParameterCount() - index - 1] = value; - } else { - index -= c->function->formalParameterCount(); - c->locals[index] = value; - } - return; + break; + } + case Heap::ExecutionContext::Type_GlobalContext: { + activation = static_cast<Heap::GlobalContext *>(ctx->d())->global; + break; + } + case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_SimpleCallContext: { + Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); + if (c->function->function) { + uint index = c->function->function->internalClass->find(name); + if (index < UINT_MAX) { + if (index < c->function->formalParameterCount()) { + c->callData->args[c->function->formalParameterCount() - index - 1] = value; + } else { + index -= c->function->formalParameterCount(); + c->locals[index] = value; } + return; } - activation = c->activation; - } else if (ctx->d()->type == Heap::ExecutionContext::Type_GlobalContext) { - activation = static_cast<Heap::GlobalContext *>(ctx->d())->global; } + activation = c->activation; + break; + } + case Heap::ExecutionContext::Type_QmlContext: { + activation = static_cast<Heap::QmlContext *>(ctx->d())->qml; + activation->put(name, value); + return; + } + } - if (activation) { - if (ctx->d()->type == Heap::ExecutionContext::Type_QmlContext) { - activation->put(name, value); - return; - } else { - uint member = activation->internalClass()->find(name); - if (member < UINT_MAX) { - activation->putValue(activation->propertyAt(member), activation->internalClass()->propertyData[member], value); - return; - } - } + if (activation) { + uint member = activation->internalClass()->find(name); + if (member < UINT_MAX) { + activation->putValue(member, value); + return; } } } - if (d()->strictMode || name->equals(d()->engine->id_this)) { + + if (d()->strictMode || name->equals(d()->engine->id_this())) { ScopedValue n(scope, name->asReturnedValue()); engine()->throwReferenceError(n); return; } - d()->engine->globalObject()->put(name, value); + d()->engine->globalObject->put(name, value); } ReturnedValue ExecutionContext::getProperty(String *name) @@ -341,14 +401,22 @@ ReturnedValue ExecutionContext::getProperty(String *name) ScopedValue v(scope); name->makeIdentifier(scope.engine); - if (name->equals(d()->engine->id_this)) + if (name->equals(d()->engine->id_this())) return thisObject().asReturnedValue(); bool hasWith = false; bool hasCatchScope = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { - if (ctx->d()->type == Heap::ExecutionContext::Type_WithContext) { + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CatchContext: { + hasCatchScope = true; + Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); + if (c->exceptionVarName->isEqualTo(name->d())) + return c->exceptionValue.asReturnedValue(); + break; + } + case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); hasWith = true; bool hasProperty = false; @@ -356,17 +424,18 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (hasProperty) { return v->asReturnedValue(); } - continue; + break; } - - else if (ctx->d()->type == Heap::ExecutionContext::Type_CatchContext) { - hasCatchScope = true; - Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); - if (c->exceptionVarName->isEqualTo(name)) - return c->exceptionValue.asReturnedValue(); + case Heap::ExecutionContext::Type_GlobalContext: { + ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + bool hasProperty = false; + v = global->get(name, &hasProperty); + if (hasProperty) + return v->asReturnedValue(); + break; } - - else if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { + case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); ScopedFunctionObject f(scope, c->function); if (f->function() && (f->needsActivation() || hasWith || hasCatchScope)) { @@ -387,85 +456,97 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (f->function() && f->function()->isNamedExpression() && name->equals(ScopedString(scope, f->function()->name()))) return f.asReturnedValue(); + break; } - - else if (ctx->d()->type == Heap::ExecutionContext::Type_GlobalContext) { - ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + case Heap::ExecutionContext::Type_QmlContext: { + ScopedObject qml(scope, static_cast<Heap::QmlContext *>(ctx->d())->qml); bool hasProperty = false; - v = global->get(name, &hasProperty); + v = qml->get(name, &hasProperty); if (hasProperty) return v->asReturnedValue(); + break; + } } } ScopedValue n(scope, name); return engine()->throwReferenceError(n); } -ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Heap::Object **base) +ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) { Scope scope(this); ScopedValue v(scope); - *base = (Heap::Object *)0; + base->setM(0); name->makeIdentifier(scope.engine); - if (name->equals(d()->engine->id_this)) + if (name->equals(d()->engine->id_this())) return thisObject().asReturnedValue(); bool hasWith = false; bool hasCatchScope = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { - if (ctx->d()->type == Heap::ExecutionContext::Type_WithContext) { + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CatchContext: { + hasCatchScope = true; + Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); + if (c->exceptionVarName->isEqualTo(name->d())) + return c->exceptionValue.asReturnedValue(); + break; + } + case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); hasWith = true; bool hasProperty = false; v = w->get(name, &hasProperty); if (hasProperty) { - *base = w->d(); + base->setM(w->d()); return v->asReturnedValue(); } - continue; + break; } - - else if (ctx->d()->type == Heap::ExecutionContext::Type_CatchContext) { - hasCatchScope = true; - Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); - if (c->exceptionVarName->isEqualTo(name)) - return c->exceptionValue.asReturnedValue(); + case Heap::ExecutionContext::Type_GlobalContext: { + ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + bool hasProperty = false; + v = global->get(name, &hasProperty); + if (hasProperty) + return v->asReturnedValue(); + break; } - - else if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { + case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); ScopedFunctionObject f(scope, c->function); if (f->function() && (f->needsActivation() || hasWith || hasCatchScope)) { uint index = f->function()->internalClass->find(name); if (index < UINT_MAX) { - if (index < f->formalParameterCount()) - return c->callData->args[f->formalParameterCount() - index - 1].asReturnedValue(); - return c->locals[index - f->formalParameterCount()].asReturnedValue(); + if (index < c->function->formalParameterCount()) + return c->callData->args[c->function->formalParameterCount() - index - 1].asReturnedValue(); + return c->locals[index - c->function->formalParameterCount()].asReturnedValue(); } } ScopedObject activation(scope, c->activation); if (activation) { bool hasProperty = false; v = activation->get(name, &hasProperty); - if (hasProperty) { - if (ctx->d()->type == Heap::ExecutionContext::Type_QmlContext) - *base = activation->d(); + if (hasProperty) return v->asReturnedValue(); - } } if (f->function() && f->function()->isNamedExpression() && name->equals(ScopedString(scope, f->function()->name()))) - return c->function->asReturnedValue(); + return f.asReturnedValue(); + break; } - - else if (ctx->d()->type == Heap::ExecutionContext::Type_GlobalContext) { - ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + case Heap::ExecutionContext::Type_QmlContext: { + ScopedObject qml(scope, static_cast<Heap::QmlContext *>(ctx->d())->qml); bool hasProperty = false; - v = global->get(name, &hasProperty); - if (hasProperty) + v = qml->get(name, &hasProperty); + if (hasProperty) { + base->setM(qml->d()); return v->asReturnedValue(); + } + break; + } } } ScopedValue n(scope, name); @@ -476,7 +557,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()) @@ -487,3 +568,19 @@ Heap::FunctionObject *ExecutionContext::getFunctionObject() const return 0; } + + +QObject *QmlContext::qmlScope() const +{ + return d()->qml->scopeObject; +} + +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 8392dd836d..6c360e7dda 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -33,11 +33,25 @@ #ifndef QMLJS_ENVIRONMENT_H #define QMLJS_ENVIRONMENT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include "qv4managed_p.h" QT_BEGIN_NAMESPACE +class QQmlContextData; +class QObject; + namespace QV4 { namespace CompiledData { @@ -45,6 +59,8 @@ struct CompilationUnit; struct Function; } +struct QmlContextWrapper; +struct Identifier; struct CallContext; struct CatchContext; struct WithContext; @@ -74,9 +90,9 @@ struct ExecutionContext : Base { Type_GlobalContext = 0x1, Type_CatchContext = 0x2, Type_WithContext = 0x3, - Type_SimpleCallContext = 0x4, - Type_CallContext = 0x5, - Type_QmlContext = 0x6 + Type_QmlContext = 0x4, + Type_SimpleCallContext = 0x5, + Type_CallContext = 0x6 }; inline ExecutionContext(ExecutionEngine *engine, ContextType t); @@ -84,8 +100,7 @@ struct ExecutionContext : Base { CallData *callData; ExecutionEngine *engine; - ExecutionContext *parent; - ExecutionContext *outer; + Pointer<ExecutionContext> outer; Lookup *lookups; CompiledData::CompilationUnit *compilationUnit; @@ -94,6 +109,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) @@ -102,29 +129,34 @@ struct CallContext : ExecutionContext { locals = 0; activation = 0; } - CallContext(ExecutionEngine *engine, QV4::Object *qml, QV4::FunctionObject *function); - FunctionObject *function; + Pointer<FunctionObject> function; Value *locals; - Object *activation; + Pointer<Object> activation; }; struct GlobalContext : ExecutionContext { GlobalContext(ExecutionEngine *engine); - Object *global; + Pointer<Object> global; }; struct CatchContext : ExecutionContext { - CatchContext(ExecutionEngine *engine, QV4::String *exceptionVarName, const Value &exceptionValue); - StringValue exceptionVarName; + CatchContext(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue); + Pointer<String> exceptionVarName; Value exceptionValue; }; struct WithContext : ExecutionContext { - WithContext(ExecutionEngine *engine, QV4::Object *with); - Object *withObject; + WithContext(ExecutionContext *outerContext, Object *with); + Pointer<Object> withObject; }; +struct QmlContextWrapper; + +struct QmlContext : ExecutionContext { + QmlContext(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml); + Pointer<QmlContextWrapper> qml; +}; } @@ -139,16 +171,17 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ExecutionEngine *engine() const { return d()->engine; } - Heap::CallContext *newCallContext(FunctionObject *f, CallData *callData); - Heap::WithContext *newWithContext(Object *with); - Heap::CatchContext *newCatchContext(String *exceptionVarName, const Value &exceptionValue); - Heap::CallContext *newQmlContext(FunctionObject *f, Object *qml); + Heap::CallContext *newCallContext(const FunctionObject *f, CallData *callData); + 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); void setProperty(String *name, const Value &value); ReturnedValue getProperty(String *name); - ReturnedValue getPropertyAndBase(String *name, Heap::Object **base); + ReturnedValue getPropertyAndBase(String *name, Value *base); bool deleteProperty(String *name); inline CallContext *asCallContext(); @@ -160,7 +193,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed static void markObjects(Heap::Base *m, ExecutionEngine *e); - const Value &thisObject() const { + Value &thisObject() const { return d()->callData->thisObject; } int argc() const { @@ -174,7 +207,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed } }; -struct CallContext : public ExecutionContext +struct Q_QML_EXPORT CallContext : public ExecutionContext { V4_MANAGED(CallContext, ExecutionContext) @@ -208,6 +241,16 @@ struct WithContext : public ExecutionContext V4_MANAGED(WithContext, ExecutionContext) }; +struct QmlContext : public ExecutionContext +{ + V4_MANAGED(QmlContext, ExecutionContext) + + QObject *qmlScope() const; + QQmlContextData *qmlContext() const; + + void takeContextOwnership(); +}; + inline CallContext *ExecutionContext::asCallContext() { return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0; diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp index 8a66c2cbfc..8901834e76 100644 --- a/src/qml/jsruntime/qv4dataview.cpp +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -33,6 +33,7 @@ #include "qv4dataview_p.h" #include "qv4arraybuffer_p.h" +#include "qv4string_p.h" #include "qendian.h" @@ -46,9 +47,9 @@ Heap::DataViewCtor::DataViewCtor(QV4::ExecutionContext *scope) { } -ReturnedValue DataViewCtor::construct(Managed *m, CallData *callData) +ReturnedValue DataViewCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<Object *>(m)->engine()); + Scope scope(static_cast<const Object *>(m)->engine()); Scoped<ArrayBuffer> buffer(scope, callData->argument(0)); if (!buffer) return scope.engine->throwTypeError(); @@ -61,7 +62,7 @@ ReturnedValue DataViewCtor::construct(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; @@ -69,21 +70,12 @@ ReturnedValue DataViewCtor::construct(Managed *m, CallData *callData) } -ReturnedValue DataViewCtor::call(Managed *that, CallData *callData) +ReturnedValue DataViewCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } -Heap::DataView::DataView(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->dataViewPrototype.asObject()), - buffer(0), - byteLength(0), - byteOffset(0) -{ -} - - void DataView::markObjects(Heap::Base *that, ExecutionEngine *e) { DataView::Data *v = static_cast<DataView::Data *>(that); @@ -94,30 +86,38 @@ void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(3)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - defineDefaultProperty(engine->id_constructor, (o = ctor)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(3)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + defineDefaultProperty(engine->id_constructor(), (o = ctor)); defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0); defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); 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 3f0c1e9e23..26347766d3 100644 --- a/src/qml/jsruntime/qv4dataview_p.h +++ b/src/qml/jsruntime/qv4dataview_p.h @@ -33,6 +33,17 @@ #ifndef QV4DATAVIEW_H #define QV4DATAVIEW_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" @@ -47,8 +58,8 @@ struct DataViewCtor : FunctionObject { }; struct DataView : Object { - DataView(ExecutionEngine *e); - ArrayBuffer *buffer; + DataView() {} + Pointer<ArrayBuffer> buffer; uint byteLength; uint byteOffset; }; @@ -59,13 +70,14 @@ struct DataViewCtor: FunctionObject { V4_OBJECT2(DataViewCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; 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 451ef2486d..a6e1f47d91 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -36,6 +36,7 @@ #include "qv4objectproto_p.h" #include "qv4scopedvalue_p.h" #include "qv4runtime_p.h" +#include "qv4string_p.h" #include <QtCore/QDebug> #include <QtCore/QDateTime> @@ -627,15 +628,14 @@ static double getLocalTZA() DEFINE_OBJECT_VTABLE(DateObject); -Heap::DateObject::DateObject(QV4::ExecutionEngine *engine, const QDateTime &date) - : Heap::Object(engine->emptyClass, engine->datePrototype.asObject()) +Heap::DateObject::DateObject(const QDateTime &date) { - value.setDouble(date.isValid() ? date.toMSecsSinceEpoch() : qSNaN()); + this->date = date.isValid() ? date.toMSecsSinceEpoch() : qSNaN(); } QDateTime DateObject::toQDateTime() const { - return ToDateTime(date().asDouble(), Qt::LocalTime); + return ToDateTime(date(), Qt::LocalTime); } DEFINE_OBJECT_VTABLE(DateCtor); @@ -645,9 +645,9 @@ Heap::DateCtor::DateCtor(QV4::ExecutionContext *scope) { } -ReturnedValue DateCtor::construct(Managed *m, CallData *callData) +ReturnedValue DateCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<DateCtor *>(m)->engine()); + Scope scope(static_cast<const DateCtor *>(m)->engine()); double t = 0; if (callData->argc == 0) @@ -655,15 +655,16 @@ ReturnedValue DateCtor::construct(Managed *m, CallData *callData) else if (callData->argc == 1) { ScopedValue arg(scope, callData->args[0]); - if (DateObject *d = arg->asDateObject()) - arg = d->date(); - else + if (DateObject *d = arg->as<DateObject>()) { + t = d->date(); + } else { arg = RuntimeHelpers::toPrimitive(arg, PREFERREDTYPE_HINT); - if (arg->isString()) - t = ParseString(arg->stringValue()->toQString()); - else - t = TimeClip(arg->toNumber()); + if (arg->isString()) + t = ParseString(arg->stringValue()->toQString()); + else + t = TimeClip(arg->toNumber()); + } } else { // d.argc > 1 @@ -683,18 +684,18 @@ ReturnedValue DateCtor::construct(Managed *m, CallData *callData) return Encode(scope.engine->newDateObject(Primitive::fromDouble(t))); } -ReturnedValue DateCtor::call(Managed *m, CallData *) +ReturnedValue DateCtor::call(const Managed *m, CallData *) { double t = currentTime(); - return static_cast<DateCtor *>(m)->engine()->newString(ToString(t))->asReturnedValue(); + return static_cast<const DateCtor *>(m)->engine()->newString(ToString(t))->asReturnedValue(); } void DatePrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(7)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(7)); LocalTZA = getLocalTZA(); ctor->defineDefaultProperty(QStringLiteral("parse"), method_parse, 1); @@ -702,13 +703,13 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor) ctor->defineDefaultProperty(QStringLiteral("now"), method_now, 0); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString, 0); + defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("toDateString"), method_toDateString, 0); defineDefaultProperty(QStringLiteral("toTimeString"), method_toTimeString, 0); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); defineDefaultProperty(QStringLiteral("toLocaleDateString"), method_toLocaleDateString, 0); defineDefaultProperty(QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString, 0); - defineDefaultProperty(engine->id_valueOf, method_valueOf, 0); + defineDefaultProperty(engine->id_valueOf(), method_valueOf, 0); defineDefaultProperty(QStringLiteral("getTime"), method_getTime, 0); defineDefaultProperty(QStringLiteral("getYear"), method_getYear, 0); defineDefaultProperty(QStringLiteral("getFullYear"), method_getFullYear, 0); @@ -752,8 +753,8 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor) double DatePrototype::getThisDate(ExecutionContext *ctx) { - if (DateObject *thisObject = ctx->thisObject().asDateObject()) - return thisObject->date().asDouble(); + if (DateObject *thisObject = ctx->thisObject().as<DateObject>()) + return thisObject->date(); else { ctx->engine()->throwTypeError(); return 0; @@ -994,8 +995,8 @@ ReturnedValue DatePrototype::method_setTime(CallContext *ctx) return ctx->engine()->throwTypeError(); double t = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); - self->date().setDouble(TimeClip(t)); - return self->date().asReturnedValue(); + self->setDate(TimeClip(t)); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx) @@ -1005,175 +1006,175 @@ ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx) if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double ms = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); - self->date().setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); - return self->date().asReturnedValue(); + self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCMilliseconds(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double ms = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); - self->date().setDouble(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))); - return self->date().asReturnedValue(); + self->setDate(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setSeconds(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double sec = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double ms = (ctx->argc() < 2) ? msFromTime(t) : ctx->args()[1].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCSeconds(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double sec = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double ms = (ctx->argc() < 2) ? msFromTime(t) : ctx->args()[1].toNumber(); t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setMinutes(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double min = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double sec = (ctx->argc() < 2) ? SecFromTime(t) : ctx->args()[1].toNumber(); double ms = (ctx->argc() < 3) ? msFromTime(t) : ctx->args()[2].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCMinutes(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double min = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double sec = (ctx->argc() < 2) ? SecFromTime(t) : ctx->args()[1].toNumber(); double ms = (ctx->argc() < 3) ? msFromTime(t) : ctx->args()[2].toNumber(); t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setHours(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double hour = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double min = (ctx->argc() < 2) ? MinFromTime(t) : ctx->args()[1].toNumber(); double sec = (ctx->argc() < 3) ? SecFromTime(t) : ctx->args()[2].toNumber(); double ms = (ctx->argc() < 4) ? msFromTime(t) : ctx->args()[3].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCHours(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double hour = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double min = (ctx->argc() < 2) ? MinFromTime(t) : ctx->args()[1].toNumber(); double sec = (ctx->argc() < 3) ? SecFromTime(t) : ctx->args()[2].toNumber(); double ms = (ctx->argc() < 4) ? msFromTime(t) : ctx->args()[3].toNumber(); t = TimeClip(MakeDate(Day(t), MakeTime(hour, min, sec, ms))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setDate(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double date = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCDate(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double date = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setMonth(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double month = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double date = (ctx->argc() < 2) ? DateFromTime(t) : ctx->args()[1].toNumber(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCMonth(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double month = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double date = (ctx->argc() < 2) ? DateFromTime(t) : ctx->args()[1].toNumber(); t = TimeClip(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setYear(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); if (std::isnan(t)) t = 0; else @@ -1189,49 +1190,49 @@ ReturnedValue DatePrototype::method_setYear(CallContext *ctx) r = UTC(MakeDate(r, TimeWithinDay(t))); r = TimeClip(r); } - self->date().setDouble(r); - return self->date().asReturnedValue(); + self->setDate(r); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCFullYear(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double year = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double month = (ctx->argc() < 2) ? MonthFromTime(t) : ctx->args()[1].toNumber(); double date = (ctx->argc() < 3) ? DateFromTime(t) : ctx->args()[2].toNumber(); t = TimeClip(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setFullYear(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); if (std::isnan(t)) t = 0; double year = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double month = (ctx->argc() < 2) ? MonthFromTime(t) : ctx->args()[1].toNumber(); double date = (ctx->argc() < 3) ? DateFromTime(t) : ctx->args()[2].toNumber(); t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_toUTCString(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); return ctx->d()->engine->newString(ToUTCString(t))->asReturnedValue(); } @@ -1250,11 +1251,11 @@ static void addZeroPrefixedInt(QString &str, int num, int nDigits) ReturnedValue DatePrototype::method_toISOString(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); if (!std::isfinite(t)) return ctx->engine()->throwRangeError(ctx->thisObject()); @@ -1297,7 +1298,7 @@ ReturnedValue DatePrototype::method_toJSON(CallContext *ctx) ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toISOString"))); ScopedValue v(scope, O->objectValue()->get(s)); - FunctionObject *toIso = v->asFunctionObject(); + FunctionObject *toIso = v->as<FunctionObject>(); if (!toIso) return ctx->engine()->throwTypeError(); diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index dad3689054..2eaa837666 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -33,6 +33,17 @@ #ifndef QV4DATEOBJECT_P_H #define QV4DATEOBJECT_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" #include <QtCore/qnumeric.h> @@ -46,21 +57,20 @@ namespace QV4 { namespace Heap { struct DateObject : Object { - DateObject(InternalClass *ic, QV4::Object *prototype) - : Object(ic, prototype) + DateObject() { - value = Encode(qSNaN()); + date = qSNaN(); } - DateObject(QV4::ExecutionEngine *engine, const Value &date) - : Object(engine->emptyClass, engine->datePrototype.asObject()) + DateObject(const Value &date) { - value = date; + this->date = date.toNumber(); } - DateObject(QV4::ExecutionEngine *engine, const QDateTime &date); - Value value; + DateObject(const QDateTime &date); + double date; }; + struct DateCtor : FunctionObject { DateCtor(QV4::ExecutionContext *scope); }; @@ -70,21 +80,26 @@ struct DateCtor : FunctionObject { struct DateObject: Object { V4_OBJECT2(DateObject, Object) Q_MANAGED_TYPE(DateObject) + V4_PROTOTYPE(datePrototype) - Value date() const { return d()->value; } - Value &date() { return d()->value; } - void setDate(const Value &date) { d()->value = date; } + double date() const { return d()->date; } + void setDate(double date) { d()->date = date; } QDateTime toQDateTime() const; }; +template<> +inline const DateObject *Value::as() const { + return isManaged() && m() && m()->vtable()->type == Managed::Type_DateObject ? static_cast<const DateObject *>(this) : 0; +} + struct DateCtor: FunctionObject { V4_OBJECT2(DateCtor, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *); }; struct DatePrototype: DateObject diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index 36e7a3558c..7706a40da6 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -38,69 +38,72 @@ #include "qv4instr_moth_p.h" #include "qv4runtime_p.h" #include "qv4script_p.h" -#include "qv4objectiterator_p.h" #include "qv4identifier_p.h" -#include <iostream> +#include "qv4string_p.h" +#include "qv4objectiterator_p.h" +#include <iostream> #include <algorithm> +#include <QtCore/QJsonArray> +#include <QtCore/QJsonDocument> +#include <QtCore/QJsonValue> + +QT_BEGIN_NAMESPACE + using namespace QV4; using namespace QV4::Debugging; -namespace { -class JavaScriptJob: public Debugger::Job -{ - QV4::ExecutionEngine *engine; - int frameNr; - const QString &script; +V4Debugger::JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, + const QString &script) + : engine(engine) + , frameNr(frameNr) + , script(script) + , resultIsException(false) +{} -public: - JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script) - : engine(engine) - , frameNr(frameNr) - , script(script) - {} - - void run() - { - Scope scope(engine); +void V4Debugger::JavaScriptJob::run() +{ + Scope scope(engine); - ExecutionContextSaver saver(scope, engine->currentContext()); + ExecutionContextSaver saver(scope); - if (frameNr > 0) { - Value *savedContexts = scope.alloc(frameNr); - for (int i = 0; i < frameNr; ++i) { - savedContexts[i] = engine->currentContext(); - engine->popContext(); - } + ExecutionContext *ctx = engine->currentContext; + if (frameNr > 0) { + for (int i = 0; i < frameNr; ++i) { + 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 - // is a side-effect of inheritContext. - script.inheritContext = true; - script.parse(); - QV4::ScopedValue result(scope); - if (!scope.engine->hasException) - result = script.run(); - if (scope.engine->hasException) - result = scope.engine->catchException(); - handleResult(result); + 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 + // is a side-effect of inheritContext. + script.inheritContext = true; + script.parse(); + QV4::ScopedValue result(scope); + if (!scope.engine->hasException) + result = script.run(); + if (scope.engine->hasException) { + result = scope.engine->catchException(); + resultIsException = true; } + handleResult(result); +} -protected: - virtual void handleResult(QV4::ScopedValue &result) = 0; -}; +bool V4Debugger::JavaScriptJob::hasExeption() const +{ + return resultIsException; +} -class EvalJob: public JavaScriptJob +class EvalJob: public V4Debugger::JavaScriptJob { bool result; public: EvalJob(QV4::ExecutionEngine *engine, const QString &script) - : JavaScriptJob(engine, /*frameNr*/-1, script) + : V4Debugger::JavaScriptJob(engine, /*frameNr*/-1, script) , result(false) {} @@ -115,58 +118,8 @@ public: } }; -class ExpressionEvalJob: public JavaScriptJob -{ - Debugger::Collector *collector; - -public: - ExpressionEvalJob(ExecutionEngine *engine, int frameNr, const QString &expression, Debugger::Collector *collector) - : JavaScriptJob(engine, frameNr, expression) - , collector(collector) - { - } - - virtual void handleResult(QV4::ScopedValue &result) - { - collector->collect(QStringLiteral("body"), result); - } -}; - -class GatherSourcesJob: public Debugger::Job -{ - QV4::ExecutionEngine *engine; - const int seq; - -public: - GatherSourcesJob(QV4::ExecutionEngine *engine, int seq) - : engine(engine) - , seq(seq) - {} - - ~GatherSourcesJob() {} - - void run() - { - QStringList sources; - - foreach (QV4::CompiledData::CompilationUnit *unit, engine->compilationUnits) { - QString fileName = unit->fileName(); - if (!fileName.isEmpty()) - sources.append(fileName); - } - - Debugger *debugger = engine->debugger; - QMetaObject::invokeMethod(debugger->agent(), "sourcesCollected", Qt::QueuedConnection, - Q_ARG(QV4::Debugging::Debugger*, debugger), - Q_ARG(QStringList, sources), - Q_ARG(int, seq)); - } -}; -} - -Debugger::Debugger(QV4::ExecutionEngine *engine) +V4Debugger::V4Debugger(QV4::ExecutionEngine *engine) : m_engine(engine) - , m_agent(0) , m_state(Running) , m_stepping(NotStepping) , m_pauseRequested(false) @@ -176,46 +129,11 @@ Debugger::Debugger(QV4::ExecutionEngine *engine) , m_gatherSources(0) , m_runningJob(0) { - qMetaTypeId<Debugger*>(); + qMetaTypeId<V4Debugger*>(); qMetaTypeId<PauseReason>(); } -Debugger::~Debugger() -{ - detachFromAgent(); -} - -void Debugger::attachToAgent(DebuggerAgent *agent) -{ - Q_ASSERT(!m_agent); - m_agent = agent; -} - -void Debugger::detachFromAgent() -{ - DebuggerAgent *agent = 0; - { - QMutexLocker locker(&m_lock); - agent = m_agent; - m_agent = 0; - } - if (agent) - agent->removeDebugger(this); -} - -void Debugger::gatherSources(int requestSequenceNr) -{ - QMutexLocker locker(&m_lock); - - m_gatherSources = new GatherSourcesJob(m_engine, requestSequenceNr); - if (m_state == Paused) { - runInEngine_havingLock(m_gatherSources); - delete m_gatherSources; - m_gatherSources = 0; - } -} - -void Debugger::pause() +void V4Debugger::pause() { QMutexLocker locker(&m_lock); if (m_state == Paused) @@ -223,7 +141,7 @@ void Debugger::pause() m_pauseRequested = true; } -void Debugger::resume(Speed speed) +void V4Debugger::resume(Speed speed) { QMutexLocker locker(&m_lock); if (m_state != Paused) @@ -232,292 +150,47 @@ 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(); } -void Debugger::addBreakPoint(const QString &fileName, int lineNumber, const QString &condition) +void V4Debugger::addBreakPoint(const QString &fileName, int lineNumber, const QString &condition) { QMutexLocker locker(&m_lock); m_breakPoints.insert(DebuggerBreakPoint(fileName.mid(fileName.lastIndexOf('/') + 1), lineNumber), condition); m_haveBreakPoints = true; } -void Debugger::removeBreakPoint(const QString &fileName, int lineNumber) +void V4Debugger::removeBreakPoint(const QString &fileName, int lineNumber) { QMutexLocker locker(&m_lock); m_breakPoints.remove(DebuggerBreakPoint(fileName.mid(fileName.lastIndexOf('/') + 1), lineNumber)); m_haveBreakPoints = !m_breakPoints.isEmpty(); } -void Debugger::setBreakOnThrow(bool onoff) +void V4Debugger::setBreakOnThrow(bool onoff) { QMutexLocker locker(&m_lock); m_breakOnThrow = onoff; } -Debugger::ExecutionState Debugger::currentExecutionState() const +V4Debugger::ExecutionState V4Debugger::currentExecutionState() const { ExecutionState state; state.fileName = getFunction()->sourceFile(); - state.lineNumber = engine()->currentContext()->lineNumber; + state.lineNumber = engine()->current->lineNumber; return state; } -QVector<StackFrame> Debugger::stackTrace(int frameLimit) const +QVector<StackFrame> V4Debugger::stackTrace(int frameLimit) const { return m_engine->stackTrace(frameLimit); } -static inline Heap::CallContext *findContext(Heap::ExecutionContext *ctxt, int frame) -{ - if (!ctxt) - return 0; - - Scope scope(ctxt->engine); - ScopedContext ctx(scope, ctxt); - while (ctx) { - CallContext *cCtxt = ctx->asCallContext(); - if (cCtxt && cCtxt->d()->function) { - if (frame < 1) - return cCtxt->d(); - --frame; - } - ctx = ctx->d()->parent; - } - - return 0; -} - -static inline Heap::CallContext *findScope(Heap::ExecutionContext *ctxt, int scope) -{ - if (!ctxt) - return 0; - - Scope s(ctxt->engine); - ScopedContext ctx(s, ctxt); - for (; scope > 0 && ctx; --scope) - ctx = ctx->d()->outer; - - return (ctx && ctx->d()) ? ctx->asCallContext()->d() : 0; -} - -void Debugger::collectArgumentsInContext(Collector *collector, int frameNr, int scopeNr) -{ - if (state() != Paused) - return; - - class ArgumentCollectJob: public Job - { - QV4::ExecutionEngine *engine; - Collector *collector; - int frameNr; - int scopeNr; - - public: - ArgumentCollectJob(QV4::ExecutionEngine *engine, Collector *collector, int frameNr, int scopeNr) - : engine(engine) - , collector(collector) - , frameNr(frameNr) - , scopeNr(scopeNr) - {} - - ~ArgumentCollectJob() {} - - void run() - { - if (frameNr < 0) - return; - - Scope scope(engine); - Scoped<CallContext> ctxt(scope, findScope(findContext(engine->currentContext(), frameNr), scopeNr)); - if (!ctxt) - return; - - ScopedValue v(scope); - int nFormals = ctxt->formalCount(); - for (unsigned i = 0, ei = nFormals; i != ei; ++i) { - QString qName; - if (Identifier *name = ctxt->formals()[nFormals - i - 1]) - qName = name->string; - v = ctxt->argument(i); - collector->collect(qName, v); - } - } - }; - - ArgumentCollectJob job(m_engine, collector, frameNr, scopeNr); - runInEngine(&job); -} - -/// Same as \c retrieveArgumentsFromContext, but now for locals. -void Debugger::collectLocalsInContext(Collector *collector, int frameNr, int scopeNr) -{ - if (state() != Paused) - return; - - class LocalCollectJob: public Job - { - QV4::ExecutionEngine *engine; - Collector *collector; - int frameNr; - int scopeNr; - - public: - LocalCollectJob(QV4::ExecutionEngine *engine, Collector *collector, int frameNr, int scopeNr) - : engine(engine) - , collector(collector) - , frameNr(frameNr) - , scopeNr(scopeNr) - {} - - void run() - { - if (frameNr < 0) - return; - - Scope scope(engine); - Scoped<CallContext> ctxt(scope, findScope(findContext(engine->currentContext(), frameNr), scopeNr)); - if (!ctxt) - return; - - ScopedValue v(scope); - for (unsigned i = 0, ei = ctxt->variableCount(); i != ei; ++i) { - QString qName; - if (Identifier *name = ctxt->variables()[i]) - qName = name->string; - v = ctxt->d()->locals[i]; - collector->collect(qName, v); - } - } - }; - - LocalCollectJob job(m_engine, collector, frameNr, scopeNr); - runInEngine(&job); -} - -bool Debugger::collectThisInContext(Debugger::Collector *collector, int frame) -{ - if (state() != Paused) - return false; - - class ThisCollectJob: public Job - { - QV4::ExecutionEngine *engine; - Collector *collector; - int frameNr; - bool *foundThis; - - public: - ThisCollectJob(QV4::ExecutionEngine *engine, Collector *collector, int frameNr, bool *foundThis) - : engine(engine) - , collector(collector) - , frameNr(frameNr) - , foundThis(foundThis) - {} - - void run() - { - *foundThis = myRun(); - } - - bool myRun() - { - Scope scope(engine); - ScopedContext ctxt(scope, findContext(engine->currentContext(), frameNr)); - while (ctxt) { - if (CallContext *cCtxt = ctxt->asCallContext()) - if (cCtxt->d()->activation) - break; - ctxt = ctxt->d()->outer; - } - - if (!ctxt) - return false; - - ScopedObject o(scope, ctxt->asCallContext()->d()->activation); - collector->collect(o); - return true; - } - }; - - bool foundThis = false; - ThisCollectJob job(m_engine, collector, frame, &foundThis); - runInEngine(&job); - return foundThis; -} - -void Debugger::collectThrownValue(Collector *collector) -{ - if (state() != Paused || !m_engine->hasException) - return; - - class ThisCollectJob: public Job - { - QV4::ExecutionEngine *engine; - Collector *collector; - - public: - ThisCollectJob(QV4::ExecutionEngine *engine, Collector *collector) - : engine(engine) - , collector(collector) - {} - - void run() - { - Scope scope(engine); - ScopedValue v(scope, engine->exceptionValue); - collector->collect(QStringLiteral("exception"), v); - } - }; - - ThisCollectJob job(m_engine, collector); - runInEngine(&job); -} - -void Debugger::collectReturnedValue(Collector *collector) const -{ - if (state() != Paused) - return; - - Scope scope(m_engine); - ScopedObject o(scope, m_returnedValue.valueRef()); - collector->collect(o); -} - -QVector<Heap::ExecutionContext::ContextType> Debugger::getScopeTypes(int frame) const -{ - QVector<Heap::ExecutionContext::ContextType> types; - - if (state() != Paused) - return types; - - Scope scope(m_engine); - Scoped<CallContext> sctxt(scope, findContext(m_engine->currentContext(), frame)); - if (!sctxt || sctxt->d()->type < Heap::ExecutionContext::Type_SimpleCallContext) - return types; - - ScopedContext it(scope, sctxt->d()); - for (; it; it = it->d()->outer) - types.append(it->d()->type); - - return types; -} - - -void Debugger::evaluateExpression(int frameNr, const QString &expression, Debugger::Collector *resultsCollector) -{ - Q_ASSERT(state() == Paused); - - Q_ASSERT(m_runningJob == 0); - ExpressionEvalJob job(m_engine, frameNr, expression, resultsCollector); - runInEngine(&job); -} - -void Debugger::maybeBreakAtInstruction() +void V4Debugger::maybeBreakAtInstruction() { if (m_runningJob) // do not re-enter when we're doing a job for the debugger. return; @@ -532,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: @@ -548,25 +221,25 @@ 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); } } } -void Debugger::enteringFunction() +void V4Debugger::enteringFunction() { if (m_runningJob) return; QMutexLocker locker(&m_lock); if (m_stepping == StepIn) { - m_currentContext.set(m_engine, m_engine->currentContext()); + m_currentContext.set(m_engine, *m_engine->currentContext); } } -void Debugger::leavingFunction(const ReturnedValue &retVal) +void V4Debugger::leavingFunction(const ReturnedValue &retVal) { if (m_runningJob) return; @@ -574,14 +247,14 @@ 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); } } -void Debugger::aboutToThrow() +void V4Debugger::aboutToThrow() { if (!m_breakOnThrow) return; @@ -593,10 +266,10 @@ void Debugger::aboutToThrow() pauseAndWait(Throwing); } -Function *Debugger::getFunction() const +Function *V4Debugger::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(); @@ -604,15 +277,13 @@ Function *Debugger::getFunction() const return context->d()->engine->globalCode; } -void Debugger::pauseAndWait(PauseReason reason) +void V4Debugger::pauseAndWait(PauseReason reason) { if (m_runningJob) return; m_state = Paused; - QMetaObject::invokeMethod(m_agent, "debuggerPaused", Qt::QueuedConnection, - Q_ARG(QV4::Debugging::Debugger*, this), - Q_ARG(QV4::Debugging::PauseReason, reason)); + emit debuggerPaused(this, reason); while (true) { m_runningCondition.wait(&m_lock); @@ -627,7 +298,7 @@ void Debugger::pauseAndWait(PauseReason reason) m_state = Running; } -bool Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr) +bool V4Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr) { BreakPoints::iterator it = m_breakPoints.find(DebuggerBreakPoint(filename.mid(filename.lastIndexOf('/') + 1), linenr)); if (it == m_breakPoints.end()) @@ -645,13 +316,13 @@ bool Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr) return evilJob.resultAsBoolean(); } -void Debugger::runInEngine(Debugger::Job *job) +void V4Debugger::runInEngine(V4Debugger::Job *job) { QMutexLocker locker(&m_lock); runInEngine_havingLock(job); } -void Debugger::runInEngine_havingLock(Debugger::Job *job) +void V4Debugger::runInEngine_havingLock(V4Debugger::Job *job) { Q_ASSERT(job); Q_ASSERT(m_runningJob == 0); @@ -662,174 +333,8 @@ void Debugger::runInEngine_havingLock(Debugger::Job *job) m_runningJob = 0; } -void DebuggerAgent::addDebugger(Debugger *debugger) -{ - Q_ASSERT(!m_debuggers.contains(debugger)); - m_debuggers << debugger; - debugger->attachToAgent(this); - - debugger->setBreakOnThrow(m_breakOnThrow); - - foreach (const BreakPoint &breakPoint, m_breakPoints.values()) - if (breakPoint.enabled) - debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition); -} - -void DebuggerAgent::removeDebugger(Debugger *debugger) -{ - m_debuggers.removeAll(debugger); - debugger->detachFromAgent(); -} - -void DebuggerAgent::pause(Debugger *debugger) const -{ - debugger->pause(); -} - -void DebuggerAgent::pauseAll() const +V4Debugger::Job::~Job() { - foreach (Debugger *debugger, m_debuggers) - pause(debugger); } -void DebuggerAgent::resumeAll() const -{ - foreach (Debugger *debugger, m_debuggers) - if (debugger->state() == Debugger::Paused) - debugger->resume(Debugger::FullThrottle); -} - -int DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition) -{ - if (enabled) - foreach (Debugger *debugger, m_debuggers) - debugger->addBreakPoint(fileName, lineNumber, condition); - - int id = m_breakPoints.size(); - m_breakPoints.insert(id, BreakPoint(fileName, lineNumber, enabled, condition)); - return id; -} - -void DebuggerAgent::removeBreakPoint(int id) -{ - BreakPoint breakPoint = m_breakPoints.value(id); - if (!breakPoint.isValid()) - return; - - m_breakPoints.remove(id); - - if (breakPoint.enabled) - foreach (Debugger *debugger, m_debuggers) - debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr); -} - -void DebuggerAgent::removeAllBreakPoints() -{ - QList<int> ids = m_breakPoints.keys(); - foreach (int id, ids) - removeBreakPoint(id); -} - -void DebuggerAgent::enableBreakPoint(int id, bool onoff) -{ - BreakPoint &breakPoint = m_breakPoints[id]; - if (!breakPoint.isValid() || breakPoint.enabled == onoff) - return; - breakPoint.enabled = onoff; - - foreach (Debugger *debugger, m_debuggers) { - if (onoff) - debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition); - else - debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr); - } -} - -QList<int> DebuggerAgent::breakPointIds(const QString &fileName, int lineNumber) const -{ - QList<int> ids; - - for (QHash<int, BreakPoint>::const_iterator i = m_breakPoints.begin(), ei = m_breakPoints.end(); i != ei; ++i) - if (i->lineNr == lineNumber && fileName.endsWith(i->fileName)) - ids.push_back(i.key()); - - return ids; -} - -void DebuggerAgent::setBreakOnThrow(bool onoff) -{ - if (onoff != m_breakOnThrow) { - m_breakOnThrow = onoff; - foreach (Debugger *debugger, m_debuggers) - debugger->setBreakOnThrow(onoff); - } -} - -DebuggerAgent::~DebuggerAgent() -{ - foreach (Debugger *debugger, m_debuggers) - debugger->detachFromAgent(); - - Q_ASSERT(m_debuggers.isEmpty()); -} - -Debugger::Collector::~Collector() -{ -} - -void Debugger::Collector::collect(const QString &name, const ScopedValue &value) -{ - switch (value->type()) { - case Value::Empty_Type: - Q_ASSERT(!"empty Value encountered"); - break; - case Value::Undefined_Type: - addUndefined(name); - break; - case Value::Null_Type: - addNull(name); - break; - case Value::Boolean_Type: - addBoolean(name, value->booleanValue()); - break; - case Value::Managed_Type: - if (String *s = value->asString()) - addString(name, s->toQString()); - else - addObject(name, value); - break; - case Value::Integer_Type: - addInteger(name, value->int_32); - break; - default: // double - addDouble(name, value->doubleValue()); - break; - } -} - -void Debugger::Collector::collect(Object *object) -{ - bool property = true; - qSwap(property, m_isProperty); - - Scope scope(m_engine); - ObjectIterator it(scope, object, ObjectIterator::EnumerableOnly); - ScopedValue name(scope); - ScopedValue value(scope); - while (true) { - Value v; - name = it.nextPropertyNameAsString(&v); - if (name->isNull()) - break; - QString key = name->toQStringNoThrow(); - value = v; - collect(key, value); - } - - qSwap(property, m_isProperty); -} - - -Debugger::Job::~Job() -{ -} +QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h index e6a9750351..fdc9cac24f 100644 --- a/src/qml/jsruntime/qv4debugging_p.h +++ b/src/qml/jsruntime/qv4debugging_p.h @@ -34,6 +34,17 @@ #ifndef DEBUGGING_H #define DEBUGGING_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include "qv4engine_p.h" #include "qv4context_p.h" @@ -44,6 +55,8 @@ #include <QMutex> #include <QWaitCondition> +#include <QtCore/QJsonObject> + QT_BEGIN_NAMESPACE namespace QV4 { @@ -59,8 +72,6 @@ enum PauseReason { Step }; -class DebuggerAgent; - struct DebuggerBreakPoint { DebuggerBreakPoint(const QString &fileName, int line) : fileName(fileName), lineNumber(line) @@ -79,43 +90,44 @@ inline bool operator==(const DebuggerBreakPoint &a, const DebuggerBreakPoint &b) typedef QHash<DebuggerBreakPoint, QString> BreakPoints; +class Q_QML_EXPORT Debugger : public QObject +{ + Q_OBJECT -class Q_QML_EXPORT Debugger +public: + virtual ~Debugger() {} + virtual bool pauseAtNextOpportunity() const = 0; + virtual void maybeBreakAtInstruction() = 0; + virtual void enteringFunction() = 0; + virtual void leavingFunction(const ReturnedValue &retVal) = 0; + virtual void aboutToThrow() = 0; +}; + +class Q_QML_EXPORT V4Debugger : public Debugger { + Q_OBJECT public: - class Job + class Q_QML_EXPORT Job { public: virtual ~Job() = 0; virtual void run() = 0; }; - class Q_QML_EXPORT Collector + class Q_QML_EXPORT JavaScriptJob: public Job { - public: - Collector(ExecutionEngine *engine): m_engine(engine), m_isProperty(false) {} - virtual ~Collector(); + QV4::ExecutionEngine *engine; + int frameNr; + const QString &script; + bool resultIsException; - void collect(const QString &name, const ScopedValue &value); - void collect(Object *object); + public: + JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script); + void run(); + bool hasExeption() const; protected: - virtual void addUndefined(const QString &name) = 0; - virtual void addNull(const QString &name) = 0; - virtual void addBoolean(const QString &name, bool value) = 0; - virtual void addString(const QString &name, const QString &value) = 0; - virtual void addObject(const QString &name, const Value &value) = 0; - virtual void addInteger(const QString &name, int value) = 0; - virtual void addDouble(const QString &name, double value) = 0; - - QV4::ExecutionEngine *engine() const { return m_engine; } - - bool isProperty() const { return m_isProperty; } - void setIsProperty(bool onoff) { m_isProperty = onoff; } - - private: - QV4::ExecutionEngine *m_engine; - bool m_isProperty; + virtual void handleResult(QV4::ScopedValue &result) = 0; }; enum State { @@ -132,17 +144,11 @@ public: NotStepping = FullThrottle }; - Debugger(ExecutionEngine *engine); - ~Debugger(); + V4Debugger(ExecutionEngine *engine); ExecutionEngine *engine() const { return m_engine; } - void attachToAgent(DebuggerAgent *agent); - void detachFromAgent(); - DebuggerAgent *agent() const { return m_agent; } - - void gatherSources(int requestSequenceNr); void pause(); void resume(Speed speed); @@ -166,14 +172,10 @@ public: } QVector<StackFrame> stackTrace(int frameLimit = -1) const; - void collectArgumentsInContext(Collector *collector, int frameNr = 0, int scopeNr = 0); - void collectLocalsInContext(Collector *collector, int frameNr = 0, int scopeNr = 0); - bool collectThisInContext(Collector *collector, int frame = 0); - void collectThrownValue(Collector *collector); - void collectReturnedValue(Collector *collector) const; QVector<Heap::ExecutionContext::ContextType> getScopeTypes(int frame = 0) const; - void evaluateExpression(int frameNr, const QString &expression, Collector *resultsCollector); + Function *getFunction() const; + void runInEngine(Job *job); public: // compile-time interface void maybeBreakAtInstruction(); @@ -183,21 +185,19 @@ public: // execution hooks void leavingFunction(const ReturnedValue &retVal); void aboutToThrow(); -private: - Function *getFunction() const; +signals: + void sourcesCollected(QV4::Debugging::V4Debugger *self, const QStringList &sources, int seq); + void debuggerPaused(QV4::Debugging::V4Debugger *self, QV4::Debugging::PauseReason reason); +private: // requires lock to be held void pauseAndWait(PauseReason reason); - bool reallyHitTheBreakPoint(const QString &filename, int linenr); - - void runInEngine(Job *job); - void runInEngine_havingLock(Debugger::Job *job); + void runInEngine_havingLock(V4Debugger::Job *job); private: QV4::ExecutionEngine *m_engine; QV4::PersistentValue m_currentContext; - DebuggerAgent *m_agent; QMutex m_lock; QWaitCondition m_runningCondition; State m_state; @@ -214,54 +214,6 @@ private: QWaitCondition m_jobIsRunning; }; -class Q_QML_EXPORT DebuggerAgent : public QObject -{ - Q_OBJECT -public: - DebuggerAgent(): m_breakOnThrow(false) {} - ~DebuggerAgent(); - - void addDebugger(Debugger *debugger); - void removeDebugger(Debugger *debugger); - - void pause(Debugger *debugger) const; - void pauseAll() const; - void resumeAll() const; - int addBreakPoint(const QString &fileName, int lineNumber, bool enabled = true, const QString &condition = QString()); - void removeBreakPoint(int id); - void removeAllBreakPoints(); - void enableBreakPoint(int id, bool onoff); - QList<int> breakPointIds(const QString &fileName, int lineNumber) const; - - bool breakOnThrow() const { return m_breakOnThrow; } - void setBreakOnThrow(bool onoff); - - Q_INVOKABLE virtual void debuggerPaused(QV4::Debugging::Debugger *debugger, - QV4::Debugging::PauseReason reason) = 0; - Q_INVOKABLE virtual void sourcesCollected(QV4::Debugging::Debugger *debugger, - QStringList sources, int requestSequenceNr) = 0; - -protected: - QList<Debugger *> m_debuggers; - - struct BreakPoint { - QString fileName; - int lineNr; - bool enabled; - QString condition; - - BreakPoint(): lineNr(-1), enabled(false) {} - BreakPoint(const QString &fileName, int lineNr, bool enabled, const QString &condition) - : fileName(fileName), lineNr(lineNr), enabled(enabled), condition(condition) - {} - - bool isValid() const { return lineNr >= 0 && !fileName.isEmpty(); } - }; - - QHash<int, BreakPoint> m_breakPoints; - bool m_breakOnThrow; -}; - } // namespace Debugging } // namespace QV4 diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index e1282eeca9..2560f065cf 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include <qv4engine_p.h> #include <qv4context_p.h> -#include <qv4value_inl_p.h> +#include <qv4value_p.h> #include <qv4object_p.h> #include <qv4objectproto_p.h> #include <qv4objectiterator_p.h> @@ -48,7 +48,7 @@ #include <qv4regexp_p.h> #include <qv4variantobject_p.h> #include <qv4runtime_p.h> -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include <qv4argumentsobject_p.h> #include <qv4dateobject_p.h> #include <qv4jsonobject_p.h> @@ -59,7 +59,6 @@ #include "qv4executableallocator_p.h" #include "qv4sequenceobject_p.h" #include "qv4qobjectwrapper_p.h" -#include "qv4qmlextensions_p.h" #include "qv4memberdata_p.h" #include "qv4arraybuffer_p.h" #include "qv4dataview_p.h" @@ -197,9 +196,11 @@ QQmlEngine *ExecutionEngine::qmlEngine() const ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) : current(0) + , hasException(false) , 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) @@ -211,17 +212,13 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) , m_engineId(engineSerial.fetchAndAddOrdered(1)) , regExpCache(0) , m_multiplyWrappedQObjects(0) - , m_qmlExtensions(0) { MemoryManager::GCBlocker gcBlocker(memoryManager); - exceptionValue = Encode::undefined(); - hasException = false; - if (!factory) { #ifdef V4_ENABLE_JIT - static const bool forceMoth = !qgetenv("QV4_FORCE_INTERPRETER").isEmpty(); + static const bool forceMoth = !qEnvironmentVariableIsEmpty("QV4_FORCE_INTERPRETER"); if (forceMoth) factory = new Moth::ISelFactory; else @@ -241,6 +238,13 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) jsStackBase = (Value *)jsStack->base(); jsStackTop = jsStackBase; + exceptionValue = jsAlloca(1); + globalObject = static_cast<Object *>(jsAlloca(1)); + jsObjects = jsAlloca(NJSObjects); + typedArrayPrototype = static_cast<Object *>(jsAlloca(NTypedArrayTypes)); + typedArrayCtors = static_cast<FunctionObject *>(jsAlloca(NTypedArrayTypes)); + jsStrings = jsAlloca(NJSStrings); + #ifdef V4_USE_VALGRIND VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, 2*JSStackLimit); #endif @@ -251,208 +255,240 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) if (!recheckCStackLimits()) qFatal("Fatal: Not enough stack space available for QML. Please increase the process stack size to more than %d KBytes.", MinimumStackSize); - Scope scope(this); - identifierTable = new IdentifierTable(this); classPool = new InternalClassPool; emptyClass = new (classPool) InternalClass(this); - id_empty = newIdentifier(QString()); - id_undefined = newIdentifier(QStringLiteral("undefined")); - id_null = newIdentifier(QStringLiteral("null")); - id_true = newIdentifier(QStringLiteral("true")); - id_false = newIdentifier(QStringLiteral("false")); - id_boolean = newIdentifier(QStringLiteral("boolean")); - id_number = newIdentifier(QStringLiteral("number")); - id_string = newIdentifier(QStringLiteral("string")); - id_object = newIdentifier(QStringLiteral("object")); - id_function = newIdentifier(QStringLiteral("function")); - id_length = newIdentifier(QStringLiteral("length")); - id_prototype = newIdentifier(QStringLiteral("prototype")); - id_constructor = newIdentifier(QStringLiteral("constructor")); - id_arguments = newIdentifier(QStringLiteral("arguments")); - id_caller = newIdentifier(QStringLiteral("caller")); - id_callee = newIdentifier(QStringLiteral("callee")); - id_this = newIdentifier(QStringLiteral("this")); - id___proto__ = newIdentifier(QStringLiteral("__proto__")); - id_enumerable = newIdentifier(QStringLiteral("enumerable")); - id_configurable = newIdentifier(QStringLiteral("configurable")); - id_writable = newIdentifier(QStringLiteral("writable")); - id_value = newIdentifier(QStringLiteral("value")); - id_get = newIdentifier(QStringLiteral("get")); - id_set = newIdentifier(QStringLiteral("set")); - id_eval = newIdentifier(QStringLiteral("eval")); - id_uintMax = newIdentifier(QStringLiteral("4294967295")); - id_name = newIdentifier(QStringLiteral("name")); - id_index = newIdentifier(QStringLiteral("index")); - id_input = newIdentifier(QStringLiteral("input")); - id_toString = newIdentifier(QStringLiteral("toString")); - id_destroy = newIdentifier(QStringLiteral("destroy")); - id_valueOf = newIdentifier(QStringLiteral("valueOf")); - id_byteLength = newIdentifier(QStringLiteral("byteLength")); - id_byteOffset = newIdentifier(QStringLiteral("byteOffset")); - id_buffer = newIdentifier(QStringLiteral("buffer")); - id_lastIndex = newIdentifier(QStringLiteral("lastIndex")); - - objectPrototype = memoryManager->alloc<ObjectPrototype>(emptyClass, (QV4::Object *)0); - - arrayClass = emptyClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable); - arrayPrototype = memoryManager->alloc<ArrayPrototype>(arrayClass, objectPrototype.asObject()); - - InternalClass *argsClass = emptyClass->addMember(id_length, Attr_NotEnumerable); - argumentsObjectClass = argsClass->addMember(id_callee, Attr_Data|Attr_NotEnumerable); - strictArgumentsObjectClass = argsClass->addMember(id_callee, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - strictArgumentsObjectClass = strictArgumentsObjectClass->addMember(id_caller, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - - m_globalObject = newObject(); - Q_ASSERT(globalObject()->d()->vtable); + jsStrings[String_Empty] = newIdentifier(QString()); + jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined")); + jsStrings[String_null] = newIdentifier(QStringLiteral("null")); + jsStrings[String_true] = newIdentifier(QStringLiteral("true")); + jsStrings[String_false] = newIdentifier(QStringLiteral("false")); + jsStrings[String_boolean] = newIdentifier(QStringLiteral("boolean")); + jsStrings[String_number] = newIdentifier(QStringLiteral("number")); + jsStrings[String_string] = newIdentifier(QStringLiteral("string")); + jsStrings[String_object] = newIdentifier(QStringLiteral("object")); + jsStrings[String_function] = newIdentifier(QStringLiteral("function")); + jsStrings[String_length] = newIdentifier(QStringLiteral("length")); + jsStrings[String_prototype] = newIdentifier(QStringLiteral("prototype")); + jsStrings[String_constructor] = newIdentifier(QStringLiteral("constructor")); + jsStrings[String_arguments] = newIdentifier(QStringLiteral("arguments")); + jsStrings[String_caller] = newIdentifier(QStringLiteral("caller")); + jsStrings[String_callee] = newIdentifier(QStringLiteral("callee")); + jsStrings[String_this] = newIdentifier(QStringLiteral("this")); + jsStrings[String___proto__] = newIdentifier(QStringLiteral("__proto__")); + jsStrings[String_enumerable] = newIdentifier(QStringLiteral("enumerable")); + jsStrings[String_configurable] = newIdentifier(QStringLiteral("configurable")); + jsStrings[String_writable] = newIdentifier(QStringLiteral("writable")); + jsStrings[String_value] = newIdentifier(QStringLiteral("value")); + jsStrings[String_get] = newIdentifier(QStringLiteral("get")); + jsStrings[String_set] = newIdentifier(QStringLiteral("set")); + jsStrings[String_eval] = newIdentifier(QStringLiteral("eval")); + jsStrings[String_uintMax] = newIdentifier(QStringLiteral("4294967295")); + jsStrings[String_name] = newIdentifier(QStringLiteral("name")); + jsStrings[String_index] = newIdentifier(QStringLiteral("index")); + jsStrings[String_input] = newIdentifier(QStringLiteral("input")); + jsStrings[String_toString] = newIdentifier(QStringLiteral("toString")); + jsStrings[String_destroy] = newIdentifier(QStringLiteral("destroy")); + jsStrings[String_valueOf] = newIdentifier(QStringLiteral("valueOf")); + jsStrings[String_byteLength] = newIdentifier(QStringLiteral("byteLength")); + jsStrings[String_byteOffset] = newIdentifier(QStringLiteral("byteOffset")); + jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer")); + jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex")); + + jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(emptyClass); + + arrayClass = emptyClass->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); + jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(arrayClass, objectPrototype()); + + InternalClass *argsClass = emptyClass->addMember(id_length(), Attr_NotEnumerable); + argumentsObjectClass = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable); + strictArgumentsObjectClass = argsClass->addMember(id_callee(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + strictArgumentsObjectClass = strictArgumentsObjectClass->addMember(id_caller(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + + *static_cast<Value *>(globalObject) = newObject(); + Q_ASSERT(globalObject->d()->vtable()); initRootContext(); - stringPrototype = memoryManager->alloc<StringPrototype>(emptyClass, objectPrototype.asObject()); - numberPrototype = memoryManager->alloc<NumberPrototype>(emptyClass, objectPrototype.asObject()); - booleanPrototype = memoryManager->alloc<BooleanPrototype>(emptyClass, objectPrototype.asObject()); - datePrototype = memoryManager->alloc<DatePrototype>(emptyClass, objectPrototype.asObject()); + 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); + InternalClass *functionProtoClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - functionPrototype = memoryManager->alloc<FunctionPrototype>(functionProtoClass, objectPrototype.asObject()); - functionClass = emptyClass->addMember(id_prototype, Attr_NotEnumerable|Attr_NotConfigurable, &index); + 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); + simpleScriptFunctionClass = functionClass->addMember(id_name(), Attr_ReadOnly, &index); Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Name); - simpleScriptFunctionClass = simpleScriptFunctionClass->addMember(id_length, Attr_ReadOnly, &index); + simpleScriptFunctionClass = simpleScriptFunctionClass->addMember(id_length(), Attr_ReadOnly, &index); Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Length); - protoClass = emptyClass->addMember(id_constructor, Attr_NotEnumerable, &index); + protoClass = emptyClass->addMember(id_constructor(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor); - regExpPrototype = memoryManager->alloc<RegExpPrototype>(this); - regExpExecArrayClass = arrayClass->addMember(id_index, Attr_Data, &index); + 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); + regExpExecArrayClass = regExpExecArrayClass->addMember(id_input(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayInput); - errorPrototype = memoryManager->alloc<ErrorPrototype>(emptyClass, objectPrototype.asObject()); - evalErrorPrototype = memoryManager->alloc<EvalErrorPrototype>(emptyClass, errorPrototype.asObject()); - rangeErrorPrototype = memoryManager->alloc<RangeErrorPrototype>(emptyClass, errorPrototype.asObject()); - referenceErrorPrototype = memoryManager->alloc<ReferenceErrorPrototype>(emptyClass, errorPrototype.asObject()); - syntaxErrorPrototype = memoryManager->alloc<SyntaxErrorPrototype>(emptyClass, errorPrototype.asObject()); - typeErrorPrototype = memoryManager->alloc<TypeErrorPrototype>(emptyClass, errorPrototype.asObject()); - uRIErrorPrototype = memoryManager->alloc<URIErrorPrototype>(emptyClass, errorPrototype.asObject()); - - variantPrototype = memoryManager->alloc<VariantPrototype>(emptyClass, objectPrototype.asObject()); - Q_ASSERT(variantPrototype.asObject()->prototype() == objectPrototype.asObject()->d()); - - sequencePrototype = ScopedValue(scope, memoryManager->alloc<SequencePrototype>(arrayClass, arrayPrototype.asObject())); - - ScopedContext global(scope, rootContext()); - objectCtor = memoryManager->alloc<ObjectCtor>(global); - stringCtor = memoryManager->alloc<StringCtor>(global); - numberCtor = memoryManager->alloc<NumberCtor>(global); - booleanCtor = memoryManager->alloc<BooleanCtor>(global); - arrayCtor = memoryManager->alloc<ArrayCtor>(global); - functionCtor = memoryManager->alloc<FunctionCtor>(global); - dateCtor = memoryManager->alloc<DateCtor>(global); - regExpCtor = memoryManager->alloc<RegExpCtor>(global); - errorCtor = memoryManager->alloc<ErrorCtor>(global); - evalErrorCtor = memoryManager->alloc<EvalErrorCtor>(global); - rangeErrorCtor = memoryManager->alloc<RangeErrorCtor>(global); - referenceErrorCtor = memoryManager->alloc<ReferenceErrorCtor>(global); - syntaxErrorCtor = memoryManager->alloc<SyntaxErrorCtor>(global); - typeErrorCtor = memoryManager->alloc<TypeErrorCtor>(global); - uRIErrorCtor = memoryManager->alloc<URIErrorCtor>(global); - - static_cast<ObjectPrototype *>(objectPrototype.asObject())->init(this, objectCtor.asObject()); - static_cast<StringPrototype *>(stringPrototype.asObject())->init(this, stringCtor.asObject()); - static_cast<NumberPrototype *>(numberPrototype.asObject())->init(this, numberCtor.asObject()); - static_cast<BooleanPrototype *>(booleanPrototype.asObject())->init(this, booleanCtor.asObject()); - static_cast<ArrayPrototype *>(arrayPrototype.asObject())->init(this, arrayCtor.asObject()); - static_cast<DatePrototype *>(datePrototype.asObject())->init(this, dateCtor.asObject()); - static_cast<FunctionPrototype *>(functionPrototype.asObject())->init(this, functionCtor.asObject()); - static_cast<RegExpPrototype *>(regExpPrototype.asObject())->init(this, regExpCtor.asObject()); - static_cast<ErrorPrototype *>(errorPrototype.asObject())->init(this, errorCtor.asObject()); - static_cast<EvalErrorPrototype *>(evalErrorPrototype.asObject())->init(this, evalErrorCtor.asObject()); - static_cast<RangeErrorPrototype *>(rangeErrorPrototype.asObject())->init(this, rangeErrorCtor.asObject()); - static_cast<ReferenceErrorPrototype *>(referenceErrorPrototype.asObject())->init(this, referenceErrorCtor.asObject()); - static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype.asObject())->init(this, syntaxErrorCtor.asObject()); - static_cast<TypeErrorPrototype *>(typeErrorPrototype.asObject())->init(this, typeErrorCtor.asObject()); - static_cast<URIErrorPrototype *>(uRIErrorPrototype.asObject())->init(this, uRIErrorCtor.asObject()); - - static_cast<VariantPrototype *>(variantPrototype.asObject())->init(); - sequencePrototype.cast<SequencePrototype>()->init(); + 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()); + + 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()); + static_cast<NumberPrototype *>(numberPrototype())->init(this, numberCtor()); + static_cast<BooleanPrototype *>(booleanPrototype())->init(this, booleanCtor()); + static_cast<ArrayPrototype *>(arrayPrototype())->init(this, arrayCtor()); + static_cast<DatePrototype *>(datePrototype())->init(this, dateCtor()); + static_cast<FunctionPrototype *>(functionPrototype())->init(this, functionCtor()); + static_cast<RegExpPrototype *>(regExpPrototype())->init(this, regExpCtor()); + static_cast<ErrorPrototype *>(errorPrototype())->init(this, errorCtor()); + static_cast<EvalErrorPrototype *>(evalErrorPrototype())->init(this, evalErrorCtor()); + static_cast<RangeErrorPrototype *>(rangeErrorPrototype())->init(this, rangeErrorCtor()); + static_cast<ReferenceErrorPrototype *>(referenceErrorPrototype())->init(this, referenceErrorCtor()); + static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype())->init(this, syntaxErrorCtor()); + static_cast<TypeErrorPrototype *>(typeErrorPrototype())->init(this, typeErrorCtor()); + static_cast<URIErrorPrototype *>(uRIErrorPrototype())->init(this, uRIErrorCtor()); + + static_cast<VariantPrototype *>(variantPrototype())->init(); + sequencePrototype()->cast<SequencePrototype>()->init(); // typed arrays - arrayBufferCtor = memoryManager->alloc<ArrayBufferCtor>(global); - arrayBufferPrototype = memoryManager->alloc<ArrayBufferPrototype>(emptyClass, objectPrototype.asObject()); - static_cast<ArrayBufferPrototype *>(arrayBufferPrototype.asObject())->init(this, arrayBufferCtor.asObject()); + jsObjects[ArrayBuffer_Ctor] = memoryManager->allocObject<ArrayBufferCtor>(global); + jsObjects[ArrayBufferProto] = memoryManager->allocObject<ArrayBufferPrototype>(); + static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor()); - dataViewCtor = memoryManager->alloc<DataViewCtor>(global); - dataViewPrototype = memoryManager->alloc<DataViewPrototype>(emptyClass, objectPrototype.asObject()); - static_cast<DataViewPrototype *>(dataViewPrototype.asObject())->init(this, dataViewCtor.asObject()); + 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) { - typedArrayCtors[i] = memoryManager->alloc<TypedArrayCtor>(global, Heap::TypedArray::Type(i)); - typedArrayPrototype[i] = memoryManager->alloc<TypedArrayPrototype>(this, Heap::TypedArray::Type(i)); - typedArrayPrototype[i].as<TypedArrayPrototype>()->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].asObject())); + 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>())); } // // set up the global object // - rootContext()->global = globalObject()->d(); - rootContext()->callData->thisObject = globalObject(); - Q_ASSERT(globalObject()->d()->vtable); - - globalObject()->defineDefaultProperty(QStringLiteral("Object"), objectCtor); - globalObject()->defineDefaultProperty(QStringLiteral("String"), stringCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Number"), numberCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Boolean"), booleanCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Array"), arrayCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Function"), functionCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Date"), dateCtor); - globalObject()->defineDefaultProperty(QStringLiteral("RegExp"), regExpCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Error"), errorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("EvalError"), evalErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("RangeError"), rangeErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("ReferenceError"), referenceErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("SyntaxError"), syntaxErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("TypeError"), typeErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("URIError"), uRIErrorCtor); - - globalObject()->defineDefaultProperty(QStringLiteral("ArrayBuffer"), arrayBufferCtor); - globalObject()->defineDefaultProperty(QStringLiteral("DataView"), dataViewCtor); - ScopedString str(scope); + rootContext()->d()->global = globalObject->d(); + rootContext()->d()->callData->thisObject = globalObject; + Q_ASSERT(globalObject->d()->vtable()); + + globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor()); + globalObject->defineDefaultProperty(QStringLiteral("String"), *stringCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Boolean"), *booleanCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Array"), *arrayCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Function"), *functionCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Date"), *dateCtor()); + globalObject->defineDefaultProperty(QStringLiteral("RegExp"), *regExpCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Error"), *errorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("EvalError"), *evalErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("RangeError"), *rangeErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("ReferenceError"), *referenceErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("SyntaxError"), *syntaxErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("TypeError"), *typeErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("URIError"), *uRIErrorCtor()); + + globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor()); + globalObject->defineDefaultProperty(QStringLiteral("DataView"), *dataViewCtor()); for (int i = 0; i < Heap::TypedArray::NTypes; ++i) - globalObject()->defineDefaultProperty((str = typedArrayCtors[i].asFunctionObject()->name())->toQString(), typedArrayCtors[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)); + 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)); - evalFunction = memoryManager->alloc<EvalFunction>(global); - globalObject()->defineDefaultProperty(QStringLiteral("eval"), (o = evalFunction)); + jsObjects[Eval_Function] = memoryManager->allocObject<EvalFunction>(global); + globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction()); - globalObject()->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2); - globalObject()->defineDefaultProperty(QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1); - globalObject()->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1); - globalObject()->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1); - globalObject()->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1); - globalObject()->defineDefaultProperty(QStringLiteral("decodeURIComponent"), GlobalFunctions::method_decodeURIComponent, 1); - globalObject()->defineDefaultProperty(QStringLiteral("encodeURI"), GlobalFunctions::method_encodeURI, 1); - globalObject()->defineDefaultProperty(QStringLiteral("encodeURIComponent"), GlobalFunctions::method_encodeURIComponent, 1); - globalObject()->defineDefaultProperty(QStringLiteral("escape"), GlobalFunctions::method_escape, 1); - globalObject()->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1); + globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2); + globalObject->defineDefaultProperty(QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1); + globalObject->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1); + globalObject->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1); + globalObject->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1); + globalObject->defineDefaultProperty(QStringLiteral("decodeURIComponent"), GlobalFunctions::method_decodeURIComponent, 1); + globalObject->defineDefaultProperty(QStringLiteral("encodeURI"), GlobalFunctions::method_encodeURI, 1); + globalObject->defineDefaultProperty(QStringLiteral("encodeURIComponent"), GlobalFunctions::method_encodeURIComponent, 1); + globalObject->defineDefaultProperty(QStringLiteral("escape"), GlobalFunctions::method_escape, 1); + globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1); ScopedString name(scope, newString(QStringLiteral("thrower"))); - thrower = BuiltinFunction::create(global, name, ::throwTypeError); + jsObjects[ThrowerObject] = BuiltinFunction::create(global, name, ::throwTypeError); } ExecutionEngine::~ExecutionEngine() @@ -471,7 +507,6 @@ ExecutionEngine::~ExecutionEngine() foreach (QV4::CompiledData::CompilationUnit *unit, remainingUnits) unit->unlink(); - delete m_qmlExtensions; emptyClass->destroy(); delete classPool; delete bumperPointerAllocator; @@ -483,11 +518,10 @@ ExecutionEngine::~ExecutionEngine() delete [] argumentsAccessors; } -void ExecutionEngine::enableDebugger() +void ExecutionEngine::setDebugger(Debugging::Debugger *debugger_) { Q_ASSERT(!debugger); - debugger = new Debugging::Debugger(this); - iselFactory.reset(new Moth::ISelFactory); + debugger = debugger_; } void ExecutionEngine::enableProfiler() @@ -502,12 +536,15 @@ void ExecutionEngine::initRootContext() Scoped<GlobalContext> r(scope, memoryManager->allocManaged<GlobalContext>(sizeof(GlobalContext::Data) + sizeof(CallData))); new (r->d()) GlobalContext::Data(this); r->d()->callData = reinterpret_cast<CallData *>(r->d() + 1); - r->d()->callData->tag = QV4::Value::_Integer_Type; + r->d()->callData->tag = QV4::Value::Integer_Type_Internal; r->d()->callData->argc = 0; - r->d()->callData->thisObject = globalObject(); + r->d()->callData->thisObject = globalObject; r->d()->callData->args[0] = Encode::undefined(); + jsObjects[RootContext] = r; + jsObjects[IntegerNull] = Encode((int)0); - m_rootContext = r->d(); + currentContext = static_cast<ExecutionContext *>(jsObjects + RootContext); + current = currentContext->d(); } InternalClass *ExecutionEngine::newClass(const InternalClass &other) @@ -515,29 +552,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()->callData; + pushContext(rootContext()->d()); + + Q_ASSERT(current == rootContext()->d()); + return currentContext; +} - Q_ASSERT(currentContext() == g->d()); - return g->d(); +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) @@ -551,31 +590,25 @@ Heap::String *ExecutionEngine::newIdentifier(const QString &text) return identifierTable->insertString(text); } -Heap::Object *ExecutionEngine::newStringObject(const Value &value) +Heap::Object *ExecutionEngine::newStringObject(const String *string) { - Scope scope(this); - Scoped<StringObject> object(scope, memoryManager->alloc<StringObject>(this, value)); - 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) @@ -585,39 +618,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(); } @@ -638,97 +692,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.asObject(), 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::Object *ExecutionEngine::qmlContextObject() const +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; @@ -740,8 +772,46 @@ Heap::Object *ExecutionEngine::qmlContextObject() const if (ctx->type != Heap::ExecutionContext::Type_QmlContext) return 0; - Q_ASSERT(static_cast<Heap::CallContext *>(ctx)->activation); - return static_cast<Heap::CallContext *>(ctx)->activation; + return static_cast<Heap::QmlContext *>(ctx); +} + +QObject *ExecutionEngine::qmlScopeObject() const +{ + Heap::QmlContext *ctx = qmlContext(); + if (!ctx) + return 0; + + return ctx->qml->scopeObject; +} + +ReturnedValue ExecutionEngine::qmlSingletonWrapper(String *name) +{ + QQmlContextData *ctx = callingQmlContext(); + if (!ctx->imports) + return Encode::undefined(); + // Search for attached properties, enums and imported scripts + QQmlTypeNameCache::Result r = ctx->imports->query(name); + + Q_ASSERT(r.isValid()); + Q_ASSERT(r.type); + Q_ASSERT(r.type->isSingleton()); + + QQmlType::SingletonInstanceInfo *siinfo = r.type->singletonInstanceInfo(); + QQmlEngine *e = qmlEngine(); + siinfo->init(e); + + if (QObject *qobjectSingleton = siinfo->qobjectApi(e)) + return QV4::QObjectWrapper::wrap(this, qobjectSingleton); + return QJSValuePrivate::convertedToValue(this, siinfo->scriptApi(e)); +} + +QQmlContextData *ExecutionEngine::callingQmlContext() const +{ + Heap::QmlContext *ctx = qmlContext(); + if (!ctx) + return 0; + + return ctx->qml->context.contextData(); } QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const @@ -750,7 +820,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(); @@ -770,14 +840,14 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const stack.append(frame); --frameLimit; } - c = c->d()->parent; + c = parentContext(c); } if (frameLimit && globalCode) { StackFrame frame; frame.source = globalCode->sourceFile(); frame.function = globalCode->name()->toQString(); - frame.line = rootContext()->lineNumber; + frame.line = rootContext()->d()->lineNumber; frame.column = -1; stack.append(frame); @@ -838,8 +908,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) { @@ -847,7 +916,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) @@ -877,10 +946,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)); } } } @@ -889,8 +958,6 @@ void ExecutionEngine::markObjects() { identifierTable->mark(this); - globalObject()->mark(this); - for (int i = 0; i < nArgumentsAccessors; ++i) { const Property &pd = argumentsAccessors[i]; if (Heap::FunctionObject *getter = pd.getter()) @@ -899,103 +966,6 @@ void ExecutionEngine::markObjects() setter->mark(this); } - Heap::ExecutionContext *c = currentContext(); - while (c) { - Q_ASSERT(c->inUse()); - if (!c->isMarked()) { - c->setMarkBit(); - c->gcGetVtable()->markObjects(c, this); - } - c = c->parent; - } - - id_empty->mark(this); - id_undefined->mark(this); - id_null->mark(this); - id_true->mark(this); - id_false->mark(this); - id_boolean->mark(this); - id_number->mark(this); - id_string->mark(this); - id_object->mark(this); - id_function->mark(this); - id_length->mark(this); - id_prototype->mark(this); - id_constructor->mark(this); - id_arguments->mark(this); - id_caller->mark(this); - id_callee->mark(this); - id_this->mark(this); - id___proto__->mark(this); - id_enumerable->mark(this); - id_configurable->mark(this); - id_writable->mark(this); - id_value->mark(this); - id_get->mark(this); - id_set->mark(this); - id_eval->mark(this); - id_uintMax->mark(this); - id_name->mark(this); - id_index->mark(this); - id_input->mark(this); - id_toString->mark(this); - id_destroy->mark(this); - id_valueOf->mark(this); - id_byteLength->mark(this); - id_byteOffset->mark(this); - id_buffer->mark(this); - id_lastIndex->mark(this); - - objectCtor.mark(this); - stringCtor.mark(this); - numberCtor.mark(this); - booleanCtor.mark(this); - arrayCtor.mark(this); - functionCtor.mark(this); - dateCtor.mark(this); - regExpCtor.mark(this); - errorCtor.mark(this); - evalErrorCtor.mark(this); - rangeErrorCtor.mark(this); - referenceErrorCtor.mark(this); - syntaxErrorCtor.mark(this); - typeErrorCtor.mark(this); - uRIErrorCtor.mark(this); - arrayBufferCtor.mark(this); - dataViewCtor.mark(this); - for (int i = 0; i < Heap::TypedArray::NTypes; ++i) - typedArrayCtors[i].mark(this); - - objectPrototype.mark(this); - arrayPrototype.mark(this); - stringPrototype.mark(this); - numberPrototype.mark(this); - booleanPrototype.mark(this); - datePrototype.mark(this); - functionPrototype.mark(this); - regExpPrototype.mark(this); - errorPrototype.mark(this); - evalErrorPrototype.mark(this); - rangeErrorPrototype.mark(this); - referenceErrorPrototype.mark(this); - syntaxErrorPrototype.mark(this); - typeErrorPrototype.mark(this); - uRIErrorPrototype.mark(this); - variantPrototype.mark(this); - sequencePrototype.mark(this); - - arrayBufferPrototype.mark(this); - dataViewPrototype.mark(this); - for (int i = 0; i < Heap::TypedArray::NTypes; ++i) - typedArrayPrototype[i].mark(this); - - exceptionValue.mark(this); - - thrower->mark(this); - - if (m_qmlExtensions) - m_qmlExtensions->markObjects(this); - classPool->markObjects(this); for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd(); @@ -1003,13 +973,6 @@ void ExecutionEngine::markObjects() (*it)->markObjects(this); } -QmlExtensions *ExecutionEngine::qmlExtensions() -{ - if (!m_qmlExtensions) - m_qmlExtensions = new QmlExtensions; - return m_qmlExtensions; -} - ReturnedValue ExecutionEngine::throwError(const Value &value) { // we can get in here with an exception already set, as the runtime @@ -1020,7 +983,7 @@ ReturnedValue ExecutionEngine::throwError(const Value &value) return Encode::undefined(); hasException = true; - exceptionValue = value; + *exceptionValue = value; QV4::Scope scope(this); QV4::Scoped<ErrorObject> error(scope, value); if (!!error) @@ -1041,8 +1004,8 @@ ReturnedValue ExecutionEngine::catchException(StackTrace *trace) *trace = exceptionStackTrace; exceptionStackTrace.clear(); hasException = false; - ReturnedValue res = exceptionValue.asReturnedValue(); - exceptionValue = Primitive::emptyValue(); + ReturnedValue res = exceptionValue->asReturnedValue(); + *exceptionValue = Primitive::emptyValue(); return res; } @@ -1139,7 +1102,7 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError() QV4::ScopedValue exception(scope, catchException(&trace)); QQmlError error; if (!trace.isEmpty()) { - QV4::StackFrame frame = trace.first(); + QV4::StackFrame frame = trace.constFirst(); error.setUrl(QUrl(frame.source)); error.setLine(frame.line); error.setColumn(frame.column); @@ -1175,7 +1138,7 @@ bool ExecutionEngine::recheckCStackLimits() typedef QSet<QV4::Heap::Object *> V4ObjectSet; static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects); static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value); -static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4ObjectSet *visitedObjects = 0); +static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects = 0); static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value, const QByteArray &targetType, void **result); @@ -1198,7 +1161,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int Q_ASSERT (!value.isEmpty()); QV4::Scope scope(e); - if (QV4::VariantObject *v = value.as<QV4::VariantObject>()) + if (const QV4::VariantObject *v = value.as<QV4::VariantObject>()) return v->d()->data; if (typeHint == QVariant::Bool) @@ -1210,10 +1173,10 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int if (typeHint == qMetaTypeId<QJSValue>()) return QVariant::fromValue(QJSValue(e, value.asReturnedValue())); - if (value.asObject()) { + if (value.as<Object>()) { QV4::ScopedObject object(scope, value); if (typeHint == QMetaType::QJsonObject - && !value.asArrayObject() && !value.asFunctionObject()) { + && !value.as<ArrayObject>() && !value.as<FunctionObject>()) { return QVariant::fromValue(QV4::JsonObject::toJsonObject(object)); } else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) { return qVariantFromValue<QObject *>(wrapper->object()); @@ -1229,7 +1192,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return QV4::SequencePrototype::toVariant(object); } - if (value.asArrayObject()) { + if (value.as<ArrayObject>()) { QV4::ScopedArrayObject a(scope, value); if (typeHint == qMetaTypeId<QList<QObject *> >()) { QList<QObject *> list; @@ -1267,11 +1230,11 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return value.asDouble(); if (value.isString()) return value.stringValue()->toQString(); - if (QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>()) + if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>()) return ld->d()->locale; - if (QV4::DateObject *d = value.asDateObject()) + if (const QV4::DateObject *d = value.as<DateObject>()) return d->toQDateTime(); - if (QV4::ArrayBuffer *d = value.as<ArrayBuffer>()) + if (const QV4::ArrayBuffer *d = value.as<ArrayBuffer>()) return d->asByteArray(); // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)! @@ -1287,7 +1250,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return objectToVariant(e, o, visitedObjects); } -static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4ObjectSet *visitedObjects) +static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects) { Q_ASSERT(o); @@ -1298,7 +1261,7 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4Objec // Avoid recursion. // For compatibility with QVariant{List,Map} conversion, we return an // empty object (and no error is thrown). - if (o->asArrayObject()) + if (o->as<ArrayObject>()) return QVariantList(); return QVariantMap(); } @@ -1306,7 +1269,7 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4Objec QVariant result; - if (o->asArrayObject()) { + if (o->as<ArrayObject>()) { QV4::Scope scope(e); QV4::ScopedArrayObject a(scope, o->asReturnedValue()); QV4::ScopedValue v(scope); @@ -1319,7 +1282,7 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4Objec } result = list; - } else if (!o->asFunctionObject()) { + } else if (!o->as<FunctionObject>()) { QVariantMap map; QV4::Scope scope(e); QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly); @@ -1497,7 +1460,7 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant) return QV4::Encode(newVariantObject(variant)); } -QVariantMap ExecutionEngine::variantMapFromJS(Object *o) +QVariantMap ExecutionEngine::variantMapFromJS(const Object *o) { return objectToVariant(this, o).toMap(); } @@ -1630,93 +1593,90 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data) return 0; } -void ExecutionEngine::assertObjectBelongsToEngine(const Value &v) +void ExecutionEngine::assertObjectBelongsToEngine(const Heap::Base &baseObject) { - Q_UNUSED(v); - Q_ASSERT(!v.isObject() || v.objectValue()->engine() == this); - Q_UNUSED(v); + Q_ASSERT(!baseObject.vtable()->isObject || static_cast<const Heap::Object&>(baseObject).internalClass->engine == this); + Q_UNUSED(baseObject); } // Converts a JS value to a meta-type. // data must point to a place that can store a value of the given type. // Returns true if conversion succeeded, false otherwise. -bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *data) +bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) { - QV4::Scope scope(this); - // check if it's one of the types we know switch (QMetaType::Type(type)) { case QMetaType::Bool: - *reinterpret_cast<bool*>(data) = value.toBoolean(); + *reinterpret_cast<bool*>(data) = value->toBoolean(); return true; case QMetaType::Int: - *reinterpret_cast<int*>(data) = value.toInt32(); + *reinterpret_cast<int*>(data) = value->toInt32(); return true; case QMetaType::UInt: - *reinterpret_cast<uint*>(data) = value.toUInt32(); + *reinterpret_cast<uint*>(data) = value->toUInt32(); return true; case QMetaType::LongLong: - *reinterpret_cast<qlonglong*>(data) = qlonglong(value.toInteger()); + *reinterpret_cast<qlonglong*>(data) = qlonglong(value->toInteger()); return true; case QMetaType::ULongLong: - *reinterpret_cast<qulonglong*>(data) = qulonglong(value.toInteger()); + *reinterpret_cast<qulonglong*>(data) = qulonglong(value->toInteger()); return true; case QMetaType::Double: - *reinterpret_cast<double*>(data) = value.toNumber(); + *reinterpret_cast<double*>(data) = value->toNumber(); return true; case QMetaType::QString: - if (value.isUndefined() || value.isNull()) + if (value->isUndefined() || value->isNull()) *reinterpret_cast<QString*>(data) = QString(); else - *reinterpret_cast<QString*>(data) = value.toQString(); + *reinterpret_cast<QString*>(data) = value->toQString(); return true; case QMetaType::Float: - *reinterpret_cast<float*>(data) = value.toNumber(); + *reinterpret_cast<float*>(data) = value->toNumber(); return true; case QMetaType::Short: - *reinterpret_cast<short*>(data) = short(value.toInt32()); + *reinterpret_cast<short*>(data) = short(value->toInt32()); return true; case QMetaType::UShort: - *reinterpret_cast<unsigned short*>(data) = value.toUInt16(); + *reinterpret_cast<unsigned short*>(data) = value->toUInt16(); return true; case QMetaType::Char: - *reinterpret_cast<char*>(data) = char(value.toInt32()); + *reinterpret_cast<char*>(data) = char(value->toInt32()); return true; case QMetaType::UChar: - *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value.toInt32()); + *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->toInt32()); return true; case QMetaType::QChar: - if (value.isString()) { - QString str = value.stringValue()->toQString(); + if (value->isString()) { + QString str = value->stringValue()->toQString(); *reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0); } else { - *reinterpret_cast<QChar*>(data) = QChar(ushort(value.toUInt16())); + *reinterpret_cast<QChar*>(data) = QChar(ushort(value->toUInt16())); } return true; case QMetaType::QDateTime: - if (QV4::DateObject *d = value.asDateObject()) { + if (const QV4::DateObject *d = value->as<DateObject>()) { *reinterpret_cast<QDateTime *>(data) = d->toQDateTime(); return true; } break; case QMetaType::QDate: - if (QV4::DateObject *d = value.asDateObject()) { + if (const QV4::DateObject *d = value->as<DateObject>()) { *reinterpret_cast<QDate *>(data) = d->toQDateTime().date(); return true; } break; case QMetaType::QRegExp: - if (QV4::RegExpObject *r = value.as<QV4::RegExpObject>()) { + if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) { *reinterpret_cast<QRegExp *>(data) = r->toQRegExp(); return true; } break; case QMetaType::QObjectStar: { - QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>(); - if (qobjectWrapper || value.isNull()) { - *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(scope.engine, value); + const QV4::QObjectWrapper *qobjectWrapper = value->as<QV4::QObjectWrapper>(); + if (qobjectWrapper || value->isNull()) { + *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(this, *value); return true; } break; } case QMetaType::QStringList: { - QV4::ScopedArrayObject a(scope, value); + const QV4::ArrayObject *a = value->as<QV4::ArrayObject>(); if (a) { *reinterpret_cast<QStringList *>(data) = a->toQStringList(); return true; @@ -1724,15 +1684,15 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da break; } case QMetaType::QVariantList: { - QV4::ScopedArrayObject a(scope, value); + const QV4::ArrayObject *a = value->as<QV4::ArrayObject>(); if (a) { - *reinterpret_cast<QVariantList *>(data) = scope.engine->toVariant(a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList(); + *reinterpret_cast<QVariantList *>(data) = toVariant(*a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList(); return true; } break; } case QMetaType::QVariantMap: { - QV4::ScopedObject o(scope, value); + const QV4::Object *o = value->as<QV4::Object>(); if (o) { *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(o); return true; @@ -1740,20 +1700,19 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da break; } case QMetaType::QVariant: - *reinterpret_cast<QVariant*>(data) = scope.engine->toVariant(value, /*typeHint*/-1, /*createJSValueForObjects*/false); + *reinterpret_cast<QVariant*>(data) = toVariant(*value, /*typeHint*/-1, /*createJSValueForObjects*/false); return true; case QMetaType::QJsonValue: - *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(value); + *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(*value); return true; case QMetaType::QJsonObject: { - QV4::ScopedObject o(scope, value); - *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(o); + *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(value->as<Object>()); return true; } case QMetaType::QJsonArray: { - QV4::ScopedArrayObject a(scope, value); + const QV4::ArrayObject *a = value->as<ArrayObject>(); if (a) { - *reinterpret_cast<QJsonArray *>(data) = QV4::JsonObject::toJsonArray(a); + *reinterpret_cast<QJsonArray *>(data) = JsonObject::toJsonArray(a); return true; } break; @@ -1763,7 +1722,7 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da } { - QV4::Scoped<QV4::QQmlValueTypeWrapper> vtw(scope, value); + const QQmlValueTypeWrapper *vtw = value->as<QQmlValueTypeWrapper>(); if (vtw && vtw->typeId() == type) { return vtw->toGadget(data); } @@ -1788,21 +1747,22 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da } #endif - // Try to use magic; for compatibility with qscriptvalue_cast. + // Try to use magic; for compatibility with qjsvalue_cast. QByteArray name = QMetaType::typeName(type); - if (convertToNativeQObject(this, value, name, reinterpret_cast<void* *>(data))) + if (convertToNativeQObject(this, *value, name, reinterpret_cast<void* *>(data))) return true; - if (value.as<QV4::VariantObject>() && name.endsWith('*')) { + if (value->as<QV4::VariantObject>() && name.endsWith('*')) { int valueType = QMetaType::type(name.left(name.size()-1)); - QVariant &var = value.as<QV4::VariantObject>()->d()->data; + QVariant &var = value->as<QV4::VariantObject>()->d()->data; if (valueType == var.userType()) { // We have T t, T* is requested, so return &t. *reinterpret_cast<void* *>(data) = var.data(); return true; - } else if (value.isObject()) { + } else if (value->isObject()) { // Look in the prototype chain. - QV4::ScopedObject proto(scope, value.objectValue()->prototype()); + QV4::Scope scope(this); + QV4::ScopedObject proto(scope, value->objectValue()->prototype()); while (proto) { bool canCast = false; if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) { @@ -1812,7 +1772,7 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da else if (proto->as<QV4::QObjectWrapper>()) { QByteArray className = name.left(name.size()-1); QV4::ScopedObject p(scope, proto.getPointer()); - if (QObject *qobject = qtObjectFromJS(scope.engine, p)) + if (QObject *qobject = qtObjectFromJS(this, p)) canCast = qobject->qt_metacast(className) != 0; } if (canCast) { @@ -1826,11 +1786,11 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da proto = proto->prototype(); } } - } else if (value.isNull() && name.endsWith('*')) { + } else if (value->isNull() && name.endsWith('*')) { *reinterpret_cast<void* *>(data) = 0; return true; } else if (type == qMetaTypeId<QJSValue>()) { - *reinterpret_cast<QJSValue*>(data) = QJSValue(this, value.asReturnedValue()); + *reinterpret_cast<QJSValue*>(data) = QJSValue(this, value->asReturnedValue()); return true; } diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index c0c88abaa5..4640f3f4cc 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -33,10 +33,22 @@ #ifndef QV4ENGINE_H #define QV4ENGINE_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include "private/qv4isel_p.h" #include "qv4managed_p.h" #include "qv4context_p.h" +#include "qv4internalclass_p.h" #include <private/qintrusivelist_p.h> namespace WTF { @@ -50,6 +62,7 @@ class QV8Engine; class QQmlError; class QJSEngine; class QQmlEngine; +class QQmlContextData; namespace QV4 { namespace Debugging { @@ -76,18 +89,16 @@ private: friend struct Heap::ExecutionContext; public: Heap::ExecutionContext *current; - Heap::ExecutionContext *currentContext() const { return current; } Value *jsStackTop; quint32 hasException; - Heap::GlobalContext *m_rootContext; - Heap::GlobalContext *rootContext() const { return m_rootContext; } MemoryManager *memoryManager; ExecutableAllocator *executableAllocator; ExecutableAllocator *regExpAllocator; QScopedPointer<EvalISelFactory> iselFactory; + ExecutionContext *currentContext; Value *jsStackLimit; quintptr cStackLimit; @@ -106,14 +117,19 @@ public: --jsStackTop; return jsStackTop->heapObject(); } + Value *jsAlloca(int nValues) { + Value *ptr = jsStackTop; + jsStackTop = ptr + nValues; + memset(ptr, 0, nValues*sizeof(Value)); + return ptr; + } IdentifierTable *identifierTable; QV4::Debugging::Debugger *debugger; QV4::Profiling::Profiler *profiler; - Value m_globalObject; - Object *globalObject() { return reinterpret_cast<Object *>(&m_globalObject); } + Object *globalObject; Function *globalCode; @@ -121,104 +137,206 @@ public: QQmlEngine *qmlEngine() const; QV8Engine *v8Engine; - Value objectCtor; - Value stringCtor; - Value numberCtor; - Value booleanCtor; - Value arrayCtor; - Value functionCtor; - Value dateCtor; - Value regExpCtor; - Value errorCtor; - Value evalErrorCtor; - Value rangeErrorCtor; - Value referenceErrorCtor; - Value syntaxErrorCtor; - Value typeErrorCtor; - Value uRIErrorCtor; - Value arrayBufferCtor; - Value dataViewCtor; - enum { NTypedArrayTypes = 9 }; // avoid header dependency - Value typedArrayCtors[NTypedArrayTypes]; - - Value objectPrototype; - Value arrayPrototype; - Value stringPrototype; - Value numberPrototype; - Value booleanPrototype; - Value datePrototype; - Value functionPrototype; - Value regExpPrototype; - Value errorPrototype; - Value evalErrorPrototype; - Value rangeErrorPrototype; - Value referenceErrorPrototype; - Value syntaxErrorPrototype; - Value typeErrorPrototype; - Value uRIErrorPrototype; - Value variantPrototype; - Value sequencePrototype; - - Value arrayBufferPrototype; - Value dataViewPrototype; - Value typedArrayPrototype[NTypedArrayTypes]; // TypedArray::NValues, avoid including the header here + enum JSObjects { + RootContext, + IntegerNull, // Has to come after the RootContext to make the context stack safe + ObjectProto, + ArrayProto, + StringProto, + NumberProto, + BooleanProto, + DateProto, + FunctionProto, + RegExpProto, + ErrorProto, + EvalErrorProto, + RangeErrorProto, + ReferenceErrorProto, + SyntaxErrorProto, + TypeErrorProto, + URIErrorProto, + VariantProto, + SequenceProto, + ArrayBufferProto, + DataViewProto, + ValueTypeProto, + SignalHandlerProto, + + Object_Ctor, + String_Ctor, + Number_Ctor, + Boolean_Ctor, + Array_Ctor, + Function_Ctor, + Date_Ctor, + RegExp_Ctor, + Error_Ctor, + EvalError_Ctor, + RangeError_Ctor, + ReferenceError_Ctor, + SyntaxError_Ctor, + TypeError_Ctor, + URIError_Ctor, + ArrayBuffer_Ctor, + 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 + 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); } + FunctionObject *booleanCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Boolean_Ctor); } + FunctionObject *arrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Array_Ctor); } + FunctionObject *functionCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Function_Ctor); } + FunctionObject *dateCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Date_Ctor); } + FunctionObject *regExpCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RegExp_Ctor); } + FunctionObject *errorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Error_Ctor); } + FunctionObject *evalErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + EvalError_Ctor); } + FunctionObject *rangeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RangeError_Ctor); } + FunctionObject *referenceErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ReferenceError_Ctor); } + FunctionObject *syntaxErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + SyntaxError_Ctor); } + FunctionObject *typeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + TypeError_Ctor); } + FunctionObject *uRIErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + URIError_Ctor); } + FunctionObject *arrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ArrayBuffer_Ctor); } + FunctionObject *dataViewCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + DataView_Ctor); } + FunctionObject *typedArrayCtors; + + Object *objectPrototype() const { return reinterpret_cast<Object *>(jsObjects + ObjectProto); } + Object *arrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayProto); } + Object *stringPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringProto); } + Object *numberPrototype() const { return reinterpret_cast<Object *>(jsObjects + NumberProto); } + Object *booleanPrototype() const { return reinterpret_cast<Object *>(jsObjects + BooleanProto); } + Object *datePrototype() const { return reinterpret_cast<Object *>(jsObjects + DateProto); } + Object *functionPrototype() const { return reinterpret_cast<Object *>(jsObjects + FunctionProto); } + Object *regExpPrototype() const { return reinterpret_cast<Object *>(jsObjects + RegExpProto); } + Object *errorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ErrorProto); } + Object *evalErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + EvalErrorProto); } + Object *rangeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + RangeErrorProto); } + Object *referenceErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ReferenceErrorProto); } + Object *syntaxErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SyntaxErrorProto); } + Object *typeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeErrorProto); } + Object *uRIErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + URIErrorProto); } + Object *variantPrototype() const { return reinterpret_cast<Object *>(jsObjects + VariantProto); } + Object *sequencePrototype() const { return reinterpret_cast<Object *>(jsObjects + SequenceProto); } + + Object *arrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayBufferProto); } + Object *dataViewPrototype() const { return reinterpret_cast<Object *>(jsObjects + DataViewProto); } + 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; - Heap::EvalFunction *evalFunction; - Heap::FunctionObject *thrower; + 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; int nArgumentsAccessors; - StringValue id_empty; - StringValue id_undefined; - StringValue id_null; - StringValue id_true; - StringValue id_false; - StringValue id_boolean; - StringValue id_number; - StringValue id_string; - StringValue id_object; - StringValue id_function; - StringValue id_length; - StringValue id_prototype; - StringValue id_constructor; - StringValue id_arguments; - StringValue id_caller; - StringValue id_callee; - StringValue id_this; - StringValue id___proto__; - StringValue id_enumerable; - StringValue id_configurable; - StringValue id_writable; - StringValue id_value; - StringValue id_get; - StringValue id_set; - StringValue id_eval; - StringValue id_uintMax; - StringValue id_name; - StringValue id_index; - StringValue id_input; - StringValue id_toString; - StringValue id_destroy; - StringValue id_valueOf; - StringValue id_byteLength; - StringValue id_byteOffset; - StringValue id_buffer; - StringValue id_lastIndex; + enum JSStrings { + String_Empty, + String_undefined, + String_null, + String_true, + String_false, + String_boolean, + String_number, + String_string, + String_object, + String_function, + String_length, + String_prototype, + String_constructor, + String_arguments, + String_caller, + String_callee, + String_this, + String___proto__, + String_enumerable, + String_configurable, + String_writable, + String_value, + String_get, + String_set, + String_eval, + String_uintMax, + String_name, + String_index, + String_input, + String_toString, + String_destroy, + String_valueOf, + String_byteLength, + String_byteOffset, + String_buffer, + String_lastIndex, + NJSStrings + }; + Value *jsStrings; + + String *id_empty() const { return reinterpret_cast<String *>(jsStrings + String_Empty); } + String *id_undefined() const { return reinterpret_cast<String *>(jsStrings + String_undefined); } + String *id_null() const { return reinterpret_cast<String *>(jsStrings + String_null); } + String *id_true() const { return reinterpret_cast<String *>(jsStrings + String_true); } + String *id_false() const { return reinterpret_cast<String *>(jsStrings + String_false); } + String *id_boolean() const { return reinterpret_cast<String *>(jsStrings + String_boolean); } + String *id_number() const { return reinterpret_cast<String *>(jsStrings + String_number); } + String *id_string() const { return reinterpret_cast<String *>(jsStrings + String_string); } + String *id_object() const { return reinterpret_cast<String *>(jsStrings + String_object); } + String *id_function() const { return reinterpret_cast<String *>(jsStrings + String_function); } + String *id_length() const { return reinterpret_cast<String *>(jsStrings + String_length); } + String *id_prototype() const { return reinterpret_cast<String *>(jsStrings + String_prototype); } + String *id_constructor() const { return reinterpret_cast<String *>(jsStrings + String_constructor); } + String *id_arguments() const { return reinterpret_cast<String *>(jsStrings + String_arguments); } + String *id_caller() const { return reinterpret_cast<String *>(jsStrings + String_caller); } + String *id_callee() const { return reinterpret_cast<String *>(jsStrings + String_callee); } + String *id_this() const { return reinterpret_cast<String *>(jsStrings + String_this); } + String *id___proto__() const { return reinterpret_cast<String *>(jsStrings + String___proto__); } + String *id_enumerable() const { return reinterpret_cast<String *>(jsStrings + String_enumerable); } + String *id_configurable() const { return reinterpret_cast<String *>(jsStrings + String_configurable); } + String *id_writable() const { return reinterpret_cast<String *>(jsStrings + String_writable); } + String *id_value() const { return reinterpret_cast<String *>(jsStrings + String_value); } + String *id_get() const { return reinterpret_cast<String *>(jsStrings + String_get); } + String *id_set() const { return reinterpret_cast<String *>(jsStrings + String_set); } + String *id_eval() const { return reinterpret_cast<String *>(jsStrings + String_eval); } + String *id_uintMax() const { return reinterpret_cast<String *>(jsStrings + String_uintMax); } + String *id_name() const { return reinterpret_cast<String *>(jsStrings + String_name); } + String *id_index() const { return reinterpret_cast<String *>(jsStrings + String_index); } + String *id_input() const { return reinterpret_cast<String *>(jsStrings + String_input); } + String *id_toString() const { return reinterpret_cast<String *>(jsStrings + String_toString); } + String *id_destroy() const { return reinterpret_cast<String *>(jsStrings + String_destroy); } + String *id_valueOf() const { return reinterpret_cast<String *>(jsStrings + String_valueOf); } + String *id_byteLength() const { return reinterpret_cast<String *>(jsStrings + String_byteLength); } + String *id_byteOffset() const { return reinterpret_cast<String *>(jsStrings + String_byteOffset); } + String *id_buffer() const { return reinterpret_cast<String *>(jsStrings + String_buffer); } + String *id_lastIndex() const { return reinterpret_cast<String *>(jsStrings + String_lastIndex); } QSet<CompiledData::CompilationUnit*> compilationUnits; @@ -248,12 +366,14 @@ public: ExecutionEngine(EvalISelFactory *iselFactory = 0); ~ExecutionEngine(); - void enableDebugger(); + void setDebugger(Debugging::Debugger *debugger); 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); @@ -261,15 +381,17 @@ public: Heap::String *newString(const QString &s = QString()); Heap::String *newIdentifier(const QString &text); - Heap::Object *newStringObject(const Value &value); + Heap::Object *newStringObject(const String *string); Heap::Object *newNumberObject(double value); 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); @@ -282,7 +404,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); @@ -291,7 +413,11 @@ public: Heap::Object *newForEachIteratorObject(Object *o); - Heap::Object *qmlContextObject() const; + Heap::QmlContext *qmlContext() const; + QObject *qmlScopeObject() const; + ReturnedValue qmlSingletonWrapper(String *name); + QQmlContextData *callingQmlContext() const; + StackTrace stackTrace(int frameLimit = -1) const; StackFrame currentStackFrame() const; @@ -305,12 +431,10 @@ public: InternalClass *newClass(const InternalClass &other); - QmlExtensions *qmlExtensions(); - bool recheckCStackLimits(); // Exception handling - Value exceptionValue; + Value *exceptionValue; StackTrace exceptionStackTrace; ReturnedValue throwError(const Value &value); @@ -335,70 +459,62 @@ public: QVariant toVariant(const QV4::Value &value, int typeHint, bool createJSValueForObjects = true); QV4::ReturnedValue fromVariant(const QVariant &); - QVariantMap variantMapFromJS(QV4::Object *o); + QVariantMap variantMapFromJS(const QV4::Object *o); - bool metaTypeFromJS(const Value &value, int type, void *data); + bool metaTypeFromJS(const Value *value, int type, void *data); QV4::ReturnedValue metaTypeToJS(int type, const void *data); - void assertObjectBelongsToEngine(const Value &v); - -private: - QmlExtensions *m_qmlExtensions; + 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(); } - -// ### Remove me inline -void Managed::mark(QV4::ExecutionEngine *engine) +void Heap::Base::mark(QV4::ExecutionEngine *engine) { Q_ASSERT(inUse()); - if (markBit()) + if (isMarked()) return; #ifndef QT_NO_DEBUG engine->assertObjectBelongsToEngine(*this); #endif - d()->setMarkBit(); - engine->pushForGC(d()); + setMarkBit(); + engine->pushForGC(this); } - -inline -void Heap::Base::mark(QV4::ExecutionEngine *engine) +inline void Value::mark(ExecutionEngine *e) { - Q_ASSERT(inUse()); - if (isMarked()) + if (!isManaged()) return; - setMarkBit(); - engine->pushForGC(this); + + Heap::Base *o = heapObject(); + if (o) + o->mark(e); } diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 9034dee6a0..87b7a88a2b 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -33,11 +33,14 @@ #include "qv4errorobject_p.h" -#include "qv4mm_p.h" +#include <QtCore/qnumeric.h> +#include <QtCore/qmath.h> #include <QtCore/QDateTime> #include <QtCore/QStringList> #include <QtCore/QDebug> +#include "qv4string_p.h" +#include <private/qv4mm_p.h> #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> #include <private/qqmljsparser_p.h> @@ -58,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; @@ -133,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) @@ -178,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.asObject(), msg, SyntaxError) -{ -} - -Heap::SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) - : Heap::ErrorObject(engine->emptyClass, engine->syntaxErrorPrototype.asObject(), msg, fileName, lineNumber, columnNumber, SyntaxError) -{ -} - -Heap::EvalErrorObject::EvalErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->evalErrorPrototype.asObject(), message, EvalError) -{ -} - -Heap::RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->rangeErrorPrototype.asObject(), 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.asObject(), 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.asObject(), 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.asObject(), 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.asObject(), 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.asObject(), 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.asObject(), 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.asObject(), message, URIError) +Heap::URIErrorObject::URIErrorObject(const Value &message) + : Heap::ErrorObject(message, URIError) { } @@ -251,16 +237,16 @@ Heap::ErrorCtor::ErrorCtor(QV4::ExecutionContext *scope, const QString &name) { } -ReturnedValue ErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue ErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<ErrorCtor *>(m)->engine()); + 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(Managed *that, CallData *callData) +ReturnedValue ErrorCtor::call(const Managed *that, CallData *callData) { - return static_cast<Object *>(that)->construct(callData); + return static_cast<const Object *>(that)->construct(callData); } Heap::EvalErrorCtor::EvalErrorCtor(QV4::ExecutionContext *scope) @@ -268,11 +254,11 @@ Heap::EvalErrorCtor::EvalErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue EvalErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue EvalErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<EvalErrorCtor *>(m)->engine()); + 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) @@ -280,11 +266,11 @@ Heap::RangeErrorCtor::RangeErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue RangeErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue RangeErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<RangeErrorCtor *>(m)->engine()); + 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) @@ -292,11 +278,11 @@ Heap::ReferenceErrorCtor::ReferenceErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ReferenceErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue ReferenceErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<ReferenceErrorCtor *>(m)->engine()); + 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) @@ -304,11 +290,11 @@ Heap::SyntaxErrorCtor::SyntaxErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue SyntaxErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue SyntaxErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<SyntaxErrorCtor *>(m)->engine()); + 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) @@ -316,11 +302,11 @@ Heap::TypeErrorCtor::TypeErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue TypeErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue TypeErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<TypeErrorCtor *>(m)->engine()); + 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) @@ -328,41 +314,43 @@ Heap::URIErrorCtor::URIErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue URIErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue URIErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<URIErrorCtor *>(m)->engine()); + 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())); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = obj)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + *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) { Scope scope(ctx); - Object *o = ctx->thisObject().asObject(); + Object *o = ctx->thisObject().as<Object>(); if (!o) return ctx->engine()->throwTypeError(); - ScopedValue name(scope, o->get(ctx->d()->engine->id_name)); + ScopedValue name(scope, o->get(ctx->d()->engine->id_name())); QString qname; if (name->isUndefined()) - qname = QString::fromLatin1("Error"); + qname = QStringLiteral("Error"); else qname = name->toQString(); - ScopedString s(scope, ctx->d()->engine->newString(QString::fromLatin1("message"))); + ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("message"))); ScopedValue message(scope, o->get(s)); QString qmessage; if (!message->isUndefined()) diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 071f5b8c9a..336050ab2b 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -33,8 +33,20 @@ #ifndef QV4ERROROBJECT_H #define QV4ERROROBJECT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" +#include "qv4string_p.h" QT_BEGIN_NAMESPACE @@ -55,43 +67,39 @@ 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; - String *stack; + Pointer<String> stack; }; 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,51 +138,75 @@ 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); }; template<> -inline ErrorObject *value_cast(const Value &v) { - return v.asErrorObject(); +inline const ErrorObject *Value::as() const { + return isManaged() && m() && m()->vtable()->isErrorObject ? reinterpret_cast<const ErrorObject *>(this) : 0; } 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()); } }; @@ -183,89 +215,94 @@ struct ErrorCtor: FunctionObject { V4_OBJECT2(ErrorCtor, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct EvalErrorCtor: ErrorCtor { V4_OBJECT2(EvalErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct RangeErrorCtor: ErrorCtor { V4_OBJECT2(RangeErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct ReferenceErrorCtor: ErrorCtor { V4_OBJECT2(ReferenceErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct SyntaxErrorCtor: ErrorCtor { V4_OBJECT2(SyntaxErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct TypeErrorCtor: ErrorCtor { V4_OBJECT2(TypeErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct URIErrorCtor: ErrorCtor { V4_OBJECT2(URIErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; 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 +311,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/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h index 0d07e3c1bd..bb63d423a6 100644 --- a/src/qml/jsruntime/qv4executableallocator_p.h +++ b/src/qml/jsruntime/qv4executableallocator_p.h @@ -34,6 +34,17 @@ #ifndef QV4EXECUTABLEALLOCATOR_H #define QV4EXECUTABLEALLOCATOR_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include <QMultiMap> diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index be63b31e1e..66b2125a4f 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -34,10 +34,10 @@ #include "qv4function_p.h" #include "qv4managed_p.h" #include "qv4string_p.h" -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #include "qv4engine_p.h" #include "qv4lookup_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> QT_BEGIN_NAMESPACE @@ -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..0e1216a45b 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -33,6 +33,17 @@ #ifndef QV4FUNCTION_H #define QV4FUNCTION_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include <private/qv4compileddata_p.h> @@ -49,11 +60,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 +80,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 0a12d013ac..1194033872 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -37,7 +37,7 @@ #include "qv4objectproto_p.h" #include "qv4stringobject_p.h" #include "qv4function_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4arrayobject_p.h" #include "qv4scopedvalue_p.h" @@ -46,7 +46,7 @@ #include <private/qqmljslexer_p.h> #include <private/qqmljsparser_p.h> #include <private/qqmljsast_p.h> -#include <private/qqmlcontextwrapper_p.h> +#include <private/qqmljavascriptexpression_p.h> #include <private/qqmlengine_p.h> #include <qv4codegen_p.h> #include "private/qlocale_tools_p.h" @@ -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.asObject()) - , 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.asObject()) - , 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.asObject()) - , 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.asObject()) - , 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.asObject()) - , 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.asObject()) - , 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()) +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,23 +141,23 @@ 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.asObject())); - 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(); + ScopedObject proto(s, scope()->engine->newObject(s.engine->protoClass, s.engine->objectPrototype())); + 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); - defineReadonlyProperty(s.engine->id_name, v); + defineReadonlyProperty(s.engine->id_name(), v); } -ReturnedValue FunctionObject::name() +ReturnedValue FunctionObject::name() const { - return get(scope()->engine->id_name); + return get(scope()->engine->id_name()); } @@ -177,13 +168,12 @@ ReturnedValue FunctionObject::newInstance() return construct(callData); } -ReturnedValue FunctionObject::construct(Managed *that, CallData *) +ReturnedValue FunctionObject::construct(const Managed *that, CallData *) { - static_cast<FunctionObject *>(that)->internalClass()->engine->throwTypeError(); - return Encode::undefined(); + return static_cast<const FunctionObject *>(that)->engine()->throwTypeError(); } -ReturnedValue FunctionObject::call(Managed *, CallData *) +ReturnedValue FunctionObject::call(const Managed *, CallData *) { return Encode::undefined(); } @@ -203,18 +193,36 @@ 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(); + return d()->vtable() == QQmlBindingFunction::staticVTable(); } bool FunctionObject::isBoundFunction() const { - return d()->vtable == BoundFunction::staticVTable(); + return d()->vtable() == BoundFunction::staticVTable(); } QQmlSourceLocation FunctionObject::sourceLocation() const @@ -237,11 +245,11 @@ Heap::FunctionCtor::FunctionCtor(QV4::ExecutionContext *scope) } // 15.3.2 -ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) +ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) { - Scope scope(static_cast<Object *>(that)->engine()); - Scoped<FunctionCtor> f(scope, static_cast<FunctionCtor *>(that)); - ScopedContext ctx(scope, scope.engine->currentContext()); + Scope scope(static_cast<const Object *>(that)->engine()); + Scoped<FunctionCtor> f(scope, static_cast<const FunctionCtor *>(that)); + QString arguments; QString body; if (callData->argc > 0) { @@ -252,10 +260,10 @@ ReturnedValue FunctionCtor::construct(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("}"); + QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1Char('}'); QQmlJS::Engine ee, *engine = ⅇ QQmlJS::Lexer lexer(engine); @@ -282,20 +290,19 @@ ReturnedValue FunctionCtor::construct(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(); } // 15.3.1: This is equivalent to new Function(...) -ReturnedValue FunctionCtor::call(Managed *that, CallData *callData) +ReturnedValue FunctionCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } DEFINE_OBJECT_VTABLE(FunctionPrototype); -Heap::FunctionPrototype::FunctionPrototype(InternalClass *ic, QV4::Object *prototype) - : Heap::FunctionObject(ic, prototype) +Heap::FunctionPrototype::FunctionPrototype() { } @@ -304,12 +311,12 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor) Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); - defineReadonlyProperty(engine->id_length, Primitive::fromInt32(0)); + defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(0)); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString, 0); + defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("apply"), method_apply, 2); defineDefaultProperty(QStringLiteral("call"), method_call, 1); defineDefaultProperty(QStringLiteral("bind"), method_bind, 1); @@ -318,7 +325,7 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor) ReturnedValue FunctionPrototype::method_toString(CallContext *ctx) { - FunctionObject *fun = ctx->thisObject().asFunctionObject(); + FunctionObject *fun = ctx->thisObject().as<FunctionObject>(); if (!fun) return ctx->engine()->throwTypeError(); @@ -328,7 +335,7 @@ ReturnedValue FunctionPrototype::method_toString(CallContext *ctx) ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) { Scope scope(ctx); - ScopedFunctionObject o(scope, ctx->thisObject().asFunctionObject()); + ScopedFunctionObject o(scope, ctx->thisObject().as<FunctionObject>()); if (!o) return ctx->engine()->throwTypeError(); @@ -370,7 +377,7 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx) { Scope scope(ctx); - ScopedFunctionObject o(scope, ctx->thisObject().asFunctionObject()); + ScopedFunctionObject o(scope, ctx->thisObject().as<FunctionObject>()); if (!o) return ctx->engine()->throwTypeError(); @@ -393,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(); } @@ -409,29 +416,30 @@ Heap::ScriptFunction::ScriptFunction(QV4::ExecutionContext *scope, Function *fun { } -ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData) +ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(that)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<ScriptFunction> f(scope, static_cast<ScriptFunction *>(that)); + 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()) - QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction); + QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction); if (v4->hasException) return Encode::undefined(); @@ -441,24 +449,24 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData) return obj.asReturnedValue(); } -ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) +ReturnedValue ScriptFunction::call(const Managed *that, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(that)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<ScriptFunction> f(scope, static_cast<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()) - QmlContextWrapper::registerQmlDependencies(ctx->d()->engine, f->function()->compiledFunction); + QQmlPropertyCapture::registerQmlDependencies(scope.engine, f->function()->compiledFunction); return result->asReturnedValue(); } @@ -466,7 +474,6 @@ ReturnedValue ScriptFunction::call(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.asObject()) { this->scope = scope->d(); @@ -481,40 +488,42 @@ Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, F if (createProto) { ScopedString name(s, function->name()); f->init(name, createProto); - f->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(f->formalParameterCount())); + 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) { ScopedProperty pd(s); - pd->value = s.engine->thrower; - pd->set = s.engine->thrower; - f->insertMember(scope->d()->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - f->insertMember(scope->d()->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + pd->value = s.engine->thrower(); + pd->set = s.engine->thrower(); + f->insertMember(scope->d()->engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + f->insertMember(scope->d()->engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); } } -ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData) +ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(that)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that)); + 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); - ctx.vtable = CallContext::staticVTable(); + ctx.mm_data = 0; + ctx.setVtable(CallContext::staticVTable()); ctx.strictMode = f->strictMode(); ctx.callData = callData; ctx.function = f->d(); @@ -524,32 +533,34 @@ ReturnedValue SimpleScriptFunction::construct(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); ScopedObject result(scope, Q_V4_PROFILE(v4, f->function())); if (f->function()->compiledFunction->hasQmlDependencies()) - QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction); + QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction); if (!result) return callData->thisObject.asReturnedValue(); return result.asReturnedValue(); } -ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData) +ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData) { - ExecutionEngine *v4 = static_cast<SimpleScriptFunction *>(that)->internalClass()->engine; + ExecutionEngine *v4 = static_cast<const SimpleScriptFunction *>(that)->internalClass()->engine; if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that)); + ExecutionContextSaver ctxSaver(scope); - ExecutionContextSaver ctxSaver(scope, v4->currentContext()); + Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); CallContext::Data ctx(v4); - ctx.vtable = CallContext::staticVTable(); + ctx.mm_data = 0; + ctx.setVtable(CallContext::staticVTable()); ctx.strictMode = f->strictMode(); ctx.callData = callData; ctx.function = f->d(); @@ -559,12 +570,13 @@ ReturnedValue SimpleScriptFunction::call(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())); if (f->function()->compiledFunction->hasQmlDependencies()) - QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction); + QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction); return result->asReturnedValue(); } @@ -575,7 +587,7 @@ Heap::Object *SimpleScriptFunction::protoForConstructor() ScopedObject p(scope, protoProperty()); if (p) return p->d(); - return scope.engine->objectPrototype.asObject()->d(); + return scope.engine->objectPrototype()->d(); } @@ -588,51 +600,53 @@ Heap::BuiltinFunction::BuiltinFunction(QV4::ExecutionContext *scope, QV4::String { } -ReturnedValue BuiltinFunction::construct(Managed *f, CallData *) +ReturnedValue BuiltinFunction::construct(const Managed *f, CallData *) { - return static_cast<BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); + return static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); } -ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData) +ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData) { - BuiltinFunction *f = static_cast<BuiltinFunction *>(that); + const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that); ExecutionEngine *v4 = f->internalClass()->engine; if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - ExecutionContextSaver ctxSaver(scope, v4->currentContext()); + ExecutionContextSaver ctxSaver(scope); CallContext::Data ctx(v4); - ctx.vtable = CallContext::staticVTable(); + ctx.mm_data = 0; + 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(Managed *that, CallData *callData) +ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callData) { - IndexedBuiltinFunction *f = static_cast<IndexedBuiltinFunction *>(that); + const IndexedBuiltinFunction *f = static_cast<const IndexedBuiltinFunction *>(that); ExecutionEngine *v4 = f->internalClass()->engine; if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - ExecutionContextSaver ctxSaver(scope, v4->currentContext()); + ExecutionContextSaver ctxSaver(scope); CallContext::Data ctx(v4); - ctx.vtable = CallContext::staticVTable(); + ctx.mm_data = 0; + 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); @@ -650,24 +664,24 @@ Heap::BoundFunction::BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionOb Scope s(scope); ScopedObject f(s, this); - ScopedValue l(s, target->get(s.engine->id_length)); + ScopedValue l(s, target->get(s.engine->id_length())); int len = l->toUInt32(); if (boundArgs) len -= boundArgs->size(); if (len < 0) len = 0; - f->defineReadonlyProperty(s.engine->id_length, Primitive::fromInt32(len)); + f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(len)); ScopedProperty pd(s); - pd->value = s.engine->thrower; - pd->set = s.engine->thrower; - f->insertMember(s.engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - f->insertMember(s.engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + pd->value = s.engine->thrower(); + pd->set = s.engine->thrower(); + f->insertMember(s.engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); } -ReturnedValue BoundFunction::call(Managed *that, CallData *dd) +ReturnedValue BoundFunction::call(const Managed *that, CallData *dd) { - BoundFunction *f = static_cast<BoundFunction *>(that); + const BoundFunction *f = static_cast<const BoundFunction *>(that); Scope scope(f->engine()); if (scope.hasException()) return Encode::undefined(); @@ -685,9 +699,9 @@ ReturnedValue BoundFunction::call(Managed *that, CallData *dd) return t->call(callData); } -ReturnedValue BoundFunction::construct(Managed *that, CallData *dd) +ReturnedValue BoundFunction::construct(const Managed *that, CallData *dd) { - BoundFunction *f = static_cast<BoundFunction *>(that); + const BoundFunction *f = static_cast<const BoundFunction *>(that); Scope scope(f->engine()); if (scope.hasException()) return Encode::undefined(); @@ -707,7 +721,8 @@ ReturnedValue BoundFunction::construct(Managed *that, CallData *dd) void BoundFunction::markObjects(Heap::Base *that, ExecutionEngine *e) { BoundFunction::Data *o = static_cast<BoundFunction::Data *>(that); - o->target->mark(e); + if (o->target) + o->target->mark(e); o->boundThis.mark(e); if (o->boundArgs) o->boundArgs->mark(e); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 252ff40a1a..896bd2a4d2 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -33,10 +33,21 @@ #ifndef QV4FUNCTIONOBJECT_H #define QV4FUNCTIONOBJECT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4function_p.h" #include "qv4context_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> QT_BEGIN_NAMESPACE @@ -58,14 +69,14 @@ 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; } - ExecutionContext *scope; + Pointer<ExecutionContext> scope; Function *function; }; @@ -74,7 +85,7 @@ struct FunctionCtor : FunctionObject { }; struct FunctionPrototype : FunctionObject { - FunctionPrototype(InternalClass *ic, QV4::Object *prototype); + FunctionPrototype(); }; struct Q_QML_EXPORT BuiltinFunction : FunctionObject { @@ -102,9 +113,9 @@ struct ScriptFunction : SimpleScriptFunction { struct BoundFunction : FunctionObject { BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs); - FunctionObject *target; + Pointer<FunctionObject> target; Value boundThis; - MemberData *boundArgs; + Pointer<MemberData> boundArgs; }; } @@ -115,14 +126,16 @@ 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() { return d()->scope; } - Function *function() { return d()->function; } + Heap::ExecutionContext *scope() const { return d()->scope; } + Function *function() const { return d()->function; } - ReturnedValue name(); - unsigned int formalParameterCount() { return d()->formalParameterCount(); } - unsigned int varCount() { return d()->varCount(); } + ReturnedValue name() const; + unsigned int formalParameterCount() const { return d()->formalParameterCount(); } + unsigned int varCount() const { return d()->varCount(); } void init(String *name, bool createProto); @@ -130,16 +143,14 @@ struct Q_QML_EXPORT FunctionObject: Object { using Object::construct; using Object::call; - static ReturnedValue construct(Managed *that, CallData *); - static ReturnedValue call(Managed *that, CallData *d); - - static FunctionObject *cast(const Value &v) { - return v.asFunctionObject(); - } + static ReturnedValue construct(const Managed *that, CallData *); + 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; } @@ -152,16 +163,17 @@ struct Q_QML_EXPORT FunctionObject: Object { }; template<> -inline FunctionObject *value_cast(const Value &v) { - return v.asFunctionObject(); +inline const FunctionObject *Value::as() const { + return isManaged() && m() && m()->vtable()->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : 0; } + struct FunctionCtor: FunctionObject { V4_OBJECT2(FunctionCtor, FunctionObject) - static ReturnedValue construct(Managed *that, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct FunctionPrototype: FunctionObject @@ -181,23 +193,23 @@ 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(Managed *, CallData *); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct IndexedBuiltinFunction: FunctionObject { V4_OBJECT2(IndexedBuiltinFunction, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *) + static ReturnedValue construct(const Managed *m, CallData *) { - return static_cast<IndexedBuiltinFunction *>(m)->engine()->throwTypeError(); + return static_cast<const IndexedBuiltinFunction *>(m)->engine()->throwTypeError(); } - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; Heap::IndexedBuiltinFunction::IndexedBuiltinFunction(QV4::ExecutionContext *scope, uint index, @@ -211,9 +223,10 @@ Heap::IndexedBuiltinFunction::IndexedBuiltinFunction(QV4::ExecutionContext *scop struct SimpleScriptFunction: FunctionObject { V4_OBJECT2(SimpleScriptFunction, FunctionObject) + V4_INTERNALCLASS(simpleScriptFunctionClass) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); Heap::Object *protoForConstructor(); }; @@ -221,8 +234,8 @@ struct SimpleScriptFunction: FunctionObject { struct ScriptFunction: SimpleScriptFunction { V4_OBJECT2(ScriptFunction, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; @@ -231,15 +244,15 @@ 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() { return d()->target; } + Heap::FunctionObject *target() const { return d()->target; } Value boundThis() const { return d()->boundThis; } Heap::MemberData *boundArgs() const { return d()->boundArgs; } - static ReturnedValue construct(Managed *, CallData *d); - static ReturnedValue call(Managed *that, CallData *dd); + static ReturnedValue construct(const Managed *, CallData *d); + static ReturnedValue call(const Managed *that, CallData *dd); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 4b08194b60..01a21ea06d 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -34,6 +34,17 @@ #ifndef QV4GLOBAL_H #define QV4GLOBAL_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) #define V4_BOOTSTRAP #endif @@ -88,6 +99,8 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } #define V4_ENABLE_JIT #endif +#elif defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX) +#define V4_ENABLE_JIT #endif // Black list some platforms @@ -168,7 +181,7 @@ struct Property; struct Value; struct Lookup; struct ArrayData; -struct ManagedVTable; +struct VTable; struct BooleanObject; struct NumberObject; @@ -211,7 +224,6 @@ class WeakValue; struct IdentifierTable; class RegExpCache; class MultiplyWrappedQObjectMap; -struct QmlExtensions; namespace Global { enum { @@ -277,8 +289,6 @@ struct PropertyAttributes setConfigurable(!(f & Attr_NotConfigurable)); } } - PropertyAttributes(const PropertyAttributes &other) : m_all(other.m_all) {} - PropertyAttributes & operator=(const PropertyAttributes &other) { m_all = other.m_all; return *this; } void setType(Type t) { m_type = t; type_set = true; } Type type() const { return type_set ? (Type)m_type : Generic; } diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 8e33cec57f..110a2c9089 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -32,13 +32,15 @@ ****************************************************************************/ #include "qv4globalobject_p.h" -#include "qv4mm_p.h" -#include "qv4value_inl_p.h" +#include <private/qv4mm_p.h> +#include "qv4value_p.h" #include "qv4context_p.h" #include "qv4function_p.h" #include "qv4debugging_p.h" +#include "qv4profiling_p.h" #include "qv4script_p.h" #include "qv4scopedvalue_p.h" +#include "qv4string_p.h" #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> @@ -47,6 +49,7 @@ #include <qv4jsir_p.h> #include <qv4codegen_p.h> #include "private/qlocale_tools_p.h" +#include "private/qtools_p.h" #include <QtCore/QDebug> #include <QtCore/QString> @@ -56,25 +59,8 @@ #include <wtf/MathExtras.h> using namespace QV4; - - -static inline char toHex(char c) -{ - static const char hexnumbers[] = "0123456789ABCDEF"; - return hexnumbers[c & 0xf]; -} - -static int fromHex(QChar ch) -{ - ushort c = ch.unicode(); - if ((c >= '0') && (c <= '9')) - return c - '0'; - if ((c >= 'A') && (c <= 'F')) - return c - 'A' + 10; - if ((c >= 'a') && (c <= 'f')) - return c - 'a' + 10; - return -1; -} +using QtMiscUtils::toHexUpper; +using QtMiscUtils::fromHex; static QString escape(const QString &input) { @@ -93,16 +79,16 @@ static QString escape(const QString &input) output.append(QChar(uc)); } else { output.append('%'); - output.append(QLatin1Char(toHex(uc >> 4))); - output.append(QLatin1Char(toHex(uc))); + output.append(QLatin1Char(toHexUpper(uc >> 4))); + output.append(QLatin1Char(toHexUpper(uc))); } } else { output.append('%'); output.append('u'); - output.append(QLatin1Char(toHex(uc >> 12))); - output.append(QLatin1Char(toHex(uc >> 8))); - output.append(QLatin1Char(toHex(uc >> 4))); - output.append(QLatin1Char(toHex(uc))); + output.append(QLatin1Char(toHexUpper(uc >> 12))); + output.append(QLatin1Char(toHexUpper(uc >> 8))); + output.append(QLatin1Char(toHexUpper(uc >> 4))); + output.append(QLatin1Char(toHexUpper(uc))); } } return output; @@ -119,10 +105,10 @@ static QString unescape(const QString &input) if ((c == '%') && (i + 1 < length)) { QChar a = input.at(i); if ((a == 'u') && (i + 4 < length)) { - int d3 = fromHex(input.at(i+1)); - int d2 = fromHex(input.at(i+2)); - int d1 = fromHex(input.at(i+3)); - int d0 = fromHex(input.at(i+4)); + int d3 = fromHex(input.at(i+1).unicode()); + int d2 = fromHex(input.at(i+2).unicode()); + int d1 = fromHex(input.at(i+3).unicode()); + int d0 = fromHex(input.at(i+4).unicode()); if ((d3 != -1) && (d2 != -1) && (d1 != -1) && (d0 != -1)) { ushort uc = ushort((d3 << 12) | (d2 << 8) | (d1 << 4) | d0); result.append(QChar(uc)); @@ -131,8 +117,8 @@ static QString unescape(const QString &input) result.append(c); } } else { - int d1 = fromHex(a); - int d0 = fromHex(input.at(i+1)); + int d1 = fromHex(a.unicode()); + int d0 = fromHex(input.at(i+1).unicode()); if ((d1 != -1) && (d0 != -1)) { c = (d1 << 4) | d0; i += 2; @@ -153,8 +139,8 @@ static const char uriUnescapedReserved[] = "-_.!~*'();/?:@&=+$,#"; static void addEscapeSequence(QString &output, uchar ch) { output.append(QLatin1Char('%')); - output.append(QLatin1Char(toHex(ch >> 4))); - output.append(QLatin1Char(toHex(ch & 0xf))); + output.append(QLatin1Char(toHexUpper(ch >> 4))); + output.append(QLatin1Char(toHexUpper(ch & 0xf))); } static QString encode(const QString &input, const char *unescapedSet, bool *ok) @@ -246,8 +232,8 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok) if (i + 2 >= length) goto error; - int d1 = fromHex(input.at(i+1)); - int d0 = fromHex(input.at(i+2)); + int d1 = fromHex(input.at(i+1).unicode()); + int d0 = fromHex(input.at(i+2).unicode()); if ((d1 == -1) || (d0 == -1)) goto error; @@ -281,8 +267,8 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok) if (input.at(i) != percent) goto error; - d1 = fromHex(input.at(i+1)); - d0 = fromHex(input.at(i+2)); + d1 = fromHex(input.at(i+1).unicode()); + d0 = fromHex(input.at(i+2).unicode()); if ((d1 == -1) || (d0 == -1)) goto error; @@ -339,25 +325,24 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok) DEFINE_OBJECT_VTABLE(EvalFunction); Heap::EvalFunction::EvalFunction(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, scope->d()->engine->id_eval) + : Heap::FunctionObject(scope, scope->d()->engine->id_eval()) { Scope s(scope); ScopedFunctionObject f(s, this); - f->defineReadonlyProperty(s.engine->id_length, Primitive::fromInt32(1)); + f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(1)); } -ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) +ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const { if (callData->argc < 1) return Encode::undefined(); 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 @@ -372,10 +357,10 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) 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(); @@ -395,14 +380,14 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) ctx->d()->strictMode = false; ctx->d()->compilationUnit = function->compilationUnit; - return function->code(ctx->engine(), function->codeData); + return Q_V4_PROFILE(ctx->engine(), function); } -ReturnedValue EvalFunction::call(Managed *that, CallData *callData) +ReturnedValue EvalFunction::call(const Managed *that, CallData *callData) { // indirect call - return static_cast<EvalFunction *>(that)->evalCall(callData, false); + return static_cast<const EvalFunction *>(that)->evalCall(callData, false); } diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h index 74de233b47..ced85621de 100644 --- a/src/qml/jsruntime/qv4globalobject_p.h +++ b/src/qml/jsruntime/qv4globalobject_p.h @@ -33,6 +33,17 @@ #ifndef QV4GLOBALOBJECT_H #define QV4GLOBALOBJECT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include "qv4functionobject_p.h" @@ -52,10 +63,10 @@ struct Q_QML_EXPORT EvalFunction : FunctionObject { V4_OBJECT2(EvalFunction, FunctionObject) - ReturnedValue evalCall(CallData *callData, bool directCall); + ReturnedValue evalCall(CallData *callData, bool directCall) const; using Object::construct; - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct GlobalFunctions diff --git a/src/qml/jsruntime/qv4identifier_p.h b/src/qml/jsruntime/qv4identifier_p.h index 7937391ff7..605b06c685 100644 --- a/src/qml/jsruntime/qv4identifier_p.h +++ b/src/qml/jsruntime/qv4identifier_p.h @@ -33,6 +33,17 @@ #ifndef QV4IDENTIFIER_H #define QV4IDENTIFIER_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <qstring.h> QT_BEGIN_NAMESPACE 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 ff374225f4..3af9db963e 100644 --- a/src/qml/jsruntime/qv4identifiertable_p.h +++ b/src/qml/jsruntime/qv4identifiertable_p.h @@ -33,6 +33,17 @@ #ifndef QV4IDENTIFIERTABLE_H #define QV4IDENTIFIERTABLE_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4identifier_p.h" #include "qv4string_p.h" #include "qv4engine_p.h" @@ -74,14 +85,16 @@ 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]; if (!entry || entry->isMarked()) continue; entry->setMarkBit(); - Q_ASSERT(entry->gcGetVtable()->markObjects); - entry->gcGetVtable()->markObjects(entry, e); + Q_ASSERT(entry->vtable()->markObjects); + entry->vtable()->markObjects(entry, e); } } }; diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index e4bd460966..90c6738c46 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -49,12 +49,13 @@ 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 (callback.asFunctionObject()) + if (qmlContext) + m_qmlContext.set(engine, *qmlContext); + if (callback.as<QV4::FunctionObject>()) m_callbackFunction.set(engine, callback); m_resultObject.set(v4, resultValue(v4)); @@ -94,14 +95,14 @@ void QV4Include::callback(const QV4::Value &callback, const QV4::Value &status) { if (!callback.isObject()) return; - QV4::ExecutionEngine *v4 = callback.asObject()->engine(); + QV4::ExecutionEngine *v4 = callback.as<QV4::Object>()->engine(); QV4::Scope scope(v4); QV4::ScopedFunctionObject f(scope, callback); if (!f) return; QV4::ScopedCallData callData(scope, 1); - callData->thisObject = v4->globalObject()->asReturnedValue(); + callData->thisObject = v4->globalObject->asReturnedValue(); callData->args[0] = status; f->call(callData); if (scope.hasException()) @@ -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) @@ -176,7 +177,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) return QV4::Encode::undefined(); QV4::Scope scope(ctx->engine()); - QQmlContextData *context = QV4::QmlContextWrapper::callingContext(scope.engine); + QQmlContextData *context = scope.engine->callingQmlContext(); if (!context || !context->isJSContext) V4THROW_ERROR("Qt.include(): Can only be called from JavaScript files"); @@ -184,18 +185,16 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) QUrl url(scope.engine->resolvedUrl(ctx->args()[0].toQStringNoThrow())); QV4::ScopedValue callbackFunction(scope, QV4::Primitive::undefinedValue()); - if (ctx->argc() >= 2 && ctx->args()[1].asFunctionObject()) + if (ctx->argc() >= 2 && ctx->args()[1].as<QV4::FunctionObject>()) callbackFunction = ctx->args()[1]; 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())); } } @@ -224,7 +223,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) QV4::ScopedValue ex(scope, scope.engine->catchException()); result = resultValue(scope.engine, Exception); QV4::ScopedString exception(scope, scope.engine->newString(QStringLiteral("exception"))); - result->asObject()->put(exception, ex); + result->as<QV4::Object>()->put(exception, ex); } else { result = resultValue(scope.engine, Ok); } diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h index 5dc94e8555..3e3cf5e770 100644 --- a/src/qml/jsruntime/qv4include_p.h +++ b/src/qml/jsruntime/qv4include_p.h @@ -50,7 +50,7 @@ #include <private/qqmlcontext_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4context_p.h> QT_BEGIN_NAMESPACE @@ -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 3289058cb7..5b91925ede 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -33,6 +33,17 @@ #ifndef QV4INTERNALCLASS_H #define QV4INTERNALCLASS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include <QHash> @@ -46,7 +57,7 @@ struct String; struct ExecutionEngine; struct Object; struct Identifier; -struct ManagedVTable; +struct VTable; struct PropertyHashData; struct PropertyHash @@ -233,6 +244,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 e7905974df..2e5283c639 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -38,8 +38,8 @@ #include <qv4objectiterator_p.h> #include <qv4scopedvalue_p.h> #include <qv4runtime_p.h> +#include "qv4string_p.h" -#include <qjsondocument.h> #include <qstack.h> #include <qstringlist.h> @@ -62,33 +62,6 @@ static int indent = 0; DEFINE_OBJECT_VTABLE(JsonObject); -class JsonParser -{ -public: - JsonParser(ExecutionEngine *engine, const QChar *json, int length); - - ReturnedValue parse(QJsonParseError *error); - -private: - inline bool eatSpace(); - inline QChar nextToken(); - - ReturnedValue parseObject(); - ReturnedValue parseArray(); - bool parseMember(Object *o); - bool parseString(QString *string); - bool parseValue(Value *val); - bool parseNumber(Value *val); - - ExecutionEngine *engine; - const QChar *head; - const QChar *json; - const QChar *end; - - int nestingLevel; - QJsonParseError::ParseError lastError; -}; - static const int nestingLimit = 1024; @@ -639,17 +612,22 @@ bool JsonParser::parseString(QString *string) struct Stringify { - ExecutionContext *ctx; + ExecutionEngine *v4; FunctionObject *replacerFunction; - // ### GC - QVector<Heap::String *> propertyList; + QV4::String *propertyList; + int propertyListSize; QString gap; QString indent; + QStack<Object *> stack; - // ### GC - QStack<Heap::Object *> stack; + bool stackContains(Object *o) { + for (int i = 0; i < stack.size(); ++i) + if (stack.at(i)->d() == o->d()) + return true; + return false; + } - Stringify(ExecutionContext *ctx) : ctx(ctx), replacerFunction(0) {} + Stringify(ExecutionEngine *e) : v4(e), replacerFunction(0), propertyList(0), propertyListSize(0) {} QString Str(const QString &key, const Value &v); QString JA(ArrayObject *a); @@ -701,26 +679,26 @@ static QString quote(const QString &str) QString Stringify::Str(const QString &key, const Value &v) { - Scope scope(ctx); + Scope scope(v4); ScopedValue value(scope, v); ScopedObject o(scope, value); if (o) { - ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toJSON"))); + ScopedString s(scope, v4->newString(QStringLiteral("toJSON"))); ScopedFunctionObject toJSON(scope, o->get(s)); if (!!toJSON) { ScopedCallData callData(scope, 1); callData->thisObject = value; - callData->args[0] = ctx->d()->engine->newString(key); + callData->args[0] = v4->newString(key); value = toJSON->call(callData); } } if (replacerFunction) { - ScopedObject holder(scope, ctx->d()->engine->newObject()); + ScopedObject holder(scope, v4->newObject()); holder->put(scope.engine, QString(), value); ScopedCallData callData(scope, 2); - callData->args[0] = ctx->d()->engine->newString(key); + callData->args[0] = v4->newString(key); callData->args[1] = value; callData->thisObject = holder; value = replacerFunction->call(callData); @@ -728,11 +706,11 @@ QString Stringify::Str(const QString &key, const Value &v) o = value->asReturnedValue(); if (o) { - if (NumberObject *n = o->asNumberObject()) + if (NumberObject *n = o->as<NumberObject>()) value = Encode(n->value()); - else if (StringObject *so = o->asStringObject()) - value = so->d()->value; - else if (BooleanObject *b =o->asBooleanObject()) + else if (StringObject *so = o->as<StringObject>()) + value = so->d()->string; + else if (BooleanObject *b = o->as<BooleanObject>()) value = Encode(b->value()); } @@ -750,8 +728,8 @@ QString Stringify::Str(const QString &key, const Value &v) o = value->asReturnedValue(); if (o) { - if (!o->asFunctionObject()) { - if (o->asArrayObject()) { + if (!o->as<FunctionObject>()) { + if (o->as<ArrayObject>()) { return JA(static_cast<ArrayObject *>(o.getPointer())); } else { return JO(o); @@ -777,20 +755,20 @@ QString Stringify::makeMember(const QString &key, const Value &v) QString Stringify::JO(Object *o) { - if (stack.contains(o->d())) { - ctx->engine()->throwTypeError(); + if (stackContains(o)) { + v4->throwTypeError(); return QString(); } - Scope scope(ctx); + Scope scope(v4); QString result; - stack.push(o->d()); + stack.push(o); QString stepback = indent; indent += gap; QStringList partial; - if (propertyList.isEmpty()) { + if (!propertyListSize) { ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); ScopedValue name(scope); @@ -805,11 +783,13 @@ QString Stringify::JO(Object *o) partial += member; } } else { - ScopedString s(scope); - for (int i = 0; i < propertyList.size(); ++i) { + ScopedValue v(scope); + for (int i = 0; i < propertyListSize; ++i) { bool exists; - s = propertyList.at(i); - ScopedValue v(scope, o->get(s, &exists)); + String *s = propertyList + i; + if (!s) + continue; + v = o->get(s, &exists); if (!exists) continue; QString member = makeMember(s->toQString(), v); @@ -821,10 +801,11 @@ QString Stringify::JO(Object *o) if (partial.isEmpty()) { result = QStringLiteral("{}"); } else if (gap.isEmpty()) { - result = QStringLiteral("{") + partial.join(QLatin1Char(',')) + QStringLiteral("}"); + result = QStringLiteral("{") + partial.join(QLatin1Char(',')) + QLatin1Char('}'); } else { QString separator = QStringLiteral(",\n") + indent; - result = QStringLiteral("{\n") + indent + partial.join(separator) + QStringLiteral("\n") + stepback + QStringLiteral("}"); + result = QStringLiteral("{\n") + indent + partial.join(separator) + QLatin1Char('\n') + + stepback + QLatin1Char('}'); } indent = stepback; @@ -834,15 +815,15 @@ QString Stringify::JO(Object *o) QString Stringify::JA(ArrayObject *a) { - if (stack.contains(a->d())) { - ctx->engine()->throwTypeError(); + if (stackContains(a)) { + v4->throwTypeError(); return QString(); } Scope scope(a->engine()); QString result; - stack.push(a->d()); + stack.push(a); QString stepback = indent; indent += gap; @@ -878,10 +859,9 @@ QString Stringify::JA(ArrayObject *a) } -Heap::JsonObject::JsonObject(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->objectPrototype.asObject()) +Heap::JsonObject::JsonObject() { - Scope scope(e); + Scope scope(internalClass->engine); ScopedObject o(scope, this); o->defineDefaultProperty(QStringLiteral("parse"), QV4::JsonObject::method_parse, 2); @@ -911,32 +891,38 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) { Scope scope(ctx); - Stringify stringify(ctx); + Stringify stringify(scope.engine); ScopedObject o(scope, ctx->argument(1)); if (o) { - stringify.replacerFunction = o->asFunctionObject(); + stringify.replacerFunction = o->as<FunctionObject>(); if (o->isArrayObject()) { uint arrayLen = o->getLength(); - ScopedValue v(scope); + stringify.propertyList = static_cast<QV4::String *>(scope.alloc(arrayLen)); for (uint i = 0; i < arrayLen; ++i) { - v = o->getIndexed(i); - if (v->asNumberObject() || v->asStringObject() || v->isNumber()) - v = RuntimeHelpers::toString(scope.engine, v); - if (v->isString()) { - String *s = v->stringValue(); - if (!stringify.propertyList.contains(s->d())) - stringify.propertyList.append(s->d()); + Value *v = stringify.propertyList + i; + *v = o->getIndexed(i); + if (v->as<NumberObject>() || v->as<StringObject>() || v->isNumber()) + *v = RuntimeHelpers::toString(scope.engine, *v); + if (!v->isString()) { + v->setM(0); + } else { + for (uint j = 0; j <i; ++j) { + if (stringify.propertyList[j].m() == v->m()) { + v->setM(0); + break; + } + } } } } } ScopedValue s(scope, ctx->argument(2)); - if (NumberObject *n = s->asNumberObject()) + if (NumberObject *n = s->as<NumberObject>()) s = Encode(n->value()); - else if (StringObject *so = s->asStringObject()) - s = so->d()->value; + else if (StringObject *so = s->as<StringObject>()) + s = so->d()->string; if (s->isNumber()) { stringify.gap = QString(qMin(10, (int)s->toInteger()), ' '); @@ -957,7 +943,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()) @@ -986,7 +972,7 @@ QJsonValue JsonObject::toJsonValue(const Value &value, V4ObjectSet &visitedObjec return QJsonValue(value.toQString()); Q_ASSERT(value.isObject()); - Scope scope(value.asObject()->engine()); + Scope scope(value.as<Object>()->engine()); ScopedArrayObject a(scope, value); if (a) return toJsonArray(a, visitedObjects); @@ -1009,22 +995,22 @@ QV4::ReturnedValue JsonObject::fromJsonObject(ExecutionEngine *engine, const QJs return o.asReturnedValue(); } -QJsonObject JsonObject::toJsonObject(Object *o, V4ObjectSet &visitedObjects) +QJsonObject JsonObject::toJsonObject(const Object *o, V4ObjectSet &visitedObjects) { QJsonObject result; - if (!o || o->asFunctionObject()) + if (!o || o->as<FunctionObject>()) return result; Scope scope(o->engine()); - if (visitedObjects.contains(o->d())) { + if (visitedObjects.contains(ObjectItem(o))) { // Avoid recursion. // For compatibility with QVariant{List,Map} conversion, we return an // empty object (and no error is thrown). return result; } - visitedObjects.insert(o->d()); + visitedObjects.insert(ObjectItem(o)); ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); ScopedValue name(scope); @@ -1035,11 +1021,11 @@ QJsonObject JsonObject::toJsonObject(Object *o, V4ObjectSet &visitedObjects) break; QString key = name->toQStringNoThrow(); - if (!val->asFunctionObject()) + if (!val->as<FunctionObject>()) result.insert(key, toJsonValue(val, visitedObjects)); } - visitedObjects.remove(o->d()); + visitedObjects.remove(ObjectItem(o)); return result; } @@ -1057,7 +1043,7 @@ QV4::ReturnedValue JsonObject::fromJsonArray(ExecutionEngine *engine, const QJso return a.asReturnedValue(); } -QJsonArray JsonObject::toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects) +QJsonArray JsonObject::toJsonArray(const ArrayObject *a, V4ObjectSet &visitedObjects) { QJsonArray result; if (!a) @@ -1065,25 +1051,25 @@ QJsonArray JsonObject::toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects) Scope scope(a->engine()); - if (visitedObjects.contains(a->d())) { + if (visitedObjects.contains(ObjectItem(a))) { // Avoid recursion. // For compatibility with QVariant{List,Map} conversion, we return an // empty array (and no error is thrown). return result; } - visitedObjects.insert(a->d()); + visitedObjects.insert(ObjectItem(a)); ScopedValue v(scope); quint32 length = a->getLength(); for (quint32 i = 0; i < length; ++i) { v = a->getIndexed(i); - if (v->asFunctionObject()) + if (v->as<FunctionObject>()) v = Encode::null(); result.append(toJsonValue(v, visitedObjects)); } - visitedObjects.remove(a->d()); + visitedObjects.remove(ObjectItem(a)); return result; } diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h index 81a783ee92..6a6e863bf6 100644 --- a/src/qml/jsruntime/qv4jsonobject_p.h +++ b/src/qml/jsruntime/qv4jsonobject_p.h @@ -33,10 +33,23 @@ #ifndef QV4JSONOBJECT_H #define QV4JSONOBJECT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include <qjsonarray.h> #include <qjsonobject.h> #include <qjsonvalue.h> +#include <qjsondocument.h> +#include <qhash.h> QT_BEGIN_NAMESPACE @@ -45,17 +58,28 @@ namespace QV4 { namespace Heap { struct JsonObject : Object { - JsonObject(ExecutionEngine *e); + JsonObject(); }; } +struct ObjectItem { + const QV4::Object *o; + ObjectItem(const QV4::Object *o) : o(o) {} +}; + +inline bool operator ==(const ObjectItem &a, const ObjectItem &b) +{ return a.o->d() == b.o->d(); } + +inline int qHash(const ObjectItem &i, uint seed = 0) +{ return ::qHash((void *)i.o->d(), seed); } + struct JsonObject : Object { Q_MANAGED_TYPE(JsonObject) V4_OBJECT2(JsonObject, Object) private: - // ### GC - typedef QSet<QV4::Heap::Base *> V4ObjectSet; + + typedef QSet<ObjectItem> V4ObjectSet; public: static ReturnedValue method_parse(CallContext *ctx); @@ -67,18 +91,45 @@ public: static inline QJsonValue toJsonValue(const QV4::Value &value) { V4ObjectSet visitedObjects; return toJsonValue(value, visitedObjects); } - static inline QJsonObject toJsonObject(QV4::Object *o) + static inline QJsonObject toJsonObject(const QV4::Object *o) { V4ObjectSet visitedObjects; return toJsonObject(o, visitedObjects); } - static inline QJsonArray toJsonArray(QV4::ArrayObject *a) + static inline QJsonArray toJsonArray(const QV4::ArrayObject *a) { V4ObjectSet visitedObjects; return toJsonArray(a, visitedObjects); } private: static QJsonValue toJsonValue(const QV4::Value &value, V4ObjectSet &visitedObjects); - static QJsonObject toJsonObject(Object *o, V4ObjectSet &visitedObjects); - static QJsonArray toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects); + static QJsonObject toJsonObject(const Object *o, V4ObjectSet &visitedObjects); + static QJsonArray toJsonArray(const ArrayObject *a, V4ObjectSet &visitedObjects); }; +class JsonParser +{ +public: + JsonParser(ExecutionEngine *engine, const QChar *json, int length); + + ReturnedValue parse(QJsonParseError *error); + +private: + inline bool eatSpace(); + inline QChar nextToken(); + + ReturnedValue parseObject(); + ReturnedValue parseArray(); + bool parseMember(Object *o); + bool parseString(QString *string); + bool parseValue(Value *val); + bool parseNumber(Value *val); + + ExecutionEngine *engine; + const QChar *head; + const QChar *json; + const QChar *end; + + int nestingLevel; + QJsonParseError::ParseError lastError; +}; + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 82b20337cb..d97abdb461 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -33,6 +33,7 @@ #include "qv4lookup_p.h" #include "qv4functionobject_p.h" #include "qv4scopedvalue_p.h" +#include "qv4string_p.h" QT_BEGIN_NAMESPACE @@ -42,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) { @@ -52,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; @@ -64,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; @@ -72,11 +75,11 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu return Primitive::emptyValue().asReturnedValue(); } -ReturnedValue Lookup::lookup(Object *thisObject, PropertyAttributes *attrs) +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; @@ -85,7 +88,8 @@ ReturnedValue Lookup::lookup(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; @@ -97,7 +101,8 @@ ReturnedValue Lookup::lookup(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; @@ -123,7 +128,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons ScopedObject o(scope, object); if (!o) { if (idx < UINT_MAX) { - if (String *str = object.asString()) { + if (const String *str = object.as<String>()) { if (idx >= (uint)str->toQString().length()) { return Encode::undefined(); } @@ -164,11 +169,11 @@ 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) { - Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (idx < s->len) if (!s->data(idx).isEmpty()) return s->data(idx).asReturnedValue(); @@ -200,7 +205,7 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value & uint idx = index.asArrayIndex(); if (idx < UINT_MAX) { if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (idx < s->len) { s->data(idx) = value; return; @@ -224,7 +229,7 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value Object *o = object.objectValue(); if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (idx < s->len) { s->data(idx) = v; return; @@ -235,7 +240,7 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (Object *o = object.asObject()) + if (const Object *o = object.as<Object>()) return o->getLookup(l); Object *proto; @@ -244,14 +249,14 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va case Value::Null_Type: return engine->throwTypeError(); case Value::Boolean_Type: - proto = engine->booleanPrototype.asObject(); + proto = engine->booleanPrototype(); break; case Value::Managed_Type: { Q_ASSERT(object.isString()); - proto = engine->stringPrototype.asObject(); + proto = engine->stringPrototype(); Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); - if (name->equals(engine->id_length)) { + 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; return stringLengthGetter(l, engine, object); @@ -260,7 +265,7 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va } case Value::Integer_Type: default: // Number - proto = engine->numberPrototype.asObject(); + proto = engine->numberPrototype(); } PropertyAttributes attrs; @@ -291,7 +296,7 @@ ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Lookup l1 = *l; if (l1.getter == Lookup::getter0 || l1.getter == Lookup::getter1) { - if (Object *o = object.asObject()) { + if (const Object *o = object.as<Object>()) { ReturnedValue v = o->getLookup(l); Lookup l2 = *l; @@ -328,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); } @@ -339,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); } @@ -352,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); } @@ -368,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(); } } } @@ -383,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); @@ -398,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); @@ -415,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; @@ -434,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(); @@ -456,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(); @@ -481,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(); @@ -501,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); @@ -513,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); @@ -525,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(); @@ -545,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(); @@ -560,7 +565,7 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engin ReturnedValue Lookup::stringLengthGetter(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (String *s = object.asString()) + if (const String *s = object.as<String>()) return Encode(s->d()->length()); l->getter = getterGeneric; @@ -569,8 +574,8 @@ ReturnedValue Lookup::stringLengthGetter(Lookup *l, ExecutionEngine *engine, con ReturnedValue Lookup::arrayLengthGetter(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (ArrayObject *a = object.asArrayObject()) - return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].asReturnedValue(); + if (const ArrayObject *a = object.as<ArrayObject>()) + return a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->asReturnedValue(); l->getter = getterGeneric; return getterGeneric(l, engine, object); @@ -579,7 +584,7 @@ ReturnedValue Lookup::arrayLengthGetter(Lookup *l, ExecutionEngine *engine, cons ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + Object *o = engine->globalObject; PropertyAttributes attrs; ReturnedValue v = l->lookup(o, &attrs); if (v != Primitive::emptyValue().asReturnedValue()) { @@ -602,15 +607,15 @@ 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); } ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + 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); @@ -618,10 +623,10 @@ ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetter1(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + 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); @@ -629,13 +634,13 @@ ReturnedValue Lookup::globalGetter1(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionEngine *engine) { - Heap::Object *o = engine->globalObject()->d(); + Heap::Object *o = engine->globalObject->d(); if (l->classList[0] == o->internalClass) { o = o->prototype; 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(); } } } @@ -645,10 +650,10 @@ ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + 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(); @@ -662,11 +667,11 @@ ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + Object *o = engine->globalObject; 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(); @@ -680,14 +685,14 @@ ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine) { - Heap::Object *o = engine->globalObject()->d(); + Heap::Object *o = engine->globalObject->d(); if (l->classList[0] == o->internalClass) { o = o->prototype; if (l->classList[1] == o->internalClass) { 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(); @@ -701,7 +706,7 @@ ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine) return globalGetterGeneric(l, engine); } -void Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { Scope scope(engine); ScopedObject o(scope, object); @@ -709,18 +714,18 @@ void Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, const Value &obje 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; } o->setLookup(l, value); } -void Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { Lookup l1 = *l; - if (Object *o = object.asObject()) { + if (Object *o = object.as<Object>()) { o->setLookup(l, value); if (l->setter == Lookup::setter0) { @@ -735,36 +740,34 @@ void Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &o setterFallback(l, engine, object, value); } -void Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { 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); } } -void Lookup::setter0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { - o->memberData()->data[l->index] = value; + *o->propertyData(l->index) = value; return; } setterTwoClasses(l, engine, object, value); } -void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + 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; } } @@ -773,16 +776,14 @@ void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, const Value &obje setterFallback(l, engine, object, value); } -void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + Object *o = object.as<Object>(); 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; } } @@ -791,18 +792,16 @@ void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, const Value &obje setterFallback(l, engine, object, value); } -void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { Heap::Object *p = o->prototype(); 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; } } @@ -812,16 +811,16 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, const Value &obje setterFallback(l, engine, object, value); } -void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + 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/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 88397dc36c..77ad1a7b65 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -33,6 +33,17 @@ #ifndef QV4LOOKUP_H #define QV4LOOKUP_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include "qv4runtime_p.h" #include "qv4engine_p.h" @@ -51,7 +62,7 @@ struct Lookup { void (*indexedSetter)(Lookup *l, const Value &object, const Value &index, const Value &v); ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object); ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine); - void (*setter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &v); + void (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v); }; union { ExecutionEngine *engine; @@ -107,17 +118,17 @@ struct Lookup { static ReturnedValue globalGetterAccessor1(Lookup *l, ExecutionEngine *engine); static ReturnedValue globalGetterAccessor2(Lookup *l, ExecutionEngine *engine); - static void setterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setter0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterInsert0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterInsert1(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterInsert2(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setter0setter0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); + static void setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); ReturnedValue lookup(const Value &thisObject, Object *obj, PropertyAttributes *attrs); - ReturnedValue lookup(Object *obj, PropertyAttributes *attrs); + ReturnedValue lookup(const Object *obj, PropertyAttributes *attrs); }; diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index c4b9fc597e..e2de36d18e 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -32,13 +32,13 @@ ****************************************************************************/ #include "qv4managed_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4errorobject_p.h" using namespace QV4; -const ManagedVTable Managed::static_vtbl = +const VTable Managed::static_vtbl = { 0, Managed::IsExecutionContext, @@ -59,7 +59,7 @@ const ManagedVTable Managed::static_vtbl = QString Managed::className() const { const char *s = 0; - switch (Type(d()->vtable->type)) { + switch (Type(d()->vtable()->type)) { case Type_Invalid: case Type_String: return QString(); @@ -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/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index aa3e668eef..6a1bd7a9a4 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -33,16 +33,27 @@ #ifndef QMLJS_MANAGED_H #define QMLJS_MANAGED_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include "qv4value_p.h" -#include "qv4internalclass_p.h" +#include <private/qv4heap_p.h> QT_BEGIN_NAMESPACE namespace QV4 { #define Q_MANAGED_CHECK \ - template <typename _T> inline void qt_check_for_QMANAGED_macro(const _T *_q_argument) const \ + template <typename Type> inline void qt_check_for_QMANAGED_macro(const Type *_q_argument) const \ { int i = qYouForgotTheQ_MANAGED_Macro(this, _q_argument); i = i + 1; } template <typename T> @@ -65,10 +76,10 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} Q_MANAGED_CHECK \ typedef QV4::Heap::DataClass Data; \ typedef superClass SuperClass; \ - static const QV4::ManagedVTable static_vtbl; \ - static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl; } \ + static const QV4::VTable static_vtbl; \ + static inline const QV4::VTable *staticVTable() { return &static_vtbl; } \ V4_MANAGED_SIZE_TEST \ - QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m); } + QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m()); } #define V4_MANAGED(DataClass, superClass) \ private: \ @@ -84,31 +95,6 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} (classname::func == QV4::Managed::func ? 0 : classname::func) -struct GCDeletable -{ - GCDeletable() : next(0), lastCall(false) {} - virtual ~GCDeletable() {} - GCDeletable *next; - bool lastCall; -}; - -struct ManagedVTable -{ - const ManagedVTable * const parent; - uint isExecutionContext : 1; - uint isString : 1; - uint isObject : 1; - uint isFunctionObject : 1; - uint isErrorObject : 1; - uint isArrayData : 1; - uint unused : 18; - uint type : 8; - const char *className; - void (*destroy)(Heap::Base *); - void (*markObjects)(Heap::Base *, ExecutionEngine *e); - bool (*isEqualTo)(Managed *m, Managed *other); -}; - #define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \ { \ parentVTable, \ @@ -127,7 +113,7 @@ struct ManagedVTable } #define DEFINE_MANAGED_VTABLE(classname) \ -const QV4::ManagedVTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname, 0) +const QV4::VTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname, 0) struct Q_QML_PRIVATE_EXPORT Managed : Value { @@ -147,8 +133,6 @@ private: public: - inline void mark(QV4::ExecutionEngine *engine); - enum Type { Type_Invalid, Type_String, @@ -173,55 +157,15 @@ public: }; Q_MANAGED_TYPE(Invalid) - template <typename T> - T *as() { - Q_ASSERT(d()->vtable); -#if !defined(QT_NO_QOBJECT_CHECK) - static_cast<T *>(this)->qt_check_for_QMANAGED_macro(static_cast<T *>(this)); -#endif - const ManagedVTable *vt = d()->vtable; - while (vt) { - if (vt == T::staticVTable()) - return static_cast<T *>(this); - vt = vt->parent; - } - return 0; - } - template <typename T> - const T *as() const { - Q_ASSERT(d()->vtable); -#if !defined(QT_NO_QOBJECT_CHECK) - static_cast<T *>(this)->qt_check_for_QMANAGED_macro(static_cast<T *>(const_cast<Managed *>(this))); -#endif - const ManagedVTable *vt = d()->vtable; - while (vt) { - if (vt == T::staticVTable()) - return static_cast<T *>(this); - vt = vt->parent; - } - return 0; - } - - String *asString() { return d()->vtable->isString ? reinterpret_cast<String *>(this) : 0; } - Object *asObject() { return d()->vtable->isObject ? reinterpret_cast<Object *>(this) : 0; } - ArrayObject *asArrayObject() { return d()->vtable->type == Type_ArrayObject ? reinterpret_cast<ArrayObject *>(this) : 0; } - FunctionObject *asFunctionObject() { return d()->vtable->isFunctionObject ? reinterpret_cast<FunctionObject *>(this) : 0; } - BooleanObject *asBooleanObject() { return d()->vtable->type == Type_BooleanObject ? reinterpret_cast<BooleanObject *>(this) : 0; } - NumberObject *asNumberObject() { return d()->vtable->type == Type_NumberObject ? reinterpret_cast<NumberObject *>(this) : 0; } - StringObject *asStringObject() { return d()->vtable->type == Type_StringObject ? reinterpret_cast<StringObject *>(this) : 0; } - DateObject *asDateObject() { return d()->vtable->type == Type_DateObject ? reinterpret_cast<DateObject *>(this) : 0; } - ErrorObject *asErrorObject() { return d()->vtable->isErrorObject ? reinterpret_cast<ErrorObject *>(this) : 0; } - ArgumentsObject *asArgumentsObject() { return d()->vtable->type == Type_ArgumentsObject ? reinterpret_cast<ArgumentsObject *>(this) : 0; } - - bool isListType() const { return d()->vtable->type == Type_QmlSequence; } - - bool isArrayObject() const { return d()->vtable->type == Type_ArrayObject; } - bool isStringObject() const { return d()->vtable->type == Type_StringObject; } + bool isListType() const { return d()->vtable()->type == Type_QmlSequence; } + + bool isArrayObject() const { return d()->vtable()->type == Type_ArrayObject; } + bool isStringObject() const { return d()->vtable()->type == Type_StringObject; } QString className() const; bool isEqualTo(const Managed *other) const - { return d()->vtable->isEqualTo(const_cast<Managed *>(this), const_cast<Managed *>(other)); } + { return d()->vtable()->isEqualTo(const_cast<Managed *>(this), const_cast<Managed *>(other)); } static bool isEqualTo(Managed *m, Managed *other); @@ -237,37 +181,15 @@ private: template<> -inline Managed *value_cast(const Value &v) { - return v.asManaged(); -} - -template<typename T> -inline T *managed_cast(Managed *m) -{ - return m ? m->as<T>() : 0; +inline const Managed *Value::as() const { + if (isManaged()) + return managed(); + return 0; } template<> -inline String *managed_cast(Managed *m) -{ - return m ? m->asString() : 0; -} -template<> -inline Object *managed_cast(Managed *m) -{ - return m ? m->asObject() : 0; -} -template<> -inline FunctionObject *managed_cast(Managed *m) -{ - return m ? m->asFunctionObject() : 0; -} - -inline Value Value::fromManaged(Managed *m) -{ - if (!m) - return QV4::Primitive::undefinedValue(); - return *m; +inline const Object *Value::as() const { + return isManaged() && m() && m()->vtable()->isObject ? objectValue() : 0; } } diff --git a/src/qml/jsruntime/qv4math_p.h b/src/qml/jsruntime/qv4math_p.h index 4f550752aa..cf627bcc5d 100644 --- a/src/qml/jsruntime/qv4math_p.h +++ b/src/qml/jsruntime/qv4math_p.h @@ -33,6 +33,17 @@ #ifndef QMLJS_MATH_H #define QMLJS_MATH_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <qglobal.h> #include <QtCore/qnumeric.h> diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp index 473e05bf88..3d3ac84576 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.asObject()) +Heap::MathObject::MathObject() { - Scope scope(e); + Scope scope(internalClass->engine); ScopedObject m(scope, this); m->defineReadonlyProperty(QStringLiteral("E"), Primitive::fromDouble(M_E)); @@ -278,10 +277,15 @@ Q_GLOBAL_STATIC(QThreadStorage<bool *>, seedCreatedStorage); ReturnedValue MathObject::method_random(CallContext *context) { if (!seedCreatedStorage()->hasLocalData()) { - qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) ^ reinterpret_cast<quintptr>(context)); + int msecs = QTime(0,0,0).msecsTo(QTime::currentTime()); + Q_ASSERT(msecs >= 0); + qsrand(uint(uint(msecs) ^ reinterpret_cast<quintptr>(context))); seedCreatedStorage()->setLocalData(new bool(true)); } - return Encode(qrand() / (double) RAND_MAX); + // rand()/qrand() return a value where the upperbound is RAND_MAX inclusive. So, instead of + // dividing by RAND_MAX (which would return 0..RAND_MAX inclusive), we divide by RAND_MAX + 1. + qint64 upperLimit = qint64(RAND_MAX) + 1; + return Encode(qrand() / double(upperLimit)); } ReturnedValue MathObject::method_round(CallContext *context) diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h index 472b2020b1..a233f74367 100644 --- a/src/qml/jsruntime/qv4mathobject_p.h +++ b/src/qml/jsruntime/qv4mathobject_p.h @@ -33,6 +33,17 @@ #ifndef QV4MATHOBJECT_H #define QV4MATHOBJECT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" QT_BEGIN_NAMESPACE @@ -42,7 +53,7 @@ namespace QV4 { namespace Heap { struct MathObject : Object { - MathObject(ExecutionEngine *e); + MathObject(); }; } diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index 03dfee3dcf..20f8d9ec0f 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -32,7 +32,8 @@ ****************************************************************************/ #include "qv4memberdata_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> +#include "qv4value_p.h" using namespace QV4; @@ -45,20 +46,30 @@ void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e) m->data[i].mark(e); } -Heap::MemberData *MemberData::reallocate(ExecutionEngine *e, Heap::MemberData *old, uint idx) +static Heap::MemberData *reallocateHelper(ExecutionEngine *e, Heap::MemberData *old, uint n) { - uint s = old ? old->size : 0; - if (idx < s) - return old; - - int newAlloc = qMax((uint)4, 2*idx); - uint alloc = sizeof(Heap::MemberData) + (newAlloc)*sizeof(Value); + uint alloc = sizeof(Heap::MemberData) + (n)*sizeof(Value); Scope scope(e); Scoped<MemberData> newMemberData(scope, e->memoryManager->allocManaged<MemberData>(alloc)); if (old) - memcpy(newMemberData->d(), old, sizeof(Heap::MemberData) + s*sizeof(Value)); + memcpy(newMemberData->d(), old, sizeof(Heap::MemberData) + old->size * sizeof(Value)); else new (newMemberData->d()) Heap::MemberData; - newMemberData->d()->size = newAlloc; + newMemberData->d()->size = n; return newMemberData->d(); } + +Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n) +{ + return reallocateHelper(e, 0, n); +} + +Heap::MemberData *MemberData::reallocate(ExecutionEngine *e, Heap::MemberData *old, uint n) +{ + uint s = old ? old->size : 0; + if (n < s) + return old; + + // n is multiplied by two to leave room for growth + return reallocateHelper(e, old, qMax((uint)4, 2*n)); +} diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 4c7cfa47cb..12f407e869 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -33,6 +33,17 @@ #ifndef QV4MEMBERDATA_H #define QV4MEMBERDATA_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include "qv4managed_p.h" @@ -61,7 +72,8 @@ struct MemberData : Managed Value *data() { return d()->data; } inline uint size() const { return d()->size; } - static Heap::MemberData *reallocate(QV4::ExecutionEngine *e, Heap::MemberData *old, uint idx); + static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n); + static Heap::MemberData *reallocate(QV4::ExecutionEngine *e, Heap::MemberData *old, uint n); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp deleted file mode 100644 index 64491e1376..0000000000 --- a/src/qml/jsruntime/qv4mm.cpp +++ /dev/null @@ -1,651 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qv4engine_p.h" -#include "qv4object_p.h" -#include "qv4objectproto_p.h" -#include "qv4mm_p.h" -#include "qv4qobjectwrapper_p.h" -#include <qqmlengine.h> -#include "PageAllocation.h" -#include "StdLibExtras.h" - -#include <QTime> -#include <QVector> -#include <QVector> -#include <QMap> - -#include <iostream> -#include <cstdlib> -#include <algorithm> -#include "qv4alloca_p.h" -#include "qv4profiling_p.h" - -#ifdef V4_USE_VALGRIND -#include <valgrind/valgrind.h> -#include <valgrind/memcheck.h> -#endif - -#if OS(QNX) -#include <sys/storage.h> // __tls() -#endif - -#if USE(PTHREADS) && HAVE(PTHREAD_NP_H) -#include <pthread_np.h> -#endif - -using namespace WTF; - -QT_BEGIN_NAMESPACE - -using namespace QV4; - -struct MemoryManager::Data -{ - struct ChunkHeader { - Heap::Base freeItems; - ChunkHeader *nextNonFull; - char *itemStart; - char *itemEnd; - int itemSize; - }; - - bool gcBlocked; - bool aggressiveGC; - bool gcStats; - ExecutionEngine *engine; - - enum { MaxItemSize = 512 }; - ChunkHeader *nonFullChunks[MaxItemSize/16]; - uint nChunks[MaxItemSize/16]; - uint availableItems[MaxItemSize/16]; - uint allocCount[MaxItemSize/16]; - int totalItems; - int totalAlloc; - uint maxShift; - std::size_t maxChunkSize; - QVector<PageAllocation> heapChunks; - std::size_t unmanagedHeapSize; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items. - std::size_t unmanagedHeapSizeGCLimit; - - struct LargeItem { - LargeItem *next; - size_t size; - void *data; - - Heap::Base *heapObject() { - return reinterpret_cast<Heap::Base *>(&data); - } - }; - - LargeItem *largeItems; - std::size_t totalLargeItemsAllocated; - - GCDeletable *deletable; - - // statistics: -#ifdef DETAILED_MM_STATS - QVector<unsigned> allocSizeCounters; -#endif // DETAILED_MM_STATS - - Data() - : gcBlocked(false) - , engine(0) - , totalItems(0) - , totalAlloc(0) - , maxShift(6) - , maxChunkSize(32*1024) - , unmanagedHeapSize(0) - , unmanagedHeapSizeGCLimit(64 * 1024) - , largeItems(0) - , totalLargeItemsAllocated(0) - , deletable(0) - { - memset(nonFullChunks, 0, sizeof(nonFullChunks)); - memset(nChunks, 0, sizeof(nChunks)); - memset(availableItems, 0, sizeof(availableItems)); - memset(allocCount, 0, sizeof(allocCount)); - aggressiveGC = !qgetenv("QV4_MM_AGGRESSIVE_GC").isEmpty(); - gcStats = !qgetenv("QV4_MM_STATS").isEmpty(); - - QByteArray overrideMaxShift = qgetenv("QV4_MM_MAXBLOCK_SHIFT"); - bool ok; - uint override = overrideMaxShift.toUInt(&ok); - if (ok && override <= 11 && override > 0) - maxShift = override; - - QByteArray maxChunkString = qgetenv("QV4_MM_MAX_CHUNK_SIZE"); - std::size_t tmpMaxChunkSize = maxChunkString.toUInt(&ok); - if (ok) - maxChunkSize = tmpMaxChunkSize; - } - - ~Data() - { - for (QVector<PageAllocation>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) { - Q_V4_PROFILE_DEALLOC(engine, 0, i->size(), Profiling::HeapPage); - i->deallocate(); - } - } -}; - -namespace { - -bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, ExecutionEngine *engine, std::size_t *unmanagedHeapSize) -{ - Q_ASSERT(unmanagedHeapSize); - - bool isEmpty = true; - Heap::Base *tail = &header->freeItems; -// qDebug("chunkStart @ %p, size=%x, pos=%x", header->itemStart, header->itemSize, header->itemSize>>4); -#ifdef V4_USE_VALGRIND - VALGRIND_DISABLE_ERROR_REPORTING; -#endif - for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) { - Heap::Base *m = reinterpret_cast<Heap::Base *>(item); -// qDebug("chunk @ %p, in use: %s, mark bit: %s", -// item, (m->inUse() ? "yes" : "no"), (m->isMarked() ? "true" : "false")); - - Q_ASSERT((qintptr) item % 16 == 0); - - if (m->isMarked()) { - Q_ASSERT(m->inUse()); - m->clearMarkBit(); - isEmpty = false; - ++(*itemsInUse); - } else { - if (m->inUse()) { -// qDebug() << "-- collecting it." << m << tail << m->nextFree(); -#ifdef V4_USE_VALGRIND - VALGRIND_ENABLE_ERROR_REPORTING; -#endif - if (std::size_t(header->itemSize) == MemoryManager::align(sizeof(Heap::String)) && m->gcGetVtable()->isString) { - std::size_t heapBytes = static_cast<Heap::String *>(m)->retainedTextSize(); - Q_ASSERT(*unmanagedHeapSize >= heapBytes); -// qDebug() << "-- it's a string holding on to" << heapBytes << "bytes"; - *unmanagedHeapSize -= heapBytes; - } - - if (m->gcGetVtable()->destroy) - m->gcGetVtable()->destroy(m); - - memset(m, 0, header->itemSize); -#ifdef V4_USE_VALGRIND - VALGRIND_DISABLE_ERROR_REPORTING; - VALGRIND_MEMPOOL_FREE(engine->memoryManager, m); -#endif - Q_V4_PROFILE_DEALLOC(engine, m, header->itemSize, Profiling::SmallItem); - ++(*itemsInUse); - } - // Relink all free blocks to rewrite references to any released chunk. - tail->setNextFree(m); - tail = m; - } - } - tail->setNextFree(0); -#ifdef V4_USE_VALGRIND - VALGRIND_ENABLE_ERROR_REPORTING; -#endif - return isEmpty; -} - -} // namespace - -MemoryManager::MemoryManager(ExecutionEngine *engine) - : m_d(new Data) - , m_persistentValues(new PersistentValueStorage(engine)) - , m_weakValues(new PersistentValueStorage(engine)) -{ -#ifdef V4_USE_VALGRIND - VALGRIND_CREATE_MEMPOOL(this, 0, true); -#endif - m_d->engine = engine; -} - -Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize) -{ - if (m_d->aggressiveGC) - runGC(); -#ifdef DETAILED_MM_STATS - willAllocate(size); -#endif // DETAILED_MM_STATS - - Q_ASSERT(size >= 16); - Q_ASSERT(size % 16 == 0); - -// qDebug() << "unmanagedHeapSize:" << m_d->unmanagedHeapSize << "limit:" << m_d->unmanagedHeapSizeGCLimit << "unmanagedSize:" << unmanagedSize; - m_d->unmanagedHeapSize += unmanagedSize; - bool didGCRun = false; - if (m_d->unmanagedHeapSize > m_d->unmanagedHeapSizeGCLimit) { - runGC(); - - if (m_d->unmanagedHeapSizeGCLimit <= m_d->unmanagedHeapSize) - 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); - didGCRun = true; - } - - size_t pos = size >> 4; - - // doesn't fit into a small bucket - if (size >= MemoryManager::Data::MaxItemSize) { - if (!didGCRun && m_d->totalLargeItemsAllocated > 8 * 1024 * 1024) - runGC(); - - // 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), - Profiling::LargeItem))); - memset(item, 0, size + sizeof(MemoryManager::Data::LargeItem)); - item->next = m_d->largeItems; - item->size = size; - m_d->largeItems = item; - m_d->totalLargeItemsAllocated += size; - return item->heapObject(); - } - - Heap::Base *m = 0; - Data::ChunkHeader *header = m_d->nonFullChunks[pos]; - if (header) { - m = header->freeItems.nextFree(); - goto found; - } - - // try to free up space, otherwise allocate - if (!didGCRun && m_d->allocCount[pos] > (m_d->availableItems[pos] >> 1) && m_d->totalAlloc > (m_d->totalItems >> 1) && !m_d->aggressiveGC) { - runGC(); - header = m_d->nonFullChunks[pos]; - if (header) { - m = header->freeItems.nextFree(); - goto found; - } - } - - // no free item available, allocate a new chunk - { - // allocate larger chunks at a time to avoid excessive GC, but cap at maximum chunk size (2MB by default) - uint shift = ++m_d->nChunks[pos]; - if (shift > m_d->maxShift) - shift = m_d->maxShift; - 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), - OSAllocator::JSGCHeapPages); - m_d->heapChunks.append(allocation); - std::sort(m_d->heapChunks.begin(), m_d->heapChunks.end()); - - header = reinterpret_cast<Data::ChunkHeader *>(allocation.base()); - header->itemSize = int(size); - header->itemStart = reinterpret_cast<char *>(allocation.base()) + roundUpToMultipleOf(16, sizeof(Data::ChunkHeader)); - header->itemEnd = reinterpret_cast<char *>(allocation.base()) + allocation.size() - header->itemSize; - - header->nextNonFull = m_d->nonFullChunks[pos]; - m_d->nonFullChunks[pos] = header; - - Heap::Base *last = &header->freeItems; - for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) { - Heap::Base *o = reinterpret_cast<Heap::Base *>(item); - last->setNextFree(o); - last = o; - - } - last->setNextFree(0); - m = header->freeItems.nextFree(); - const size_t increase = (header->itemEnd - header->itemStart) / header->itemSize; - m_d->availableItems[pos] += uint(increase); - m_d->totalItems += int(increase); -#ifdef V4_USE_VALGRIND - VALGRIND_MAKE_MEM_NOACCESS(allocation.base(), allocSize); - VALGRIND_MEMPOOL_ALLOC(this, header, sizeof(Data::ChunkHeader)); -#endif - } - - found: -#ifdef V4_USE_VALGRIND - VALGRIND_MEMPOOL_ALLOC(this, m, size); -#endif - Q_V4_PROFILE_ALLOC(m_d->engine, size, Profiling::SmallItem); - - ++m_d->allocCount[pos]; - ++m_d->totalAlloc; - header->freeItems.setNextFree(m->nextFree()); - if (!header->freeItems.nextFree()) - m_d->nonFullChunks[pos] = header->nextNonFull; - return m; -} - -static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase) -{ - while (engine->jsStackTop > markBase) { - Heap::Base *h = engine->popForGC(); - Q_ASSERT (h->gcGetVtable()->markObjects); - h->gcGetVtable()->markObjects(h, engine); - } -} - -void MemoryManager::mark() -{ - Value *markBase = m_d->engine->jsStackTop; - - m_d->engine->markObjects(); - - m_persistentValues->mark(m_d->engine); - - collectFromJSStack(); - - // Preserve QObject ownership rules within JavaScript: A parent with c++ ownership - // keeps all of its children alive in JavaScript. - - // Do this _after_ collectFromStack to ensure that processing the weak - // managed objects in the loop down there doesn't make then end up as leftovers - // on the stack and thus always get collected. - for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { - if (!(*it).isManaged()) - continue; - if ((*it).managed()->d()->gcGetVtable() != QObjectWrapper::staticVTable()) - continue; - QObjectWrapper *qobjectWrapper = static_cast<QObjectWrapper*>((*it).managed()); - if (!qobjectWrapper) - continue; - QObject *qobject = qobjectWrapper->object(); - if (!qobject) - continue; - bool keepAlive = QQmlData::keepAliveDuringGarbageCollection(qobject); - - if (!keepAlive) { - if (QObject *parent = qobject->parent()) { - while (parent->parent()) - parent = parent->parent(); - - keepAlive = QQmlData::keepAliveDuringGarbageCollection(parent); - } - } - - if (keepAlive) - qobjectWrapper->mark(m_d->engine); - - if (m_d->engine->jsStackTop >= m_d->engine->jsStackLimit) - drainMarkStack(m_d->engine, markBase); - } - - drainMarkStack(m_d->engine, markBase); -} - -void MemoryManager::sweep(bool lastSweep) -{ - if (m_weakValues) { - for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { - if (Managed *m = (*it).asManaged()) { - if (!m->markBit()) - (*it) = Primitive::undefinedValue(); - } - } - } - - if (MultiplyWrappedQObjectMap *multiplyWrappedQObjects = m_d->engine->m_multiplyWrappedQObjects) { - for (MultiplyWrappedQObjectMap::Iterator it = multiplyWrappedQObjects->begin(); it != multiplyWrappedQObjects->end();) { - if (!it.value().isNullOrUndefined()) - it = multiplyWrappedQObjects->erase(it); - else - ++it; - } - } - - bool *chunkIsEmpty = (bool *)alloca(m_d->heapChunks.size() * sizeof(bool)); - uint itemsInUse[MemoryManager::Data::MaxItemSize/16]; - memset(itemsInUse, 0, sizeof(itemsInUse)); - memset(m_d->nonFullChunks, 0, sizeof(m_d->nonFullChunks)); - - 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); - } - - QVector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin(); - for (int i = 0; i < m_d->heapChunks.size(); ++i) { - Q_ASSERT(chunkIter != m_d->heapChunks.end()); - Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(chunkIter->base()); - const size_t pos = header->itemSize >> 4; - const size_t decrease = (header->itemEnd - header->itemStart) / header->itemSize; - - // 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); -#ifdef V4_USE_VALGRIND - VALGRIND_MEMPOOL_FREE(this, header); -#endif - --m_d->nChunks[pos]; - m_d->availableItems[pos] -= uint(decrease); - m_d->totalItems -= int(decrease); - chunkIter->deallocate(); - chunkIter = m_d->heapChunks.erase(chunkIter); - continue; - } else if (header->freeItems.nextFree()) { - header->nextNonFull = m_d->nonFullChunks[pos]; - m_d->nonFullChunks[pos] = header; - } - ++chunkIter; - } - - Data::LargeItem *i = m_d->largeItems; - Data::LargeItem **last = &m_d->largeItems; - while (i) { - Heap::Base *m = i->heapObject(); - Q_ASSERT(m->inUse()); - if (m->isMarked()) { - m->clearMarkBit(); - last = &i->next; - i = i->next; - continue; - } - if (m->gcGetVtable()->destroy) - m->gcGetVtable()->destroy(m); - - *last = i->next; - free(Q_V4_PROFILE_DEALLOC(m_d->engine, i, i->size + sizeof(Data::LargeItem), - Profiling::LargeItem)); - i = *last; - } - - GCDeletable *deletable = m_d->deletable; - m_d->deletable = 0; - while (deletable) { - GCDeletable *next = deletable->next; - deletable->lastCall = lastSweep; - delete deletable; - deletable = next; - } - - // some execution contexts are allocated on the stack, make sure we clear their markBit as well - if (!lastSweep) { - Heap::ExecutionContext *ctx = engine()->current; - while (ctx) { - ctx->clearMarkBit(); - ctx = ctx->parent; - } - } -} - -bool MemoryManager::isGCBlocked() const -{ - return m_d->gcBlocked; -} - -void MemoryManager::setGCBlocked(bool blockGC) -{ - m_d->gcBlocked = blockGC; -} - -void MemoryManager::runGC() -{ - if (m_d->gcBlocked) { -// qDebug() << "Not running GC."; - return; - } - - if (!m_d->gcStats) { - mark(); - sweep(); - } else { - const size_t totalMem = getAllocatedMem(); - - QTime t; - t.start(); - mark(); - int markTime = t.elapsed(); - t.restart(); - const size_t usedBefore = getUsedMem(); - int chunksBefore = m_d->heapChunks.size(); - sweep(); - const size_t usedAfter = getUsedMem(); - int sweepTime = t.elapsed(); - - qDebug() << "========== GC =========="; - qDebug() << "Marked object in" << markTime << "ms."; - qDebug() << "Sweeped object in" << sweepTime << "ms."; - qDebug() << "Allocated" << totalMem << "bytes in" << m_d->heapChunks.size() << "chunks."; - qDebug() << "Used memory before GC:" << usedBefore; - qDebug() << "Used memory after GC:" << usedAfter; - qDebug() << "Freed up bytes:" << (usedBefore - usedAfter); - qDebug() << "Released chunks:" << (chunksBefore - m_d->heapChunks.size()); - qDebug() << "======== End GC ========"; - } - - memset(m_d->allocCount, 0, sizeof(m_d->allocCount)); - m_d->totalAlloc = 0; - m_d->totalLargeItemsAllocated = 0; -} - -size_t MemoryManager::getUsedMem() const -{ - size_t usedMem = 0; - for (QVector<PageAllocation>::const_iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i) { - Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(i->base()); - for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) { - Heap::Base *m = reinterpret_cast<Heap::Base *>(item); - Q_ASSERT((qintptr) item % 16 == 0); - if (m->inUse()) - usedMem += header->itemSize; - } - } - return usedMem; -} - -size_t MemoryManager::getAllocatedMem() const -{ - size_t total = 0; - for (int i = 0; i < m_d->heapChunks.size(); ++i) - total += m_d->heapChunks.at(i).size(); - return total; -} - -size_t MemoryManager::getLargeItemsMem() const -{ - size_t total = 0; - for (const Data::LargeItem *i = m_d->largeItems; i != 0; i = i->next) - total += i->size; - return total; -} - -void MemoryManager::growUnmanagedHeapSizeUsage(size_t delta) -{ - m_d->unmanagedHeapSize += delta; -} - -MemoryManager::~MemoryManager() -{ - delete m_persistentValues; - delete m_weakValues; - m_weakValues = 0; - - sweep(/*lastSweep*/true); -#ifdef V4_USE_VALGRIND - VALGRIND_DESTROY_MEMPOOL(this); -#endif -} - -ExecutionEngine *MemoryManager::engine() const -{ - return m_d->engine; -} - -void MemoryManager::dumpStats() const -{ -#ifdef DETAILED_MM_STATS - std::cerr << "=================" << std::endl; - std::cerr << "Allocation stats:" << std::endl; - std::cerr << "Requests for each chunk size:" << std::endl; - for (int i = 0; i < m_d->allocSizeCounters.size(); ++i) { - if (unsigned count = m_d->allocSizeCounters[i]) { - std::cerr << "\t" << (i << 4) << " bytes chunks: " << count << std::endl; - } - } -#endif // DETAILED_MM_STATS -} - -void MemoryManager::registerDeletable(GCDeletable *d) -{ - d->next = m_d->deletable; - m_d->deletable = d; -} - -#ifdef DETAILED_MM_STATS -void MemoryManager::willAllocate(std::size_t size) -{ - unsigned alignedSize = (size + 15) >> 4; - QVector<unsigned> &counters = m_d->allocSizeCounters; - if ((unsigned) counters.size() < alignedSize + 1) - counters.resize(alignedSize + 1); - counters[alignedSize]++; -} - -#endif // DETAILED_MM_STATS - -void MemoryManager::collectFromJSStack() const -{ - Value *v = m_d->engine->jsStackBase; - Value *top = m_d->engine->jsStackTop; - while (v < top) { - Managed *m = v->asManaged(); - if (m && m->inUse()) - // Skip pointers to already freed objects, they are bogus as well - m->mark(m_d->engine); - ++v; - } -} -QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/jsruntime/qv4mm_p.h deleted file mode 100644 index 7f6d2edba3..0000000000 --- a/src/qml/jsruntime/qv4mm_p.h +++ /dev/null @@ -1,198 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QV4GC_H -#define QV4GC_H - -#include "qv4global_p.h" -#include "qv4value_inl_p.h" -#include "qv4scopedvalue_p.h" - -//#define DETAILED_MM_STATS - -QT_BEGIN_NAMESPACE - -namespace QV4 { - -struct GCDeletable; - -class Q_QML_EXPORT MemoryManager -{ - Q_DISABLE_COPY(MemoryManager); - -public: - struct Data; - - class GCBlocker - { - public: - GCBlocker(MemoryManager *mm) - : mm(mm) - , wasBlocked(mm->isGCBlocked()) - { - mm->setGCBlocked(true); - } - - ~GCBlocker() - { - mm->setGCBlocked(wasBlocked); - } - - private: - MemoryManager *mm; - bool wasBlocked; - }; - -public: - MemoryManager(ExecutionEngine *engine); - ~MemoryManager(); - - // TODO: this is only for 64bit (and x86 with SSE/AVX), so exend it for other architectures to be slightly more efficient (meaning, align on 8-byte boundaries). - // Note: all occurrences of "16" in alloc/dealloc are also due to the alignment. - static inline std::size_t align(std::size_t size) - { return (size + 15) & ~0xf; } - - template<typename ManagedType> - inline typename ManagedType::Data *allocManaged(std::size_t size, std::size_t unmanagedSize = 0) - { - size = align(size); - Heap::Base *o = allocData(size, unmanagedSize); - o->vtable = ManagedType::staticVTable(); - return static_cast<typename ManagedType::Data *>(o); - } - - template <typename ManagedType> - typename ManagedType::Data *alloc() - { - Scope scope(engine()); - Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data))); - (void)new (t->d()) typename ManagedType::Data(); - return t->d(); - } - - template <typename ManagedType, typename Arg1> - typename ManagedType::Data *alloc(Arg1 arg1) - { - 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()); - Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data))); - (void)new (t->d()) typename ManagedType::Data(arg1, arg2); - return t->d(); - } - - template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3> - typename ManagedType::Data *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3) - { - 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(); - } - - 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()); - Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data))); - (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4); - return t->d(); - } - - 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()); - 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(); - } - - bool isGCBlocked() const; - void setGCBlocked(bool blockGC); - void runGC(); - - ExecutionEngine *engine() const; - - void dumpStats() const; - - void registerDeletable(GCDeletable *d); - - size_t getUsedMem() const; - size_t getAllocatedMem() const; - size_t getLargeItemsMem() const; - - void growUnmanagedHeapSizeUsage(size_t delta); // called when a JS object grows itself. Specifically: Heap::String::append - -protected: - /// expects size to be aligned - // TODO: try to inline - Heap::Base *allocData(std::size_t size, std::size_t unmanagedSize); - -#ifdef DETAILED_MM_STATS - void willAllocate(std::size_t size); -#endif // DETAILED_MM_STATS - -private: - void collectFromJSStack() const; - void mark(); - void sweep(bool lastSweep = false); - -protected: - QScopedPointer<Data> m_d; -public: - PersistentValueStorage *m_persistentValues; - PersistentValueStorage *m_weakValues; -}; - -} - -QT_END_NAMESPACE - -#endif // QV4GC_H diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 4a1a94e872..4ae30a7f35 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -33,6 +33,7 @@ #include "qv4numberobject_p.h" #include "qv4runtime_p.h" +#include "qv4string_p.h" #include <QtCore/qnumeric.h> #include <QtCore/qmath.h> @@ -50,14 +51,14 @@ Heap::NumberCtor::NumberCtor(QV4::ExecutionContext *scope) { } -ReturnedValue NumberCtor::construct(Managed *m, CallData *callData) +ReturnedValue NumberCtor::construct(const Managed *m, CallData *callData) { Scope scope(m->cast<NumberCtor>()->engine()); double dbl = callData->argc ? callData->args[0].toNumber() : 0.; return Encode(scope.engine->newNumberObject(dbl)); } -ReturnedValue NumberCtor::call(Managed *, CallData *callData) +ReturnedValue NumberCtor::call(const Managed *, CallData *callData) { double dbl = callData->argc ? callData->args[0].toNumber() : 0.; return Encode(dbl); @@ -67,8 +68,8 @@ void NumberPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); ctor->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(qSNaN())); ctor->defineReadonlyProperty(QStringLiteral("NEGATIVE_INFINITY"), Primitive::fromDouble(-qInf())); @@ -81,9 +82,9 @@ QT_WARNING_DISABLE_INTEL(239) QT_WARNING_POP defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString); + defineDefaultProperty(engine->id_toString(), method_toString); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); - defineDefaultProperty(engine->id_valueOf, method_valueOf); + defineDefaultProperty(engine->id_valueOf(), method_valueOf); defineDefaultProperty(QStringLiteral("toFixed"), method_toFixed, 1); defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential); defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision); @@ -93,7 +94,7 @@ inline ReturnedValue thisNumberValue(ExecutionContext *ctx) { if (ctx->thisObject().isNumber()) return ctx->thisObject().asReturnedValue(); - NumberObject *n = ctx->thisObject().asNumberObject(); + NumberObject *n = ctx->thisObject().as<NumberObject>(); if (!n) return ctx->engine()->throwTypeError(); return Encode(n->value()); @@ -103,7 +104,7 @@ inline double thisNumber(ExecutionContext *ctx) { if (ctx->thisObject().isNumber()) return ctx->thisObject().asDouble(); - NumberObject *n = ctx->thisObject().asNumberObject(); + NumberObject *n = ctx->thisObject().as<NumberObject>(); if (!n) return ctx->engine()->throwTypeError(); return n->value(); @@ -119,7 +120,7 @@ ReturnedValue NumberPrototype::method_toString(CallContext *ctx) if (ctx->argc() && !ctx->args()[0].isUndefined()) { int radix = ctx->args()[0].toInt32(); if (radix < 2 || radix > 36) - return ctx->engine()->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix") + return ctx->engine()->throwError(QStringLiteral("Number.prototype.toString: %0 is not a valid radix") .arg(radix)); if (std::isnan(num)) { @@ -197,7 +198,7 @@ ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx) QString str; if (std::isnan(v)) - str = QString::fromLatin1("NaN"); + str = QStringLiteral("NaN"); else if (qIsInf(v)) str = QString::fromLatin1(v < 0 ? "-Infinity" : "Infinity"); else if (v < 1.e21) { diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h index 205995701b..cc5033531e 100644 --- a/src/qml/jsruntime/qv4numberobject_p.h +++ b/src/qml/jsruntime/qv4numberobject_p.h @@ -33,6 +33,17 @@ #ifndef QV4NUMBEROBJECT_H #define QV4NUMBEROBJECT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" #include <QtCore/qnumeric.h> @@ -53,8 +64,8 @@ struct NumberCtor: FunctionObject { V4_OBJECT2(NumberCtor, FunctionObject) - static ReturnedValue construct(Managed *that, CallData *callData); - static ReturnedValue call(Managed *, CallData *callData); + static ReturnedValue construct(const Managed *that, CallData *callData); + static ReturnedValue call(const Managed *, CallData *callData); }; struct NumberPrototype: NumberObject diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 211fd1812e..ba29d52bc6 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -37,12 +37,14 @@ #include "qv4objectproto_p.h" #include "qv4stringobject_p.h" #include "qv4argumentsobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4lookup_p.h" #include "qv4scopedvalue_p.h" #include "qv4memberdata_p.h" #include "qv4objectiterator_p.h" #include "qv4identifier_p.h" +#include "qv4string_p.h" +#include "qv4identifiertable_p.h" #include <stdint.h> @@ -50,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) @@ -80,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; @@ -115,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(); } @@ -136,9 +152,9 @@ 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)); + function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(s, function); } @@ -146,9 +162,9 @@ 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)); + function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(name, function); } @@ -165,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); @@ -188,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) @@ -196,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) @@ -206,102 +230,97 @@ 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; } } // Section 8.12.1 -Property *Object::__getOwnProperty__(String *name, PropertyAttributes *attrs) +void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) - return __getOwnProperty__(idx, attrs); + return getOwnProperty(idx, attrs, p); uint member = internalClass()->find(name); if (member < UINT_MAX) { - if (attrs) - *attrs = internalClass()->propertyData[member]; - return propertyAt(member); + *attrs = internalClass()->propertyData[member]; + if (p) { + p->value = *propertyData(member); + if (attrs->isAccessor()) + p->set = *propertyData(member + SetterOffset); + } + return; } if (attrs) *attrs = Attr_Invalid; - return 0; + return; } -Property *Object::__getOwnProperty__(uint index, PropertyAttributes *attrs) +void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p) { - Property *p = arrayData() ? arrayData()->getProperty(index) : 0; - if (p) { - if (attrs) - *attrs = arrayData()->attributes(index); - return p; + Property *pd = arrayData() ? arrayData()->getProperty(index) : 0; + if (pd) { + *attrs = arrayData()->attributes(index); + if (p) + p->copy(pd, *attrs); + return; } if (isStringObject()) { - if (attrs) - *attrs = Attr_NotConfigurable|Attr_NotWritable; - return static_cast<StringObject *>(this)->getIndex(index); + *attrs = Attr_NotConfigurable|Attr_NotWritable; + if (p) + p->value = static_cast<StringObject *>(this)->getIndex(index); + return; } if (attrs) *attrs = Attr_Invalid; - return 0; + return; } // Section 8.12.2 -Property *Object::__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const +Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs) { - uint idx = name->asArrayIndex(); - if (idx != UINT_MAX) - return __getPropertyDescriptor__(idx, 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) { - if (attrs) - *attrs = o->arrayData->attributes(index); - return p; + *attrs = o->arrayData->attributes(index); + return attrs->isAccessor() ? &p->set : &p->value; } - if (o->vtable->type == Type_StringObject) { - Property *p = static_cast<const Heap::StringObject *>(o)->getIndex(index); - if (p) { - if (attrs) - *attrs = (Attr_NotWritable|Attr_NotConfigurable); - return p; + 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<Value *>(0x1); } } o = o->prototype; } - if (attrs) - *attrs = Attr_Invalid; + *attrs = Attr_Invalid; return 0; } @@ -356,8 +375,7 @@ bool Object::hasOwnProperty(uint index) const return true; if (isStringObject()) { - String *s = static_cast<const StringObject *>(this)->d()->value.asString(); - if (index < (uint)s->d()->length()) + if (index < static_cast<const StringObject *>(this)->length()) return true; } if (!queryIndexed(index).isEmpty()) @@ -365,24 +383,24 @@ bool Object::hasOwnProperty(uint index) const return false; } -ReturnedValue Object::construct(Managed *m, CallData *) +ReturnedValue Object::construct(const Managed *m, CallData *) { - return static_cast<Object *>(m)->engine()->throwTypeError(); + return static_cast<const Object *>(m)->engine()->throwTypeError(); } -ReturnedValue Object::call(Managed *m, CallData *) +ReturnedValue Object::call(const Managed *m, CallData *) { - return static_cast<Object *>(m)->engine()->throwTypeError(); + return static_cast<const Object *>(m)->engine()->throwTypeError(); } -ReturnedValue Object::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue Object::get(const Managed *m, String *name, bool *hasProperty) { - return static_cast<Object *>(m)->internalGet(name, hasProperty); + return static_cast<const Object *>(m)->internalGet(name, hasProperty); } -ReturnedValue Object::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue Object::getIndexed(const Managed *m, uint index, bool *hasProperty) { - return static_cast<Object *>(m)->internalGetIndexed(index, hasProperty); + return static_cast<const Object *>(m)->internalGetIndexed(index, hasProperty); } void Object::put(Managed *m, String *name, const Value &value) @@ -416,8 +434,7 @@ PropertyAttributes Object::queryIndexed(const Managed *m, uint index) return o->arrayData()->attributes(index); if (o->isStringObject()) { - String *s = static_cast<const StringObject *>(o)->d()->value.asString(); - if (index < (uint)s->d()->length()) + if (index < static_cast<const StringObject *>(o)->length()) return (Attr_NotWritable|Attr_NotConfigurable); } return Attr_Invalid; @@ -433,9 +450,9 @@ bool Object::deleteIndexedProperty(Managed *m, uint index) return static_cast<Object *>(m)->internalDeleteIndexedProperty(index); } -ReturnedValue Object::getLookup(Managed *m, Lookup *l) +ReturnedValue Object::getLookup(const Managed *m, Lookup *l) { - Object *o = static_cast<Object *>(m); + const Object *o = static_cast<const Object *>(m); PropertyAttributes attrs; ReturnedValue v = l->lookup(o, &attrs); if (v != Primitive::emptyValue().asReturnedValue()) { @@ -468,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); @@ -477,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; } } @@ -516,10 +533,10 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value) l->setter = Lookup::setterGeneric; } -void Object::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *pd, PropertyAttributes *attrs) +void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *pd, PropertyAttributes *attrs) { Object *o = static_cast<Object *>(m); - *name = 0; + name->setM(0); *index = UINT_MAX; if (o->arrayData()) { @@ -531,7 +548,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name while (it->arrayNode != o->sparseEnd()) { int k = it->arrayNode->key(); uint pidx = it->arrayNode->value; - Heap::SparseArrayData *sa = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *sa = o->d()->arrayData.cast<Heap::SparseArrayData>(); Property *p = reinterpret_cast<Property *>(sa->arrayData + pidx); it->arrayNode = it->arrayNode->nextNode(); PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data; @@ -548,7 +565,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name } // dense arrays while (it->arrayIndex < o->d()->arrayData->len) { - Heap::SimpleArrayData *sa = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *sa = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Value &val = sa->data(it->arrayIndex); PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex); ++it->arrayIndex; @@ -570,13 +587,15 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name 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 = 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; } } @@ -585,7 +604,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name } // Section 8.12.3 -ReturnedValue Object::internalGet(String *name, bool *hasProperty) +ReturnedValue Object::internalGet(String *name, bool *hasProperty) const { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) @@ -600,7 +619,7 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) 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(); @@ -611,7 +630,7 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) return Encode::undefined(); } -ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) +ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const { Property *pd = 0; PropertyAttributes attrs; @@ -625,10 +644,12 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) break; } if (o->isStringObject()) { - pd = static_cast<StringObject *>(o.getPointer())->getIndex(index); - if (pd) { + ScopedString str(scope, static_cast<StringObject *>(o.getPointer())->getIndex(index)); + if (str) { attrs = (Attr_NotWritable|Attr_NotConfigurable); - break; + if (hasProperty) + *hasProperty = true; + return str.asReturnedValue(); } } o = o->prototype(); @@ -637,7 +658,7 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) if (pd) { if (hasProperty) *hasProperty = true; - return getValue(pd, attrs); + return getValue(pd->value, attrs); } if (hasProperty) @@ -659,22 +680,22 @@ 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()) goto reject; - else if (isArrayObject() && name->equals(engine()->id_length)) { + else if (isArrayObject() && name->equals(engine()->id_length())) { bool ok; uint l = value.asArrayLength(&ok); if (!ok) { @@ -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()) { - 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,27 +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()) { - pd = static_cast<StringObject *>(this)->getIndex(index); - if (pd) + 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()) @@ -768,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; @@ -783,11 +801,11 @@ void Object::internalPutIndexed(uint index, const Value &value) cont: // Clause 5 - if (pd && attrs.isAccessor()) { - 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; @@ -799,7 +817,7 @@ void Object::internalPutIndexed(uint index, const Value &value) return; reject: - if (engine()->currentContext()->strictMode) + if (engine()->current->strictMode) engine()->throwTypeError(); } @@ -821,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; } @@ -839,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; } @@ -854,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)) + if (isArrayObject() && name->equals(engine->id_length())) { + Q_ASSERT(Heap::ArrayObject::LengthPropertyIndex == internalClass()->find(engine->id_length())); + 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) { @@ -877,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; @@ -886,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; @@ -903,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; } @@ -919,23 +936,23 @@ 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; } bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Property *p, PropertyAttributes attrs) { - Property *current = 0; + bool hasProperty = 0; // Clause 1 if (arrayData()) { - current = arrayData()->getProperty(index); - if (!current && isStringObject()) - current = static_cast<StringObject *>(this)->getIndex(index); + hasProperty = arrayData()->getProperty(index); + if (!hasProperty && isStringObject()) + hasProperty = (index < static_cast<StringObject *>(this)->length()); } - if (!current) { + if (!hasProperty) { // clause 3 if (!isExtensible()) goto reject; @@ -955,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; } @@ -966,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); } @@ -1006,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); @@ -1017,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(); } @@ -1029,9 +1045,9 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * } else { // clause 10 Q_ASSERT(cattrs.isAccessor() && attrs.isAccessor()); if (!cattrs.isConfigurable()) { - if (!p->value.isEmpty() && current->value.val != p->value.val) + if (!p->value.isEmpty() && current->value.rawValue() != p->value.rawValue()) goto reject; - if (!p->set.isEmpty() && current->set.val != p->set.val) + if (!p->set.isEmpty() && current->set.rawValue() != p->set.rawValue()) goto reject; } } @@ -1041,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; } @@ -1089,7 +1107,7 @@ void Object::copyArrayData(Object *other) dd->len = other->d()->arrayData->len; dd->offset = other->d()->arrayData->offset; } - memcpy(d()->arrayData->arrayData, other->d()->arrayData->arrayData, d()->arrayData->alloc*sizeof(Value)); + memcpy(d()->arrayData->arrayData, other->d()->arrayData->arrayData, other->d()->arrayData->alloc*sizeof(Value)); } setArrayLengthUnchecked(other->getLength()); } @@ -1097,7 +1115,7 @@ void Object::copyArrayData(Object *other) uint Object::getLength(const Managed *m) { Scope scope(static_cast<const Object *>(m)->engine()); - ScopedValue v(scope, static_cast<Object *>(const_cast<Managed *>(m))->get(scope.engine->id_length)); + ScopedValue v(scope, static_cast<Object *>(const_cast<Managed *>(m))->get(scope.engine->id_length())); return v->toUInt32(); } @@ -1136,11 +1154,11 @@ void Object::initSparseArray() DEFINE_OBJECT_VTABLE(ArrayObject); -Heap::ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list) - : Heap::Object(engine->arrayClass, engine->arrayPrototype.asObject()) +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. @@ -1151,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(Managed *m, Lookup *l) +ReturnedValue ArrayObject::getLookup(const Managed *m, Lookup *l) { - Scope scope(static_cast<Object *>(m)->engine()); - ScopedString name(scope, scope.engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); - if (name->equals(scope.engine->id_length)) { + Scope scope(static_cast<const Object *>(m)->engine()); + 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; - ArrayObject *a = static_cast<ArrayObject *>(m); - return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].asReturnedValue(); + const ArrayObject *a = static_cast<const ArrayObject *>(m); + return a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->asReturnedValue(); } return Object::getLookup(m, l); } @@ -1171,9 +1189,9 @@ ReturnedValue ArrayObject::getLookup(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 e2250b9f18..5c660f7e3f 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -33,31 +33,43 @@ #ifndef QV4_OBJECT_H #define QV4_OBJECT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4managed_p.h" #include "qv4memberdata_p.h" #include "qv4arraydata_p.h" +#include "qv4engine_p.h" +#include "qv4scopedvalue_p.h" +#include "qv4value_p.h" QT_BEGIN_NAMESPACE + namespace QV4 { namespace Heap { struct Object : Base { - Object(ExecutionEngine *engine) - : internalClass(engine->emptyClass), - prototype(static_cast<Object *>(engine->objectPrototype.m)) - { - } - 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; - Heap::Object *prototype; - MemberData *memberData; - ArrayData *arrayData; + Pointer<Object> prototype; + Pointer<MemberData> memberData; + Pointer<ArrayData> arrayData; }; } @@ -67,9 +79,9 @@ struct Object : Base { Q_MANAGED_CHECK \ typedef superClass SuperClass; \ static const QV4::ObjectVTable static_vtbl; \ - static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \ + static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \ V4_MANAGED_SIZE_TEST \ - Data *d() const { return static_cast<Data *>(m); } + Data *d() const { return static_cast<Data *>(m()); } #define V4_OBJECT2(DataClass, superClass) \ private: \ @@ -80,33 +92,40 @@ struct Object : Base { typedef QV4::Heap::DataClass Data; \ typedef superClass SuperClass; \ static const QV4::ObjectVTable static_vtbl; \ - static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \ + static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \ V4_MANAGED_SIZE_TEST \ - QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m); } + 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 { - ManagedVTable managedVTable; - ReturnedValue (*call)(Managed *, CallData *data); - ReturnedValue (*construct)(Managed *, CallData *data); - ReturnedValue (*get)(Managed *, String *name, bool *hasProperty); - ReturnedValue (*getIndexed)(Managed *, uint index, bool *hasProperty); + VTable vTable; + ReturnedValue (*call)(const Managed *, CallData *data); + ReturnedValue (*construct)(const Managed *, CallData *data); + ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty); + ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty); void (*put)(Managed *, String *name, const Value &value); void (*putIndexed)(Managed *, uint index, const Value &value); PropertyAttributes (*query)(const Managed *, String *name); PropertyAttributes (*queryIndexed)(const Managed *, uint index); bool (*deleteProperty)(Managed *m, String *name); bool (*deleteIndexedProperty)(Managed *m, uint index); - ReturnedValue (*getLookup)(Managed *m, Lookup *l); + ReturnedValue (*getLookup)(const Managed *m, Lookup *l); void (*setLookup)(Managed *m, Lookup *l, const Value &v); uint (*getLength)(const Managed *m); - void (*advanceIterator)(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes); + void (*advanceIterator)(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); }; #define DEFINE_OBJECT_VTABLE(classname) \ const QV4::ObjectVTable classname::static_vtbl = \ { \ - DEFINE_MANAGED_VTABLE_INT(classname, &classname::SuperClass::static_vtbl == &Object::static_vtbl ? 0 : &classname::SuperClass::static_vtbl.managedVTable), \ + DEFINE_MANAGED_VTABLE_INT(classname, &classname::SuperClass::static_vtbl == &Object::static_vtbl ? 0 : &classname::SuperClass::static_vtbl.vTable), \ call, \ construct, \ get, \ @@ -128,31 +147,36 @@ 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); } + const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(d()->vtable()); } Heap::Object *prototype() const { return d()->prototype; } bool setPrototype(Object *proto); - Property *__getOwnProperty__(String *name, PropertyAttributes *attrs = 0); - Property *__getOwnProperty__(uint index, PropertyAttributes *attrs = 0); + void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0); + void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = 0); - Property *__getPropertyDescriptor__(String *name, PropertyAttributes *attrs = 0) const; - Property *__getPropertyDescriptor__(uint index, PropertyAttributes *attrs = 0) const; + Value *getValueOrSetter(String *name, PropertyAttributes *attrs); + Value *getValueOrSetter(uint index, PropertyAttributes *attrs); bool hasProperty(String *name) const; bool hasProperty(uint index) const; @@ -171,14 +195,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) { @@ -193,10 +217,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); @@ -273,11 +293,10 @@ public: return false; } - void ensureMemberIndex(uint idx); - inline ReturnedValue get(String *name, bool *hasProperty = 0) + inline ReturnedValue get(String *name, bool *hasProperty = 0) const { return vtable()->get(this, name, hasProperty); } - inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) + inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) const { return vtable()->getIndexed(this, idx, hasProperty); } inline void put(String *name, const Value &v) { vtable()->put(this, name, v); } @@ -291,38 +310,40 @@ public: { return vtable()->deleteProperty(this, name); } bool deleteIndexedProperty(uint index) { return vtable()->deleteIndexedProperty(this, index); } - ReturnedValue getLookup(Lookup *l) + ReturnedValue getLookup(Lookup *l) const { return vtable()->getLookup(this, l); } void setLookup(Lookup *l, const Value &v) { vtable()->setLookup(this, l, v); } - void advanceIterator(ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes) + void advanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes) { vtable()->advanceIterator(this, it, name, index, p, attributes); } uint getLength() const { return vtable()->getLength(this); } - inline ReturnedValue construct(CallData *d) + inline ReturnedValue construct(CallData *d) const { return vtable()->construct(this, d); } - inline ReturnedValue call(CallData *d) + inline ReturnedValue call(CallData *d) const { return vtable()->call(this, d); } protected: static void markObjects(Heap::Base *that, ExecutionEngine *e); - static ReturnedValue construct(Managed *m, CallData *); - static ReturnedValue call(Managed *m, CallData *); - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue construct(const Managed *m, CallData *); + static ReturnedValue call(const Managed *m, CallData *); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); static void putIndexed(Managed *m, uint index, const Value &value); static PropertyAttributes query(const Managed *m, String *name); static PropertyAttributes queryIndexed(const Managed *m, uint index); static bool deleteProperty(Managed *m, String *name); static bool deleteIndexedProperty(Managed *m, uint index); - static ReturnedValue getLookup(Managed *m, Lookup *l); + static ReturnedValue getLookup(const Managed *m, Lookup *l); static void setLookup(Managed *m, Lookup *l, const Value &v); - static void advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes); + 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); - ReturnedValue internalGetIndexed(uint index, bool *hasProperty); + ReturnedValue internalGet(String *name, bool *hasProperty) const; + ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const; void internalPut(String *name, const Value &value); void internalPutIndexed(uint index, const Value &value); bool internalDeleteProperty(String *name); @@ -335,32 +356,18 @@ private: namespace Heap { struct BooleanObject : Object { - BooleanObject(InternalClass *ic, QV4::Object *prototype) - : Object(ic, prototype), - b(false) - { - } - - BooleanObject(ExecutionEngine *engine, bool b) - : Object(engine->emptyClass, engine->booleanPrototype.asObject()), - 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.asObject()), - value(val) - { - } + NumberObject() {} + NumberObject(double val) + : value(val) + {} double value; }; @@ -369,15 +376,11 @@ struct ArrayObject : Object { LengthPropertyIndex = 0 }; - ArrayObject(ExecutionEngine *engine) - : Heap::Object(engine->arrayClass, engine->arrayPrototype.asObject()) - { 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); } }; } @@ -385,6 +388,7 @@ struct ArrayObject : Object { struct BooleanObject: Object { V4_OBJECT2(BooleanObject, Object) Q_MANAGED_TYPE(BooleanObject) + V4_PROTOTYPE(booleanPrototype) bool value() const { return d()->b; } @@ -393,6 +397,7 @@ struct BooleanObject: Object { struct NumberObject: Object { V4_OBJECT2(NumberObject, Object) Q_MANAGED_TYPE(NumberObject) + V4_PROTOTYPE(numberPrototype) double value() const { return d()->value; } }; @@ -400,10 +405,12 @@ struct NumberObject: Object { struct ArrayObject: Object { V4_OBJECT2(ArrayObject, Object) Q_MANAGED_TYPE(ArrayObject) + V4_INTERNALCLASS(arrayClass) + V4_PROTOTYPE(arrayPrototype) void init(ExecutionEngine *engine); - static ReturnedValue getLookup(Managed *m, Lookup *l); + static ReturnedValue getLookup(const Managed *m, Lookup *l); using Object::getLength; static uint getLength(const Managed *m); @@ -413,7 +420,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) @@ -436,10 +443,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); } @@ -451,20 +455,15 @@ 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); } -template<> -inline Object *value_cast(const Value &v) { - return v.asObject(); -} template<> -inline ArrayObject *value_cast(const Value &v) { - return v.asArrayObject(); +inline const ArrayObject *Value::as() const { + return isManaged() && m() && m()->vtable()->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : 0; } #ifndef V4_BOOTSTRAP diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index f36ee554a7..1413f439b1 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -35,6 +35,7 @@ #include "qv4stringobject_p.h" #include "qv4identifier_p.h" #include "qv4argumentsobject_p.h" +#include "qv4string_p.h" using namespace QV4; @@ -50,7 +51,7 @@ ObjectIterator::ObjectIterator(ExecutionEngine *e, Value *scratch1, Value *scrat init(o); } -ObjectIterator::ObjectIterator(Scope &scope, Object *o, uint flags) +ObjectIterator::ObjectIterator(Scope &scope, const Object *o, uint flags) : engine(scope.engine) , object(scope.alloc(1)) , current(scope.alloc(1)) @@ -62,14 +63,14 @@ ObjectIterator::ObjectIterator(Scope &scope, Object *o, uint flags) init(o); } -void ObjectIterator::init(Object *o) +void ObjectIterator::init(const Object *o) { - object->m = o ? o->m : 0; - current->m = o ? o->m : 0; + object->setM(o ? o->m() : 0); + current->setM(o ? o->m() : 0); -#if QT_POINTER_SIZE == 4 - object->tag = QV4::Value::Managed_Type; - current->tag = QV4::Value::Managed_Type; +#ifndef QV4_USE_64_BIT_VALUE_ENCODING + object->setTag(QV4::Value::Managed_Type); + current->setTag(QV4::Value::Managed_Type); #endif if (object->as<ArgumentsObject>()) { @@ -78,12 +79,12 @@ void ObjectIterator::init(Object *o) } } -void ObjectIterator::next(Heap::String **name, uint *index, Property *pd, PropertyAttributes *attrs) +void ObjectIterator::next(Value *name, uint *index, Property *pd, PropertyAttributes *attrs) { - *name = 0; + name->setM(0); *index = UINT_MAX; - if (!object->asObject()) { + if (!object->as<Object>()) { *attrs = PropertyAttributes(); return; } @@ -92,19 +93,19 @@ void ObjectIterator::next(Heap::String **name, uint *index, Property *pd, Proper ScopedString n(scope); while (1) { - if (!current->asObject()) + if (!current->as<Object>()) break; while (1) { - current->asObject()->advanceIterator(this, name, index, pd, attrs); + current->as<Object>()->advanceIterator(this, name, index, pd, attrs); if (attrs->isEmpty()) break; // check the property is not already defined earlier in the proto chain if (current->heapObject() != object->heapObject()) { - o = object->asObject(); + o = object->as<Object>(); n = *name; bool shadowed = false; - while (o->asObject()->d() != current->heapObject()) { + while (o->d() != current->heapObject()) { if ((!!n && o->hasOwnProperty(n)) || (*index != UINT_MAX && o->hasOwnProperty(*index))) { shadowed = true; @@ -119,9 +120,9 @@ void ObjectIterator::next(Heap::String **name, uint *index, Property *pd, Proper } if (flags & WithProtoChain) - current->m = current->objectValue()->prototype(); + current->setM(current->objectValue()->prototype()); else - current->m = (Heap::Base *)0; + current->setM(0); arrayIndex = 0; memberIndex = 0; @@ -131,7 +132,7 @@ void ObjectIterator::next(Heap::String **name, uint *index, Property *pd, Proper ReturnedValue ObjectIterator::nextPropertyName(Value *value) { - if (!object->asObject()) + if (!object->as<Object>()) return Encode::null(); PropertyAttributes attrs; @@ -143,17 +144,17 @@ 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(); - assert(index < UINT_MAX); + Q_ASSERT(index < UINT_MAX); return Encode(index); } ReturnedValue ObjectIterator::nextPropertyNameAsString(Value *value) { - if (!object->asObject()) + if (!object->as<Object>()) return Encode::null(); PropertyAttributes attrs; @@ -165,17 +166,17 @@ 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(); - assert(index < UINT_MAX); + Q_ASSERT(index < UINT_MAX); return Encode(engine->newString(QString::number(index))); } ReturnedValue ObjectIterator::nextPropertyNameAsString() { - if (!object->asObject()) + if (!object->as<Object>()) return Encode::null(); PropertyAttributes attrs; diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index a7abd2ca10..877b34c22d 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -33,6 +33,17 @@ #ifndef QV4OBJECTITERATOR_H #define QV4OBJECTITERATOR_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include "qv4object_p.h" @@ -57,9 +68,9 @@ struct Q_QML_EXPORT ObjectIterator uint flags; ObjectIterator(ExecutionEngine *e, Value *scratch1, Value *scratch2, Object *o, uint flags); - ObjectIterator(Scope &scope, Object *o, uint flags); - void init(Object *o); - void next(Heap::String **name, uint *index, Property *pd, PropertyAttributes *attributes = 0); + ObjectIterator(Scope &scope, const Object *o, uint flags); + void init(const Object *o); + void next(Value *name, uint *index, Property *pd, PropertyAttributes *attributes = 0); ReturnedValue nextPropertyName(Value *value); ReturnedValue nextPropertyNameAsString(Value *value); ReturnedValue nextPropertyNameAsString(); @@ -67,7 +78,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 +96,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 9356ea434e..df7441ef5d 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -34,10 +34,11 @@ #include "qv4objectproto_p.h" #include "qv4argumentsobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4scopedvalue_p.h" #include "qv4runtime_p.h" #include "qv4objectiterator_p.h" +#include "qv4string_p.h" #include <QtCore/QDateTime> #include <QtCore/QStringList> @@ -52,14 +53,14 @@ Heap::ObjectCtor::ObjectCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ObjectCtor::construct(Managed *that, CallData *callData) +ReturnedValue ObjectCtor::construct(const Managed *that, CallData *callData) { - ObjectCtor *ctor = static_cast<ObjectCtor *>(that); + const ObjectCtor *ctor = static_cast<const ObjectCtor *>(that); ExecutionEngine *v4 = ctor->engine(); Scope scope(v4); if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) { ScopedObject obj(scope, v4->newObject()); - ScopedObject proto(scope, ctor->get(v4->id_prototype)); + ScopedObject proto(scope, ctor->get(v4->id_prototype())); if (!!proto) obj->setPrototype(proto); return obj.asReturnedValue(); @@ -67,9 +68,9 @@ ReturnedValue ObjectCtor::construct(Managed *that, CallData *callData) return RuntimeHelpers::toObject(scope.engine, callData->args[0]); } -ReturnedValue ObjectCtor::call(Managed *m, CallData *callData) +ReturnedValue ObjectCtor::call(const Managed *m, CallData *callData) { - ObjectCtor *ctor = static_cast<ObjectCtor *>(m); + const ObjectCtor *ctor = static_cast<const ObjectCtor *>(m); ExecutionEngine *v4 = ctor->engine(); if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) return v4->newObject()->asReturnedValue(); @@ -81,8 +82,8 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) Scope scope(v4); ScopedObject o(scope, this); - ctor->defineReadonlyProperty(v4->id_prototype, o); - ctor->defineReadonlyProperty(v4->id_length, Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(v4->id_prototype(), o); + ctor->defineReadonlyProperty(v4->id_length(), Primitive::fromInt32(1)); ctor->defineDefaultProperty(QStringLiteral("getPrototypeOf"), method_getPrototypeOf, 1); ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), method_getOwnPropertyDescriptor, 2); ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyNames"), method_getOwnPropertyNames, 1); @@ -98,20 +99,20 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) ctor->defineDefaultProperty(QStringLiteral("keys"), method_keys, 1); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(v4->id_toString, method_toString, 0); + defineDefaultProperty(v4->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); - defineDefaultProperty(v4->id_valueOf, method_valueOf, 0); + defineDefaultProperty(v4->id_valueOf(), method_valueOf, 0); defineDefaultProperty(QStringLiteral("hasOwnProperty"), method_hasOwnProperty, 1); defineDefaultProperty(QStringLiteral("isPrototypeOf"), method_isPrototypeOf, 1); defineDefaultProperty(QStringLiteral("propertyIsEnumerable"), method_propertyIsEnumerable, 1); 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); - insertMember(v4->id___proto__, p, Attr_Accessor|Attr_NotEnumerable); + p->value = BuiltinFunction::create(global, v4->id___proto__(), method_get_proto); + p->set = BuiltinFunction::create(global, v4->id___proto__(), method_set_proto); + insertMember(v4->id___proto__(), p, Attr_Accessor|Attr_NotEnumerable); } ReturnedValue ObjectPrototype::method_getPrototypeOf(CallContext *ctx) @@ -140,7 +141,8 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx) if (scope.hasException()) return Encode::undefined(); PropertyAttributes attrs; - Property *desc = O->__getOwnProperty__(name, &attrs); + ScopedProperty desc(scope); + O->getOwnProperty(name, &attrs, desc); return fromPropertyDescriptor(scope.engine, desc, attrs); } @@ -163,7 +165,7 @@ ReturnedValue ObjectPrototype::method_create(CallContext *ctx) return ctx->engine()->throwTypeError(); ScopedObject newObject(scope, ctx->d()->engine->newObject()); - newObject->setPrototype(O->asObject()); + newObject->setPrototype(O->as<Object>()); if (ctx->argc() > 1 && !ctx->args()[1].isUndefined()) { ctx->d()->callData->args[0] = newObject.asReturnedValue(); @@ -220,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(); @@ -390,7 +392,7 @@ ReturnedValue ObjectPrototype::method_toString(CallContext *ctx) } else { ScopedObject obj(scope, RuntimeHelpers::toObject(scope.engine, ctx->thisObject())); QString className = obj->className(); - return ctx->d()->engine->newString(QString::fromLatin1("[object %1]").arg(className))->asReturnedValue(); + return ctx->d()->engine->newString(QStringLiteral("[object %1]").arg(className))->asReturnedValue(); } } @@ -400,7 +402,7 @@ ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx) ScopedObject o(scope, ctx->thisObject().toObject(scope.engine)); if (!o) return Encode::undefined(); - ScopedFunctionObject f(scope, o->get(ctx->d()->engine->id_toString)); + ScopedFunctionObject f(scope, o->get(ctx->d()->engine->id_toString())); if (!f) return ctx->engine()->throwTypeError(); ScopedCallData callData(scope); @@ -462,7 +464,7 @@ ReturnedValue ObjectPrototype::method_propertyIsEnumerable(CallContext *ctx) if (scope.engine->hasException) return Encode::undefined(); PropertyAttributes attrs; - o->__getOwnProperty__(p, &attrs); + o->getOwnProperty(p, &attrs); return Encode(attrs.isEnumerable()); } @@ -484,7 +486,7 @@ ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx) if (!o) { if (!ctx->thisObject().isUndefined()) return Encode::undefined(); - o = ctx->d()->engine->globalObject(); + o = ctx->d()->engine->globalObject; } ScopedProperty pd(scope); @@ -512,7 +514,7 @@ ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx) if (!o) { if (!ctx->thisObject().isUndefined()) return Encode::undefined(); - o = ctx->d()->engine->globalObject(); + o = ctx->d()->engine->globalObject; } ScopedProperty pd(scope); @@ -525,7 +527,7 @@ ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx) ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx) { Scope scope(ctx); - ScopedObject o(scope, ctx->thisObject().asObject()); + ScopedObject o(scope, ctx->thisObject().as<Object>()); if (!o) return ctx->engine()->throwTypeError(); @@ -572,15 +574,15 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value desc->set = Primitive::emptyValue(); ScopedValue tmp(scope); - if (o->hasProperty(engine->id_enumerable)) - attrs->setEnumerable((tmp = o->get(engine->id_enumerable))->toBoolean()); + if (o->hasProperty(engine->id_enumerable())) + attrs->setEnumerable((tmp = o->get(engine->id_enumerable()))->toBoolean()); - if (o->hasProperty(engine->id_configurable)) - attrs->setConfigurable((tmp = o->get(engine->id_configurable))->toBoolean()); + if (o->hasProperty(engine->id_configurable())) + attrs->setConfigurable((tmp = o->get(engine->id_configurable()))->toBoolean()); - if (o->hasProperty(engine->id_get)) { - ScopedValue get(scope, o->get(engine->id_get)); - FunctionObject *f = get->asFunctionObject(); + if (o->hasProperty(engine->id_get())) { + ScopedValue get(scope, o->get(engine->id_get())); + FunctionObject *f = get->as<FunctionObject>(); if (f || get->isUndefined()) { desc->value = get; } else { @@ -590,9 +592,9 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value attrs->setType(PropertyAttributes::Accessor); } - if (o->hasProperty(engine->id_set)) { - ScopedValue set(scope, o->get(engine->id_set)); - FunctionObject *f = set->asFunctionObject(); + if (o->hasProperty(engine->id_set())) { + ScopedValue set(scope, o->get(engine->id_set())); + FunctionObject *f = set->as<FunctionObject>(); if (f || set->isUndefined()) { desc->set = set; } else { @@ -602,22 +604,22 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value attrs->setType(PropertyAttributes::Accessor); } - if (o->hasProperty(engine->id_writable)) { + if (o->hasProperty(engine->id_writable())) { if (attrs->isAccessor()) { engine->throwTypeError(); return; } - attrs->setWritable((tmp = o->get(engine->id_writable))->toBoolean()); + attrs->setWritable((tmp = o->get(engine->id_writable()))->toBoolean()); // writable forces it to be a data descriptor desc->value = Primitive::undefinedValue(); } - if (o->hasProperty(engine->id_value)) { + if (o->hasProperty(engine->id_value())) { if (attrs->isAccessor()) { engine->throwTypeError(); return; } - desc->value = o->get(engine->id_value); + desc->value = o->get(engine->id_value()); attrs->setType(PropertyAttributes::Data); } @@ -628,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/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h index 4e96681017..ec829e4bd2 100644 --- a/src/qml/jsruntime/qv4objectproto_p.h +++ b/src/qml/jsruntime/qv4objectproto_p.h @@ -33,6 +33,17 @@ #ifndef QV4ECMAOBJECTS_P_H #define QV4ECMAOBJECTS_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" #include <QtCore/qnumeric.h> @@ -53,8 +64,8 @@ struct ObjectCtor: FunctionObject { V4_OBJECT2(ObjectCtor, FunctionObject) - static ReturnedValue construct(Managed *that, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct ObjectPrototype: Object diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 88dc1946b8..4a0f84b685 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include "qv4persistent_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4object_p.h" #include "PageAllocation.h" @@ -78,11 +78,11 @@ Page *allocatePage(PersistentValueStorage *storage) if (p->header.next) p->header.next->header.prev = &p->header.next; for (int i = 0; i < kEntriesPerPage - 1; ++i) { - p->values[i].tag = QV4::Value::Empty_Type; - p->values[i].int_32 = i + 1; + p->values[i].setTag(QV4::Value::Empty_Type); + p->values[i].setInt_32(i + 1); } - p->values[kEntriesPerPage - 1].tag = QV4::Value::Empty_Type; - p->values[kEntriesPerPage - 1].int_32 = -1; + p->values[kEntriesPerPage - 1].setTag(QV4::Value::Empty_Type); + p->values[kEntriesPerPage - 1].setInt_32(-1); storage->firstPage = p; @@ -93,15 +93,57 @@ Page *allocatePage(PersistentValueStorage *storage) } +PersistentValueStorage::Iterator::Iterator(void *p, int idx) + : p(p), index(idx) +{ + Page *page = static_cast<Page *>(p); + if (page) + ++page->header.refCount; +} + +PersistentValueStorage::Iterator::Iterator(const PersistentValueStorage::Iterator &o) + : p(o.p), index(o.index) +{ + Page *page = static_cast<Page *>(p); + if (page) + ++page->header.refCount; +} + +PersistentValueStorage::Iterator &PersistentValueStorage::Iterator::operator=(const PersistentValueStorage::Iterator &o) +{ + Page *page = static_cast<Page *>(p); + if (page && !--page->header.refCount) + freePage(p); + p = o.p; + index = o.index; + page = static_cast<Page *>(p); + if (page) + ++page->header.refCount; + + return *this; +} + +PersistentValueStorage::Iterator::~Iterator() +{ + Page *page = static_cast<Page *>(p); + if (page && !--page->header.refCount) + freePage(page); +} + PersistentValueStorage::Iterator &PersistentValueStorage::Iterator::operator++() { while (p) { while (index < kEntriesPerPage - 1) { ++index; - if (static_cast<Page *>(p)->values[index].tag != QV4::Value::Empty_Type) + if (static_cast<Page *>(p)->values[index].tag() != QV4::Value::Empty_Type) return *this; } index = -1; - p = static_cast<Page *>(p)->header.next; + Page *next = static_cast<Page *>(p)->header.next; + if (!--static_cast<Page *>(p)->header.refCount) + freePage(p); + p = next; + if (next) + ++next->header.refCount; } index = 0; return *this; @@ -147,10 +189,10 @@ Value *PersistentValueStorage::allocate() p = allocatePage(this); Value *v = p->values + p->header.freeList; - p->header.freeList = v->int_32; + p->header.freeList = v->int_32(); ++p->header.refCount; - v->val = Encode::undefined(); + v->setRawValue(Encode::undefined()); return v; } @@ -162,24 +204,19 @@ void PersistentValueStorage::free(Value *v) Page *p = getPage(v); - v->tag = QV4::Value::Empty_Type; - v->int_32 = p->header.freeList; + v->setTag(QV4::Value::Empty_Type); + v->setInt_32(p->header.freeList); p->header.freeList = v - p->values; - if (!--p->header.refCount) { - if (p->header.prev) - *p->header.prev = p->header.next; - if (p->header.next) - p->header.next->header.prev = p->header.prev; - p->header.alloc.deallocate(); - } + if (!--p->header.refCount) + freePage(p); } static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase) { while (engine->jsStackTop > markBase) { Heap::Base *h = engine->popForGC(); - Q_ASSERT (h->gcGetVtable()->markObjects); - h->gcGetVtable()->markObjects(h, engine); + Q_ASSERT (h->vtable()->markObjects); + h->vtable()->markObjects(h, engine); } } @@ -190,7 +227,7 @@ void PersistentValueStorage::mark(ExecutionEngine *e) Page *p = static_cast<Page *>(firstPage); while (p) { for (int i = 0; i < kEntriesPerPage; ++i) { - if (Managed *m = p->values[i].asManaged()) + if (Managed *m = p->values[i].as<Managed>()) m->mark(e); } drainMarkStack(e, markBase); @@ -204,6 +241,16 @@ ExecutionEngine *PersistentValueStorage::getEngine(Value *v) return getPage(v)->header.engine; } +void PersistentValueStorage::freePage(void *page) +{ + Page *p = static_cast<Page *>(page); + if (p->header.prev) + *p->header.prev = p->header.next; + if (p->header.next) + p->header.next->header.prev = p->header.prev; + p->header.alloc.deallocate(); +} + PersistentValue::PersistentValue(const PersistentValue &other) : val(0) @@ -312,6 +359,12 @@ WeakValue::WeakValue(const WeakValue &other) } } +WeakValue::WeakValue(ExecutionEngine *engine, const Value &value) +{ + val = engine->memoryManager->m_weakValues->allocate(); + *val = value; +} + WeakValue &WeakValue::operator=(const WeakValue &other) { if (!val) { diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h index 7cac2ed95f..80b4ecdea8 100644 --- a/src/qml/jsruntime/qv4persistent_p.h +++ b/src/qml/jsruntime/qv4persistent_p.h @@ -33,7 +33,19 @@ #ifndef QV4PERSISTENT_H #define QV4PERSISTENT_H -#include "qv4value_inl_p.h" +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qv4value_p.h" +#include "qv4managed_p.h" QT_BEGIN_NAMESPACE @@ -50,8 +62,10 @@ struct Q_QML_EXPORT PersistentValueStorage void mark(ExecutionEngine *e); struct Iterator { - Q_DECL_CONSTEXPR Iterator(void *p, int idx) - : p(p), index(idx) {} + Iterator(void *p, int idx); + Iterator(const Iterator &o); + Iterator & operator=(const Iterator &o); + ~Iterator(); void *p; int index; Iterator &operator++(); @@ -67,6 +81,8 @@ struct Q_QML_EXPORT PersistentValueStorage ExecutionEngine *engine; void *firstPage; +private: + static void freePage(void *page); }; class Q_QML_EXPORT PersistentValue @@ -96,7 +112,13 @@ public: Managed *asManaged() const { if (!val) return 0; - return val->asManaged(); + return val->as<Managed>(); + } + template<typename T> + T *as() const { + if (!val) + return 0; + return val->as<T>(); } ExecutionEngine *engine() const { @@ -122,6 +144,7 @@ class Q_QML_EXPORT WeakValue public: WeakValue() : val(0) {} WeakValue(const WeakValue &other); + WeakValue(ExecutionEngine *engine, const Value &value); WeakValue &operator=(const WeakValue &other); ~WeakValue(); @@ -138,7 +161,13 @@ public: Managed *asManaged() const { if (!val) return 0; - return val->asManaged(); + return val->as<Managed>(); + } + template <typename T> + T *as() const { + if (!val) + return 0; + return val->as<T>(); } ExecutionEngine *engine() const { diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index a7019d0558..b62f367601 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -32,12 +32,13 @@ ****************************************************************************/ #include "qv4profiling_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> +#include <private/qv4string_p.h> QT_BEGIN_NAMESPACE -using namespace QV4; -using namespace QV4::Profiling; +namespace QV4 { +namespace Profiling { FunctionCallProperties FunctionCall::resolve() const { @@ -55,42 +56,43 @@ FunctionCallProperties FunctionCall::resolve() const Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine(engine) { - static int metatype = qRegisterMetaType<QList<QV4::Profiling::FunctionCallProperties> >(); - static int metatype2 = qRegisterMetaType<QList<QV4::Profiling::MemoryAllocationProperties> >(); - Q_UNUSED(metatype); - Q_UNUSED(metatype2); + static int meta = qRegisterMetaType<QVector<QV4::Profiling::FunctionCallProperties> >(); + static int meta2 = qRegisterMetaType<QVector<QV4::Profiling::MemoryAllocationProperties> >(); + Q_UNUSED(meta); + Q_UNUSED(meta2); m_timer.start(); } -struct FunctionCallComparator { - bool operator()(const FunctionCallProperties &p1, const FunctionCallProperties &p2) - { return p1.start < p2.start; } -}; - void Profiler::stopProfiling() { featuresEnabled = 0; reportData(); } +bool operator<(const FunctionCall &call1, const FunctionCall &call2) +{ + return call1.m_start < call2.m_start || + (call1.m_start == call2.m_start && (call1.m_end < call2.m_end || + (call1.m_end == call2.m_end && call1.m_function < call2.m_function))); +} + void Profiler::reportData() { - QList<FunctionCallProperties> resolved; + std::sort(m_data.begin(), m_data.end()); + QVector<FunctionCallProperties> resolved; resolved.reserve(m_data.size()); - FunctionCallComparator comp; - foreach (const FunctionCall &call, m_data) { - FunctionCallProperties props = call.resolve(); - resolved.insert(std::upper_bound(resolved.begin(), resolved.end(), props, comp), props); - } + + foreach (const FunctionCall &call, m_data) + resolved.append(call.resolve()); + emit dataReady(resolved, m_memory_data); + m_data.clear(); + m_memory_data.clear(); } void Profiler::startProfiling(quint64 features) { if (featuresEnabled == 0) { - m_data.clear(); - m_memory_data.clear(); - if (features & (1 << FeatureMemoryAllocation)) { qint64 timestamp = m_timer.nsecsElapsed(); MemoryAllocationProperties heap = {timestamp, @@ -111,4 +113,7 @@ void Profiler::startProfiling(quint64 features) } } +} // namespace Profiling +} // namespace QV4 + QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index c3441eaacd..6c54fc9bbd 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -34,6 +34,17 @@ #ifndef QV4PROFILING_H #define QV4PROFILING_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include "qv4engine_p.h" #include "qv4function_p.h" @@ -104,6 +115,7 @@ public: FunctionCallProperties resolve() const; private: + friend bool operator<(const FunctionCall &call1, const FunctionCall &call2); Function *m_function; qint64 m_start; @@ -155,14 +167,14 @@ public slots: void setTimer(const QElapsedTimer &timer) { m_timer = timer; } signals: - void dataReady(const QList<QV4::Profiling::FunctionCallProperties> &, - const QList<QV4::Profiling::MemoryAllocationProperties> &); + void dataReady(const QVector<QV4::Profiling::FunctionCallProperties> &, + const QVector<QV4::Profiling::MemoryAllocationProperties> &); private: QV4::ExecutionEngine *m_engine; QElapsedTimer m_timer; QVector<FunctionCall> m_data; - QList<MemoryAllocationProperties> m_memory_data; + QVector<MemoryAllocationProperties> m_memory_data; friend class FunctionCallProfiler; }; @@ -202,7 +214,7 @@ Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_MOVABLE_TYPE); QT_END_NAMESPACE -Q_DECLARE_METATYPE(QList<QV4::Profiling::FunctionCallProperties>) -Q_DECLARE_METATYPE(QList<QV4::Profiling::MemoryAllocationProperties>) +Q_DECLARE_METATYPE(QVector<QV4::Profiling::FunctionCallProperties>) +Q_DECLARE_METATYPE(QVector<QV4::Profiling::MemoryAllocationProperties>) #endif // QV4PROFILING_H diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h index 1b55abd1f7..8ddb4cf6f7 100644 --- a/src/qml/jsruntime/qv4property_p.h +++ b/src/qml/jsruntime/qv4property_p.h @@ -33,9 +33,19 @@ #ifndef QV4PROPERTYDESCRIPTOR_H #define QV4PROPERTYDESCRIPTOR_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include "qv4value_p.h" -#include "qv4internalclass_p.h" QT_BEGIN_NAMESPACE @@ -73,8 +83,8 @@ struct Property { inline Heap::FunctionObject *getter() const { return value.isManaged() ? reinterpret_cast<Heap::FunctionObject *>(value.heapObject()) : 0; } inline Heap::FunctionObject *setter() const { return set.isManaged() ? reinterpret_cast<Heap::FunctionObject *>(set.heapObject()) : 0; } - inline void setGetter(FunctionObject *g) { value = Primitive::fromManaged(reinterpret_cast<Managed *>(g)); } - inline void setSetter(FunctionObject *s) { set = s ? Primitive::fromManaged(reinterpret_cast<Managed *>(s)) : Value::fromHeapObject(0); } + inline void setGetter(FunctionObject *g) { value = reinterpret_cast<Managed *>(g); } + inline void setSetter(FunctionObject *s) { set = (s ? reinterpret_cast<Managed *>(s) : 0); } void copy(const Property *other, PropertyAttributes attrs) { value = other->value; @@ -85,12 +95,12 @@ struct Property { explicit Property() { value = Encode::undefined(); set = Value::fromHeapObject(0); } explicit Property(Value v) : value(v) { set = Value::fromHeapObject(0); } Property(FunctionObject *getter, FunctionObject *setter) { - value = Primitive::fromManaged(reinterpret_cast<Managed *>(getter)); - set = Primitive::fromManaged(reinterpret_cast<Managed *>(setter)); + value = reinterpret_cast<Managed *>(getter); + set = reinterpret_cast<Managed *>(setter); } Property(Heap::FunctionObject *getter, Heap::FunctionObject *setter) { - value.m = reinterpret_cast<Heap::Base *>(getter); - set.m = reinterpret_cast<Heap::Base *>(setter); + value.setM(reinterpret_cast<Heap::Base *>(getter)); + set.setM(reinterpret_cast<Heap::Base *>(setter)); } Property &operator=(Value v) { value = v; return *this; } private: diff --git a/src/qml/jsruntime/qv4qmlextensions.cpp b/src/qml/jsruntime/qv4qmlextensions.cpp deleted file mode 100644 index c1c4e0ec78..0000000000 --- a/src/qml/jsruntime/qv4qmlextensions.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qv4qmlextensions_p.h" -#include "qv4object_p.h" - -using namespace QV4; - -void QmlExtensions::markObjects(ExecutionEngine *e) -{ - if (valueTypeWrapperPrototype) - valueTypeWrapperPrototype->mark(e); -} diff --git a/src/qml/jsruntime/qv4qmlextensions_p.h b/src/qml/jsruntime/qv4qmlextensions_p.h deleted file mode 100644 index e4b9f75298..0000000000 --- a/src/qml/jsruntime/qv4qmlextensions_p.h +++ /dev/null @@ -1,58 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QV4QMLEXTENSIONS_P_H -#define QV4QMLEXTENSIONS_P_H - -#include <qtqmlglobal.h> -#include <qv4global_p.h> - -QT_BEGIN_NAMESPACE - -namespace QV4 { - -struct Q_QML_EXPORT QmlExtensions -{ - QmlExtensions() - : valueTypeWrapperPrototype(0) - {} - - Heap::Object *valueTypeWrapperPrototype; - - void markObjects(ExecutionEngine *e); -}; - -} // namespace QV4 - -QT_END_NAMESPACE - -#endif diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 0a1aa56aab..8f471132b7 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -55,6 +55,7 @@ #include <private/qv4objectproto_p.h> #include <private/qv4jsonobject_p.h> #include <private/qv4regexpobject_p.h> +#include <private/qv4dateobject_p.h> #include <private/qv4scopedvalue_p.h> #include <private/qv4mm_p.h> #include <private/qqmlscriptstring_p.h> @@ -92,7 +93,7 @@ static QPair<QObject *, int> extractQtMethod(QV4::FunctionObject *function) static QPair<QObject *, int> extractQtSignal(const Value &value) { if (value.isObject()) { - QV4::ExecutionEngine *v4 = value.asObject()->engine(); + QV4::ExecutionEngine *v4 = value.as<Object>()->engine(); QV4::Scope scope(v4); QV4::ScopedFunctionObject function(scope, value); if (function) @@ -227,16 +228,15 @@ 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) { } void QObjectWrapper::initializeBindings(ExecutionEngine *engine) { - engine->functionPrototype.asObject()->defineDefaultProperty(QStringLiteral("connect"), method_connect); - engine->functionPrototype.asObject()->defineDefaultProperty(QStringLiteral("disconnect"), method_disconnect); + engine->functionPrototype()->defineDefaultProperty(QStringLiteral("connect"), method_connect); + engine->functionPrototype()->defineDefaultProperty(QStringLiteral("disconnect"), method_disconnect); } QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const @@ -254,8 +254,8 @@ QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlCont return result; } -ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *n, QObjectWrapper::RevisionMode revisionMode, - bool *hasProperty, bool includeImports) +ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *name, QObjectWrapper::RevisionMode revisionMode, + bool *hasProperty, bool includeImports) const { if (QQmlData::wasDeleted(d()->object)) { if (hasProperty) @@ -263,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()) { @@ -291,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"); @@ -317,14 +315,11 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String if (hasProperty) *hasProperty = true; - ScopedContext ctx(scope, scope.engine->currentContext()); - return getProperty(d()->object, ctx, result); + return getProperty(v4, d()->object, result); } -ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired) +ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired) { - QV4::Scope scope(ctx); - QQmlData::flushPendingBinding(object, property->coreIndex); if (property->isFunction() && !property->isVarProperty()) { @@ -333,25 +328,19 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx Q_ASSERT(vmemo); return vmemo->vmeMethod(property->coreIndex); } else if (property->isV4Function()) { - QV4::ScopedObject qmlcontextobject(scope, ctx->d()->engine->qmlContextObject()); - ScopedContext global(scope, scope.engine->rootContext()); - return QV4::QObjectMethod::create(global, object, property->coreIndex, qmlcontextobject); + 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>(ctx->d()->engine, object, property->coreIndex)); - - QV4::ScopedString connect(scope, ctx->d()->engine->newIdentifier(QStringLiteral("connect"))); - QV4::ScopedString disconnect(scope, ctx->d()->engine->newIdentifier(QStringLiteral("disconnect"))); - handler->put(connect, QV4::ScopedValue(scope, ctx->d()->engine->functionPrototype.asObject()->get(connect))); - handler->put(disconnect, QV4::ScopedValue(scope, ctx->d()->engine->functionPrototype.asObject()->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; @@ -360,37 +349,38 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx if (ep && ep->propertyCapture && property->accessors->notifier) nptr = &n; - QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->d()->engine, object, *property, nptr)); + Scope scope(engine); + QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(engine, object, *property, nptr)); if (captureRequired) { if (property->accessors->notifier) { - if (n) - ep->captureProperty(n); + if (n && ep->propertyCapture) + ep->propertyCapture->captureProperty(n); } else { - ep->captureProperty(object, property->coreIndex, property->notifyIndex); + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(object, property->coreIndex, property->notifyIndex); } } return rv->asReturnedValue(); } - if (captureRequired && ep && !property->isConstant()) - ep->captureProperty(object, property->coreIndex, property->notifyIndex); + if (captureRequired && ep && ep->propertyCapture && !property->isConstant()) + ep->propertyCapture->captureProperty(object, property->coreIndex, property->notifyIndex); if (property->isVarProperty()) { QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); return vmemo->vmeProperty(property->coreIndex); } else if (property->isDirect()) { - return LoadProperty<ReadAccessor::Direct>(ctx->d()->engine, object, *property, 0); + return LoadProperty<ReadAccessor::Direct>(engine, object, *property, 0); } else { - return LoadProperty<ReadAccessor::Indirect>(ctx->d()->engine, object, *property, 0); + return LoadProperty<ReadAccessor::Indirect>(engine, object, *property, 0); } } 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,23 +420,21 @@ bool QObjectWrapper::setQmlProperty(ExecutionEngine *engine, QQmlContextData *qm return false; } - Scope scope(engine); - ScopedContext ctx(scope, engine->currentContext()); - setProperty(object, ctx, result, value); + setProperty(engine, object, result, value); return true; } -void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, const Value &value) +void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, const Value &value) { if (!property->isWritable() && !property->isQList()) { QString error = QLatin1String("Cannot assign to read-only property \"") + property->name(object) + QLatin1Char('\"'); - ctx->engine()->throwTypeError(error); + engine->throwTypeError(error); return; } QQmlBinding *newBinding = 0; - QV4::Scope scope(ctx); + QV4::Scope scope(engine); QV4::ScopedFunctionObject f(scope, value); if (f) { if (!f->isBinding()) { @@ -460,25 +445,25 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro error += QLatin1String("[unknown property type]"); else error += QLatin1String(QMetaType::typeName(property->propType)); - ctx->engine()->throwError(error); + scope.engine->throwError(error); return; } } else { // binding assignment. - QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->d()->engine); + QQmlContextData *callingQmlContext = scope.engine->callingQmlContext(); QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); bindingFunction->initBindingLocation(); newBinding = new QQmlBinding(value, object, callingQmlContext); - newBinding->setTarget(object, *property, callingQmlContext); + newBinding->setTarget(object, *property); } } - QQmlAbstractBinding *oldBinding = - QQmlPropertyPrivate::setBinding(object, property->coreIndex, -1, newBinding); - if (oldBinding) - oldBinding->destroy(); + if (newBinding) + QQmlPropertyPrivate::setBinding(newBinding); + else + QQmlPropertyPrivate::removeBinding(object, property->encodedIndex()); if (!newBinding && property->isVarProperty()) { // allow assignment of "special" values (null, undefined, function) to var properties @@ -505,16 +490,16 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro } else if (value.isUndefined() && property->propType == QMetaType::QJsonValue) { PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined)); } else if (!newBinding && property->propType == qMetaTypeId<QJSValue>()) { - PROPERTY_STORE(QJSValue, QJSValue(ctx->d()->engine, value.asReturnedValue())); + PROPERTY_STORE(QJSValue, QJSValue(scope.engine, value.asReturnedValue())); } else if (value.isUndefined() && property->propType != qMetaTypeId<QQmlScriptString>()) { QString error = QLatin1String("Cannot assign [undefined] to "); if (!QMetaType::typeName(property->propType)) error += QLatin1String("[unknown property type]"); else error += QLatin1String(QMetaType::typeName(property->propType)); - ctx->engine()->throwError(error); + scope.engine->throwError(error); return; - } else if (value.asFunctionObject()) { + } else if (value.as<FunctionObject>()) { // this is handled by the binding creation above } else if (property->propType == QMetaType::Int && value.isNumber()) { PROPERTY_STORE(int, value.asDouble()); @@ -543,11 +528,11 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro } else { QVariant v; if (property->isQList()) - v = ctx->d()->engine->toVariant(value, qMetaTypeId<QList<QObject *> >()); + v = scope.engine->toVariant(value, qMetaTypeId<QList<QObject *> >()); else - v = ctx->d()->engine->toVariant(value, property->propType); + v = scope.engine->toVariant(value, property->propType); - QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->d()->engine); + QQmlContextData *callingQmlContext = scope.engine->callingQmlContext(); if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) { const char *valueType = 0; if (v.userType() == QVariant::Invalid) valueType = "null"; @@ -561,7 +546,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro QLatin1String(valueType) + QLatin1String(" to ") + QLatin1String(targetTypeName); - ctx->engine()->throwError(error); + scope.engine->throwError(error); return; } } @@ -634,7 +619,7 @@ void QObjectWrapper::markWrapper(QObject *object, ExecutionEngine *engine) engine->m_multiplyWrappedQObjects->mark(object, engine); } -ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, int propertyIndex, bool captureRequired) +ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired) { if (QQmlData::wasDeleted(object)) return QV4::Encode::null(); @@ -646,14 +631,19 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx Q_ASSERT(cache); QQmlPropertyData *property = cache->property(propertyIndex); Q_ASSERT(property); // We resolved this property earlier, so it better exist! - return getProperty(object, ctx, property, captureRequired); + return getProperty(engine, object, property, captureRequired); +} + +void QObjectWrapper::setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value) +{ + setProperty(engine, d()->object, propertyIndex, value); } -void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const Value &value) +void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, const Value &value) { - if (QQmlData::wasDeleted(d()->object)) + if (QQmlData::wasDeleted(object)) return; - QQmlData *ddata = QQmlData::get(d()->object, /*create*/false); + QQmlData *ddata = QQmlData::get(object, /*create*/false); if (!ddata) return; @@ -661,14 +651,14 @@ void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const Q_ASSERT(cache); QQmlPropertyData *property = cache->property(propertyIndex); Q_ASSERT(property); // We resolved this property earlier, so it better exist! - return setProperty(d()->object, ctx, property, value); + return setProperty(engine, object, property, value); } bool QObjectWrapper::isEqualTo(Managed *a, Managed *b) { Q_ASSERT(a->as<QV4::QObjectWrapper>()); QV4::QObjectWrapper *qobjectWrapper = static_cast<QV4::QObjectWrapper *>(a); - QV4::Object *o = b->asObject(); + QV4::Object *o = b->as<Object>(); if (o) { if (QV4::QmlTypeWrapper *qmlTypeWrapper = o->as<QV4::QmlTypeWrapper>()) return qmlTypeWrapper->toVariant().value<QObject*>() == qobjectWrapper->object(); @@ -681,13 +671,13 @@ 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(Managed *m, String *name, bool *hasProperty) +QV4::ReturnedValue QObjectWrapper::get(const Managed *m, String *name, bool *hasProperty) { - QObjectWrapper *that = static_cast<QObjectWrapper*>(m); - QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(that->engine()); + const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m); + QQmlContextData *qmlContext = that->engine()->callingQmlContext(); return that->getQmlProperty(qmlContext, name, IgnoreRevision, hasProperty, /*includeImports*/ true); } @@ -699,7 +689,7 @@ void QObjectWrapper::put(Managed *m, String *name, const Value &value) if (v4->hasException || QQmlData::wasDeleted(that->d()->object)) return; - QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4); + QQmlContextData *qmlContext = v4->callingQmlContext(); if (!setQmlProperty(v4, qmlContext, that->d()->object, name, QV4::QObjectWrapper::IgnoreRevision, value)) { QQmlData *ddata = QQmlData::get(that->d()->object); // Types created by QML are not extensible at run-time, but for other QObjects we can store them @@ -718,23 +708,23 @@ PropertyAttributes QObjectWrapper::query(const Managed *m, String *name) { const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m); ExecutionEngine *engine = that->engine(); - QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(engine); + QQmlContextData *qmlContext = engine->callingQmlContext(); QQmlPropertyData local; if (that->findProperty(engine, qmlContext, name, IgnoreRevision, &local) - || name->equals(engine->id_destroy) || name->equals(engine->id_toString)) + || name->equals(engine->id_destroy()) || name->equals(engine->id_toString())) return QV4::Attr_Data; else return QV4::Object::query(m, name); } -void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes) +void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes) { // Used to block access to QObject::destroyed() and QObject::deleteLater() from QML static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)"); static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()"); static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()"); - *name = (Heap::String *)0; + name->setM(0); *index = UINT_MAX; QObjectWrapper *that = static_cast<QObjectWrapper*>(m); @@ -745,10 +735,9 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Heap::Strin const bool preventDestruction = mo->superClass() || mo == &QObject::staticMetaObject; const int propertyCount = mo->propertyCount(); if (it->arrayIndex < static_cast<uint>(propertyCount)) { - // #### GC Scope scope(that->engine()); ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name()))); - *name = propName->d(); + name->setM(propName->d()); ++it->arrayIndex; *attributes = QV4::Attr_Data; p->value = that->get(propName); @@ -761,10 +750,9 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Heap::Strin ++it->arrayIndex; if (method.access() == QMetaMethod::Private || (preventDestruction && (index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2))) continue; - // #### GC Scope scope(that->engine()); ScopedString methodName(scope, that->engine()->newString(QString::fromUtf8(method.name()))); - *name = methodName->d(); + name->setM(methodName->d()); *attributes = QV4::Attr_Data; p->value = that->get(methodName); return; @@ -811,7 +799,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase QV4::ScopedFunctionObject f(scope, This->function.value()); QV4::ScopedCallData callData(scope, argCount); - callData->thisObject = This->thisObject.isUndefined() ? v4->globalObject()->asReturnedValue() : This->thisObject.value(); + callData->thisObject = This->thisObject.isUndefined() ? v4->globalObject->asReturnedValue() : This->thisObject.value(); for (int ii = 0; ii < argCount; ++ii) { int type = argsTypes[ii + 1]; if (type == qMetaTypeId<QVariant>()) { @@ -826,7 +814,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase QQmlError error = v4->catchExceptionAsQmlError(); if (error.description().isEmpty()) { QV4::ScopedString name(scope, f->name()); - error.setDescription(QString::fromLatin1("Unknown exception occurred during evaluation of connected function: %1").arg(name->toQString())); + error.setDescription(QStringLiteral("Unknown exception occurred during evaluation of connected function: %1").arg(name->toQString())); } if (QQmlEngine *qmlEngine = v4->qmlEngine()) { QQmlEnginePrivate::get(qmlEngine)->warning(error); @@ -1028,56 +1016,35 @@ void QObjectWrapper::markObjects(Heap::Base *that, QV4::ExecutionEngine *e) QV4::Object::markObjects(that, e); } -namespace { - struct QObjectDeleter : public QV4::GCDeletable - { - QObjectDeleter(QObject *o) - : m_objectToDelete(o) - {} - ~QObjectDeleter() - { - QQmlData *ddata = QQmlData::get(m_objectToDelete, false); - if (ddata && ddata->ownContext && ddata->context) - ddata->context->emitDestruction(); - // This object is notionally destroyed now - ddata->isQueuedForDeletion = true; - if (lastCall) - delete m_objectToDelete; - else - m_objectToDelete->deleteLater(); - } - - QObject *m_objectToDelete; - }; -} - -void QObjectWrapper::destroy(Heap::Base *that) +void QObjectWrapper::destroyObject(bool lastCall) { - Heap::QObjectWrapper *This = static_cast<Heap::QObjectWrapper*>(that); - QPointer<QObject> object = This->object; - ExecutionEngine *engine = This->internalClass->engine; - This->~Data(); - This = 0; - if (!object) - return; - - QQmlData *ddata = QQmlData::get(object, false); - if (!ddata) - return; - - if (object->parent() || ddata->indestructible) - return; + Heap::QObjectWrapper *h = d(); + if (!h->internalClass) + return; // destroyObject already got called + + if (h->object) { + QQmlData *ddata = QQmlData::get(h->object, false); + if (ddata) { + 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 h->object; + else + h->object->deleteLater(); + } + } + } - QObjectDeleter *deleter = new QObjectDeleter(object); - engine->memoryManager->registerDeletable(deleter); + h->internalClass = 0; + h->~Data(); } 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, @@ -1229,7 +1196,7 @@ static int MatchScore(const QV4::Value &actual, int conversionType) default: return 10; } - } else if (actual.asDateObject()) { + } else if (actual.as<DateObject>()) { switch (conversionType) { case QMetaType::QDateTime: return 0; @@ -1247,7 +1214,7 @@ static int MatchScore(const QV4::Value &actual, int conversionType) default: return 10; } - } else if (actual.asArrayObject()) { + } else if (actual.as<ArrayObject>()) { switch (conversionType) { case QMetaType::QJsonArray: return 3; @@ -1276,7 +1243,7 @@ static int MatchScore(const QV4::Value &actual, int conversionType) return 10; } } - } else if (QV4::Object *obj = actual.asObject()) { + } else if (const Object *obj = actual.as<Object>()) { if (obj->as<QV4::VariantObject>()) { if (conversionType == qMetaTypeId<QVariant>()) return 0; @@ -1379,7 +1346,7 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ if (returnType == QMetaType::UnknownType) { QString typeName = QString::fromLatin1(unknownTypeError); - QString error = QString::fromLatin1("Unknown method return type: %1").arg(typeName); + QString error = QStringLiteral("Unknown method return type: %1").arg(typeName); return engine->throwError(error); } @@ -1392,7 +1359,7 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ if (!args) { QString typeName = QString::fromLatin1(unknownTypeError); - QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName); + QString error = QStringLiteral("Unknown method parameter type: %1").arg(typeName); return engine->throwError(error); } @@ -1606,9 +1573,9 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q type = callType; } else if (callType == QMetaType::QObjectStar) { qobjectPtr = 0; - if (QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) + if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) qobjectPtr = qobjectWrapper->object(); - else if (QV4::QmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QmlTypeWrapper>()) + else if (const QV4::QmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QmlTypeWrapper>()) queryEngine = qmlTypeWrapper->isSingleton(); type = callType; } else if (callType == qMetaTypeId<QVariant>()) { @@ -1630,7 +1597,7 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q } } else { QObject *o = 0; - if (QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) + if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) o = qobjectWrapper->object(); qlistPtr->append(o); } @@ -1739,29 +1706,26 @@ QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine) } } -ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, int index, const Value &qmlGlobal) +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()->qmlGlobal = qmlGlobal; - method->d()->valueTypeWrapper = Primitive::undefinedValue(); return method.asReturnedValue(); } -ReturnedValue QObjectMethod::create(ExecutionContext *scope, QQmlValueTypeWrapper *valueType, int index, const Value &qmlGlobal) +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()->qmlGlobal = qmlGlobal; - method->d()->valueTypeWrapper = valueType; + method->d()->valueTypeWrapper = valueType->d(); return method.asReturnedValue(); } @@ -1777,7 +1741,7 @@ const QMetaObject *Heap::QObjectMethod::metaObject() return object->metaObject(); } -QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) +QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) const { QString result; if (const QMetaObject *metaObject = d()->metaObject()) { @@ -1803,7 +1767,7 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) return ctx->d()->engine->newString(result)->asReturnedValue(); } -QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) +QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const { if (!d()->object) return Encode::undefined(); @@ -1822,16 +1786,16 @@ QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, con return Encode::undefined(); } -ReturnedValue QObjectMethod::call(Managed *m, CallData *callData) +ReturnedValue QObjectMethod::call(const Managed *m, CallData *callData) { - QObjectMethod *This = static_cast<QObjectMethod*>(m); + const QObjectMethod *This = static_cast<const QObjectMethod*>(m); return This->callInternal(callData); } -ReturnedValue QObjectMethod::callInternal(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) @@ -1839,11 +1803,10 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) 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; @@ -1875,12 +1838,9 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) } if (method.isV4Function()) { + Scope scope(v4); QV4::ScopedValue rv(scope, QV4::Primitive::undefinedValue()); - - QV4::ScopedValue qmlGlobal(scope, d()->qmlGlobal); - QQmlV4Function func(callData, rv, qmlGlobal, - QmlContextWrapper::getContext(qmlGlobal), - scope.engine); + QQmlV4Function func(callData, rv, v4); QQmlV4Function *funcptr = &func; void *args[] = { 0, &funcptr }; @@ -1890,32 +1850,46 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) } 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->qmlGlobal.mark(e); - 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 24e8b29e08..1126013806 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -54,7 +54,7 @@ #include <private/qqmlpropertycache_p.h> #include <private/qintrusivelist_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> QT_BEGIN_NAMESPACE @@ -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; }; @@ -79,15 +81,14 @@ struct QObjectMethod : FunctionObject { QPointer<QObject> object; QQmlRefPointer<QQmlPropertyCache> propertyCache; int index; - Value qmlGlobal; - 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; }; @@ -104,7 +105,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object QObject *object() const { return d()->object.data(); } - ReturnedValue getQmlProperty(QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = 0, bool includeImports = false); + ReturnedValue getQmlProperty(QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = 0, bool includeImports = false) const; static ReturnedValue getQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = 0); static bool setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value); @@ -114,26 +115,27 @@ struct Q_QML_EXPORT QObjectWrapper : public Object using Object::get; - static ReturnedValue getProperty(QObject *object, ExecutionContext *ctx, int propertyIndex, bool captureRequired); - void setProperty(ExecutionContext *ctx, int propertyIndex, const Value &value); + static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired); + static void setProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, const Value &value); + void setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value); + + void destroyObject(bool lastCall); protected: static bool isEqualTo(Managed *that, Managed *o); -private: - static ReturnedValue getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired = true); - static void setProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, const Value &value); + static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired = true); + static void setProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, const Value &value); static ReturnedValue create(ExecutionEngine *engine, QObject *object); QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const; - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); static PropertyAttributes query(const Managed *, String *name); - static void advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes); + static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); - static void destroy(Heap::Base *that); static ReturnedValue method_connect(CallContext *ctx); static ReturnedValue method_disconnect(CallContext *ctx); @@ -148,18 +150,18 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject enum { DestroyMethod = -1, ToStringMethod = -2 }; - static ReturnedValue create(QV4::ExecutionContext *scope, QObject *object, int index, const Value &qmlGlobal = Primitive::undefinedValue()); - static ReturnedValue create(QV4::ExecutionContext *scope, QQmlValueTypeWrapper *valueType, int index, const Value &qmlGlobal = Primitive::undefinedValue()); + static ReturnedValue create(QV4::ExecutionContext *scope, QObject *object, int index); + static ReturnedValue create(QV4::ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index); int methodIndex() const { return d()->index; } QObject *object() const { return d()->object.data(); } - QV4::ReturnedValue method_toString(QV4::ExecutionContext *ctx); - QV4::ReturnedValue method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc); + QV4::ReturnedValue method_toString(QV4::ExecutionContext *ctx) const; + QV4::ReturnedValue method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const; - static ReturnedValue call(Managed *, CallData *callData); + static ReturnedValue call(const Managed *, CallData *callData); - ReturnedValue callInternal(CallData *callData); + ReturnedValue callInternal(CallData *callData) const; static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); }; @@ -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/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index 8e18a5fbdd..31fee534ad 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -34,16 +34,16 @@ #include "qv4regexp_p.h" #include "qv4engine_p.h" #include "qv4scopedvalue_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> using namespace QV4; RegExpCache::~RegExpCache() { - for (RegExpCache::Iterator it = begin(), e = end(); - it != e; ++it) - it.value()->cache = 0; - clear(); + for (RegExpCache::Iterator it = begin(), e = end(); it != e; ++it) { + if (RegExp *re = it.value().as<RegExp>()) + re->d()->cache = 0; + } } DEFINE_MANAGED_VTABLE(RegExp); @@ -68,19 +68,18 @@ Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bo RegExpCacheKey key(pattern, ignoreCase, multiline); RegExpCache *cache = engine->regExpCache; - if (cache) { - if (Heap::RegExp *result = cache->value(key)) - return result; - } + if (!cache) + cache = engine->regExpCache = new RegExpCache; + + QV4::WeakValue &cachedValue = (*cache)[key]; + if (QV4::RegExp *result = cachedValue.as<RegExp>()) + return result->d(); Scope scope(engine); Scoped<RegExp> result(scope, engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline)); - if (!cache) - cache = engine->regExpCache = new RegExpCache; - result->d()->cache = cache; - cache->insert(key, result->d()); + cachedValue.set(engine, result); return result->d(); } diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h index 819e31e5f1..928362a995 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -33,6 +33,17 @@ #ifndef QV4REGEXP_H #define QV4REGEXP_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QString> #include <QVector> @@ -133,8 +144,7 @@ inline RegExpCacheKey::RegExpCacheKey(const RegExp::Data *re) inline uint qHash(const RegExpCacheKey& key, uint seed = 0) Q_DECL_NOTHROW { return qHash(key.pattern, seed); } -// ### GC -class RegExpCache : public QHash<RegExpCacheKey, Heap::RegExp*> +class RegExpCache : public QHash<RegExpCacheKey, WeakValue> { public: ~RegExpCache(); diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index f6e88e62b7..1839ff17ab 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -37,7 +37,7 @@ #include "qv4objectproto_p.h" #include "qv4regexp_p.h" #include "qv4stringobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4scopedvalue_p.h" #include <private/qqmljsengine_p.h> @@ -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.asObject()) - , 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.asObject()) +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); + Q_ASSERT(0 == internalClass()->find(engine()->id_lastIndex())); + return propertyData(0); } // Converts a JS RegExp to a QRegExp. @@ -231,25 +221,24 @@ Heap::RegExpCtor::RegExpCtor(QV4::ExecutionContext *scope) void Heap::RegExpCtor::clearLastMatch() { lastMatch = Primitive::nullValue(); - lastInput = internalClass->engine->id_empty; + lastInput = internalClass->engine->id_empty()->d(); lastMatchStart = 0; lastMatchEnd = 0; } -ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) +ReturnedValue RegExpCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<Object *>(m)->engine()); - ScopedContext ctx(scope, scope.engine->currentContext()); + Scope scope(static_cast<const Object *>(m)->engine()); 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,19 +263,19 @@ ReturnedValue RegExpCtor::construct(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(Managed *that, CallData *callData) +ReturnedValue RegExpCtor::call(const Managed *that, CallData *callData) { if (callData->argc > 0 && callData->args[0].as<RegExpObject>()) { if (callData->argc == 1 || callData->args[1].isUndefined()) @@ -300,7 +289,7 @@ void RegExpCtor::markObjects(Heap::Base *that, ExecutionEngine *e) { RegExpCtor::Data *This = static_cast<RegExpCtor::Data *>(that); This->lastMatch.mark(e); - This->lastInput.mark(e); + This->lastInput->mark(e); FunctionObject::markObjects(that, e); } @@ -310,8 +299,8 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor) ScopedObject o(scope); ScopedObject ctor(scope, constructor); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(2)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(2)); // Properties deprecated in the spec but required by "the web" :( ctor->defineAccessorProperty(QStringLiteral("lastMatch"), method_get_lastMatch_n<0>, 0); @@ -337,7 +326,7 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor) defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(QStringLiteral("exec"), method_exec, 1); defineDefaultProperty(QStringLiteral("test"), method_test, 1); - defineDefaultProperty(engine->id_toString, method_toString, 0); + defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("compile"), method_compile, 2); } @@ -354,25 +343,25 @@ 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(); } uint* matchOffsets = (uint*)alloca(r->value()->captureCount() * 2 * sizeof(uint)); const int result = Scoped<RegExp>(scope, r->value())->match(s, offset, matchOffsets); - Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor); + Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor()); regExpCtor->d()->clearLastMatch(); if (result == -1) { - r->lastIndexProperty()->value = Primitive::fromInt32(0); + *r->lastIndexProperty() = Primitive::fromInt32(0); return Encode::null(); } // fill in result data - ScopedArrayObject array(scope, scope.engine->newArrayObject(scope.engine->regExpExecArrayClass, scope.engine->arrayPrototype.asObject())); + ScopedArrayObject array(scope, scope.engine->newArrayObject(scope.engine->regExpExecArrayClass, scope.engine->arrayPrototype())); int len = r->value()->captureCount(); array->arrayReserve(len); ScopedValue v(scope); @@ -383,17 +372,17 @@ 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; - dd->lastInput = arg->stringValue(); + dd->lastInput = arg->stringValue()->d(); dd->lastMatchStart = matchOffsets[0]; dd->lastMatchEnd = matchOffsets[1]; if (r->global()) - r->lastIndexProperty()->value = Primitive::fromInt32(matchOffsets[1]); + *r->lastIndexProperty() = Primitive::fromInt32(matchOffsets[1]); return array.asReturnedValue(); } @@ -425,7 +414,7 @@ ReturnedValue RegExpPrototype::method_compile(CallContext *ctx) ScopedCallData callData(scope, ctx->argc()); memcpy(callData->args, ctx->args(), ctx->argc()*sizeof(Value)); - Scoped<RegExpObject> re(scope, ctx->d()->engine->regExpCtor.asFunctionObject()->construct(callData)); + Scoped<RegExpObject> re(scope, ctx->d()->engine->regExpCtor()->as<FunctionObject>()->construct(callData)); r->d()->value = re->value(); r->d()->global = re->global(); @@ -436,7 +425,7 @@ template <int index> ReturnedValue RegExpPrototype::method_get_lastMatch_n(CallContext *ctx) { Scope scope(ctx); - ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastMatch()); + ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastMatch()); ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(index) : Encode::undefined()); if (result->isUndefined()) return ctx->d()->engine->newString()->asReturnedValue(); @@ -446,7 +435,7 @@ ReturnedValue RegExpPrototype::method_get_lastMatch_n(CallContext *ctx) ReturnedValue RegExpPrototype::method_get_lastParen(CallContext *ctx) { Scope scope(ctx); - ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastMatch()); + ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastMatch()); ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined()); if (result->isUndefined()) return ctx->d()->engine->newString()->asReturnedValue(); @@ -455,13 +444,13 @@ ReturnedValue RegExpPrototype::method_get_lastParen(CallContext *ctx) ReturnedValue RegExpPrototype::method_get_input(CallContext *ctx) { - return static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastInput().asReturnedValue(); + return static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastInput()->asReturnedValue(); } ReturnedValue RegExpPrototype::method_get_leftContext(CallContext *ctx) { Scope scope(ctx); - Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor); + Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor()); QString lastInput = regExpCtor->lastInput()->toQString(); return ctx->d()->engine->newString(lastInput.left(regExpCtor->lastMatchStart()))->asReturnedValue(); } @@ -469,7 +458,7 @@ ReturnedValue RegExpPrototype::method_get_leftContext(CallContext *ctx) ReturnedValue RegExpPrototype::method_get_rightContext(CallContext *ctx) { Scope scope(ctx); - Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor); + Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor()); QString lastInput = regExpCtor->lastInput()->toQString(); return ctx->d()->engine->newString(lastInput.mid(regExpCtor->lastMatchEnd()))->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index f5f255faf5..81ea9cf14b 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -33,6 +33,17 @@ #ifndef QV4REGEXPOBJECT_H #define QV4REGEXPOBJECT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4runtime_p.h" #include "qv4engine_p.h" #include "qv4context_p.h" @@ -57,33 +68,30 @@ 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); - RegExp *value; + Pointer<RegExp> value; bool global; }; struct RegExpCtor : FunctionObject { RegExpCtor(QV4::ExecutionContext *scope); Value lastMatch; - StringValue lastInput; + Pointer<String> lastInput; int lastMatchStart; int lastMatchEnd; 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 +101,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 +113,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; @@ -117,19 +130,17 @@ struct RegExpCtor: FunctionObject V4_OBJECT2(RegExpCtor, FunctionObject) Value lastMatch() { return d()->lastMatch; } - StringValue lastInput() { return d()->lastInput; } + Heap::String *lastInput() { return d()->lastInput; } int lastMatchStart() { return d()->lastMatchStart; } int lastMatchEnd() { return d()->lastMatchEnd; } - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; struct RegExpPrototype: RegExpObject { - V4_OBJECT2(RegExpPrototype, RegExpObject) - void init(ExecutionEngine *engine, Object *ctor); static ReturnedValue method_exec(CallContext *ctx); @@ -145,11 +156,6 @@ struct RegExpPrototype: RegExpObject static ReturnedValue method_get_rightContext(CallContext *ctx); }; -inline Heap::RegExpPrototype::RegExpPrototype(ExecutionEngine *e) - : RegExpObject(e->emptyClass, e->objectPrototype.asObject()) -{ -} - } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index b66e917b87..a988313f5f 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -40,12 +40,15 @@ #include "qv4stringobject_p.h" #include "qv4argumentsobject_p.h" #include "qv4objectiterator_p.h" +#include "qv4dateobject_p.h" #include "qv4lookup_p.h" #include "qv4function_p.h" #include "private/qlocale_tools_p.h" #include "qv4scopedvalue_p.h" #include <private/qqmlcontextwrapper_p.h> #include <private/qqmltypewrapper_p.h> +#include <private/qqmlengine_p.h> +#include <private/qqmljavascriptexpression_p.h> #include "qv4qobjectwrapper_p.h" #include <private/qv8engine_p.h> #endif @@ -265,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) @@ -289,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); } @@ -305,22 +307,21 @@ 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) { Scope scope(engine); - ScopedFunctionObject f(scope, right.asFunctionObject()); + ScopedFunctionObject f(scope, right.as<FunctionObject>()); if (!f) return engine->throwTypeError(); if (f->isBoundFunction()) f = static_cast<BoundFunction *>(f.getPointer())->target(); - ScopedObject v(scope, left.asObject()); + ScopedObject v(scope, left.as<Object>()); if (!v) return Encode(false); @@ -380,10 +381,10 @@ Heap::String *RuntimeHelpers::stringFromNumber(ExecutionEngine *engine, double n return engine->newString(qstr); } -ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) +ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeHint) { if (typeHint == PREFERREDTYPE_HINT) { - if (object->asDateObject()) + if (object->as<DateObject>()) typeHint = STRING_HINT; else typeHint = NUMBER_HINT; @@ -393,18 +394,18 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) if (engine->hasException) return Encode::undefined(); - StringValue *meth1 = &engine->id_toString; - StringValue *meth2 = &engine->id_valueOf; + String *meth1 = engine->id_toString(); + String *meth2 = engine->id_valueOf(); if (typeHint == NUMBER_HINT) qSwap(meth1, meth2); Scope scope(engine); ScopedCallData callData(scope, 0); - callData->thisObject = object; + callData->thisObject = *object; - ScopedValue conv(scope, object->get(*meth1)); - if (FunctionObject *o = conv->asFunctionObject()) { + ScopedValue conv(scope, object->get(meth1)); + if (FunctionObject *o = conv->as<FunctionObject>()) { ScopedValue r(scope, o->call(callData)); if (r->isPrimitive()) return r->asReturnedValue(); @@ -413,8 +414,8 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) if (engine->hasException) return Encode::undefined(); - conv = object->get(*meth2); - if (FunctionObject *o = conv->asFunctionObject()) { + conv = object->get(meth2); + if (FunctionObject *o = conv->as<FunctionObject>()) { ScopedValue r(scope, o->call(callData)); if (r->isPrimitive()) return r->asReturnedValue(); @@ -437,7 +438,7 @@ Heap::Object *RuntimeHelpers::convertToObject(ExecutionEngine *engine, const Val return engine->newBooleanObject(value.booleanValue()); case Value::Managed_Type: Q_ASSERT(value.isString()); - return engine->newStringObject(value); + return engine->newStringObject(value.stringValue()); case Value::Integer_Type: default: // double return engine->newNumberObject(value.asDouble()); @@ -450,14 +451,14 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Val case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); case Value::Undefined_Type: - return engine->id_undefined->d(); + return engine->id_undefined()->d(); case Value::Null_Type: - return engine->id_null->d(); + return engine->id_null()->d(); case Value::Boolean_Type: if (value.booleanValue()) - return engine->id_true->d(); + return engine->id_true()->d(); else - return engine->id_false->d(); + return engine->id_false()->d(); case Value::Managed_Type: if (value.isString()) return value.stringValue()->d(); @@ -467,7 +468,7 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Val return RuntimeHelpers::convertToString(engine, prim); } case Value::Integer_Type: - return RuntimeHelpers::stringFromNumber(engine, value.int_32); + return RuntimeHelpers::stringFromNumber(engine, value.int_32()); default: // double return RuntimeHelpers::stringFromNumber(engine, value.doubleValue()); } // switch @@ -481,14 +482,14 @@ static Heap::String *convert_to_string_add(ExecutionEngine *engine, const Value case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); case Value::Undefined_Type: - return engine->id_undefined->d(); + return engine->id_undefined()->d(); case Value::Null_Type: - return engine->id_null->d(); + return engine->id_null()->d(); case Value::Boolean_Type: if (value.booleanValue()) - return engine->id_true->d(); + return engine->id_true()->d(); else - return engine->id_false->d(); + return engine->id_false()->d(); case Value::Managed_Type: if (value.isString()) return value.stringValue()->d(); @@ -498,7 +499,7 @@ static Heap::String *convert_to_string_add(ExecutionEngine *engine, const Value return RuntimeHelpers::convertToString(engine, prim); } case Value::Integer_Type: - return RuntimeHelpers::stringFromNumber(engine, value.int_32); + return RuntimeHelpers::stringFromNumber(engine, value.int_32()); default: // double return RuntimeHelpers::stringFromNumber(engine, value.doubleValue()); } // switch @@ -563,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; @@ -578,7 +579,7 @@ ReturnedValue Runtime::getElement(ExecutionEngine *engine, const Value &object, ScopedObject o(scope, object); if (!o) { if (idx < UINT_MAX) { - if (String *str = object.asString()) { + if (const String *str = object.as<String>()) { if (idx >= (uint)str->toQString().length()) { return Encode::undefined(); } @@ -660,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) @@ -688,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 @@ -906,13 +905,13 @@ 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]); - if (o->d() == scope.engine->evalFunction && name->equals(scope.engine->id_eval)) + 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); return o->call(callData); @@ -923,18 +922,17 @@ 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(); if (base) callData->thisObject = base; - FunctionObject *o = func->asFunctionObject(); + FunctionObject *o = func->as<FunctionObject>(); if (!o) { QString objectAsString = QStringLiteral("[null]"); if (base) @@ -943,17 +941,41 @@ ReturnedValue Runtime::callActivationProperty(ExecutionEngine *engine, int nameI return engine->throwTypeError(msg); } - if (o->d() == scope.engine->evalFunction && name->equals(scope.engine->id_eval)) { + if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) { return static_cast<EvalFunction *>(o)->evalCall(callData, true); } return o->call(callData); } +ReturnedValue Runtime::callQmlScopeObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData) +{ + Scope scope(engine); + ScopedFunctionObject o(scope, getQmlScopeObjectProperty(engine, callData->thisObject, propertyIndex)); + if (!o) { + QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(propertyIndex).arg(callData->thisObject.toQStringNoThrow()); + return engine->throwTypeError(error); + } + + return o->call(callData); +} + +ReturnedValue Runtime::callQmlContextObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData) +{ + Scope scope(engine); + ScopedFunctionObject o(scope, getQmlContextObjectProperty(engine, callData->thisObject, propertyIndex)); + if (!o) { + QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(propertyIndex).arg(callData->thisObject.toQStringNoThrow()); + return engine->throwTypeError(error); + } + + return o->call(callData); +} + 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()); @@ -979,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()) @@ -1019,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(); @@ -1031,13 +1053,12 @@ 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(); - Object *f = func->asObject(); + Object *f = func->as<Object>(); if (!f) return engine->throwTypeError(); @@ -1046,7 +1067,7 @@ ReturnedValue Runtime::constructActivationProperty(ExecutionEngine *engine, int ReturnedValue Runtime::constructValue(ExecutionEngine *engine, const Value &func, CallData *callData) { - Object *f = func.asObject(); + const Object *f = func.as<Object>(); if (!f) return engine->throwTypeError(); @@ -1057,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(); @@ -1070,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()) @@ -1092,24 +1113,24 @@ ReturnedValue Runtime::typeofValue(ExecutionEngine *engine, const Value &value) ScopedString res(scope); switch (value.type()) { case Value::Undefined_Type: - res = engine->id_undefined; + res = engine->id_undefined(); break; case Value::Null_Type: - res = engine->id_object; + res = engine->id_object(); break; case Value::Boolean_Type: - res = engine->id_boolean; + res = engine->id_boolean(); break; case Value::Managed_Type: if (value.isString()) - res = engine->id_string; - else if (value.objectValue()->asFunctionObject()) - res = engine->id_function; + res = engine->id_string(); + else if (value.objectValue()->as<FunctionObject>()) + res = engine->id_function(); else - res = engine->id_object; // ### implementation-defined + res = engine->id_object(); // ### implementation-defined break; default: - res = engine->id_number; + res = engine->id_number(); break; } return res.asReturnedValue(); @@ -1118,18 +1139,39 @@ 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); } +#ifndef V4_BOOTSTRAP +ReturnedValue Runtime::typeofScopeObjectProperty(ExecutionEngine *engine, const Value &context, + int propertyIndex) +{ + Scope scope(engine); + ScopedValue prop(scope, getQmlScopeObjectProperty(engine, context, propertyIndex)); + if (scope.engine->hasException) + return Encode::undefined(); + return Runtime::typeofValue(engine, prop); +} + +ReturnedValue Runtime::typeofContextObjectProperty(ExecutionEngine *engine, const Value &context, + int propertyIndex) +{ + Scope scope(engine); + ScopedValue prop(scope, getQmlContextObjectProperty(engine, context, propertyIndex)); + if (scope.engine->hasException) + return Encode::undefined(); + return Runtime::typeofValue(engine, prop); +} +#endif // V4_BOOTSTRAP + 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(); @@ -1148,14 +1190,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) @@ -1163,46 +1197,48 @@ 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]; - ScopedObject o(scope, engine->newObject(klass, engine->objectPrototype.asObject())); + QV4::InternalClass *klass = engine->current->compilationUnit->runtimeClasses[classId]; + ScopedObject o(scope, engine->newObject(klass, engine->objectPrototype())); { bool needSparseArray = arrayGetterSetterCountAndFlags >> 30; @@ -1211,7 +1247,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); @@ -1242,10 +1278,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 @@ -1329,32 +1365,14 @@ unsigned Runtime::doubleToUInt(const double &d) #ifndef V4_BOOTSTRAP -ReturnedValue Runtime::regexpLiteral(ExecutionEngine *engine, int id) -{ - return engine->currentContext()->compilationUnit->runtimeRegularExpressions[id].asReturnedValue(); -} - -ReturnedValue Runtime::getQmlIdArray(NoThrowEngine *engine) -{ - Q_ASSERT(engine->qmlContextObject()); - Scope scope(engine); - Scoped<QmlContextWrapper> wrapper(scope, engine->qmlContextObject()); - return wrapper->idObjectsArray(); -} - -ReturnedValue Runtime::getQmlContextObject(NoThrowEngine *engine) +ReturnedValue Runtime::getQmlContext(NoThrowEngine *engine) { - QQmlContextData *context = QmlContextWrapper::callingContext(engine); - if (!context) - return Encode::undefined(); - return QObjectWrapper::wrap(engine, context->contextObject); + return engine->qmlContext()->asReturnedValue(); } -ReturnedValue Runtime::getQmlScopeObject(NoThrowEngine *engine) +ReturnedValue Runtime::regexpLiteral(ExecutionEngine *engine, int id) { - Scope scope(engine); - QV4::Scoped<QmlContextWrapper> c(scope, engine->qmlContextObject()); - return QObjectWrapper::wrap(engine, c->getScopeObject()); + return engine->current->compilationUnit->runtimeRegularExpressions[id].asReturnedValue(); } ReturnedValue Runtime::getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired) @@ -1365,21 +1383,29 @@ ReturnedValue Runtime::getQmlQObjectProperty(ExecutionEngine *engine, const Valu engine->throwTypeError(QStringLiteral("Cannot read property of null")); return Encode::undefined(); } - ScopedContext ctx(scope, engine->currentContext()); - return QV4::QObjectWrapper::getProperty(wrapper->object(), ctx, propertyIndex, captureRequired); + return QV4::QObjectWrapper::getProperty(scope.engine, wrapper->object(), propertyIndex, captureRequired); } QV4::ReturnedValue Runtime::getQmlAttachedProperty(ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex) { - Scope scope(engine); - QV4::Scoped<QmlContextWrapper> c(scope, engine->qmlContextObject()); - QObject *scopeObject = c->getScopeObject(); + QObject *scopeObject = engine->qmlScopeObject(); QObject *attachedObject = qmlAttachedPropertiesObjectById(attachedPropertiesId, scopeObject); QJSEngine *jsEngine = engine->jsEngine(); QQmlData::ensurePropertyCache(jsEngine, attachedObject); - ScopedContext ctx(scope, engine->currentContext()); - return QV4::QObjectWrapper::getProperty(attachedObject, ctx, propertyIndex, /*captureRequired*/true); + return QV4::QObjectWrapper::getProperty(engine, attachedObject, propertyIndex, /*captureRequired*/true); +} + +ReturnedValue Runtime::getQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex) +{ + const QmlContext &c = static_cast<const QmlContext &>(context); + return QV4::QObjectWrapper::getProperty(engine, c.d()->qml->scopeObject, propertyIndex, false); +} + +ReturnedValue Runtime::getQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex) +{ + const QmlContext &c = static_cast<const QmlContext &>(context); + return QV4::QObjectWrapper::getProperty(engine, c.d()->qml->context->contextObject, propertyIndex, false); } ReturnedValue Runtime::getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired) @@ -1390,8 +1416,34 @@ ReturnedValue Runtime::getQmlSingletonQObjectProperty(ExecutionEngine *engine, c scope.engine->throwTypeError(QStringLiteral("Cannot read property of null")); return Encode::undefined(); } - ScopedContext ctx(scope, engine->currentContext()); - return QV4::QObjectWrapper::getProperty(wrapper->singletonObject(), ctx, propertyIndex, captureRequired); + return QV4::QObjectWrapper::getProperty(scope.engine, wrapper->singletonObject(), propertyIndex, captureRequired); +} + +ReturnedValue Runtime::getQmlIdObject(ExecutionEngine *engine, const Value &c, uint index) +{ + Scope scope(engine); + const QmlContext &qmlContext = static_cast<const QmlContext &>(c); + QQmlContextData *context = qmlContext.d()->qml->context; + if (!context || index >= (uint)context->idValueCount) + return Encode::undefined(); + + QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; + if (ep && ep->propertyCapture) + ep->propertyCapture->captureProperty(&context->idValues[index].bindings); + + return QObjectWrapper::wrap(engine, context->idValues[index].data()); +} + +void Runtime::setQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value) +{ + const QmlContext &c = static_cast<const QmlContext &>(context); + return QV4::QObjectWrapper::setProperty(engine, c.d()->qml->scopeObject, propertyIndex, value); +} + +void Runtime::setQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value) +{ + const QmlContext &c = static_cast<const QmlContext &>(context); + return QV4::QObjectWrapper::setProperty(engine, c.d()->qml->context->contextObject, propertyIndex, value); } void Runtime::setQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value) @@ -1402,13 +1454,12 @@ void Runtime::setQmlQObjectProperty(ExecutionEngine *engine, const Value &object engine->throwTypeError(QStringLiteral("Cannot write property of null")); return; } - ScopedContext ctx(scope, engine->currentContext()); - wrapper->setProperty(ctx, propertyIndex, value); + wrapper->setProperty(engine, propertyIndex, value); } ReturnedValue Runtime::getQmlImportedScripts(NoThrowEngine *engine) { - QQmlContextData *context = QmlContextWrapper::callingContext(engine); + QQmlContextData *context = engine->callingQmlContext(); if (!context) return Encode::undefined(); return context->importedScripts.value(); @@ -1417,18 +1468,17 @@ 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]); - Scoped<QmlContextWrapper> wrapper(scope, engine->qmlContextObject()); - return wrapper->qmlSingletonWrapper(engine, name); + 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()) { - *t = engine->globalObject()->asReturnedValue(); + *t = engine->globalObject->asReturnedValue(); } else { *t = t->toObject(engine)->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index f2f90bbc15..0d81edca1e 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -33,9 +33,21 @@ #ifndef QMLJS_RUNTIME_H #define QMLJS_RUNTIME_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #include "qv4context_p.h" +#include "qv4engine_p.h" #include "qv4math_p.h" #include <QtCore/qnumeric.h> @@ -90,6 +102,8 @@ struct Q_QML_PRIVATE_EXPORT Runtime { // call static ReturnedValue callGlobalLookup(ExecutionEngine *engine, uint index, CallData *callData); static ReturnedValue callActivationProperty(ExecutionEngine *engine, int nameIndex, CallData *callData); + static ReturnedValue callQmlScopeObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData); + static ReturnedValue callQmlContextObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData); static ReturnedValue callProperty(ExecutionEngine *engine, int nameIndex, CallData *callData); static ReturnedValue callPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData); static ReturnedValue callElement(ExecutionEngine *engine, const Value &index, CallData *callData); @@ -113,6 +127,8 @@ struct Q_QML_PRIVATE_EXPORT Runtime { // typeof static ReturnedValue typeofValue(ExecutionEngine *engine, const Value &val); static ReturnedValue typeofName(ExecutionEngine *engine, int nameIndex); + static ReturnedValue typeofScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex); + static ReturnedValue typeofContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex); static ReturnedValue typeofMember(ExecutionEngine *engine, const Value &base, int nameIndex); static ReturnedValue typeofElement(ExecutionEngine *engine, const Value &base, const Value &index); @@ -206,19 +222,23 @@ struct Q_QML_PRIVATE_EXPORT Runtime { static unsigned doubleToUInt(const double &d); // qml - static ReturnedValue getQmlIdArray(NoThrowEngine *ctx); - static ReturnedValue getQmlImportedScripts(NoThrowEngine *ctx); - static ReturnedValue getQmlContextObject(NoThrowEngine *ctx); - static ReturnedValue getQmlScopeObject(NoThrowEngine *ctx); - static ReturnedValue getQmlSingleton(NoThrowEngine *ctx, int nameIndex); + static ReturnedValue getQmlContext(NoThrowEngine *engine); + static ReturnedValue getQmlImportedScripts(NoThrowEngine *engine); + static ReturnedValue getQmlSingleton(NoThrowEngine *engine, int nameIndex); static ReturnedValue getQmlAttachedProperty(ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex); + static ReturnedValue getQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex); + static ReturnedValue getQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex); static ReturnedValue getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired); static ReturnedValue getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired); + static ReturnedValue getQmlIdObject(ExecutionEngine *engine, const Value &context, uint index); + + static void setQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value); + static void setQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value); static void setQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value); }; struct Q_QML_PRIVATE_EXPORT RuntimeHelpers { - static ReturnedValue objectDefaultValue(Object *object, int typeHint); + static ReturnedValue objectDefaultValue(const Object *object, int typeHint); static ReturnedValue toPrimitive(const Value &value, int typeHint); static double stringToNumber(const QString &s); @@ -243,7 +263,7 @@ struct Q_QML_PRIVATE_EXPORT RuntimeHelpers { #ifndef V4_BOOTSTRAP inline ReturnedValue RuntimeHelpers::toPrimitive(const Value &value, int typeHint) { - Object *o = value.asObject(); + const Object *o = value.as<Object>(); if (!o) return value.asReturnedValue(); return RuntimeHelpers::objectDefaultValue(o, typeHint); @@ -262,7 +282,7 @@ inline ReturnedValue Runtime::uPlus(const Value &value) if (value.isNumber()) return value.asReturnedValue(); if (value.integerCompatible()) - return Encode(value.int_32); + return Encode(value.int_32()); double n = value.toNumberImpl(); return Encode(n); @@ -369,6 +389,15 @@ inline ReturnedValue Runtime::div(const Value &left, const Value &right) { TRACE2(left, right); + if (Value::integerCompatible(left, right)) { + int lval = left.integerValue(); + int rval = right.integerValue(); + if (rval != 0 && (lval % rval == 0)) + return Encode(int(lval / rval)); + else + return Encode(double(lval) / rval); + } + double lval = left.toNumber(); double rval = right.toNumber(); return Primitive::fromDouble(lval / rval).asReturnedValue(); diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 908248f0f0..d7fd44e1d6 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -33,6 +33,17 @@ #ifndef QV4SCOPEDVALUE_P_H #define QV4SCOPEDVALUE_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4engine_p.h" #include "qv4value_p.h" #include "qv4persistent_p.h" @@ -54,18 +65,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 +78,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,13 +88,7 @@ struct Scope { } Value *alloc(int nValues) { -#ifndef QT_NO_DEBUG - size += nValues; -#endif - Value *ptr = engine->jsStackTop; - engine->jsStackTop = ptr + nValues; - memset(ptr, 0, nValues*sizeof(Value)); - return ptr; + return engine->jsAlloca(nValues); } bool hasException() const { @@ -97,9 +97,6 @@ struct Scope { ExecutionEngine *engine; Value *mark; -#ifndef QT_NO_DEBUG - mutable int size; -#endif private: Q_DISABLE_COPY(Scope) @@ -110,49 +107,34 @@ struct ScopedValue ScopedValue(const Scope &scope) { ptr = scope.engine->jsStackTop++; - ptr->val = 0; -#ifndef QT_NO_DEBUG - ++scope.size; -#endif + ptr->setRawValue(0); } 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) { ptr = scope.engine->jsStackTop++; - ptr->m = o; -#if QT_POINTER_SIZE == 4 - ptr->tag = QV4::Value::Managed_Type; -#endif -#ifndef QT_NO_DEBUG - ++scope.size; + ptr->setM(o); +#ifndef QV4_USE_64_BIT_VALUE_ENCODING + ptr->setTag(QV4::Value::Managed_Type); #endif } ScopedValue(const Scope &scope, Managed *m) { ptr = scope.engine->jsStackTop++; - ptr->val = m->asReturnedValue(); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif + ptr->setRawValue(m->asReturnedValue()); } ScopedValue(const Scope &scope, const ReturnedValue &v) { ptr = scope.engine->jsStackTop++; - ptr->val = v; -#ifndef QT_NO_DEBUG - ++scope.size; -#endif + ptr->setRawValue(v); } ScopedValue &operator=(const Value &v) { @@ -161,9 +143,9 @@ struct ScopedValue } ScopedValue &operator=(Heap::Base *o) { - ptr->m = o; -#if QT_POINTER_SIZE == 4 - ptr->tag = QV4::Value::Managed_Type; + ptr->setM(o); +#ifndef QV4_USE_64_BIT_VALUE_ENCODING + ptr->setTag(QV4::Value::Managed_Type); #endif return *this; } @@ -174,7 +156,7 @@ struct ScopedValue } ScopedValue &operator=(const ReturnedValue &v) { - ptr->val = v; + ptr->setRawValue(v); return *this; } @@ -200,111 +182,78 @@ struct ScopedValue template<typename T> struct Scoped { - enum _Convert { Convert }; + enum ConvertType { Convert }; - inline void setPointer(Managed *p) { - ptr->m = p ? p->m : 0; -#if QT_POINTER_SIZE == 4 - ptr->tag = QV4::Value::Managed_Type; + inline void setPointer(const Managed *p) { + ptr->setM(p ? p->m() : 0); +#ifndef QV4_USE_64_BIT_VALUE_ENCODING + ptr->setTag(QV4::Value::Managed_Type); #endif } Scoped(const Scope &scope) { ptr = scope.engine->jsStackTop++; - ptr->m = 0; -#if QT_POINTER_SIZE == 4 - ptr->tag = QV4::Value::Managed_Type; -#endif -#ifndef QT_NO_DEBUG - ++scope.size; + ptr->setM(0); +#ifndef QV4_USE_64_BIT_VALUE_ENCODING + ptr->setTag(QV4::Value::Managed_Type); #endif } - // ### GC FIX casting below to be safe Scoped(const Scope &scope, const Value &v) { ptr = scope.engine->jsStackTop++; - setPointer(value_cast<T>(v)); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif + setPointer(v.as<T>()); } Scoped(const Scope &scope, Heap::Base *o) { Value v; v = o; ptr = scope.engine->jsStackTop++; - setPointer(value_cast<T>(v)); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif + setPointer(v.as<T>()); } Scoped(const Scope &scope, const ScopedValue &v) { ptr = scope.engine->jsStackTop++; - setPointer(value_cast<T>(*v.ptr)); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif + setPointer(v.ptr->as<T>()); } - Scoped(const Scope &scope, const Value &v, _Convert) + Scoped(const Scope &scope, const Value &v, ConvertType) { ptr = scope.engine->jsStackTop++; - ptr->val = value_convert<T>(scope.engine, v); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif + ptr->setRawValue(value_convert<T>(scope.engine, v)); } Scoped(const Scope &scope, const Value *v) { ptr = scope.engine->jsStackTop++; - setPointer(v ? value_cast<T>(*v) : 0); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif + setPointer(v ? v->as<T>() : 0); } 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(value_cast<T>(QV4::Value::fromReturnedValue(v))); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif + setPointer(QV4::Value::fromReturnedValue(v).as<T>()); } - Scoped(const Scope &scope, const ReturnedValue &v, _Convert) + Scoped(const Scope &scope, const ReturnedValue &v, ConvertType) { ptr = scope.engine->jsStackTop++; - ptr->val = value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v)); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif + ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v))); } Scoped<T> &operator=(Heap::Base *o) { - Value v; - v = o; - setPointer(value_cast<T>(v)); + setPointer(Value::fromHeapObject(o).as<T>()); return *this; } Scoped<T> &operator=(typename T::Data *t) { @@ -312,16 +261,16 @@ struct Scoped return *this; } Scoped<T> &operator=(const Value &v) { - setPointer(value_cast<T>(v)); + setPointer(v.as<T>()); return *this; } Scoped<T> &operator=(Value *v) { - setPointer(v ? value_cast<T>(*v) : 0); + setPointer(v ? v->as<T>() : 0); return *this; } Scoped<T> &operator=(const ReturnedValue &v) { - setPointer(value_cast<T>(QV4::Value::fromReturnedValue(v))); + setPointer(QV4::Value::fromReturnedValue(v).as<T>()); return *this; } @@ -347,21 +296,21 @@ struct Scoped } bool operator!() const { - return !ptr->m; + return !ptr->m(); } operator void *() const { - return ptr->m; + return ptr->m(); } T *getPointer() { return ptr->cast<T>(); } - typename T::Data **getRef() { - return reinterpret_cast<typename T::Data **>(&ptr->m); + Value *getRef() { + return ptr; } ReturnedValue asReturnedValue() const { - return ptr->m ? ptr->val : Encode::undefined(); + return ptr->m() ? ptr->rawValue() : Encode::undefined(); } Value *ptr; @@ -390,41 +339,14 @@ struct ScopedCallData { inline Value &Value::operator =(const ScopedValue &v) { - val = v.ptr->val; + _val = v.ptr->val(); return *this; } template<typename T> inline Value &Value::operator=(const Scoped<T> &t) { - val = t.ptr->val; - return *this; -} - -template<typename T> -inline TypedValue<T> &TypedValue<T>::operator =(T *t) -{ - m = t ? t->m : 0; -#if QT_POINTER_SIZE == 4 - tag = Managed_Type; -#endif - return *this; -} - -template<typename T> -inline TypedValue<T> &TypedValue<T>::operator =(const Scoped<T> &v) -{ - m = v.ptr->m; -#if QT_POINTER_SIZE == 4 - tag = Managed_Type; -#endif - return *this; -} - -template<typename T> -inline TypedValue<T> &TypedValue<T>::operator=(const TypedValue<T> &t) -{ - val = t.val; + _val = t.ptr->val(); return *this; } @@ -447,29 +369,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->m = context->d(); -#if QT_POINTER_SIZE == 4 - savedContext->tag = QV4::Value::Managed_Type; -#endif - } - ExecutionContextSaver(Scope &scope, Heap::ExecutionContext *context) - : engine(context->engine) - , savedContext(scope.alloc(1)) - { - savedContext->m = context; -#if QT_POINTER_SIZE == 4 - savedContext->tag = 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 4fde0e2445..7f2f22780e 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -32,11 +32,12 @@ ****************************************************************************/ #include "qv4script_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4functionobject_p.h" #include "qv4function_p.h" #include "qv4context_p.h" #include "qv4debugging_p.h" +#include "qv4profiling_p.h" #include "qv4scopedvalue_p.h" #include <private/qqmljsengine_p.h> @@ -44,6 +45,7 @@ #include <private/qqmljsparser_p.h> #include <private/qqmljsast_p.h> #include <private/qqmlengine_p.h> +#include <private/qv4profiling_p.h> #include <qv4jsir_p.h> #include <qv4codegen_p.h> #include <private/qqmlcontextwrapper_p.h> @@ -57,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 @@ -71,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 @@ -86,117 +97,52 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlBindingWrapper); DEFINE_OBJECT_VTABLE(CompilationUnitHolder); -Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::Object *qml) - : Heap::FunctionObject(scope, scope->d()->engine->id_eval, /*createProto = */ false) - , qml(qml->d()) +Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::QmlContext *scope, Function *f) + : Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false) { Q_ASSERT(scope->inUse()); function = f; if (function) function->compilationUnit->addref(); - - Scope s(scope); - Scoped<QV4::QmlBindingWrapper> o(s, this); - - o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1)); - - ScopedContext ctx(s, s.engine->currentContext()); - o->d()->qmlContext = ctx->newQmlContext(o, qml); - s.engine->popContext(); } -Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::Object *qml) - : Heap::FunctionObject(scope, scope->d()->engine->id_eval, /*createProto = */ false) - , qml(qml->d()) +ReturnedValue QmlBindingWrapper::call(const Managed *that, CallData *callData) { - Q_ASSERT(scope->inUse()); - - Scope s(scope); - Scoped<QV4::QmlBindingWrapper> o(s, this); - - o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1)); - - ScopedContext ctx(s, s.engine->currentContext()); - o->d()->qmlContext = ctx->newQmlContext(o, qml); - s.engine->popContext(); -} + const QmlBindingWrapper *This = static_cast<const QmlBindingWrapper *>(that); + ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); + if (v4->hasException) + return Encode::undefined(); + CHECK_STACK_LIMITS(v4); -ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *) -{ - ExecutionEngine *engine = static_cast<Object *>(that)->engine(); - CHECK_STACK_LIMITS(engine); + Scope scope(v4); + ExecutionContextSaver ctxSaver(scope); - Scope scope(engine); - QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that); - if (!This->function()) + QV4::Function *f = This->function(); + if (!f) return QV4::Encode::undefined(); - Scoped<CallContext> ctx(scope, This->d()->qmlContext); - std::fill(ctx->d()->locals, ctx->d()->locals + ctx->d()->function->varCount(), Primitive::undefinedValue()); - engine->pushContext(ctx); - ScopedValue result(scope, This->function()->code(engine, This->function()->codeData)); - engine->popContext(); + Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(This, callData)); + v4->pushContext(ctx); - return result->asReturnedValue(); -} - -void QmlBindingWrapper::markObjects(Heap::Base *m, ExecutionEngine *e) -{ - QmlBindingWrapper::Data *wrapper = static_cast<QmlBindingWrapper::Data *>(m); - if (wrapper->qml) - wrapper->qml->mark(e); - FunctionObject::markObjects(m, e); - if (wrapper->qmlContext) - wrapper->qmlContext->mark(e); -} - -static ReturnedValue signalParameterGetter(QV4::CallContext *ctx, uint parameterIndex) -{ - QV4::Scope scope(ctx); - QV4::Scoped<CallContext> signalEmittingContext(scope, static_cast<Heap::CallContext *>(ctx->d()->parent)); - Q_ASSERT(signalEmittingContext && signalEmittingContext->d()->type >= QV4::Heap::ExecutionContext::Type_SimpleCallContext); - return signalEmittingContext->argument(parameterIndex); -} + ScopedValue result(scope, Q_V4_PROFILE(v4, f)); -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::ScopedObject qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine, qmlContext, scopeObject)); - ScopedContext global(valueScope, valueScope.engine->rootContext()); - QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, engine->memoryManager->alloc<QV4::QmlBindingWrapper>(global, qmlScopeObject)); - QV4::Scoped<CallContext> wrapperContext(valueScope, wrapper->context()); - - 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(); + return result->asReturnedValue(); } -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); } } @@ -214,7 +160,7 @@ void Script::parse() parsed = true; - ExecutionEngine *v4 = scope->engine; + ExecutionEngine *v4 = scope->engine(); Scope valueScope(v4); MemoryManager::GCBlocker gcBlocker(v4->memoryManager); @@ -267,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); } @@ -285,23 +231,22 @@ ReturnedValue Script::run() if (!vmFunction) return Encode::undefined(); - QV4::ExecutionEngine *engine = scope->engine; + 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->strictMode = vmFunction->isStrict(); - scope->lookups = vmFunction->compilationUnit->runtimeLookups; - scope->compilationUnit = vmFunction->compilationUnit; + scope->d()->strictMode = vmFunction->isStrict(); + scope->d()->lookups = vmFunction->compilationUnit->runtimeLookups; + scope->d()->compilationUnit = vmFunction->compilationUnit; - return vmFunction->code(engine, vmFunction->codeData); + return Q_V4_PROFILE(engine, vmFunction); } else { - ScopedObject qmlObj(valueScope, qml.value()); - ScopedContext ctx(valueScope, scope); - ScopedFunctionObject f(valueScope, engine->memoryManager->alloc<QmlBindingWrapper>(ctx, 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); @@ -376,18 +321,17 @@ ReturnedValue Script::qmlBinding() { if (!parsed) parse(); - ExecutionEngine *v4 = scope->engine; + ExecutionEngine *v4 = scope->engine(); Scope valueScope(v4); - ScopedObject qmlObj(valueScope, qml.value()); - ScopedContext ctx(valueScope, scope); - ScopedObject v(valueScope, v4->memoryManager->alloc<QmlBindingWrapper>(ctx, 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 05a9e45f45..4fecf62082 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -33,9 +33,21 @@ #ifndef QV4SCRIPT_H #define QV4SCRIPT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" #include "qv4engine_p.h" #include "qv4functionobject_p.h" +#include "qv4context_p.h" #include <QQmlError> @@ -63,7 +75,7 @@ struct ContextStateSaver { , compilationUnit(context->d()->compilationUnit) , lineNumber(context->d()->lineNumber) { - savedContext->m = context->d(); + savedContext->setM(context->d()); } ContextStateSaver(Scope &scope, Heap::ExecutionContext *context) : savedContext(scope.alloc(1)) @@ -72,12 +84,12 @@ struct ContextStateSaver { , compilationUnit(context->compilationUnit) , lineNumber(context->lineNumber) { - savedContext->m = context; + savedContext->setM(context); } ~ContextStateSaver() { - Heap::ExecutionContext *ctx = static_cast<Heap::ExecutionContext *>(savedContext->m); + Heap::ExecutionContext *ctx = static_cast<Heap::ExecutionContext *>(savedContext->m()); ctx->strictMode = strictMode; ctx->lookups = lookups; ctx->compilationUnit = compilationUnit; @@ -85,52 +97,29 @@ struct ContextStateSaver { } }; -namespace Heap { -struct QmlBindingWrapper : Heap::FunctionObject { - QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::Object *qml); - // Constructor for QML functions and signal handlers, resulting binding wrapper is not callable! - QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::Object *qml); - Object *qml; - CallContext *qmlContext; -}; - -} - -struct Q_QML_EXPORT QmlBindingWrapper : FunctionObject { - V4_OBJECT2(QmlBindingWrapper, FunctionObject) - - static ReturnedValue call(Managed *that, CallData *); - static void markObjects(Heap::Base *m, ExecutionEngine *e); - - Heap::CallContext *context() const { return d()->qmlContext; } - - static Heap::FunctionObject *createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, - const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0); - -private: -}; - 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->d()), strictMode(false), inheritContext(false), parsed(false) + , 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; int column; QString sourceCode; - // ### GC - Heap::ExecutionContext *scope; + ExecutionContext *scope; bool strictMode; bool inheritContext; bool parsed; - QV4::PersistentValue qml; + QV4::PersistentValue qmlContext; QV4::PersistentValue compilationUnitHolder; Function *vmFunction; bool parseAsBinding; @@ -144,7 +133,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 f1f546bece..36ee848d00 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -175,7 +175,7 @@ template <> QUrl convertValueToElement(const Value &value) template <> QModelIndex convertValueToElement(const Value &value) { - const QQmlValueTypeWrapper *v = value_cast<QQmlValueTypeWrapper>(value); + const QQmlValueTypeWrapper *v = value.as<QQmlValueTypeWrapper>(); if (v) return v->toVariant().toModelIndex(); return QModelIndex(); @@ -183,7 +183,7 @@ template <> QModelIndex convertValueToElement(const Value &value) template <> QItemSelectionRange convertValueToElement(const Value &value) { - const QQmlValueTypeWrapper *v = value_cast<QQmlValueTypeWrapper>(value); + const QQmlValueTypeWrapper *v = value.as<QQmlValueTypeWrapper>(); if (v) return v->toVariant().value<QItemSelectionRange>(); return QItemSelectionRange(); @@ -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: @@ -231,7 +232,7 @@ public: defineAccessorProperty(QStringLiteral("length"), method_get_length, method_set_length); } - QV4::ReturnedValue containerGetIndexed(uint index, bool *hasProperty) + QV4::ReturnedValue containerGetIndexed(uint index, bool *hasProperty) const { /* Qt containers have int (rather than uint) allowable indexes. */ if (index > INT_MAX) { @@ -316,9 +317,9 @@ public: return (signedIdx < d()->container.count()) ? QV4::Attr_Data : QV4::Attr_Invalid; } - void containerAdvanceIterator(ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attrs) + void containerAdvanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) { - *name = (Heap::String *)0; + name->setM(0); *index = UINT_MAX; if (d()->isReference) { @@ -400,7 +401,7 @@ public: ScopedCallData callData(scope, 2); callData->args[0] = convertElementToValue(this->m_ctx->d()->engine, lhs); callData->args[1] = convertElementToValue(this->m_ctx->d()->engine, rhs); - callData->thisObject = this->m_ctx->d()->engine->globalObject(); + callData->thisObject = this->m_ctx->d()->engine->globalObject; QV4::ScopedValue result(scope, compare->call(callData)); return result->toNumber() < 0; } @@ -419,7 +420,7 @@ public: } QV4::Scope scope(ctx); - if (ctx->argc() == 1 && ctx->args()[0].asFunctionObject()) { + if (ctx->argc() == 1 && ctx->args()[0].as<FunctionObject>()) { CompareFunctor cf(ctx, ctx->args()[0]); std::sort(d()->container.begin(), d()->container.end(), cf); } else { @@ -526,8 +527,8 @@ public: QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a); } - static QV4::ReturnedValue getIndexed(QV4::Managed *that, uint index, bool *hasProperty) - { return static_cast<QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); } + static QV4::ReturnedValue getIndexed(const QV4::Managed *that, uint index, bool *hasProperty) + { return static_cast<const QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); } static void putIndexed(Managed *that, uint index, const QV4::Value &value) { static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); } static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index) @@ -536,33 +537,31 @@ public: { return static_cast<QQmlSequence<Container> *>(that)->containerDeleteIndexedProperty(index); } static bool isEqualTo(Managed *that, Managed *other) { return static_cast<QQmlSequence<Container> *>(that)->containerIsEqualTo(other); } - static void advanceIterator(Managed *that, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attrs) + static void advanceIterator(Managed *that, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) { return static_cast<QQmlSequence<Container> *>(that)->containerAdvanceIterator(it, name, index, p, attrs); } }; template <typename Container> -Heap::QQmlSequence<Container>::QQmlSequence(QV4::ExecutionEngine *engine, const Container &container) - : Heap::Object(engine->emptyClass, engine->sequencePrototype.asObject()) - , 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.asObject()) - , 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(); @@ -605,7 +604,7 @@ void SequencePrototype::init() { FOREACH_QML_SEQUENCE_TYPE(REGISTER_QML_SEQUENCE_METATYPE) defineDefaultProperty(QStringLiteral("sort"), method_sort, 1); - defineDefaultProperty(engine()->id_valueOf, method_valueOf, 0); + defineDefaultProperty(engine()->id_valueOf(), method_valueOf, 0); } #undef REGISTER_QML_SEQUENCE_METATYPE @@ -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 @@ -700,11 +699,11 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, int typeHint, boo { *succeeded = true; - if (!array.asArrayObject()) { + if (!array.as<ArrayObject>()) { *succeeded = false; return QVariant(); } - QV4::Scope scope(array.asObject()->engine()); + QV4::Scope scope(array.as<Object>()->engine()); QV4::ScopedArrayObject a(scope, array); FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_TO_VARIANT) { /* else */ *succeeded = false; return QVariant(); } @@ -717,7 +716,7 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, int typeHint, boo return qMetaTypeId<SequenceType>(); \ } else -int SequencePrototype::metaTypeForSequence(QV4::Object *object) +int SequencePrototype::metaTypeForSequence(const QV4::Object *object) { FOREACH_QML_SEQUENCE_TYPE(MAP_META_TYPE) /*else*/ { diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h index 9949278a89..560c3c27ca 100644 --- a/src/qml/jsruntime/qv4sequenceobject_p.h +++ b/src/qml/jsruntime/qv4sequenceobject_p.h @@ -48,9 +48,10 @@ #include <QtCore/qglobal.h> #include <QtCore/qvariant.h> -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #include "qv4object_p.h" #include "qv4context_p.h" +#include "qv4string_p.h" QT_BEGIN_NAMESPACE @@ -70,7 +71,7 @@ struct SequencePrototype : public QV4::Object static bool isSequenceType(int sequenceTypeId); static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded); static ReturnedValue fromVariant(QV4::ExecutionEngine *engine, const QVariant& v, bool *succeeded); - static int metaTypeForSequence(Object *object); + static int metaTypeForSequence(const Object *object); static QVariant toVariant(Object *object); static QVariant toVariant(const Value &array, int typeHint, bool *succeeded); }; diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp index 31d85df13e..33b40796a4 100644 --- a/src/qml/jsruntime/qv4serialize.cpp +++ b/src/qml/jsruntime/qv4serialize.cpp @@ -37,7 +37,7 @@ #include <private/qqmllistmodel_p.h> #include <private/qqmllistmodelworkeragent_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4dateobject_p.h> #include <private/qv4regexpobject_p.h> #include <private/qv4sequenceobject_p.h> @@ -168,11 +168,11 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine char *buffer = data.data() + offset; memcpy(buffer, qstr.constData(), length*sizeof(QChar)); - } else if (v.asFunctionObject()) { + } else if (v.as<FunctionObject>()) { // XXX TODO: Implement passing function objects between the main and // worker scripts push(data, valueheader(WorkerUndefined)); - } else if (QV4::ArrayObject *array = v.asArrayObject()) { + } else if (const QV4::ArrayObject *array = v.as<ArrayObject>()) { uint length = array->getLength(); if (length > 0xFFFFFF) { push(data, valueheader(WorkerUndefined)); @@ -195,11 +195,11 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine reserve(data, sizeof(quint32) + sizeof(double)); push(data, valueheader(WorkerNumber)); push(data, v.asDouble()); - } else if (QV4::DateObject *d = v.asDateObject()) { + } else if (const QV4::DateObject *d = v.as<DateObject>()) { reserve(data, sizeof(quint32) + sizeof(double)); push(data, valueheader(WorkerDate)); - push(data, d->date().asDouble()); - } else if (RegExpObject *re = v.as<RegExpObject>()) { + push(data, d->date()); + } else if (const RegExpObject *re = v.as<RegExpObject>()) { quint32 flags = re->flags(); QString pattern = re->source(); int length = pattern.length() + 1; @@ -218,7 +218,7 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine char *buffer = data.data() + offset; memcpy(buffer, pattern.constData(), length*sizeof(QChar)); - } else if (QObjectWrapper *qobjectWrapper = v.as<QV4::QObjectWrapper>()) { + } else if (const QObjectWrapper *qobjectWrapper = v.as<QV4::QObjectWrapper>()) { // XXX TODO: Generalize passing objects between the main thread and worker scripts so // that others can trivially plug in their elements. QQmlListModel *lm = qobject_cast<QQmlListModel *>(qobjectWrapper->object()); @@ -231,10 +231,10 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine } // No other QObject's are allowed to be sent push(data, valueheader(WorkerUndefined)); - } else if (Object *o = v.asObject()) { + } else if (const Object *o = v.as<Object>()) { if (o->isListType()) { // valid sequence. we generate a length (sequence length + 1 for the sequence type) - uint seqLength = ScopedValue(scope, o->get(engine->id_length))->toUInt32(); + uint seqLength = ScopedValue(scope, o->get(engine->id_length()))->toUInt32(); uint length = seqLength + 1; if (length > 0xFFFFFF) { push(data, valueheader(WorkerUndefined)); @@ -265,7 +265,7 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine s = properties->getIndexed(ii); serialize(data, s, engine); - QV4::String *str = s->asString(); + QV4::String *str = s->as<String>(); val = o->get(str); if (scope.hasException()) scope.engine->catchException(); @@ -356,7 +356,7 @@ ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine) QVariant var = qVariantFromValue(ref); QV4::ScopedValue v(scope, scope.engine->fromVariant(var)); QV4::ScopedString s(scope, engine->newString(QStringLiteral("__qml:hidden:ref"))); - rv->asObject()->defineReadonlyProperty(s, v); + rv->as<Object>()->defineReadonlyProperty(s, v); agent->release(); agent->setEngine(engine); diff --git a/src/qml/jsruntime/qv4serialize_p.h b/src/qml/jsruntime/qv4serialize_p.h index 06eaffe4c4..d5d48edee7 100644 --- a/src/qml/jsruntime/qv4serialize_p.h +++ b/src/qml/jsruntime/qv4serialize_p.h @@ -46,7 +46,7 @@ // #include <QtCore/qbytearray.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QT_BEGIN_NAMESPACE 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/qv4sparsearray_p.h b/src/qml/jsruntime/qv4sparsearray_p.h index 861c7dd28d..136f26a25c 100644 --- a/src/qml/jsruntime/qv4sparsearray_p.h +++ b/src/qml/jsruntime/qv4sparsearray_p.h @@ -34,12 +34,19 @@ #ifndef QV4SPARSEARRAY_H #define QV4SPARSEARRAY_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" -#include <QtCore/qmap.h> -#include "qv4value_inl_p.h" -#include "qv4scopedvalue_p.h" -#include "qv4property_p.h" -#include <assert.h> +#include <QtCore/qlist.h> //#define Q_MAP_DEBUG #ifdef Q_MAP_DEBUG @@ -188,7 +195,7 @@ public: typedef qptrdiff difference_type; typedef int size_type; -#ifndef QT_NO_DEBUG +#ifdef Q_MAP_DEBUG void dump() const; #endif }; @@ -261,7 +268,7 @@ inline void SparseArray::push_back(uint index, uint len) n->value = index; } -#ifndef QT_NO_DEBUG +#ifdef Q_MAP_DEBUG inline void SparseArray::dump() const { const SparseArrayNode *it = begin(); @@ -344,4 +351,4 @@ inline SparseArrayNode *SparseArray::upperBound(uint akey) QT_END_NAMESPACE -#endif // QMAP_H +#endif diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 6d55eb2c18..24a13ddd10 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include "qv4string_p.h" -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #ifndef V4_BOOTSTRAP #include "qv4identifiertable_p.h" #include "qv4runtime_p.h" @@ -110,7 +110,7 @@ bool String::isEqualTo(Managed *t, Managed *o) if (t == o) return true; - if (!o->d()->vtable->isString) + if (!o->d()->vtable()->isString) return false; return static_cast<String *>(t)->isEqualTo(static_cast<String *>(o)); diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 1cf8f51a29..85433369fc 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -33,6 +33,17 @@ #ifndef QV4STRING_H #define QV4STRING_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/qstring.h> #include "qv4managed_p.h" @@ -188,6 +199,20 @@ public: static uint toArrayIndex(const QString &str); }; +template<> +inline const String *Value::as() const { + return isManaged() && m() && m()->vtable()->isString ? static_cast<const String *>(this) : 0; +} + +#ifndef V4_BOOTSTRAP +template<> +inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v) +{ + return v.toString(e)->asReturnedValue(); +} +#endif + + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index e0b84f6da3..757ec6c6bf 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -36,7 +36,7 @@ #include "qv4regexp_p.h" #include "qv4regexpobject_p.h" #include "qv4objectproto_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4scopedvalue_p.h" #include "qv4alloca_p.h" #include <QtCore/QDateTime> @@ -67,68 +67,62 @@ 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()); - value = ic->engine->newString()->asReturnedValue(); - tmpProperty.value = Primitive::undefinedValue(); - - Scope scope(ic->engine); - ScopedObject s(scope, this); - s->defineReadonlyProperty(ic->engine->id_length, Primitive::fromInt32(0)); + Q_ASSERT(vtable() == QV4::StringObject::staticVTable()); + string = internalClass->engine->id_empty()->d(); + *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); } -Heap::StringObject::StringObject(ExecutionEngine *engine, const Value &val) - : Heap::Object(engine->emptyClass, engine->stringPrototype.asObject()) +Heap::StringObject::StringObject(const QV4::String *str) { - value = val; - Q_ASSERT(value.isString()); - tmpProperty.value = Primitive::undefinedValue(); - - Scope scope(engine); - ScopedObject s(scope, this); - s->defineReadonlyProperty(engine->id_length, Primitive::fromUInt32(value.stringValue()->toQString().length())); + string = str->d(); + *propertyData(LengthPropertyIndex) = Primitive::fromInt32(length()); } -Property *Heap::StringObject::getIndex(uint index) const +Heap::String *Heap::StringObject::getIndex(uint index) const { - QString str = value.stringValue()->toQString(); + QString str = string->toQString(); if (index >= (uint)str.length()) return 0; - tmpProperty.value = Encode(internalClass->engine->newString(str.mid(index, 1))); - return &tmpProperty; + return internalClass->engine->newString(str.mid(index, 1)); +} + +uint Heap::StringObject::length() const +{ + return string->len; } bool StringObject::deleteIndexedProperty(Managed *m, uint index) { ExecutionEngine *v4 = static_cast<StringObject *>(m)->engine(); Scope scope(v4); - Scoped<StringObject> o(scope, m->asStringObject()); + Scoped<StringObject> o(scope, m->as<StringObject>()); Q_ASSERT(!!o); - if (index < static_cast<uint>(o->d()->value.stringValue()->toQString().length())) { - if (v4->currentContext()->strictMode) + if (index < static_cast<uint>(o->d()->string->toQString().length())) { + if (v4->current->strictMode) v4->throwTypeError(); return false; } return true; } -void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attrs) +void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) { - *name = (Heap::String *)0; + name->setM(0); StringObject *s = static_cast<StringObject *>(m); - uint slen = s->d()->value.stringValue()->toQString().length(); + uint slen = s->d()->string->toQString().length(); if (it->arrayIndex <= slen) { while (it->arrayIndex < slen) { *index = it->arrayIndex; ++it->arrayIndex; PropertyAttributes a; - Property *pd = s->__getOwnProperty__(*index, &a); + Property pd; + s->getOwnProperty(*index, &a, &pd); if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { *attrs = a; - p->copy(pd, a); + p->copy(&pd, a); return; } } @@ -146,8 +140,7 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Heap::String void StringObject::markObjects(Heap::Base *that, ExecutionEngine *e) { StringObject::Data *o = static_cast<StringObject::Data *>(that); - o->value.stringValue()->mark(e); - o->tmpProperty.value.mark(e); + o->string->mark(e); Object::markObjects(that, e); } @@ -158,11 +151,11 @@ Heap::StringCtor::StringCtor(QV4::ExecutionContext *scope) { } -ReturnedValue StringCtor::construct(Managed *m, CallData *callData) +ReturnedValue StringCtor::construct(const Managed *m, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(m)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(m)->engine(); Scope scope(v4); - ScopedValue value(scope); + ScopedString value(scope); if (callData->argc) value = callData->args[0].toString(v4); else @@ -170,9 +163,9 @@ ReturnedValue StringCtor::construct(Managed *m, CallData *callData) return Encode(v4->newStringObject(value)); } -ReturnedValue StringCtor::call(Managed *m, CallData *callData) +ReturnedValue StringCtor::call(const Managed *m, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(m)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(m)->engine(); Scope scope(v4); ScopedValue value(scope); if (callData->argc) @@ -187,13 +180,13 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor) Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); ctor->defineDefaultProperty(QStringLiteral("fromCharCode"), method_fromCharCode, 1); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString); - defineDefaultProperty(engine->id_valueOf, method_toString); // valueOf and toString are identical + defineDefaultProperty(engine->id_toString(), method_toString); + defineDefaultProperty(engine->id_valueOf(), method_toString); // valueOf and toString are identical defineDefaultProperty(QStringLiteral("charAt"), method_charAt, 1); defineDefaultProperty(QStringLiteral("charCodeAt"), method_charCodeAt, 1); defineDefaultProperty(QStringLiteral("concat"), method_concat, 1); @@ -220,8 +213,8 @@ static QString getThisString(ExecutionContext *ctx) ScopedValue t(scope, ctx->thisObject()); if (t->isString()) return t->stringValue()->toQString(); - if (StringObject *thisString = t->asStringObject()) - return thisString->d()->value.stringValue()->toQString(); + if (StringObject *thisString = t->as<StringObject>()) + return thisString->d()->string->toQString(); if (t->isUndefined() || t->isNull()) { scope.engine->throwTypeError(); return QString(); @@ -234,10 +227,10 @@ ReturnedValue StringPrototype::method_toString(CallContext *context) if (context->thisObject().isString()) return context->thisObject().asReturnedValue(); - StringObject *o = context->thisObject().asStringObject(); + StringObject *o = context->thisObject().as<StringObject>(); if (!o) return context->engine()->throwTypeError(); - return o->d()->value.asReturnedValue(); + return Encode(o->d()->string); } ReturnedValue StringPrototype::method_charAt(CallContext *context) @@ -368,7 +361,7 @@ ReturnedValue StringPrototype::method_match(CallContext *context) if (!rx) { ScopedCallData callData(scope, 1); callData->args[0] = regexp; - rx = context->d()->engine->regExpCtor.asFunctionObject()->construct(callData); + rx = context->d()->engine->regExpCtor()->construct(callData); } if (!rx) @@ -379,7 +372,7 @@ ReturnedValue StringPrototype::method_match(CallContext *context) // ### use the standard builtin function, not the one that might be redefined in the proto ScopedString execString(scope, scope.engine->newString(QStringLiteral("exec"))); - ScopedFunctionObject exec(scope, scope.engine->regExpPrototype.asObject()->get(execString)); + ScopedFunctionObject exec(scope, scope.engine->regExpPrototype()->get(execString)); ScopedCallData callData(scope, 1); callData->thisObject = rx; @@ -470,8 +463,8 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) { Scope scope(ctx); QString string; - if (StringObject *thisString = ctx->thisObject().asStringObject()) - string = thisString->d()->value.stringValue()->toQString(); + if (StringObject *thisString = ctx->thisObject().as<StringObject>()) + string = thisString->d()->string->toQString(); else string = ctx->thisObject().toQString(); @@ -481,12 +474,12 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) uint allocatedMatchOffsets = 64; uint _matchOffsets[64]; uint *matchOffsets = _matchOffsets; - uint nMatchOffsets = 0; ScopedValue searchValue(scope, ctx->argument(0)); Scoped<RegExpObject> regExp(scope, searchValue); if (regExp) { uint offset = 0; + uint nMatchOffsets = 0; // We extract the pointer here to work around a compiler bug on Android. Scoped<RegExp> re(scope, regExp->value()); @@ -510,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 { @@ -519,7 +512,6 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) int idx = string.indexOf(searchString); if (idx != -1) { numStringMatches = 1; - nMatchOffsets = 2; matchOffsets[0] = idx; matchOffsets[1] = idx + searchString.length(); } @@ -593,7 +585,7 @@ ReturnedValue StringPrototype::method_search(CallContext *ctx) if (!regExp) { ScopedCallData callData(scope, 1); callData->args[0] = regExpValue; - regExpValue = ctx->d()->engine->regExpCtor.asFunctionObject()->construct(callData); + regExpValue = ctx->d()->engine->regExpCtor()->construct(callData); if (scope.engine->hasException) return Encode::undefined(); regExp = regExpValue->as<RegExpObject>(); diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index 459dc1322e..7d4f78d3c5 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -33,6 +33,17 @@ #ifndef QV4STRINGOBJECT_P_H #define QV4STRINGOBJECT_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" #include <QtCore/qnumeric.h> @@ -44,13 +55,16 @@ namespace QV4 { namespace Heap { struct StringObject : Object { - StringObject(InternalClass *ic, QV4::Object *prototype); - StringObject(ExecutionEngine *engine, const Value &value); - Value value; + enum { + LengthPropertyIndex = 0 + }; + + StringObject(); + StringObject(const QV4::String *string); + String *string; - Property *getIndex(uint index) const; - // ### get rid of tmpProperty - mutable Property tmpProperty; + Heap::String *getIndex(uint index) const; + uint length() const; }; struct StringCtor : FunctionObject { @@ -62,15 +76,20 @@ struct StringCtor : FunctionObject { struct StringObject: Object { V4_OBJECT2(StringObject, Object) Q_MANAGED_TYPE(StringObject) + V4_INTERNALCLASS(stringClass) + V4_PROTOTYPE(stringPrototype) - Property *getIndex(uint index) const { + Heap::String *getIndex(uint index) const { return d()->getIndex(index); } + uint length() const { + return d()->length(); + } static bool deleteIndexedProperty(Managed *m, uint index); protected: - static void advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attrs); + static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; @@ -78,8 +97,8 @@ struct StringCtor: FunctionObject { V4_OBJECT2(StringCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct StringPrototype: StringObject diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 19e541dba8..b45bbb713c 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -32,6 +32,7 @@ ****************************************************************************/ #include "qv4typedarray_p.h" #include "qv4arraybuffer_p.h" +#include "qv4string_p.h" #include <cmath> @@ -201,10 +202,10 @@ Heap::TypedArrayCtor::TypedArrayCtor(QV4::ExecutionContext *scope, TypedArray::T { } -ReturnedValue TypedArrayCtor::construct(Managed *m, CallData *callData) +ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<Object *>(m)->engine()); - Scoped<TypedArrayCtor> that(scope, static_cast<TypedArrayCtor *>(m)); + Scope scope(static_cast<const Object *>(m)->engine()); + Scoped<TypedArrayCtor> that(scope, static_cast<const TypedArrayCtor *>(m)); if (!callData->argc || !callData->args[0].isObject()) { // ECMA 6 22.2.1.1 @@ -215,11 +216,11 @@ ReturnedValue TypedArrayCtor::construct(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; @@ -235,11 +236,11 @@ ReturnedValue TypedArrayCtor::construct(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; @@ -257,7 +258,7 @@ ReturnedValue TypedArrayCtor::construct(Managed *m, CallData *callData) TypedArrayWrite write =array->d()->type->write; for (uint i = 0; i < l; ++i) { Primitive val; - val.val = read(src, i*srcElementSize); + val.setRawValue(read(src, i*srcElementSize)); write(scope.engine, dest, i*destElementSize, val); } } @@ -289,7 +290,7 @@ ReturnedValue TypedArrayCtor::construct(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; @@ -299,16 +300,16 @@ ReturnedValue TypedArrayCtor::construct(Managed *m, CallData *callData) // ECMA 6 22.2.1.3 ScopedObject o(scope, callData->argument(0)); - uint l = (uint) qBound(0., ScopedValue(scope, o->get(scope.engine->id_length))->toInteger(), (double)UINT_MAX); + uint l = (uint) qBound(0., ScopedValue(scope, o->get(scope.engine->id_length()))->toInteger(), (double)UINT_MAX); if (scope.engine->hasException) 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; @@ -329,28 +330,32 @@ ReturnedValue TypedArrayCtor::construct(Managed *m, CallData *callData) return array.asReturnedValue(); } -ReturnedValue TypedArrayCtor::call(Managed *that, CallData *callData) +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].asObject()), - 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); Object::markObjects(that, e); } -ReturnedValue TypedArray::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProperty) { - Scope scope(static_cast<Object *>(m)->engine()); - Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m)); + Scope scope(static_cast<const Object *>(m)->engine()); + Scoped<TypedArray> a(scope, static_cast<const TypedArray *>(m)); uint bytesPerElement = a->d()->type->bytesPerElement; uint byteOffset = a->d()->byteOffset + index * bytesPerElement; @@ -382,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(); } @@ -390,10 +395,10 @@ void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(3)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(3)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); ctor->defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Primitive::fromInt32(operations[ctor->d()->type].bytesPerElement)); - defineDefaultProperty(engine->id_constructor, (o = ctor)); + defineDefaultProperty(engine->id_constructor(), (o = ctor)); defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0); defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); @@ -470,7 +475,7 @@ ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx) if (scope.engine->hasException || !o) return scope.engine->throwTypeError(); - double len = ScopedValue(scope, o->get(scope.engine->id_length))->toNumber(); + double len = ScopedValue(scope, o->get(scope.engine->id_length()))->toNumber(); uint l = (uint)len; if (scope.engine->hasException || l != len) return scope.engine->throwTypeError(); @@ -523,7 +528,7 @@ ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx) TypedArrayWrite write = a->d()->type->write; for (uint i = 0; i < l; ++i) { Primitive val; - val.val = read(src, i*srcElementSize); + val.setRawValue(read(src, i*srcElementSize)); write(scope.engine, dest, i*elementSize, val); } @@ -563,7 +568,7 @@ ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx) int newLen = end - begin; - ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor)); + ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor())); if (!constructor) return scope.engine->throwTypeError(); diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index afd1bb97e7..67e04c8ac0 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -33,6 +33,17 @@ #ifndef QV4TYPEDARRAY_H #define QV4TYPEDARRAY_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" #include "qv4arraybuffer_p.h" @@ -69,10 +80,10 @@ struct TypedArray : Object { NTypes }; - TypedArray(ExecutionEngine *e, Type t); + TypedArray(Type t); const TypedArrayOperations *type; - ArrayBuffer *buffer; + Pointer<ArrayBuffer> buffer; uint byteLength; uint byteOffset; Type arrayType; @@ -85,7 +96,7 @@ struct TypedArrayCtor : FunctionObject { }; struct TypedArrayPrototype : Object { - inline TypedArrayPrototype(ExecutionEngine *e, TypedArray::Type t); + inline TypedArrayPrototype(TypedArray::Type t); TypedArray::Type type; }; @@ -96,6 +107,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; } @@ -113,7 +126,7 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object } static void markObjects(Heap::Base *that, ExecutionEngine *e); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static void putIndexed(Managed *m, uint index, const Value &value); }; @@ -121,8 +134,8 @@ struct TypedArrayCtor: FunctionObject { V4_OBJECT2(TypedArrayCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; @@ -142,9 +155,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/qv4util_p.h b/src/qml/jsruntime/qv4util_p.h index f9ae37855e..329831f134 100644 --- a/src/qml/jsruntime/qv4util_p.h +++ b/src/qml/jsruntime/qv4util_p.h @@ -33,6 +33,17 @@ #ifndef QV4UTIL_H #define QV4UTIL_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4global_p.h" QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index 68228f06bb..4c81199a07 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -32,10 +32,11 @@ ****************************************************************************/ #include <qv4engine_p.h> #include <qv4runtime_p.h> +#include <qv4string_p.h> #ifndef V4_BOOTSTRAP #include <qv4object_p.h> #include <qv4objectproto_p.h> -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #endif #include <wtf/MathExtras.h> @@ -68,10 +69,32 @@ int Value::toUInt16() const return (unsigned short)number; } +bool Value::toBoolean() const +{ + switch (type()) { + case Value::Undefined_Type: + case Value::Null_Type: + return false; + case Value::Boolean_Type: + case Value::Integer_Type: + return (bool)int_32(); + case Value::Managed_Type: +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); +#else + if (isString()) + return stringValue()->toQString().length() > 0; +#endif + return true; + default: // double + return doubleValue() && !std::isnan(doubleValue()); + } +} + double Value::toInteger() const { if (integerCompatible()) - return int_32; + return int_32(); return Primitive::toInteger(toNumber()); } @@ -87,10 +110,10 @@ double Value::toNumberImpl() const #else if (isString()) return RuntimeHelpers::stringToNumber(stringValue()->toQString()); - { - Q_ASSERT(isObject()); - Scope scope(objectValue()->engine()); - ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, NUMBER_HINT)); + { + Q_ASSERT(isObject()); + Scope scope(objectValue()->engine()); + ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, NUMBER_HINT)); if (scope.engine->hasException) return 0; return prim->toNumber(); @@ -99,7 +122,7 @@ double Value::toNumberImpl() const case QV4::Value::Null_Type: case QV4::Value::Boolean_Type: case QV4::Value::Integer_Type: - return int_32; + return int_32(); default: // double Q_UNREACHABLE(); } @@ -148,7 +171,7 @@ QString Value::toQStringNoThrow() const } case Value::Integer_Type: { QString str; - RuntimeHelpers::numberToString(&str, (double)int_32, 10); + RuntimeHelpers::numberToString(&str, (double)int_32(), 10); return str; } default: { // double @@ -184,7 +207,7 @@ QString Value::toQString() const } case Value::Integer_Type: { QString str; - RuntimeHelpers::numberToString(&str, (double)int_32, 10); + RuntimeHelpers::numberToString(&str, (double)int_32(), 10); return str; } default: { // double @@ -197,14 +220,14 @@ QString Value::toQString() const #endif // V4_BOOTSTRAP bool Value::sameValue(Value other) const { - if (val == other.val) + if (_val == other._val) return true; if (isString() && other.isString()) return stringValue()->isEqualTo(other.stringValue()); if (isInteger() && other.isDouble()) - return int_32 ? (double(int_32) == other.doubleValue()) : (other.val == 0); + return int_32() ? (double(int_32()) == other.doubleValue()) : (other._val == 0); if (isDouble() && other.isInteger()) - return other.int_32 ? (doubleValue() == double(other.int_32)) : (val == 0); + return other.int_32() ? (doubleValue() == double(other.int_32())) : (_val == 0); return false; } @@ -281,4 +304,35 @@ Heap::Object *Value::toObject(ExecutionEngine *e) const return RuntimeHelpers::convertToObject(e, *this); } +uint Value::asArrayLength(bool *ok) const +{ + *ok = true; + if (isInteger()) { + if (int_32() >= 0) { + return (uint)int_32(); + } else { + *ok = false; + return UINT_MAX; + } + } + if (isNumber()) { + double d = doubleValue(); + uint idx = (uint)d; + if (idx != d) { + *ok = false; + return UINT_MAX; + } + return idx; + } + if (isString()) + return stringValue()->toUInt(ok); + + uint idx = toUInt32(); + double d = toNumber(); + if (d != idx) { + *ok = false; + return UINT_MAX; + } + return idx; +} #endif // V4_BOOTSTRAP diff --git a/src/qml/jsruntime/qv4value_inl_p.h b/src/qml/jsruntime/qv4value_inl_p.h deleted file mode 100644 index f3026900d6..0000000000 --- a/src/qml/jsruntime/qv4value_inl_p.h +++ /dev/null @@ -1,293 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QV4VALUE_INL_H -#define QV4VALUE_INL_H - -#include <cmath> // this HAS to come - -#include "qv4value_p.h" - -#include "qv4string_p.h" -#include "qv4managed_p.h" -#include "qv4engine_p.h" - -QT_BEGIN_NAMESPACE - -namespace QV4 { - -inline bool Value::isString() const -{ - if (!isManaged()) - return false; - return m && m->vtable->isString; -} -inline bool Value::isObject() const -{ - if (!isManaged()) - return false; - return m && m->vtable->isObject; -} - -inline bool Value::isPrimitive() const -{ - return !isObject(); -} - -inline String *Value::asString() const -{ - if (isString()) - return stringValue(); - return 0; -} - -inline void Value::mark(ExecutionEngine *e) const -{ - if (!val) - return; - Managed *m = asManaged(); - if (m) - m->mark(e); -} - -inline Primitive Primitive::nullValue() -{ - Primitive v; -#ifdef QV4_USE_64_BIT_VALUE_ENCODING - v.val = quint64(_Null_Type) << Tag_Shift; -#else - v.tag = _Null_Type; - v.int_32 = 0; -#endif - return v; -} - -inline Primitive Primitive::fromBoolean(bool b) -{ - Primitive v; - v.tag = _Boolean_Type; - v.int_32 = (bool)b; - return v; -} - -inline Primitive Primitive::fromDouble(double d) -{ - Primitive v; - v.setDouble(d); - return v; -} - -inline Primitive Primitive::fromInt32(int i) -{ - Primitive v; - v.tag = _Integer_Type; - v.int_32 = i; - return v; -} - -inline Primitive Primitive::fromUInt32(uint i) -{ - Primitive v; - if (i < INT_MAX) { - v.tag = _Integer_Type; - v.int_32 = (int)i; - } else { - v.setDouble(i); - } - return v; -} - -inline double Value::toNumber() const -{ - if (isInteger()) - return int_32; - if (isDouble()) - return doubleValue(); - return toNumberImpl(); -} - -inline int Value::toInt32() const -{ - if (isInteger()) - return int_32; - double d = isNumber() ? doubleValue() : toNumberImpl(); - - const double D32 = 4294967296.0; - const double D31 = D32 / 2.0; - - if ((d >= -D31 && d < D31)) - return static_cast<int>(d); - - return Primitive::toInt32(d); -} - -inline unsigned int Value::toUInt32() const -{ - return (unsigned int)toInt32(); -} - - -inline bool Value::toBoolean() const -{ - switch (type()) { - case Value::Undefined_Type: - case Value::Null_Type: - return false; - case Value::Boolean_Type: - case Value::Integer_Type: - return (bool)int_32; - case Value::Managed_Type: -#ifdef V4_BOOTSTRAP - Q_UNIMPLEMENTED(); -#else - if (isString()) - return stringValue()->toQString().length() > 0; -#endif - return true; - default: // double - return doubleValue() && !std::isnan(doubleValue()); - } -} - -#ifndef V4_BOOTSTRAP -inline uint Value::asArrayIndex() const -{ -#ifdef QV4_USE_64_BIT_VALUE_ENCODING - if (!isNumber()) - return UINT_MAX; - if (isInteger()) - return int_32 >= 0 ? (uint)int_32 : UINT_MAX; -#else - if (isInteger() && int_32 >= 0) - return (uint)int_32; - if (!isDouble()) - return UINT_MAX; -#endif - double d = doubleValue(); - uint idx = (uint)d; - if (idx != d) - return UINT_MAX; - return idx; -} - -inline uint Value::asArrayLength(bool *ok) const -{ - *ok = true; - if (isInteger()) { - if (int_32 >= 0) { - return (uint)int_32; - } else { - *ok = false; - return UINT_MAX; - } - } - if (isNumber()) { - double d = doubleValue(); - uint idx = (uint)d; - if (idx != d) { - *ok = false; - return UINT_MAX; - } - return idx; - } - if (isString()) - return stringValue()->toUInt(ok); - - uint idx = toUInt32(); - double d = toNumber(); - if (d != idx) { - *ok = false; - return UINT_MAX; - } - return idx; -} - -inline Object *Value::asObject() const -{ - return isObject() ? objectValue() : 0; -} - -inline FunctionObject *Value::asFunctionObject() const -{ - return isObject() ? managed()->asFunctionObject() : 0; -} - -inline NumberObject *Value::asNumberObject() const -{ - return isObject() ? managed()->asNumberObject() : 0; -} - -inline StringObject *Value::asStringObject() const -{ - return isObject() ? managed()->asStringObject() : 0; -} - -inline DateObject *Value::asDateObject() const -{ - return isObject() ? managed()->asDateObject() : 0; -} - -inline ArrayObject *Value::asArrayObject() const -{ - return isObject() ? managed()->asArrayObject() : 0; -} - -inline ErrorObject *Value::asErrorObject() const -{ - return isObject() ? managed()->asErrorObject() : 0; -} - -template<typename T> -inline T *Value::as() const { Managed *m = isObject() ? managed() : 0; return m ? m->as<T>() : 0; } - -#ifndef V4_BOOTSTRAP - -template<> -inline String *value_cast(const Value &v) { - return v.asString(); -} - -template<> -inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v) -{ - return v.toString(e)->asReturnedValue(); -} - -#endif - -#endif - -} // namespace QV4 - -QT_END_NAMESPACE - -#endif diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 628950784a..089b2bbd34 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -33,10 +33,22 @@ #ifndef QV4VALUE_P_H #define QV4VALUE_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <limits.h> #include <QtCore/QString> #include "qv4global_p.h" +#include <private/qv4heap_p.h> /* We cannot rely on QT_POINTER_SIZE to be set correctly on host builds. In qmldevtools the Value objects are only used to store primitives, never object pointers. So we can use the 64-bit encoding. */ @@ -50,56 +62,12 @@ QT_BEGIN_NAMESPACE namespace QV4 { -typedef uint Bool; - namespace Heap { - -struct Q_QML_EXPORT Base { - union { - const ManagedVTable *vtable; - quintptr mm_data; - }; - - inline ReturnedValue asReturnedValue() const; - inline void mark(QV4::ExecutionEngine *engine); - - enum { - MarkBit = 0x1, - NotInUse = 0x2, - PointerMask = ~0x3 - }; - - ManagedVTable *gcGetVtable() const { - return reinterpret_cast<ManagedVTable *>(mm_data & PointerMask); - } - inline bool isMarked() const { - return mm_data & MarkBit; - } - inline void setMarkBit() { - mm_data |= MarkBit; - } - inline void clearMarkBit() { - mm_data &= ~MarkBit; - } - - inline bool inUse() const { - return !(mm_data & NotInUse); - } - - Base *nextFree() { - return reinterpret_cast<Base *>(mm_data & PointerMask); - } - void setNextFree(Base *m) { - mm_data = (reinterpret_cast<quintptr>(m) | NotInUse); - } - - void *operator new(size_t, Managed *m) { return m; } - void *operator new(size_t, Heap::Base *m) { return m; } - void operator delete(void *, Heap::Base *) {} -}; - + struct Base; } +typedef uint Bool; + struct Q_QML_PRIVATE_EXPORT Value { /* @@ -124,30 +92,38 @@ struct Q_QML_PRIVATE_EXPORT Value Bit 15-17 is then used to encode other immediates. */ + quint64 _val; + + Q_ALWAYS_INLINE quint64 val() const { return _val; } + Q_ALWAYS_INLINE void setVal(quint64 v) { _val = v; } + Q_ALWAYS_INLINE void setValue(quint32 v) { memcpy(&_val, &v, 4); } + Q_ALWAYS_INLINE void setTag(quint32 t) { memcpy(4 + (quint8 *)&_val, &t, 4); } - union { - quint64 val; -#ifdef QV4_USE_64_BIT_VALUE_ENCODING - Heap::Base *m; -#else - double dbl; -#endif - struct { -#if Q_BYTE_ORDER != Q_LITTLE_ENDIAN - uint tag; -#endif - union { - uint uint_32; - int int_32; -#ifndef QV4_USE_64_BIT_VALUE_ENCODING - Heap::Base *m; -#endif - }; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - uint tag; + static inline int valueOffset() { return 0; } + static inline int tagOffset() { return 4; } + Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; } + Q_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); } + Q_ALWAYS_INLINE quint32 tag() const { return _val >> 32; } +#else // !Q_LITTLE_ENDIAN + static inline int valueOffset() { return 4; } + static inline int tagOffset() { return 0; } + Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(value) << 32 | tag; } + Q_ALWAYS_INLINE quint32 tag() const { return _val & quint64(~quint32(0)); } + Q_ALWAYS_INLINE quint32 value() const { return _val >> 32; } +#endif + +#ifdef QV4_USE_64_BIT_VALUE_ENCODING + Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; memcpy(&b, &_val, 8); return b; } + Q_ALWAYS_INLINE void setM(Heap::Base *b) { memcpy(&_val, &b, 8); } +#else // !QV4_USE_64_BIT_VALUE_ENCODING + Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; quint32 v = value(); memcpy(&b, &v, 4); return b; } + Q_ALWAYS_INLINE void setM(Heap::Base *b) { quint32 v; memcpy(&v, &b, 4); setValue(v); } #endif - }; - }; + + Q_ALWAYS_INLINE int int_32() const { int i; quint32 v = value(); memcpy(&i, &v, 4); return i; } + Q_ALWAYS_INLINE void setInt_32(int i) { quint32 u; memcpy(&u, &i, 4); setValue(u); } + Q_ALWAYS_INLINE uint uint_32() const { return value(); } #ifndef QV4_USE_64_BIT_VALUE_ENCODING enum Masks { @@ -173,9 +149,9 @@ struct Q_QML_PRIVATE_EXPORT Value }; enum ValueTypeInternal { - _Null_Type = Null_Type | ConvertibleToInt, - _Boolean_Type = Boolean_Type | ConvertibleToInt, - _Integer_Type = Integer_Type | ConvertibleToInt, + Null_Type_Internal = Null_Type | ConvertibleToInt, + Boolean_Type_Internal = Boolean_Type | ConvertibleToInt, + Integer_Type_Internal = Integer_Type | ConvertibleToInt, }; #else @@ -213,134 +189,134 @@ struct Q_QML_PRIVATE_EXPORT Value enum ValueTypeInternal { - _Null_Type = Null_Type, - _Boolean_Type = Boolean_Type, - _Integer_Type = Integer_Type + Null_Type_Internal = Null_Type, + Boolean_Type_Internal = Boolean_Type, + Integer_Type_Internal = Integer_Type }; #endif inline unsigned type() const { - return tag & Type_Mask; + return tag() & Type_Mask; } // used internally in property - inline bool isEmpty() const { return tag == Empty_Type; } + inline bool isEmpty() const { return tag() == Empty_Type; } - inline bool isUndefined() const { return tag == Undefined_Type; } - inline bool isNull() const { return tag == _Null_Type; } - inline bool isBoolean() const { return tag == _Boolean_Type; } + inline bool isUndefined() const { return tag() == Undefined_Type; } + inline bool isNull() const { return tag() == Null_Type_Internal; } + inline bool isBoolean() const { return tag ()== Boolean_Type_Internal; } #ifdef QV4_USE_64_BIT_VALUE_ENCODING - inline bool isInteger() const { return (val >> IsNumber_Shift) == 1; } - inline bool isDouble() const { return (val >> IsDouble_Shift); } - inline bool isNumber() const { return (val >> IsNumber_Shift); } - inline bool isManaged() const { return !(val >> IsManaged_Shift); } - inline bool isNullOrUndefined() const { return ((val >> IsManaged_Shift) & ~2) == 1; } - inline bool integerCompatible() const { return ((val >> IsConvertibleToInt_Shift) & ~2) == 1; } + inline bool isInteger() const { return (_val >> IsNumber_Shift) == 1; } + inline bool isDouble() const { return (_val >> IsDouble_Shift); } + inline bool isNumber() const { return (_val >> IsNumber_Shift); } + inline bool isManaged() const { return !(_val >> IsManaged_Shift); } + inline bool isNullOrUndefined() const { return ((_val >> IsManaged_Shift) & ~2) == 1; } + inline bool integerCompatible() const { return ((_val >> IsConvertibleToInt_Shift) & ~2) == 1; } static inline bool integerCompatible(Value a, Value b) { return a.integerCompatible() && b.integerCompatible(); } static inline bool bothDouble(Value a, Value b) { return a.isDouble() && b.isDouble(); } - double doubleValue() const { - Q_ASSERT(isDouble()); - union { - quint64 i; - double d; - } v; - v.i = val ^ NaNEncodeMask; - return v.d; - } - void setDouble(double d) { - union { - quint64 i; - double d; - } v; - v.d = d; - val = v.i ^ NaNEncodeMask; - Q_ASSERT(isDouble()); - } - inline bool isNaN() const { return (tag & 0x7fff8000) == 0x00078000; } + inline bool isNaN() const { return (tag() & 0x7fff8000) == 0x00078000; } #else - inline bool isInteger() const { return tag == _Integer_Type; } - inline bool isDouble() const { return (tag & NotDouble_Mask) != NotDouble_Mask; } - inline bool isNumber() const { return tag == _Integer_Type || (tag & NotDouble_Mask) != NotDouble_Mask; } - inline bool isManaged() const { return tag == Managed_Type; } - inline bool isNullOrUndefined() const { return (tag & IsNullOrUndefined_Mask) == Undefined_Type; } - inline bool integerCompatible() const { return (tag & ConvertibleToInt) == ConvertibleToInt; } + inline bool isInteger() const { return tag() == Integer_Type_Internal; } + inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; } + inline bool isNumber() const { return tag() == Integer_Type_Internal || (tag() & NotDouble_Mask) != NotDouble_Mask; } + inline bool isManaged() const { return tag() == Managed_Type; } + inline bool isNullOrUndefined() const { return (tag() & IsNullOrUndefined_Mask) == Undefined_Type; } + inline bool integerCompatible() const { return (tag() & ConvertibleToInt) == ConvertibleToInt; } static inline bool integerCompatible(Value a, Value b) { - return ((a.tag & b.tag) & ConvertibleToInt) == ConvertibleToInt; + return ((a.tag() & b.tag()) & ConvertibleToInt) == ConvertibleToInt; } static inline bool bothDouble(Value a, Value b) { - return ((a.tag | b.tag) & NotDouble_Mask) != NotDouble_Mask; + return ((a.tag() | b.tag()) & NotDouble_Mask) != NotDouble_Mask; } - double doubleValue() const { Q_ASSERT(isDouble()); return dbl; } - void setDouble(double d) { dbl = d; Q_ASSERT(isDouble()); } - inline bool isNaN() const { return (tag & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; } + inline bool isNaN() const { return (tag() & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; } #endif + Q_ALWAYS_INLINE double doubleValue() const { + Q_ASSERT(isDouble()); + double d; + quint64 v = _val; +#ifdef QV4_USE_64_BIT_VALUE_ENCODING + v ^= NaNEncodeMask; +#endif + memcpy(&d, &v, 8); + return d; + } + Q_ALWAYS_INLINE void setDouble(double d) { + memcpy(&_val, &d, 8); +#ifdef QV4_USE_64_BIT_VALUE_ENCODING + _val ^= NaNEncodeMask; +#endif + Q_ASSERT(isDouble()); + } inline bool isString() const; inline bool isObject() const; inline bool isInt32() { - if (tag == _Integer_Type) + if (tag() == Integer_Type_Internal) return true; if (isDouble()) { double d = doubleValue(); int i = (int)d; if (i == d) { - int_32 = i; - tag = _Integer_Type; + setInt_32(i); + setTag(Integer_Type_Internal); return true; } } return false; } double asDouble() const { - if (tag == _Integer_Type) - return int_32; + if (tag() == Integer_Type_Internal) + return int_32(); return doubleValue(); } bool booleanValue() const { - return int_32; + return int_32(); } int integerValue() const { - return int_32; + return int_32(); } - String *stringValue() const { - return m ? reinterpret_cast<String*>(const_cast<Value *>(this)) : 0; + Q_ALWAYS_INLINE String *stringValue() const { + return m() ? reinterpret_cast<String*>(const_cast<Value *>(this)) : 0; } - Object *objectValue() const { - return m ? reinterpret_cast<Object*>(const_cast<Value *>(this)) : 0; + Q_ALWAYS_INLINE Object *objectValue() const { + return m() ? reinterpret_cast<Object*>(const_cast<Value *>(this)) : 0; } - Managed *managed() const { - return m ? reinterpret_cast<Managed*>(const_cast<Value *>(this)) : 0; + Q_ALWAYS_INLINE Managed *managed() const { + return m() ? reinterpret_cast<Managed*>(const_cast<Value *>(this)) : 0; } - Heap::Base *heapObject() const { - return m; + Q_ALWAYS_INLINE Heap::Base *heapObject() const { + return m(); } - quint64 rawValue() const { - return val; + Q_ALWAYS_INLINE quint64 &rawValueRef() { + return _val; + } + Q_ALWAYS_INLINE quint64 rawValue() const { + return _val; } + Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; } static inline Value fromHeapObject(Heap::Base *m) { Value v; - v.m = m; + v.setRawValue(0); + v.setM(m); #ifndef QV4_USE_64_BIT_VALUE_ENCODING - v.tag = Managed_Type; + v.setTag(Managed_Type); #endif return v; } - static inline Value fromManaged(Managed *m); - int toUInt16() const; inline int toInt32() const; inline unsigned int toUInt32() const; - inline bool toBoolean() const; + bool toBoolean() const; double toInteger() const; inline double toNumber() const; double toNumberImpl() const; @@ -353,21 +329,32 @@ struct Q_QML_PRIVATE_EXPORT Value inline bool tryIntegerConversion() { bool b = integerCompatible(); if (b) - tag = _Integer_Type; + setTag(Integer_Type_Internal); return b; } - inline String *asString() const; - inline Managed *asManaged() const; - inline Object *asObject() const; - inline FunctionObject *asFunctionObject() const; - inline NumberObject *asNumberObject() const; - inline StringObject *asStringObject() const; - inline DateObject *asDateObject() const; - inline ArrayObject *asArrayObject() const; - inline ErrorObject *asErrorObject() const; + template <typename T> + const T *as() const { + if (!m() || !isManaged()) + return 0; + + Q_ASSERT(m()->vtable()); +#if !defined(QT_NO_QOBJECT_CHECK) + static_cast<const T *>(this)->qt_check_for_QMANAGED_macro(static_cast<const T *>(this)); +#endif + const VTable *vt = m()->vtable(); + while (vt) { + if (vt == T::staticVTable()) + return static_cast<const T *>(this); + vt = vt->parent; + } + return 0; + } + template <typename T> + T *as() { + return const_cast<T *>(const_cast<const Value *>(this)->as<T>()); + } - template<typename T> inline T *as() const; template<typename T> inline T *cast() { return static_cast<T *>(managed()); } @@ -376,26 +363,32 @@ struct Q_QML_PRIVATE_EXPORT Value } inline uint asArrayIndex() const; - inline uint asArrayLength(bool *ok) const; +#ifndef V4_BOOTSTRAP + uint asArrayLength(bool *ok) const; +#endif - ReturnedValue asReturnedValue() const { return val; } - static Value fromReturnedValue(ReturnedValue val) { Value v; v.val = val; return v; } + ReturnedValue asReturnedValue() const { return _val; } + static Value fromReturnedValue(ReturnedValue val) { Value v; v._val = val; return v; } // Section 9.12 bool sameValue(Value other) const; - inline void mark(ExecutionEngine *e) const; + inline void mark(ExecutionEngine *e); Value &operator =(const ScopedValue &v); - Value &operator=(ReturnedValue v) { val = v; return *this; } + Value &operator=(ReturnedValue v) { _val = v; return *this; } Value &operator=(Managed *m) { - val = Value::fromManaged(m).val; + if (!m) { + setTagValue(Undefined_Type, 0); + } else { + _val = reinterpret_cast<Value *>(m)->_val; + } return *this; } Value &operator=(Heap::Base *o) { - m = o; + setM(o); #ifndef QV4_USE_64_BIT_VALUE_ENCODING - tag = Managed_Type; + setTag(Managed_Type); #endif return *this; } @@ -403,18 +396,69 @@ struct Q_QML_PRIVATE_EXPORT Value template<typename T> Value &operator=(const Scoped<T> &t); Value &operator=(const Value &v) { - val = v.val; + _val = v._val; return *this; } }; -inline Managed *Value::asManaged() const +inline bool Value::isString() const { - if (isManaged()) - return managed(); - return 0; + if (!isManaged()) + return false; + return m() && m()->vtable()->isString; +} +inline bool Value::isObject() const +{ + if (!isManaged()) + return false; + return m() && m()->vtable()->isObject; } +inline bool Value::isPrimitive() const +{ + return !isObject(); +} + +inline double Value::toNumber() const +{ + if (isInteger()) + return int_32(); + if (isDouble()) + return doubleValue(); + return toNumberImpl(); +} + + +#ifndef V4_BOOTSTRAP +inline uint Value::asArrayIndex() const +{ +#ifdef QV4_USE_64_BIT_VALUE_ENCODING + if (!isNumber()) + return UINT_MAX; + if (isInteger()) + return int_32() >= 0 ? (uint)int_32() : UINT_MAX; +#else + if (isInteger() && int_32() >= 0) + return (uint)int_32(); + if (!isDouble()) + return UINT_MAX; +#endif + double d = doubleValue(); + uint idx = (uint)d; + if (idx != d) + return UINT_MAX; + return idx; +} +#endif + +inline +ReturnedValue Heap::Base::asReturnedValue() const +{ + return Value::fromHeapObject(const_cast<Heap::Base *>(this)).asReturnedValue(); +} + + + struct Q_QML_PRIVATE_EXPORT Primitive : public Value { inline static Primitive emptyValue(); @@ -437,10 +481,11 @@ inline Primitive Primitive::undefinedValue() { Primitive v; #ifdef QV4_USE_64_BIT_VALUE_ENCODING - v.val = quint64(Undefined_Type) << Tag_Shift; + v.setRawValue(quint64(Undefined_Type) << Tag_Shift); #else - v.tag = Undefined_Type; - v.int_32 = 0; + v.setRawValue(0); + v.setTag(Undefined_Type); + v.setValue(0); #endif return v; } @@ -448,66 +493,81 @@ inline Primitive Primitive::undefinedValue() inline Primitive Primitive::emptyValue() { Primitive v; - v.tag = Value::Empty_Type; - v.uint_32 = 0; + v.setTagValue(Value::Empty_Type, 0); return v; } -template <typename T> -struct TypedValue : public Value +inline Primitive Primitive::nullValue() { - template<typename X> - TypedValue &operator =(X *x) { - m = x; + Primitive v; #ifndef QV4_USE_64_BIT_VALUE_ENCODING - tag = Managed_Type; + v.setRawValue(quint64(Null_Type_Internal) << Tag_Shift); +#else + v.setTagValue(Null_Type_Internal, 0); #endif - return *this; - } - TypedValue &operator =(T *t); - TypedValue &operator =(const Scoped<T> &v); -// TypedValue &operator =(const ManagedRef<T> &v); - - TypedValue &operator =(const TypedValue<T> &t); + return v; +} - bool operator!() const { return !managed(); } +inline Primitive Primitive::fromBoolean(bool b) +{ + Primitive v; + v.setTagValue(Boolean_Type_Internal, b); + return v; +} - operator T *() { return static_cast<T *>(managed()); } - T *operator->() { return static_cast<T *>(managed()); } - const T *operator->() const { return static_cast<T *>(managed()); } - T *getPointer() const { return static_cast<T *>(managed()); } +inline Primitive Primitive::fromDouble(double d) +{ + Primitive v; + v.setDouble(d); + return v; +} - void mark(ExecutionEngine *e) { if (managed()) managed()->mark(e); } -}; -typedef TypedValue<String> StringValue; +inline Primitive Primitive::fromInt32(int i) +{ + Primitive v; + v.setTagValue(Integer_Type_Internal, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors. + v.setInt_32(i); + return v; +} +inline Primitive Primitive::fromUInt32(uint i) +{ + Primitive v; + if (i < INT_MAX) { + v.setTagValue(Integer_Type_Internal, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors. + v.setInt_32((int)i); + } else { + v.setDouble(i); + } + return v; +} struct Encode { static ReturnedValue undefined() { return quint64(Value::Undefined_Type) << Value::Tag_Shift; } static ReturnedValue null() { - return quint64(Value::_Null_Type) << Value::Tag_Shift; + return quint64(Value::Null_Type_Internal) << Value::Tag_Shift; } Encode(bool b) { - val = (quint64(Value::_Boolean_Type) << Value::Tag_Shift) | (uint)b; + val = (quint64(Value::Boolean_Type_Internal) << Value::Tag_Shift) | (uint)b; } Encode(double d) { Value v; v.setDouble(d); - val = v.val; + val = v.rawValue(); } Encode(int i) { - val = (quint64(Value::_Integer_Type) << Value::Tag_Shift) | (uint)i; + val = (quint64(Value::Integer_Type_Internal) << Value::Tag_Shift) | (uint)i; } Encode(uint i) { if (i <= INT_MAX) { - val = (quint64(Value::_Integer_Type) << Value::Tag_Shift) | i; + val = (quint64(Value::Integer_Type_Internal) << Value::Tag_Shift) | i; } else { Value v; v.setDouble(i); - val = v.val; + val = v.rawValue(); } } Encode(ReturnedValue v) { @@ -527,21 +587,29 @@ private: Encode(void *); }; -inline -ReturnedValue Heap::Base::asReturnedValue() const +template<typename T> +ReturnedValue value_convert(ExecutionEngine *e, const Value &v); + +inline int Value::toInt32() const { - return Value::fromHeapObject(const_cast<Heap::Base *>(this)).asReturnedValue(); -} + if (isInteger()) + return int_32(); + double d = isNumber() ? doubleValue() : toNumberImpl(); + const double D32 = 4294967296.0; + const double D31 = D32 / 2.0; -template<typename T> -T *value_cast(const Value &v) + if ((d >= -D31 && d < D31)) + return static_cast<int>(d); + + return Primitive::toInt32(d); +} + +inline unsigned int Value::toUInt32() const { - return v.as<T>(); + return (unsigned int)toInt32(); } -template<typename T> -ReturnedValue value_convert(ExecutionEngine *e, const Value &v); } diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index 966f83acef..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.asObject()) +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 @@ -96,8 +99,8 @@ void VariantPrototype::init() { defineDefaultProperty(QStringLiteral("preserve"), method_preserve, 0); defineDefaultProperty(QStringLiteral("destroy"), method_destroy, 0); - defineDefaultProperty(engine()->id_valueOf, method_valueOf, 0); - defineDefaultProperty(engine()->id_toString, method_toString, 0); + defineDefaultProperty(engine()->id_valueOf(), method_valueOf, 0); + defineDefaultProperty(engine()->id_toString(), method_toString, 0); } QV4::ReturnedValue VariantPrototype::method_preserve(CallContext *ctx) @@ -129,7 +132,7 @@ QV4::ReturnedValue VariantPrototype::method_toString(CallContext *ctx) return Encode::undefined(); QString result = o->d()->data.toString(); if (result.isEmpty() && !o->d()->data.canConvert(QVariant::String)) - result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(o->d()->data.typeName())); + result = QStringLiteral("QVariant(%0)").arg(QString::fromLatin1(o->d()->data.typeName())); return Encode(ctx->d()->engine->newString(result)); } diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h index 2b48412c4d..4680912354 100644 --- a/src/qml/jsruntime/qv4variantobject_p.h +++ b/src/qml/jsruntime/qv4variantobject_p.h @@ -49,7 +49,7 @@ #include <QtQml/qqmllist.h> #include <QtCore/qvariant.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> QT_BEGIN_NAMESPACE @@ -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 390bbf5ee3..024a72bde2 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -37,13 +37,14 @@ #include <QtCore/qjsondocument.h> #include <QtCore/qjsonobject.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4debugging_p.h> #include <private/qv4function_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4math_p.h> #include <private/qv4scopedvalue_p.h> #include <private/qv4lookup_p.h> +#include <private/qv4string_p.h> #include <iostream> #include "qv4alloca_p.h" @@ -374,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); @@ -512,6 +513,28 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code STOREVALUE(instr.result, Runtime::getQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); MOTH_END_INSTR(LoadQObjectProperty) + MOTH_BEGIN_INSTR(StoreScopeObjectProperty) + Runtime::setQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); + CHECK_EXCEPTION; + MOTH_END_INSTR(StoreScopeObjectProperty) + + MOTH_BEGIN_INSTR(LoadScopeObjectProperty) + STOREVALUE(instr.result, Runtime::getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex)); + MOTH_END_INSTR(LoadScopeObjectProperty) + + MOTH_BEGIN_INSTR(StoreContextObjectProperty) + Runtime::setQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); + CHECK_EXCEPTION; + MOTH_END_INSTR(StoreContextObjectProperty) + + MOTH_BEGIN_INSTR(LoadContextObjectProperty) + STOREVALUE(instr.result, Runtime::getQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex)); + MOTH_END_INSTR(LoadContextObjectProperty) + + MOTH_BEGIN_INSTR(LoadIdObject) + STOREVALUE(instr.result, Runtime::getQmlIdObject(engine, VALUE(instr.base), instr.index)); + MOTH_END_INSTR(LoadIdObject) + MOTH_BEGIN_INSTR(LoadAttachedQObjectProperty) STOREVALUE(instr.result, Runtime::getQmlAttachedProperty(engine, instr.attachedPropertiesId, instr.propertyIndex)); MOTH_END_INSTR(LoadAttachedQObjectProperty) @@ -565,6 +588,26 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code STOREVALUE(instr.result, Runtime::callPropertyLookup(engine, instr.lookupIndex, callData)); MOTH_END_INSTR(CallPropertyLookup) + MOTH_BEGIN_INSTR(CallScopeObjectProperty) + TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); + callData->tag = QV4::Value::Integer_Type; + callData->argc = instr.argc; + callData->thisObject = VALUE(instr.base); + STOREVALUE(instr.result, Runtime::callQmlScopeObjectProperty(engine, instr.index, callData)); + MOTH_END_INSTR(CallScopeObjectProperty) + + MOTH_BEGIN_INSTR(CallContextObjectProperty) + TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); + callData->tag = QV4::Value::Integer_Type; + callData->argc = instr.argc; + callData->thisObject = VALUE(instr.base); + STOREVALUE(instr.result, Runtime::callQmlContextObjectProperty(engine, instr.index, callData)); + MOTH_END_INSTR(CallContextObjectProperty) + MOTH_BEGIN_INSTR(CallElement) Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); @@ -607,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) @@ -641,6 +684,14 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code STOREVALUE(instr.result, Runtime::deleteName(engine, instr.name)); MOTH_END_INSTR(CallBuiltinDeleteName) + MOTH_BEGIN_INSTR(CallBuiltinTypeofScopeObjectProperty) + STOREVALUE(instr.result, Runtime::typeofScopeObjectProperty(engine, VALUE(instr.base), instr.index)); + MOTH_END_INSTR(CallBuiltinTypeofMember) + + MOTH_BEGIN_INSTR(CallBuiltinTypeofContextObjectProperty) + STOREVALUE(instr.result, Runtime::typeofContextObjectProperty(engine, VALUE(instr.base), instr.index)); + MOTH_END_INSTR(CallBuiltinTypeofMember) + MOTH_BEGIN_INSTR(CallBuiltinTypeofMember) STOREVALUE(instr.result, Runtime::typeofMember(engine, VALUE(instr.base), instr.member)); MOTH_END_INSTR(CallBuiltinTypeofMember) @@ -846,7 +897,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(); @@ -855,31 +906,23 @@ 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(Debug) + MOTH_END_INSTR(Line) MOTH_BEGIN_INSTR(LoadThis) VALUE(instr.result) = context->thisObject(); MOTH_END_INSTR(LoadThis) - MOTH_BEGIN_INSTR(LoadQmlIdArray) - VALUE(instr.result) = Runtime::getQmlIdArray(static_cast<QV4::NoThrowEngine*>(engine)); - MOTH_END_INSTR(LoadQmlIdArray) + MOTH_BEGIN_INSTR(LoadQmlContext) + VALUE(instr.result) = Runtime::getQmlContext(static_cast<QV4::NoThrowEngine*>(engine)); + MOTH_END_INSTR(LoadQmlContext) MOTH_BEGIN_INSTR(LoadQmlImportedScripts) VALUE(instr.result) = Runtime::getQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine)); MOTH_END_INSTR(LoadQmlImportedScripts) - MOTH_BEGIN_INSTR(LoadQmlContextObject) - VALUE(instr.result) = Runtime::getQmlContextObject(static_cast<QV4::NoThrowEngine*>(engine)); - MOTH_END_INSTR(LoadContextObject) - - MOTH_BEGIN_INSTR(LoadQmlScopeObject) - VALUE(instr.result) = Runtime::getQmlScopeObject(static_cast<QV4::NoThrowEngine*>(engine)); - MOTH_END_INSTR(LoadScopeObject) - MOTH_BEGIN_INSTR(LoadQmlSingleton) VALUE(instr.result) = Runtime::getQmlSingleton(static_cast<QV4::NoThrowEngine*>(engine), instr.name); MOTH_END_INSTR(LoadQmlSingleton) diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h index 55cac75a66..c0421022d2 100644 --- a/src/qml/jsruntime/qv4vme_moth_p.h +++ b/src/qml/jsruntime/qv4vme_moth_p.h @@ -34,6 +34,17 @@ #ifndef QV4VME_MOTH_P_H #define QV4VME_MOTH_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qv4runtime_p.h> #include <private/qv4instr_moth_p.h> |