diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2015-09-25 20:56:51 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2015-09-25 20:56:51 +0200 |
commit | f9ef039ad955db67dc3ab6e9056afc4a325aa9a3 (patch) | |
tree | 4928ff85fb630639e306ea4eb7137a2064a80c8b /src/qml/jsruntime | |
parent | 0238c739f81911f0963cf2c40b27dcfc8e3d38b7 (diff) | |
parent | 52fb4685e95e5b44e54d2d0f8ea27dea866c75e9 (diff) |
Merge remote-tracking branch 'origin/5.6' into dev
Conflicts:
src/qml/debugger/qqmldebug.cpp
Change-Id: I93de5a81b18cdece475870cf7cfba1b9baef2304
Diffstat (limited to 'src/qml/jsruntime')
57 files changed, 1263 insertions, 1182 deletions
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 2f6cf40beb..698b4c325c 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -40,9 +40,7 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(ArgumentsObject); Heap::ArgumentsObject::ArgumentsObject(QV4::CallContext *context) - : Heap::Object(context->d()->strictMode ? context->d()->engine->strictArgumentsObjectClass : context->d()->engine->argumentsObjectClass, - context->d()->engine->objectPrototype()) - , context(context->d()) + : context(context->d()) , fullyCreated(false) { Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable()); @@ -56,20 +54,20 @@ Heap::ArgumentsObject::ArgumentsObject(QV4::CallContext *context) if (context->d()->strictMode) { Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller())); - args->propertyAt(CalleePropertyIndex)->value = v4->thrower(); - args->propertyAt(CalleePropertyIndex)->set = v4->thrower(); - args->propertyAt(CallerPropertyIndex)->value = v4->thrower(); - args->propertyAt(CallerPropertyIndex)->set = v4->thrower(); + *args->propertyData(CalleePropertyIndex + QV4::Object::GetterOffset) = v4->thrower(); + *args->propertyData(CalleePropertyIndex + QV4::Object::SetterOffset) = v4->thrower(); + *args->propertyData(CallerPropertyIndex + QV4::Object::GetterOffset) = v4->thrower(); + *args->propertyData(CallerPropertyIndex + QV4::Object::SetterOffset) = v4->thrower(); args->arrayReserve(context->argc()); args->arrayPut(0, context->args(), context->argc()); args->d()->fullyCreated = true; } else { Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); - args->memberData()->data[CalleePropertyIndex] = context->d()->function->asReturnedValue(); + *args->propertyData(CalleePropertyIndex) = context->d()->function->asReturnedValue(); } Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length())); - args->memberData()->data[LengthPropertyIndex] = Primitive::fromInt32(context->d()->callData->argc); + *args->propertyData(LengthPropertyIndex) = Primitive::fromInt32(context->d()->callData->argc); } void ArgumentsObject::fullyCreate() @@ -84,10 +82,9 @@ void ArgumentsObject::fullyCreate() Scope scope(engine()); Scoped<MemberData> md(scope, d()->mappedArguments); - if (!md || md->size() < numAccessors) - d()->mappedArguments = md->reallocate(engine(), d()->mappedArguments, numAccessors); + d()->mappedArguments = md->allocate(engine(), numAccessors); for (uint i = 0; i < numAccessors; ++i) { - mappedArguments()->data[i] = context()->callData->args[i]; + d()->mappedArguments->data[i] = context()->callData->args[i]; arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor); } arrayPut(numAccessors, context()->callData->args + numAccessors, argCount - numAccessors); @@ -117,13 +114,13 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con map->copy(pd, mapAttrs); setArrayAttributes(index, Attr_Data); pd = arrayData()->getProperty(index); - pd->value = mappedArguments()->data[index]; + pd->value = d()->mappedArguments->data[index]; } - bool strict = engine->currentContext()->strictMode; - engine->currentContext()->strictMode = false; + bool strict = engine->current->strictMode; + engine->current->strictMode = false; bool result = Object::defineOwnProperty2(scope.engine, index, desc, attrs); - engine->currentContext()->strictMode = strict; + engine->current->strictMode = strict; if (isMapped && attrs.isData()) { Q_ASSERT(arrayData()); @@ -140,7 +137,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con } } - if (engine->currentContext()->strictMode && !result) + if (engine->current->strictMode && !result) return engine->throwTypeError(); return result; } diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index aab5e2c156..98a600fab6 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -103,7 +103,6 @@ struct ArgumentsObject: Object { Heap::CallContext *context() const { return d()->context; } bool fullyCreated() const { return d()->fullyCreated; } - Heap::MemberData *mappedArguments() { return d()->mappedArguments; } static bool isNonStrictArgumentsObject(Managed *m) { return m->d()->vtable()->type == Type_ArgumentsObject && diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp index 23c9695cf4..0a3aa414de 100644 --- a/src/qml/jsruntime/qv4arraybuffer.cpp +++ b/src/qml/jsruntime/qv4arraybuffer.cpp @@ -58,7 +58,7 @@ ReturnedValue ArrayBufferCtor::construct(const Managed *m, CallData *callData) if (len != dl) return v4->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length")); - Scoped<ArrayBuffer> a(scope, v4->memoryManager->alloc<ArrayBuffer>(v4, len)); + Scoped<ArrayBuffer> a(scope, v4->newArrayBuffer(len)); if (scope.engine->hasException) return Encode::undefined(); return a.asReturnedValue(); @@ -83,22 +83,20 @@ ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx) } -Heap::ArrayBuffer::ArrayBuffer(ExecutionEngine *e, size_t length) - : Heap::Object(e->emptyClass, e->arrayBufferPrototype()) +Heap::ArrayBuffer::ArrayBuffer(size_t length) { data = QTypedArrayData<char>::allocate(length + 1); if (!data) { data = 0; - e->throwRangeError(QStringLiteral("ArrayBuffer: out of memory")); + internalClass->engine->throwRangeError(QStringLiteral("ArrayBuffer: out of memory")); return; } data->size = int(length); memset(data->data(), 0, length + 1); } -Heap::ArrayBuffer::ArrayBuffer(ExecutionEngine *e, const QByteArray& array) - : Heap::Object(e->emptyClass, e->arrayBufferPrototype()) - , data(const_cast<QByteArray&>(array).data_ptr()) +Heap::ArrayBuffer::ArrayBuffer(const QByteArray& array) + : data(const_cast<QByteArray&>(array).data_ptr()) { data->ref.ref(); } diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h index a7f9e92c80..19fd74465c 100644 --- a/src/qml/jsruntime/qv4arraybuffer_p.h +++ b/src/qml/jsruntime/qv4arraybuffer_p.h @@ -47,8 +47,8 @@ struct ArrayBufferCtor : FunctionObject { }; struct Q_QML_PRIVATE_EXPORT ArrayBuffer : Object { - ArrayBuffer(ExecutionEngine *e, size_t length); - ArrayBuffer(ExecutionEngine *e, const QByteArray& array); + ArrayBuffer(size_t length); + ArrayBuffer(const QByteArray& array); ~ArrayBuffer(); QTypedArrayData<char> *data; @@ -72,6 +72,7 @@ struct Q_QML_PRIVATE_EXPORT ArrayBuffer : Object { V4_OBJECT2(ArrayBuffer, Object) V4_NEEDS_DESTROY + V4_PROTOTYPE(arrayBufferPrototype) QByteArray asByteArray() const; uint byteLength() const { return d()->byteLength(); } diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index da91db6aae..ec0185de64 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -584,7 +584,7 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n) ScopedValue v(scope); for (const SparseArrayNode *it = os->sparse->begin(); it != os->sparse->end(); it = it->nextNode()) { - v = otherObj->getValue(reinterpret_cast<Property *>(os->arrayData + it->value), other->d()->attrs[it->value]); + v = otherObj->getValue(os->arrayData[it->value], other->d()->attrs[it->value]); obj->arraySet(oldSize + it->key(), v); } } else { @@ -607,7 +607,7 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n) return oldSize + n; } -Property *ArrayData::insert(Object *o, uint index, bool isAccessor) +void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor) { if (!isAccessor && o->d()->arrayData->type != Heap::ArrayData::Sparse) { Heap::SimpleArrayData *d = o->d()->arrayData.cast<Heap::SimpleArrayData>(); @@ -622,7 +622,8 @@ Property *ArrayData::insert(Object *o, uint index, bool isAccessor) d->data(i) = Primitive::emptyValue(); d->len = index + 1; } - return reinterpret_cast<Property *>(d->arrayData + d->mappedIndex(index)); + d->arrayData[d->mappedIndex(index)] = *v; + return; } } @@ -632,7 +633,9 @@ Property *ArrayData::insert(Object *o, uint index, bool isAccessor) if (n->value == UINT_MAX) n->value = SparseArrayData::allocate(o, isAccessor); s = o->d()->arrayData.cast<Heap::SparseArrayData>(); - return reinterpret_cast<Property *>(s->arrayData + n->value); + s->arrayData[n->value] = *v; + if (isAccessor) + s->arrayData[n->value + Object::SetterOffset] = v[Object::SetterOffset]; } @@ -769,7 +772,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c break; PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data; - d->data(i) = thisObject->getValue(reinterpret_cast<Property *>(sparse->arrayData() + n->value), a); + d->data(i) = thisObject->getValue(sparse->arrayData()[n->value], a); d->attrs[i] = a.isAccessor() ? Attr_Data : a; n = n->nextNode(); diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 729e657b1a..cca5bf7f20 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -101,7 +101,10 @@ struct ArrayData : public Base { inline ReturnedValue get(uint i) const { return vtable()->get(this, i); } + inline void getProperty(uint index, Property *p, PropertyAttributes *attrs); + inline void setProperty(uint index, const Property *p); inline Property *getProperty(uint index); + inline Value *getValueOrSetter(uint index, PropertyAttributes *attrs); inline PropertyAttributes attributes(uint i) const; bool isEmpty(uint i) const { @@ -205,7 +208,7 @@ struct Q_QML_EXPORT ArrayData : public Managed static void sort(ExecutionEngine *engine, Object *thisObject, const Value &comparefn, uint dataLen); static uint append(Object *obj, ArrayObject *otherObj, uint n); - static Property *insert(Object *o, uint index, bool isAccessor = false); + static void insert(Object *o, uint index, const Value *v, bool isAccessor = false); }; struct Q_QML_EXPORT SimpleArrayData : public ArrayData @@ -270,6 +273,25 @@ inline SparseArrayData::~SparseArrayData() delete sparse; } +void ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs) +{ + Property *pd = getProperty(index); + Q_ASSERT(pd); + *attrs = attributes(index); + p->value = pd->value; + if (attrs->isAccessor()) + p->set = pd->set; +} + +void ArrayData::setProperty(uint index, const Property *p) +{ + Property *pd = getProperty(index); + Q_ASSERT(pd); + pd->value = p->value; + if (attributes(index).isAccessor()) + pd->set = p->set; +} + inline Property *ArrayData::getProperty(uint index) { if (isSparse()) @@ -284,6 +306,19 @@ inline PropertyAttributes ArrayData::attributes(uint i) const return static_cast<const SimpleArrayData *>(this)->attributes(i); } +Value *ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs) +{ + Property *p = getProperty(index); + if (!p) { + *attrs = Attr_Invalid; + return 0; + } + + *attrs = attributes(index); + return attrs->isAccessor() ? &p->set : &p->value; +} + + } diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index f50c5ab017..403beacf39 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -83,21 +83,31 @@ Heap::CallContext *ExecutionContext::newCallContext(const FunctionObject *functi return c; } -Heap::WithContext *ExecutionContext::newWithContext(Object *with) +Heap::WithContext *ExecutionContext::newWithContext(Heap::Object *with) { - return d()->engine->memoryManager->alloc<WithContext>(d()->engine, with); + return d()->engine->memoryManager->alloc<WithContext>(d(), with); } -Heap::CatchContext *ExecutionContext::newCatchContext(String *exceptionVarName, const Value &exceptionValue) +Heap::CatchContext *ExecutionContext::newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue) { - return d()->engine->memoryManager->alloc<CatchContext>(d()->engine, exceptionVarName, exceptionValue); + Scope scope(this); + ScopedValue e(scope, exceptionValue); + return d()->engine->memoryManager->alloc<CatchContext>(d(), exceptionVarName, e); } Heap::QmlContext *ExecutionContext::newQmlContext(QmlContextWrapper *qml) { - return d()->engine->memoryManager->alloc<QmlContext>(this, qml); + Heap::QmlContext *c = d()->engine->memoryManager->alloc<QmlContext>(this, qml); + return c; } +Heap::QmlContext *ExecutionContext::newQmlContext(QQmlContextData *context, QObject *scopeObject) +{ + Scope scope(this); + Scoped<QmlContextWrapper> qml(scope, QmlContextWrapper::qmlScope(scope.engine, context, scopeObject)); + Heap::QmlContext *c = d()->engine->memoryManager->alloc<QmlContext>(this, qml); + return c; +} void ExecutionContext::createMutableBinding(String *name, bool deletable) { @@ -142,38 +152,38 @@ Heap::GlobalContext::GlobalContext(ExecutionEngine *eng) global = eng->globalObject->d(); } -Heap::WithContext::WithContext(ExecutionEngine *engine, QV4::Object *with) - : Heap::ExecutionContext(engine, Heap::ExecutionContext::Type_WithContext) +Heap::WithContext::WithContext(ExecutionContext *outerContext, Object *with) + : Heap::ExecutionContext(outerContext->engine, Heap::ExecutionContext::Type_WithContext) { - callData = parent->callData; - outer = parent; - lookups = parent->lookups; - compilationUnit = parent->compilationUnit; + outer = outerContext; + callData = outer->callData; + lookups = outer->lookups; + compilationUnit = outer->compilationUnit; - withObject = with ? with->d() : 0; + withObject = with; } -Heap::CatchContext::CatchContext(ExecutionEngine *engine, QV4::String *exceptionVarName, const Value &exceptionValue) - : Heap::ExecutionContext(engine, Heap::ExecutionContext::Type_CatchContext) +Heap::CatchContext::CatchContext(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue) + : Heap::ExecutionContext(outerContext->engine, Heap::ExecutionContext::Type_CatchContext) { - strictMode = parent->strictMode; - callData = parent->callData; - outer = parent; - lookups = parent->lookups; - compilationUnit = parent->compilationUnit; + outer = outerContext; + strictMode = outer->strictMode; + callData = outer->callData; + lookups = outer->lookups; + compilationUnit = outer->compilationUnit; - this->exceptionVarName = exceptionVarName->d(); + this->exceptionVarName = exceptionVarName; this->exceptionValue = exceptionValue; } -Heap::QmlContext::QmlContext(QV4::ExecutionContext *outer, QV4::QmlContextWrapper *qml) - : Heap::ExecutionContext(outer->engine(), Heap::ExecutionContext::Type_QmlContext) +Heap::QmlContext::QmlContext(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml) + : Heap::ExecutionContext(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext) { + outer = outerContext->d(); strictMode = false; - callData = parent->callData; - this->outer = outer->d(); - lookups = parent->lookups; - compilationUnit = parent->compilationUnit; + callData = outer->callData; + lookups = outer->lookups; + compilationUnit = outer->compilationUnit; this->qml = qml->d(); } @@ -362,7 +372,7 @@ void ExecutionContext::setProperty(String *name, const Value &value) if (activation) { uint member = activation->internalClass()->find(name); if (member < UINT_MAX) { - activation->putValue(activation->propertyAt(member), activation->internalClass()->propertyData[member], value); + activation->putValue(member, value); return; } } @@ -538,7 +548,7 @@ Heap::FunctionObject *ExecutionContext::getFunctionObject() const { Scope scope(d()->engine); ScopedContext it(scope, this->d()); - for (; it; it = it->d()->parent) { + for (; it; it = it->d()->outer) { if (const CallContext *callCtx = it->asCallContext()) return callCtx->d()->function; else if (it->asCatchContext() || it->asWithContext()) @@ -560,3 +570,8 @@ QQmlContextData *QmlContext::qmlContext() const { return d()->qml->context; } + +void QmlContext::takeContextOwnership() { + d()->qml->ownsContext = true; +} + diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 2667bbe0b2..2807d1e29c 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -89,7 +89,6 @@ struct ExecutionContext : Base { CallData *callData; ExecutionEngine *engine; - Pointer<ExecutionContext> parent; Pointer<ExecutionContext> outer; Lookup *lookups; CompiledData::CompilationUnit *compilationUnit; @@ -99,6 +98,18 @@ struct ExecutionContext : Base { int lineNumber; }; +inline +ExecutionContext::ExecutionContext(ExecutionEngine *engine, ContextType t) + : engine(engine) + , outer(0) + , lookups(0) + , compilationUnit(0) + , type(t) + , strictMode(false) + , lineNumber(-1) +{} + + struct CallContext : ExecutionContext { CallContext(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext) : ExecutionContext(engine, t) @@ -119,20 +130,20 @@ struct GlobalContext : ExecutionContext { }; struct CatchContext : ExecutionContext { - CatchContext(ExecutionEngine *engine, QV4::String *exceptionVarName, const Value &exceptionValue); + CatchContext(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue); Pointer<String> exceptionVarName; Value exceptionValue; }; struct WithContext : ExecutionContext { - WithContext(ExecutionEngine *engine, QV4::Object *with); + WithContext(ExecutionContext *outerContext, Object *with); Pointer<Object> withObject; }; struct QmlContextWrapper; struct QmlContext : ExecutionContext { - QmlContext(QV4::ExecutionContext *outer, QV4::QmlContextWrapper *qml); + QmlContext(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml); Pointer<QmlContextWrapper> qml; }; @@ -150,9 +161,10 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ExecutionEngine *engine() const { return d()->engine; } Heap::CallContext *newCallContext(const FunctionObject *f, CallData *callData); - Heap::WithContext *newWithContext(Object *with); - Heap::CatchContext *newCatchContext(String *exceptionVarName, const Value &exceptionValue); + Heap::WithContext *newWithContext(Heap::Object *with); + Heap::CatchContext *newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue); Heap::QmlContext *newQmlContext(QmlContextWrapper *qml); + Heap::QmlContext *newQmlContext(QQmlContextData *context, QObject *scopeObject); void createMutableBinding(String *name, bool deletable); @@ -224,6 +236,8 @@ struct QmlContext : public ExecutionContext QObject *qmlScope() const; QQmlContextData *qmlContext() const; + + void takeContextOwnership(); }; inline CallContext *ExecutionContext::asCallContext() diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp index a741d61d10..8901834e76 100644 --- a/src/qml/jsruntime/qv4dataview.cpp +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -62,7 +62,7 @@ ReturnedValue DataViewCtor::construct(const Managed *m, CallData *callData) if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength) return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range")); - Scoped<DataView> a(scope, scope.engine->memoryManager->alloc<DataView>(scope.engine)); + Scoped<DataView> a(scope, scope.engine->memoryManager->allocObject<DataView>()); a->d()->buffer = buffer->d(); a->d()->byteLength = byteLength; a->d()->byteOffset = byteOffset; @@ -76,15 +76,6 @@ ReturnedValue DataViewCtor::call(const Managed *that, CallData *callData) } -Heap::DataView::DataView(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->dataViewPrototype()), - buffer(0), - byteLength(0), - byteOffset(0) -{ -} - - void DataView::markObjects(Heap::Base *that, ExecutionEngine *e) { DataView::Data *v = static_cast<DataView::Data *>(that); @@ -103,22 +94,30 @@ void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor) defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); defineDefaultProperty(QStringLiteral("getInt8"), method_getChar<signed char>, 0); - defineDefaultProperty(QStringLiteral("getUInt8"), method_getChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("getUint8"), method_getChar<unsigned char>, 0); defineDefaultProperty(QStringLiteral("getInt16"), method_get<short>, 0); - defineDefaultProperty(QStringLiteral("getUInt16"), method_get<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("getUint16"), method_get<unsigned short>, 0); defineDefaultProperty(QStringLiteral("getInt32"), method_get<int>, 0); - defineDefaultProperty(QStringLiteral("getUInt32"), method_get<unsigned int>, 0); + defineDefaultProperty(QStringLiteral("getUint32"), method_get<unsigned int>, 0); defineDefaultProperty(QStringLiteral("getFloat32"), method_getFloat<float>, 0); defineDefaultProperty(QStringLiteral("getFloat64"), method_getFloat<double>, 0); defineDefaultProperty(QStringLiteral("setInt8"), method_setChar<signed char>, 0); - defineDefaultProperty(QStringLiteral("setUInt8"), method_setChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("setUint8"), method_setChar<unsigned char>, 0); defineDefaultProperty(QStringLiteral("setInt16"), method_set<short>, 0); - defineDefaultProperty(QStringLiteral("setUInt16"), method_set<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("setUint16"), method_set<unsigned short>, 0); defineDefaultProperty(QStringLiteral("setInt32"), method_set<int>, 0); - defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 0); + defineDefaultProperty(QStringLiteral("setUint32"), method_set<unsigned int>, 0); defineDefaultProperty(QStringLiteral("setFloat32"), method_setFloat<float>, 0); defineDefaultProperty(QStringLiteral("setFloat64"), method_setFloat<double>, 0); + + // For backword compatibility + defineDefaultProperty(QStringLiteral("getUInt8"), method_getChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("getUInt16"), method_get<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("getUInt32"), method_get<unsigned int>, 0); + defineDefaultProperty(QStringLiteral("setUInt8"), method_setChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("setUInt16"), method_set<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 0); } ReturnedValue DataViewPrototype::method_get_buffer(CallContext *ctx) diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h index e98239396a..37a8363645 100644 --- a/src/qml/jsruntime/qv4dataview_p.h +++ b/src/qml/jsruntime/qv4dataview_p.h @@ -47,7 +47,7 @@ struct DataViewCtor : FunctionObject { }; struct DataView : Object { - DataView(ExecutionEngine *e); + DataView() {} Pointer<ArrayBuffer> buffer; uint byteLength; uint byteOffset; @@ -66,6 +66,7 @@ struct DataViewCtor: FunctionObject struct DataView : Object { V4_OBJECT2(DataView, Object) + V4_PROTOTYPE(dataViewPrototype) static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 3f45751695..a6e1f47d91 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -628,8 +628,7 @@ static double getLocalTZA() DEFINE_OBJECT_VTABLE(DateObject); -Heap::DateObject::DateObject(QV4::ExecutionEngine *engine, const QDateTime &date) - : Heap::Object(engine->emptyClass, engine->datePrototype()) +Heap::DateObject::DateObject(const QDateTime &date) { this->date = date.isValid() ? date.toMSecsSinceEpoch() : qSNaN(); } diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index 7a6413e820..a324e216e4 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -46,18 +46,16 @@ namespace QV4 { namespace Heap { struct DateObject : Object { - DateObject(InternalClass *ic, QV4::Object *prototype) - : Object(ic, prototype) + DateObject() { date = qSNaN(); } - DateObject(QV4::ExecutionEngine *engine, const Value &date) - : Object(engine->emptyClass, engine->datePrototype()) + DateObject(const Value &date) { this->date = date.toNumber(); } - DateObject(QV4::ExecutionEngine *engine, const QDateTime &date); + DateObject(const QDateTime &date); double date; }; @@ -71,6 +69,7 @@ struct DateCtor : FunctionObject { struct DateObject: Object { V4_OBJECT2(DateObject, Object) Q_MANAGED_TYPE(DateObject) + V4_PROTOTYPE(datePrototype) double date() const { return d()->date; } diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index 6efc3793ce..79fd58f700 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -66,17 +66,16 @@ void Debugger::JavaScriptJob::run() { Scope scope(engine); - ExecutionContextSaver saver(scope, engine->currentContext()); + ExecutionContextSaver saver(scope); + ExecutionContext *ctx = engine->currentContext; if (frameNr > 0) { - Value *savedContexts = scope.alloc(frameNr); for (int i = 0; i < frameNr; ++i) { - savedContexts[i] = engine->currentContext(); - engine->popContext(); + ctx = engine->parentContext(ctx); } + engine->pushContext(ctx); } - ScopedContext ctx(scope, engine->currentContext()); QV4::Script script(ctx, this->script); script.strictMode = ctx->d()->strictMode; // In order for property lookups in QML to work, we need to disable fast v4 lookups. That @@ -151,7 +150,7 @@ void Debugger::resume(Speed speed) if (!m_returnedValue.isUndefined()) m_returnedValue.set(m_engine, Encode::undefined()); - m_currentContext.set(m_engine, m_engine->currentContext()); + m_currentContext.set(m_engine, *m_engine->currentContext); m_stepping = speed; m_runningCondition.wakeAll(); } @@ -181,7 +180,7 @@ Debugger::ExecutionState Debugger::currentExecutionState() const { ExecutionState state; state.fileName = getFunction()->sourceFile(); - state.lineNumber = engine()->currentContext()->lineNumber; + state.lineNumber = engine()->current->lineNumber; return state; } @@ -206,7 +205,7 @@ void Debugger::maybeBreakAtInstruction() switch (m_stepping) { case StepOver: - if (m_currentContext.asManaged()->d() != m_engine->currentContext()) + if (m_currentContext.asManaged()->d() != m_engine->current) break; // fall through case StepIn: @@ -222,7 +221,7 @@ void Debugger::maybeBreakAtInstruction() pauseAndWait(PauseRequest); } else if (m_haveBreakPoints) { if (Function *f = getFunction()) { - const int lineNumber = engine()->currentContext()->lineNumber; + const int lineNumber = engine()->current->lineNumber; if (reallyHitTheBreakPoint(f->sourceFile(), lineNumber)) pauseAndWait(BreakPoint); } @@ -236,7 +235,7 @@ void Debugger::enteringFunction() QMutexLocker locker(&m_lock); if (m_stepping == StepIn) { - m_currentContext.set(m_engine, m_engine->currentContext()); + m_currentContext.set(m_engine, *m_engine->currentContext); } } @@ -248,8 +247,8 @@ void Debugger::leavingFunction(const ReturnedValue &retVal) QMutexLocker locker(&m_lock); - if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->currentContext()) { - m_currentContext.set(m_engine, m_engine->currentContext()->parent); + if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->current) { + m_currentContext.set(m_engine, *m_engine->parentContext(m_engine->currentContext)); m_stepping = StepOver; m_returnedValue.set(m_engine, retVal); } @@ -270,7 +269,7 @@ void Debugger::aboutToThrow() Function *Debugger::getFunction() const { Scope scope(m_engine); - ScopedContext context(scope, m_engine->currentContext()); + ExecutionContext *context = m_engine->currentContext; ScopedFunctionObject function(scope, context->getFunctionObject()); if (function) return function->function(); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index caf07e8b0b..6fe14da850 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -200,6 +200,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) , memoryManager(new QV4::MemoryManager(this)) , executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) + , currentContext(0) , bumperPointerAllocator(new WTF::BumpPointerAllocator) , jsStack(new WTF::PageAllocation) , debugger(0) @@ -297,10 +298,10 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer")); jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex")); - jsObjects[ObjectProto] = memoryManager->alloc<ObjectPrototype>(emptyClass, (QV4::Object *)0); + jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(emptyClass); arrayClass = emptyClass->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); - jsObjects[ArrayProto] = memoryManager->alloc<ArrayPrototype>(arrayClass, objectPrototype()); + jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(arrayClass, objectPrototype()); InternalClass *argsClass = emptyClass->addMember(id_length(), Attr_NotEnumerable); argumentsObjectClass = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable); @@ -311,15 +312,17 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) Q_ASSERT(globalObject->d()->vtable()); initRootContext(); - jsObjects[StringProto] = memoryManager->alloc<StringPrototype>(emptyClass, objectPrototype()); - jsObjects[NumberProto] = memoryManager->alloc<NumberPrototype>(emptyClass, objectPrototype()); - jsObjects[BooleanProto] = memoryManager->alloc<BooleanPrototype>(emptyClass, objectPrototype()); - jsObjects[DateProto] = memoryManager->alloc<DatePrototype>(emptyClass, objectPrototype()); + stringClass = emptyClass->addMember(id_length(), Attr_ReadOnly); + Q_ASSERT(stringClass->find(id_length()) == Heap::StringObject::LengthPropertyIndex); + jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(stringClass, objectPrototype()); + jsObjects[NumberProto] = memoryManager->allocObject<NumberPrototype>(emptyClass, objectPrototype()); + jsObjects[BooleanProto] = memoryManager->allocObject<BooleanPrototype>(emptyClass, objectPrototype()); + jsObjects[DateProto] = memoryManager->allocObject<DatePrototype>(emptyClass, objectPrototype()); uint index; InternalClass *functionProtoClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - jsObjects[FunctionProto] = memoryManager->alloc<FunctionPrototype>(functionProtoClass, objectPrototype()); + jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(functionProtoClass, objectPrototype()); functionClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); simpleScriptFunctionClass = functionClass->addMember(id_name(), Attr_ReadOnly, &index); @@ -329,42 +332,72 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) protoClass = emptyClass->addMember(id_constructor(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor); - jsObjects[RegExpProto] = memoryManager->alloc<RegExpPrototype>(this); + Scope scope(this); + ScopedString str(scope); + regExpObjectClass = emptyClass->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index); + Q_ASSERT(index == RegExpObject::Index_LastIndex); + regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index); + Q_ASSERT(index == RegExpObject::Index_Source); + regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index); + Q_ASSERT(index == RegExpObject::Index_Global); + regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index); + Q_ASSERT(index == RegExpObject::Index_IgnoreCase); + regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index); + Q_ASSERT(index == RegExpObject::Index_Multiline); + + jsObjects[RegExpProto] = memoryManager->allocObject<RegExpPrototype>(regExpObjectClass, objectPrototype()); regExpExecArrayClass = arrayClass->addMember(id_index(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayIndex); regExpExecArrayClass = regExpExecArrayClass->addMember(id_input(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayInput); - jsObjects[ErrorProto] = memoryManager->alloc<ErrorPrototype>(emptyClass, objectPrototype()); - jsObjects[EvalErrorProto] = memoryManager->alloc<EvalErrorPrototype>(emptyClass, errorPrototype()); - jsObjects[RangeErrorProto] = memoryManager->alloc<RangeErrorPrototype>(emptyClass, errorPrototype()); - jsObjects[ReferenceErrorProto] = memoryManager->alloc<ReferenceErrorPrototype>(emptyClass, errorPrototype()); - jsObjects[SyntaxErrorProto] = memoryManager->alloc<SyntaxErrorPrototype>(emptyClass, errorPrototype()); - jsObjects[TypeErrorProto] = memoryManager->alloc<TypeErrorPrototype>(emptyClass, errorPrototype()); - jsObjects[URIErrorProto] = memoryManager->alloc<URIErrorPrototype>(emptyClass, errorPrototype()); - - jsObjects[VariantProto] = memoryManager->alloc<VariantPrototype>(emptyClass, objectPrototype()); + errorClass = emptyClass->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorObject::Index_Stack); + errorClass = errorClass->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorObject::Index_FileName); + errorClass = errorClass->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorObject::Index_LineNumber); + errorClassWithMessage = errorClass->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorObject::Index_Message); + errorProtoClass = emptyClass->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorPrototype::Index_Constructor); + errorProtoClass = errorProtoClass->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorPrototype::Index_Message); + errorProtoClass = errorProtoClass->addMember(id_name(), Attr_Data|Attr_NotEnumerable, &index); + Q_ASSERT(index == ErrorPrototype::Index_Name); + + jsObjects[GetStack_Function] = BuiltinFunction::create(rootContext(), str = newIdentifier(QStringLiteral("stack")), ErrorObject::method_get_stack); + getStackFunction()->defineReadonlyProperty(id_length(), Primitive::fromInt32(0)); + + jsObjects[ErrorProto] = memoryManager->allocObject<ErrorPrototype>(errorProtoClass, objectPrototype()); + jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(errorProtoClass, errorPrototype()); + jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(errorProtoClass, errorPrototype()); + jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(errorProtoClass, errorPrototype()); + jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(errorProtoClass, errorPrototype()); + jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(errorProtoClass, errorPrototype()); + jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(errorProtoClass, errorPrototype()); + + jsObjects[VariantProto] = memoryManager->allocObject<VariantPrototype>(emptyClass, objectPrototype()); Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d()); - Scope scope(this); - jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->alloc<SequencePrototype>(arrayClass, arrayPrototype())); - - ScopedContext global(scope, rootContext()); - jsObjects[Object_Ctor] = memoryManager->alloc<ObjectCtor>(global); - jsObjects[String_Ctor] = memoryManager->alloc<StringCtor>(global); - jsObjects[Number_Ctor] = memoryManager->alloc<NumberCtor>(global); - jsObjects[Boolean_Ctor] = memoryManager->alloc<BooleanCtor>(global); - jsObjects[Array_Ctor] = memoryManager->alloc<ArrayCtor>(global); - jsObjects[Function_Ctor] = memoryManager->alloc<FunctionCtor>(global); - jsObjects[Date_Ctor] = memoryManager->alloc<DateCtor>(global); - jsObjects[RegExp_Ctor] = memoryManager->alloc<RegExpCtor>(global); - jsObjects[Error_Ctor] = memoryManager->alloc<ErrorCtor>(global); - jsObjects[EvalError_Ctor] = memoryManager->alloc<EvalErrorCtor>(global); - jsObjects[RangeError_Ctor] = memoryManager->alloc<RangeErrorCtor>(global); - jsObjects[ReferenceError_Ctor] = memoryManager->alloc<ReferenceErrorCtor>(global); - jsObjects[SyntaxError_Ctor] = memoryManager->alloc<SyntaxErrorCtor>(global); - jsObjects[TypeError_Ctor] = memoryManager->alloc<TypeErrorCtor>(global); - jsObjects[URIError_Ctor] = memoryManager->alloc<URIErrorCtor>(global); + jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(arrayClass, arrayPrototype())); + + ExecutionContext *global = rootContext(); + jsObjects[Object_Ctor] = memoryManager->allocObject<ObjectCtor>(global); + jsObjects[String_Ctor] = memoryManager->allocObject<StringCtor>(global); + jsObjects[Number_Ctor] = memoryManager->allocObject<NumberCtor>(global); + jsObjects[Boolean_Ctor] = memoryManager->allocObject<BooleanCtor>(global); + jsObjects[Array_Ctor] = memoryManager->allocObject<ArrayCtor>(global); + jsObjects[Function_Ctor] = memoryManager->allocObject<FunctionCtor>(global); + jsObjects[Date_Ctor] = memoryManager->allocObject<DateCtor>(global); + jsObjects[RegExp_Ctor] = memoryManager->allocObject<RegExpCtor>(global); + jsObjects[Error_Ctor] = memoryManager->allocObject<ErrorCtor>(global); + jsObjects[EvalError_Ctor] = memoryManager->allocObject<EvalErrorCtor>(global); + jsObjects[RangeError_Ctor] = memoryManager->allocObject<RangeErrorCtor>(global); + jsObjects[ReferenceError_Ctor] = memoryManager->allocObject<ReferenceErrorCtor>(global); + jsObjects[SyntaxError_Ctor] = memoryManager->allocObject<SyntaxErrorCtor>(global); + jsObjects[TypeError_Ctor] = memoryManager->allocObject<TypeErrorCtor>(global); + jsObjects[URIError_Ctor] = memoryManager->allocObject<URIErrorCtor>(global); static_cast<ObjectPrototype *>(objectPrototype())->init(this, objectCtor()); static_cast<StringPrototype *>(stringPrototype())->init(this, stringCtor()); @@ -388,18 +421,19 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) // typed arrays - jsObjects[ArrayBuffer_Ctor] = memoryManager->alloc<ArrayBufferCtor>(global); - jsObjects[ArrayBufferProto] = memoryManager->alloc<ArrayBufferPrototype>(emptyClass, objectPrototype()); + jsObjects[ArrayBuffer_Ctor] = memoryManager->allocObject<ArrayBufferCtor>(global); + jsObjects[ArrayBufferProto] = memoryManager->allocObject<ArrayBufferPrototype>(); static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor()); - jsObjects[DataView_Ctor] = memoryManager->alloc<DataViewCtor>(global); - jsObjects[DataViewProto] = memoryManager->alloc<DataViewPrototype>(emptyClass, objectPrototype()); + jsObjects[DataView_Ctor] = memoryManager->allocObject<DataViewCtor>(global); + jsObjects[DataViewProto] = memoryManager->allocObject<DataViewPrototype>(); static_cast<DataViewPrototype *>(dataViewPrototype())->init(this, dataViewCtor()); jsObjects[ValueTypeProto] = (Heap::Base *) 0; + jsObjects[SignalHandlerProto] = (Heap::Base *) 0; for (int i = 0; i < Heap::TypedArray::NTypes; ++i) { - static_cast<Value &>(typedArrayCtors[i]) = memoryManager->alloc<TypedArrayCtor>(global, Heap::TypedArray::Type(i)); - static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->alloc<TypedArrayPrototype>(this, Heap::TypedArray::Type(i)); + static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocObject<TypedArrayCtor>(global, Heap::TypedArray::Type(i)); + static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->allocObject<TypedArrayPrototype>(Heap::TypedArray::Type(i)); typedArrayPrototype[i].as<TypedArrayPrototype>()->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].as<Object>())); } @@ -428,19 +462,18 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor()); globalObject->defineDefaultProperty(QStringLiteral("DataView"), *dataViewCtor()); - ScopedString str(scope); for (int i = 0; i < Heap::TypedArray::NTypes; ++i) globalObject->defineDefaultProperty((str = typedArrayCtors[i].as<FunctionObject>()->name())->toQString(), typedArrayCtors[i]); ScopedObject o(scope); - globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->alloc<MathObject>(this))); - globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->alloc<JsonObject>(this))); + globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->allocObject<MathObject>())); + globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->allocObject<JsonObject>())); globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Primitive::undefinedValue()); globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(std::numeric_limits<double>::quiet_NaN())); globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Primitive::fromDouble(Q_INFINITY)); - jsObjects[Eval_Function] = memoryManager->alloc<EvalFunction>(global); + jsObjects[Eval_Function] = memoryManager->allocObject<EvalFunction>(global); globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction()); globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2); @@ -508,8 +541,11 @@ void ExecutionEngine::initRootContext() r->d()->callData->argc = 0; r->d()->callData->thisObject = globalObject; r->d()->callData->args[0] = Encode::undefined(); + jsObjects[RootContext] = r; + jsObjects[IntegerNull] = Encode((int)0); - jsObjects[RootContect] = r; + currentContext = static_cast<ExecutionContext *>(jsObjects + RootContext); + current = currentContext->d(); } InternalClass *ExecutionEngine::newClass(const InternalClass &other) @@ -517,29 +553,31 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other) return new (classPool) InternalClass(other); } -Heap::ExecutionContext *ExecutionEngine::pushGlobalContext() +ExecutionContext *ExecutionEngine::pushGlobalContext() { - Scope scope(this); - Scoped<GlobalContext> g(scope, memoryManager->alloc<GlobalContext>(this)); - g->d()->callData = rootContext()->d()->callData; + pushContext(rootContext()->d()); - Q_ASSERT(currentContext() == g->d()); - return g->d(); + Q_ASSERT(current == rootContext()->d()); + return currentContext; +} + +ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *context) const +{ + Value *offset = static_cast<Value *>(context) + 1; + Q_ASSERT(offset->isInteger()); + int o = offset->integerValue(); + return o ? context - o : 0; } Heap::Object *ExecutionEngine::newObject() { - Scope scope(this); - ScopedObject object(scope, memoryManager->alloc<Object>(this)); - return object->d(); + return memoryManager->allocObject<Object>(); } Heap::Object *ExecutionEngine::newObject(InternalClass *internalClass, QV4::Object *prototype) { - Scope scope(this); - ScopedObject object(scope, memoryManager->alloc<Object>(internalClass, prototype)); - return object->d(); + return memoryManager->allocObject<Object>(internalClass, prototype); } Heap::String *ExecutionEngine::newString(const QString &s) @@ -555,29 +593,23 @@ Heap::String *ExecutionEngine::newIdentifier(const QString &text) Heap::Object *ExecutionEngine::newStringObject(const String *string) { - Scope scope(this); - Scoped<StringObject> object(scope, memoryManager->alloc<StringObject>(this, string)); - return object->d(); + return memoryManager->allocObject<StringObject>(string); } Heap::Object *ExecutionEngine::newNumberObject(double value) { - Scope scope(this); - Scoped<NumberObject> object(scope, memoryManager->alloc<NumberObject>(this, value)); - return object->d(); + return memoryManager->allocObject<NumberObject>(value); } Heap::Object *ExecutionEngine::newBooleanObject(bool b) { - Scope scope(this); - ScopedObject object(scope, memoryManager->alloc<BooleanObject>(this, b)); - return object->d(); + return memoryManager->allocObject<BooleanObject>(b); } Heap::ArrayObject *ExecutionEngine::newArrayObject(int count) { Scope scope(this); - ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(this)); + ScopedArrayObject object(scope, memoryManager->allocObject<ArrayObject>()); if (count) { if (count < 0x1000) @@ -587,39 +619,60 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(int count) return object->d(); } +Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int length) +{ + Scope scope(this); + ScopedArrayObject a(scope, memoryManager->allocObject<ArrayObject>()); + + if (length) { + size_t size = sizeof(Heap::ArrayData) + (length-1)*sizeof(Value); + Heap::SimpleArrayData *d = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size); + new (d) Heap::SimpleArrayData; + d->alloc = length; + d->type = Heap::ArrayData::Simple; + d->offset = 0; + d->len = length; + memcpy(&d->arrayData, values, length*sizeof(Value)); + a->d()->arrayData = d; + a->setArrayLengthUnchecked(length); + } + return a->d(); +} + Heap::ArrayObject *ExecutionEngine::newArrayObject(const QStringList &list) { Scope scope(this); - ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(this, list)); + ScopedArrayObject object(scope, memoryManager->allocObject<ArrayObject>(list)); return object->d(); } -Heap::ArrayObject *ExecutionEngine::newArrayObject(InternalClass *ic, Object *prototype) +Heap::ArrayObject *ExecutionEngine::newArrayObject(InternalClass *internalClass, Object *prototype) { Scope scope(this); - ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(ic, prototype)); + ScopedArrayObject object(scope, memoryManager->allocObject<ArrayObject>(internalClass, prototype)); return object->d(); } Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(const QByteArray &array) { - Scope scope(this); - Scoped<ArrayBuffer> object(scope, memoryManager->alloc<ArrayBuffer>(this, array)); - return object->d(); + return memoryManager->allocObject<ArrayBuffer>(array); +} + +Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(size_t length) +{ + return memoryManager->allocObject<ArrayBuffer>(length); } Heap::DateObject *ExecutionEngine::newDateObject(const Value &value) { - Scope scope(this); - Scoped<DateObject> object(scope, memoryManager->alloc<DateObject>(this, value)); - return object->d(); + return memoryManager->allocObject<DateObject>(value); } Heap::DateObject *ExecutionEngine::newDateObject(const QDateTime &dt) { Scope scope(this); - Scoped<DateObject> object(scope, memoryManager->alloc<DateObject>(this, dt)); + Scoped<DateObject> object(scope, memoryManager->allocObject<DateObject>(dt)); return object->d(); } @@ -640,97 +693,75 @@ Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int Heap::RegExpObject *ExecutionEngine::newRegExpObject(RegExp *re, bool global) { - Scope scope(this); - Scoped<RegExpObject> object(scope, memoryManager->alloc<RegExpObject>(this, re, global)); - return object->d(); + return memoryManager->allocObject<RegExpObject>(re, global); } Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re) { - Scope scope(this); - Scoped<RegExpObject> object(scope, memoryManager->alloc<RegExpObject>(this, re)); - return object->d(); + return memoryManager->allocObject<RegExpObject>(re); } Heap::Object *ExecutionEngine::newErrorObject(const Value &value) { - Scope scope(this); - ScopedObject object(scope, memoryManager->alloc<ErrorObject>(emptyClass, errorPrototype(), value)); - return object->d(); + return ErrorObject::create<ErrorObject>(this, value); } Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message) { - Scope scope(this); - ScopedString s(scope, newString(message)); - ScopedObject error(scope, memoryManager->alloc<SyntaxErrorObject>(this, s)); - return error->d(); + return ErrorObject::create<SyntaxErrorObject>(this, message); } Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column) { - Scope scope(this); - ScopedObject error(scope, memoryManager->alloc<SyntaxErrorObject>(this, message, fileName, line, column)); - return error->d(); + return ErrorObject::create<SyntaxErrorObject>(this, message, fileName, line, column); } Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message) { - Scope scope(this); - ScopedObject o(scope, memoryManager->alloc<ReferenceErrorObject>(this, message)); - return o->d(); + return ErrorObject::create<ReferenceErrorObject>(this, message); } -Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber, int columnNumber) +Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int line, int column) { - Scope scope(this); - ScopedObject o(scope, memoryManager->alloc<ReferenceErrorObject>(this, message, fileName, lineNumber, columnNumber)); - return o->d(); + return ErrorObject::create<ReferenceErrorObject>(this, message, fileName, line, column); } Heap::Object *ExecutionEngine::newTypeErrorObject(const QString &message) { - Scope scope(this); - ScopedObject o(scope, memoryManager->alloc<TypeErrorObject>(this, message)); - return o->d(); + return ErrorObject::create<TypeErrorObject>(this, message); } Heap::Object *ExecutionEngine::newRangeErrorObject(const QString &message) { - Scope scope(this); - ScopedObject o(scope, memoryManager->alloc<RangeErrorObject>(this, message)); - return o->d(); + return ErrorObject::create<RangeErrorObject>(this, message); } Heap::Object *ExecutionEngine::newURIErrorObject(const Value &message) { - Scope scope(this); - ScopedObject o(scope, memoryManager->alloc<URIErrorObject>(this, message)); - return o->d(); + return ErrorObject::create<URIErrorObject>(this, message); } Heap::Object *ExecutionEngine::newVariantObject(const QVariant &v) { - Scope scope(this); - ScopedObject o(scope, memoryManager->alloc<VariantObject>(this, v)); - return o->d(); + return memoryManager->allocObject<VariantObject>(v); } Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o) { Scope scope(this); - ScopedObject obj(scope, memoryManager->alloc<ForEachIteratorObject>(this, o)); + ScopedObject obj(scope, memoryManager->allocObject<ForEachIteratorObject>(o)); return obj->d(); } Heap::QmlContext *ExecutionEngine::qmlContext() const { - Heap::ExecutionContext *ctx = currentContext(); + Heap::ExecutionContext *ctx = current; + // get the correct context when we're within a builtin function if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer) - ctx = ctx->parent; + ctx = parentContext(currentContext)->d(); if (!ctx->outer) return 0; @@ -745,18 +776,13 @@ Heap::QmlContext *ExecutionEngine::qmlContext() const return static_cast<Heap::QmlContext *>(ctx); } -Heap::QmlContextWrapper *ExecutionEngine::qmlContextObject() const +QObject *ExecutionEngine::qmlScopeObject() const { Heap::QmlContext *ctx = qmlContext(); if (!ctx) return 0; - Q_ASSERT(ctx->qml); - return ctx->qml; -} -QObject *ExecutionEngine::qmlScopeObject() const -{ - return qmlContextObject()->scopeObject; + return ctx->qml->scopeObject; } ReturnedValue ExecutionEngine::qmlSingletonWrapper(String *name) @@ -782,9 +808,11 @@ ReturnedValue ExecutionEngine::qmlSingletonWrapper(String *name) QQmlContextData *ExecutionEngine::callingQmlContext() const { - Heap::QmlContextWrapper *w = qmlContextObject(); + Heap::QmlContext *ctx = qmlContext(); + if (!ctx) + return 0; - return w ? w->context.contextData() : 0; + return ctx->qml->context.contextData(); } QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const @@ -793,7 +821,7 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const ScopedString name(scope); QVector<StackFrame> stack; - ScopedContext c(scope, currentContext()); + ExecutionContext *c = currentContext; ScopedFunctionObject function(scope); while (c && frameLimit) { function = c->getFunctionObject(); @@ -813,7 +841,7 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const stack.append(frame); --frameLimit; } - c = c->d()->parent; + c = parentContext(c); } if (frameLimit && globalCode) { @@ -881,8 +909,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) return src; QUrl base; - Scope scope(this); - ScopedContext c(scope, currentContext()); + ExecutionContext *c = currentContext; while (c) { CallContext *callCtx = c->asCallContext(); if (callCtx && callCtx->d()->function) { @@ -890,7 +917,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) base.setUrl(callCtx->d()->function->function->sourceFile()); break; } - c = c->d()->parent; + c = parentContext(c); } if (base.isEmpty() && globalCode) @@ -920,10 +947,10 @@ void ExecutionEngine::requireArgumentsAccessors(int n) memcpy(argumentsAccessors, oldAccessors, oldSize*sizeof(Property)); delete [] oldAccessors; } - ScopedContext global(scope, scope.engine->rootContext()); + ExecutionContext *global = rootContext(); for (int i = oldSize; i < nArgumentsAccessors; ++i) { - argumentsAccessors[i].value = ScopedValue(scope, memoryManager->alloc<ArgumentsGetterFunction>(global, i)); - argumentsAccessors[i].set = ScopedValue(scope, memoryManager->alloc<ArgumentsSetterFunction>(global, i)); + argumentsAccessors[i].value = ScopedValue(scope, memoryManager->allocObject<ArgumentsGetterFunction>(global, i)); + argumentsAccessors[i].set = ScopedValue(scope, memoryManager->allocObject<ArgumentsSetterFunction>(global, i)); } } } @@ -940,16 +967,6 @@ void ExecutionEngine::markObjects() setter->mark(this); } - Heap::ExecutionContext *c = currentContext(); - while (c) { - Q_ASSERT(c->inUse()); - if (!c->isMarked()) { - c->setMarkBit(); - c->vtable()->markObjects(c, this); - } - c = c->parent; - } - classPool->markObjects(this); for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd(); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 90564a9652..ffcd904013 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -78,7 +78,6 @@ private: friend struct Heap::ExecutionContext; public: Heap::ExecutionContext *current; - Heap::ExecutionContext *currentContext() const { return current; } Value *jsStackTop; quint32 hasException; @@ -88,6 +87,7 @@ public: ExecutableAllocator *regExpAllocator; QScopedPointer<EvalISelFactory> iselFactory; + ExecutionContext *currentContext; Value *jsStackLimit; quintptr cStackLimit; @@ -127,7 +127,8 @@ public: QV8Engine *v8Engine; enum JSObjects { - RootContect, + RootContext, + IntegerNull, // Has to come after the RootContext to make the context stack safe ObjectProto, ArrayProto, StringProto, @@ -148,6 +149,7 @@ public: ArrayBufferProto, DataViewProto, ValueTypeProto, + SignalHandlerProto, Object_Ctor, String_Ctor, @@ -168,13 +170,14 @@ public: DataView_Ctor, Eval_Function, + GetStack_Function, ThrowerObject, NJSObjects }; Value *jsObjects; enum { NTypedArrayTypes = 9 }; // == TypedArray::NValues, avoid header dependency - GlobalContext *rootContext() const { return reinterpret_cast<GlobalContext *>(jsObjects + RootContect); } + GlobalContext *rootContext() const { return reinterpret_cast<GlobalContext *>(jsObjects + RootContext); } FunctionObject *objectCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Object_Ctor); } FunctionObject *stringCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + String_Ctor); } FunctionObject *numberCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Number_Ctor); } @@ -217,22 +220,30 @@ public: Object *typedArrayPrototype; Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); } + Object *signalHandlerPrototype() const { return reinterpret_cast<Object *>(jsObjects + SignalHandlerProto); } InternalClassPool *classPool; InternalClass *emptyClass; InternalClass *arrayClass; + InternalClass *stringClass; InternalClass *functionClass; InternalClass *simpleScriptFunctionClass; InternalClass *protoClass; InternalClass *regExpExecArrayClass; + InternalClass *regExpObjectClass; InternalClass *argumentsObjectClass; InternalClass *strictArgumentsObjectClass; + InternalClass *errorClass; + InternalClass *errorClassWithMessage; + InternalClass *errorProtoClass; + EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); } + FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); } FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); } Property *argumentsAccessors; @@ -347,9 +358,11 @@ public: void enableDebugger(); void enableProfiler(); - Heap::ExecutionContext *pushGlobalContext(); - void pushContext(CallContext *context); - Heap::ExecutionContext *popContext(); + ExecutionContext *pushGlobalContext(); + void pushContext(Heap::ExecutionContext *context); + void pushContext(ExecutionContext *context); + void popContext(); + ExecutionContext *parentContext(ExecutionContext *context) const; Heap::Object *newObject(); Heap::Object *newObject(InternalClass *internalClass, Object *prototype); @@ -362,10 +375,12 @@ public: Heap::Object *newBooleanObject(bool b); Heap::ArrayObject *newArrayObject(int count = 0); + Heap::ArrayObject *newArrayObject(const Value *values, int length); Heap::ArrayObject *newArrayObject(const QStringList &list); Heap::ArrayObject *newArrayObject(InternalClass *ic, Object *prototype); Heap::ArrayBuffer *newArrayBuffer(const QByteArray &array); + Heap::ArrayBuffer *newArrayBuffer(size_t length); Heap::DateObject *newDateObject(const Value &value); Heap::DateObject *newDateObject(const QDateTime &dt); @@ -378,7 +393,7 @@ public: Heap::Object *newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column); Heap::Object *newSyntaxErrorObject(const QString &message); Heap::Object *newReferenceErrorObject(const QString &message); - Heap::Object *newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber, int columnNumber); + Heap::Object *newReferenceErrorObject(const QString &message, const QString &fileName, int line, int column); Heap::Object *newTypeErrorObject(const QString &message); Heap::Object *newRangeErrorObject(const QString &message); Heap::Object *newURIErrorObject(const Value &message); @@ -388,7 +403,6 @@ public: Heap::Object *newForEachIteratorObject(Object *o); Heap::QmlContext *qmlContext() const; - QV4::Heap::QmlContextWrapper *qmlContextObject() const; QObject *qmlScopeObject() const; ReturnedValue qmlSingletonWrapper(String *name); QQmlContextData *callingQmlContext() const; @@ -442,36 +456,33 @@ public: void assertObjectBelongsToEngine(const Heap::Base &baseObject); }; -inline void ExecutionEngine::pushContext(CallContext *context) +inline void ExecutionEngine::pushContext(Heap::ExecutionContext *context) { - Q_ASSERT(current && context && context->d()); - context->d()->parent = current; - current = context->d(); + Q_ASSERT(currentContext && context); + Value *v = jsAlloca(2); + v[0] = Encode(context); + v[1] = Encode((int)(v - static_cast<Value *>(currentContext))); + currentContext = static_cast<ExecutionContext *>(v); + current = currentContext->d(); } -inline Heap::ExecutionContext *ExecutionEngine::popContext() +inline void ExecutionEngine::pushContext(ExecutionContext *context) { - Q_ASSERT(current->parent); - current = current->parent; - Q_ASSERT(current); - return current; + pushContext(context->d()); } -inline -Heap::ExecutionContext::ExecutionContext(ExecutionEngine *engine, ContextType t) - : engine(engine) - , parent(engine->currentContext()) - , outer(0) - , lookups(0) - , compilationUnit(0) - , type(t) - , strictMode(false) - , lineNumber(-1) + +inline void ExecutionEngine::popContext() { - engine->current = this; + Q_ASSERT(jsStackTop > currentContext); + QV4::Value *offset = (currentContext + 1); + Q_ASSERT(offset->isInteger()); + int o = offset->integerValue(); + Q_ASSERT(o); + currentContext -= o; + current = currentContext->d(); } - inline void Heap::Base::mark(QV4::ExecutionEngine *engine) { @@ -487,11 +498,12 @@ void Heap::Base::mark(QV4::ExecutionEngine *engine) inline void Value::mark(ExecutionEngine *e) { - if (!_val) + if (!isManaged()) return; - Managed *m = as<Managed>(); - if (m) - m->d()->mark(e); + + Heap::Base *o = heapObject(); + if (o) + o->mark(e); } diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index a6c2a25b91..87b7a88a2b 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -61,72 +61,49 @@ using namespace QV4; -Heap::ErrorObject::ErrorObject(InternalClass *ic, QV4::Object *prototype) - : Heap::Object(ic, prototype) - , stack(Q_NULLPTR) +Heap::ErrorObject::ErrorObject() { - Scope scope(ic->engine); + Scope scope(internalClass->engine); Scoped<QV4::ErrorObject> e(scope, this); - ScopedString s(scope, scope.engine->newString(QStringLiteral("Error"))); - e->defineDefaultProperty(QStringLiteral("name"), s); -} - -Heap::ErrorObject::ErrorObject(InternalClass *ic, QV4::Object *prototype, const Value &message, ErrorType t) - : Heap::Object(ic, prototype) -{ - errorType = t; + if (internalClass == scope.engine->errorProtoClass) + return; - Scope scope(ic->engine); - Scoped<QV4::ErrorObject> e(scope, this); - - e->defineAccessorProperty(QStringLiteral("stack"), QV4::ErrorObject::method_get_stack, 0); - - if (!message.isUndefined()) - e->defineDefaultProperty(QStringLiteral("message"), message); - ScopedString s(scope); - e->defineDefaultProperty(QStringLiteral("name"), (s = scope.engine->newString(e->className()))); - - e->d()->stackTrace = scope.engine->stackTrace(); - if (!e->d()->stackTrace.isEmpty()) { - e->defineDefaultProperty(QStringLiteral("fileName"), (s = scope.engine->newString(e->d()->stackTrace.at(0).source))); - e->defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(e->d()->stackTrace.at(0).line)); - } + *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); + *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); + *propertyData(QV4::ErrorObject::Index_FileName) = Encode::undefined(); + *propertyData(QV4::ErrorObject::Index_LineNumber) = Encode::undefined(); } -Heap::ErrorObject::ErrorObject(InternalClass *ic, QV4::Object *prototype, const QString &message, ErrorObject::ErrorType t) - : Heap::Object(ic, prototype) +Heap::ErrorObject::ErrorObject(const Value &message, ErrorType t) { errorType = t; - Scope scope(ic->engine); + Scope scope(internalClass->engine); Scoped<QV4::ErrorObject> e(scope, this); - ScopedString s(scope); - - e->defineAccessorProperty(QStringLiteral("stack"), QV4::ErrorObject::method_get_stack, 0); - ScopedValue v(scope, scope.engine->newString(message)); - e->defineDefaultProperty(QStringLiteral("message"), v); - e->defineDefaultProperty(QStringLiteral("name"), (s = scope.engine->newString(e->className()))); + *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); + *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); e->d()->stackTrace = scope.engine->stackTrace(); if (!e->d()->stackTrace.isEmpty()) { - e->defineDefaultProperty(QStringLiteral("fileName"), (s = scope.engine->newString(e->d()->stackTrace.at(0).source))); - e->defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(e->d()->stackTrace.at(0).line)); + *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace.at(0).source); + *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace.at(0).line); } + + if (!message.isUndefined()) + *propertyData(QV4::ErrorObject::Index_Message) = message; } -Heap::ErrorObject::ErrorObject(InternalClass *ic, QV4::Object *prototype, const QString &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t) - : Heap::Object(ic, prototype) +Heap::ErrorObject::ErrorObject(const Value &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t) { errorType = t; - Scope scope(ic->engine); + Scope scope(internalClass->engine); Scoped<QV4::ErrorObject> e(scope, this); - ScopedString s(scope); - e->defineAccessorProperty(QStringLiteral("stack"), QV4::ErrorObject::method_get_stack, 0); - e->defineDefaultProperty(QStringLiteral("name"), (s = scope.engine->newString(e->className()))); + *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); + *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); e->d()->stackTrace = scope.engine->stackTrace(); StackFrame frame; @@ -136,12 +113,33 @@ Heap::ErrorObject::ErrorObject(InternalClass *ic, QV4::Object *prototype, const e->d()->stackTrace.prepend(frame); if (!e->d()->stackTrace.isEmpty()) { - e->defineDefaultProperty(QStringLiteral("fileName"), (s = scope.engine->newString(e->d()->stackTrace.at(0).source))); - e->defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(e->d()->stackTrace.at(0).line)); + *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace.at(0).source); + *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace.at(0).line); } - ScopedValue v(scope, scope.engine->newString(message)); - e->defineDefaultProperty(QStringLiteral("message"), v); + if (!message.isUndefined()) + *propertyData(QV4::ErrorObject::Index_Message) = message; +} + +const char *ErrorObject::className(Heap::ErrorObject::ErrorType t) +{ + switch (t) { + case Heap::ErrorObject::Error: + return "Error"; + case Heap::ErrorObject::EvalError: + return "EvalError"; + case Heap::ErrorObject::RangeError: + return "RangeError"; + case Heap::ErrorObject::ReferenceError: + return "ReferenceError"; + case Heap::ErrorObject::SyntaxError: + return "SyntaxError"; + case Heap::ErrorObject::TypeError: + return "TypeError"; + case Heap::ErrorObject::URIError: + return "URIError"; + } + Q_UNREACHABLE(); } ReturnedValue ErrorObject::method_get_stack(CallContext *ctx) @@ -181,58 +179,43 @@ DEFINE_OBJECT_VTABLE(ErrorObject); DEFINE_OBJECT_VTABLE(SyntaxErrorObject); -Heap::SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const Value &msg) - : Heap::ErrorObject(engine->emptyClass, engine->syntaxErrorPrototype(), msg, SyntaxError) -{ -} - -Heap::SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) - : Heap::ErrorObject(engine->emptyClass, engine->syntaxErrorPrototype(), msg, fileName, lineNumber, columnNumber, SyntaxError) -{ -} - -Heap::EvalErrorObject::EvalErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->evalErrorPrototype(), message, EvalError) -{ -} - -Heap::RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->rangeErrorPrototype(), message, RangeError) +Heap::SyntaxErrorObject::SyntaxErrorObject(const Value &msg) + : Heap::ErrorObject(msg, SyntaxError) { } -Heap::RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const QString &message) - : Heap::ErrorObject(engine->emptyClass, engine->rangeErrorPrototype(), message, RangeError) +Heap::SyntaxErrorObject::SyntaxErrorObject(const Value &msg, const QString &fileName, int lineNumber, int columnNumber) + : Heap::ErrorObject(msg, fileName, lineNumber, columnNumber, SyntaxError) { } -Heap::ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype(), message, ReferenceError) +Heap::EvalErrorObject::EvalErrorObject(const Value &message) + : Heap::ErrorObject(message, EvalError) { } -Heap::ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &message) - : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype(), message, ReferenceError) +Heap::RangeErrorObject::RangeErrorObject(const Value &message) + : Heap::ErrorObject(message, RangeError) { } -Heap::ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) - : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype(), msg, fileName, lineNumber, columnNumber, ReferenceError) +Heap::ReferenceErrorObject::ReferenceErrorObject(const Value &message) + : Heap::ErrorObject(message, ReferenceError) { } -Heap::TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->typeErrorPrototype(), message, TypeError) +Heap::ReferenceErrorObject::ReferenceErrorObject(const Value &msg, const QString &fileName, int lineNumber, int columnNumber) + : Heap::ErrorObject(msg, fileName, lineNumber, columnNumber, ReferenceError) { } -Heap::TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const QString &message) - : Heap::ErrorObject(engine->emptyClass, engine->typeErrorPrototype(), message, TypeError) +Heap::TypeErrorObject::TypeErrorObject(const Value &message) + : Heap::ErrorObject(message, TypeError) { } -Heap::URIErrorObject::URIErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->uRIErrorPrototype(), message, URIError) +Heap::URIErrorObject::URIErrorObject(const Value &message) + : Heap::ErrorObject(message, URIError) { } @@ -258,7 +241,7 @@ ReturnedValue ErrorCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const ErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return Encode(scope.engine->newErrorObject(v)); + return ErrorObject::create<ErrorObject>(scope.engine, v)->asReturnedValue(); } ReturnedValue ErrorCtor::call(const Managed *that, CallData *callData) @@ -275,7 +258,7 @@ ReturnedValue EvalErrorCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const EvalErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return (scope.engine->memoryManager->alloc<EvalErrorObject>(scope.engine, v))->asReturnedValue(); + return ErrorObject::create<EvalErrorObject>(scope.engine, v)->asReturnedValue(); } Heap::RangeErrorCtor::RangeErrorCtor(QV4::ExecutionContext *scope) @@ -287,7 +270,7 @@ ReturnedValue RangeErrorCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const RangeErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return (scope.engine->memoryManager->alloc<RangeErrorObject>(scope.engine, v))->asReturnedValue(); + return ErrorObject::create<RangeErrorObject>(scope.engine, v)->asReturnedValue(); } Heap::ReferenceErrorCtor::ReferenceErrorCtor(QV4::ExecutionContext *scope) @@ -299,7 +282,7 @@ ReturnedValue ReferenceErrorCtor::construct(const Managed *m, CallData *callData { Scope scope(static_cast<const ReferenceErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return (scope.engine->memoryManager->alloc<ReferenceErrorObject>(scope.engine, v))->asReturnedValue(); + return ErrorObject::create<ReferenceErrorObject>(scope.engine, v)->asReturnedValue(); } Heap::SyntaxErrorCtor::SyntaxErrorCtor(QV4::ExecutionContext *scope) @@ -311,7 +294,7 @@ ReturnedValue SyntaxErrorCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const SyntaxErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return (scope.engine->memoryManager->alloc<SyntaxErrorObject>(scope.engine, v))->asReturnedValue(); + return ErrorObject::create<SyntaxErrorObject>(scope.engine, v)->asReturnedValue(); } Heap::TypeErrorCtor::TypeErrorCtor(QV4::ExecutionContext *scope) @@ -323,7 +306,7 @@ ReturnedValue TypeErrorCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const TypeErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return (scope.engine->memoryManager->alloc<TypeErrorObject>(scope.engine, v))->asReturnedValue(); + return ErrorObject::create<TypeErrorObject>(scope.engine, v)->asReturnedValue(); } Heap::URIErrorCtor::URIErrorCtor(QV4::ExecutionContext *scope) @@ -335,19 +318,21 @@ ReturnedValue URIErrorCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const URIErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return (scope.engine->memoryManager->alloc<URIErrorObject>(scope.engine, v))->asReturnedValue(); + return ErrorObject::create<URIErrorObject>(scope.engine, v)->asReturnedValue(); } -void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj) +void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t) { Scope scope(engine); ScopedString s(scope); ScopedObject o(scope); ctor->defineReadonlyProperty(engine->id_prototype(), (o = obj)); ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); - obj->defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - obj->defineDefaultProperty(engine->id_toString(), method_toString, 0); - obj->defineDefaultProperty(QStringLiteral("message"), (s = engine->newString())); + *obj->propertyData(Index_Constructor) = ctor; + *obj->propertyData(Index_Message) = engine->id_empty(); + *obj->propertyData(Index_Name) = engine->newString(QString::fromLatin1(ErrorObject::className(t))); + if (t == Heap::ErrorObject::Error) + obj->defineDefaultProperty(engine->id_toString(), method_toString, 0); } ReturnedValue ErrorPrototype::method_toString(CallContext *ctx) diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index e0fbcb4d8d..7f3babaa79 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -35,6 +35,7 @@ #include "qv4object_p.h" #include "qv4functionobject_p.h" +#include "qv4string_p.h" QT_BEGIN_NAMESPACE @@ -55,10 +56,9 @@ struct ErrorObject : Object { URIError }; - ErrorObject(InternalClass *ic, QV4::Object *prototype); - ErrorObject(InternalClass *ic, QV4::Object *prototype, const Value &message, ErrorType t = Error); - ErrorObject(InternalClass *ic, QV4::Object *prototype, const QString &message, ErrorType t = Error); - ErrorObject(InternalClass *ic, QV4::Object *prototype, const QString &message, const QString &fileName, int line, int column, ErrorType t = Error); + ErrorObject(); + ErrorObject(const Value &message, ErrorType t = Error); + ErrorObject(const Value &message, const QString &fileName, int line, int column, ErrorType t = Error); ErrorType errorType; StackTrace stackTrace; @@ -66,32 +66,29 @@ struct ErrorObject : Object { }; struct EvalErrorObject : ErrorObject { - EvalErrorObject(ExecutionEngine *engine, const Value &message); + EvalErrorObject(const Value &message); }; struct RangeErrorObject : ErrorObject { - RangeErrorObject(ExecutionEngine *engine, const Value &message); - RangeErrorObject(ExecutionEngine *engine, const QString &msg); + RangeErrorObject(const Value &message); }; struct ReferenceErrorObject : ErrorObject { - ReferenceErrorObject(ExecutionEngine *engine, const Value &message); - ReferenceErrorObject(ExecutionEngine *engine, const QString &msg); - ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber); + ReferenceErrorObject(const Value &message); + ReferenceErrorObject(const Value &msg, const QString &fileName, int lineNumber, int columnNumber); }; struct SyntaxErrorObject : ErrorObject { - SyntaxErrorObject(ExecutionEngine *engine, const Value &message); - SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber); + SyntaxErrorObject(const Value &message); + SyntaxErrorObject(const Value &msg, const QString &fileName, int lineNumber, int columnNumber); }; struct TypeErrorObject : ErrorObject { - TypeErrorObject(ExecutionEngine *engine, const Value &message); - TypeErrorObject(ExecutionEngine *engine, const QString &msg); + TypeErrorObject(const Value &message); }; struct URIErrorObject : ErrorObject { - URIErrorObject(ExecutionEngine *engine, const Value &message); + URIErrorObject(const Value &message); }; struct ErrorCtor : Heap::FunctionObject { @@ -130,12 +127,30 @@ struct ErrorObject: Object { IsErrorObject = true }; + enum { + Index_Stack = 0, // Accessor Property + Index_FileName = 2, + Index_LineNumber = 3, + Index_Message = 4 + }; + V4_OBJECT2(ErrorObject, Object) Q_MANAGED_TYPE(ErrorObject) + V4_INTERNALCLASS(errorClass) + V4_PROTOTYPE(errorPrototype) V4_NEEDS_DESTROY + template <typename T> + static Heap::Object *create(ExecutionEngine *e, const Value &message); + template <typename T> + static Heap::Object *create(ExecutionEngine *e, const QString &message); + template <typename T> + static Heap::Object *create(ExecutionEngine *e, const QString &message, const QString &filename, int line, int column); + SyntaxErrorObject *asSyntaxError(); + static const char *className(Heap::ErrorObject::ErrorType t); + static ReturnedValue method_get_stack(CallContext *ctx); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; @@ -147,34 +162,40 @@ inline const ErrorObject *Value::as() const { struct EvalErrorObject: ErrorObject { typedef Heap::EvalErrorObject Data; + V4_PROTOTYPE(evalErrorPrototype) const Data *d() const { return static_cast<const Data *>(ErrorObject::d()); } Data *d() { return static_cast<Data *>(ErrorObject::d()); } }; struct RangeErrorObject: ErrorObject { typedef Heap::RangeErrorObject Data; + V4_PROTOTYPE(rangeErrorPrototype) const Data *d() const { return static_cast<const Data *>(ErrorObject::d()); } Data *d() { return static_cast<Data *>(ErrorObject::d()); } }; struct ReferenceErrorObject: ErrorObject { typedef Heap::ReferenceErrorObject Data; + V4_PROTOTYPE(referenceErrorPrototype) const Data *d() const { return static_cast<const Data *>(ErrorObject::d()); } Data *d() { return static_cast<Data *>(ErrorObject::d()); } }; struct SyntaxErrorObject: ErrorObject { V4_OBJECT2(SyntaxErrorObject, ErrorObject) + V4_PROTOTYPE(syntaxErrorPrototype) }; struct TypeErrorObject: ErrorObject { typedef Heap::TypeErrorObject Data; + V4_PROTOTYPE(typeErrorPrototype) const Data *d() const { return static_cast<const Data *>(ErrorObject::d()); } Data *d() { return static_cast<Data *>(ErrorObject::d()); } }; struct URIErrorObject: ErrorObject { typedef Heap::URIErrorObject Data; + V4_PROTOTYPE(uRIErrorPrototype) const Data *d() const { return static_cast<const Data *>(ErrorObject::d()); } Data *d() { return static_cast<Data *>(ErrorObject::d()); } }; @@ -232,40 +253,45 @@ struct URIErrorCtor: ErrorCtor struct ErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { init(engine, ctor, this); } + enum { + Index_Constructor = 0, + Index_Message = 1, + Index_Name = 2 + }; + void init(ExecutionEngine *engine, Object *ctor) { init(engine, ctor, this, Heap::ErrorObject::Error); } - static void init(ExecutionEngine *engine, Object *ctor, Object *obj); + static void init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t); static ReturnedValue method_toString(CallContext *ctx); }; struct EvalErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this, Heap::ErrorObject::EvalError); } }; struct RangeErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this, Heap::ErrorObject::RangeError); } }; struct ReferenceErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this, Heap::ErrorObject::ReferenceError); } }; struct SyntaxErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this, Heap::ErrorObject::SyntaxError); } }; struct TypeErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this, Heap::ErrorObject::TypeError); } }; struct URIErrorPrototype : ErrorObject { - void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this, Heap::ErrorObject::URIError); } }; @@ -274,6 +300,25 @@ inline SyntaxErrorObject *ErrorObject::asSyntaxError() return d()->errorType == QV4::Heap::ErrorObject::SyntaxError ? static_cast<SyntaxErrorObject *>(this) : 0; } + +template <typename T> +Heap::Object *ErrorObject::create(ExecutionEngine *e, const Value &message) { + return e->memoryManager->allocObject<T>(message.isUndefined() ? e->errorClass : e->errorClassWithMessage, T::defaultPrototype(e), message); +} +template <typename T> +Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message) { + Scope scope(e); + ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue()); + return e->memoryManager->allocObject<T>(v->isUndefined() ? e->errorClass : e->errorClassWithMessage, T::defaultPrototype(e), v); +} +template <typename T> +Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message, const QString &filename, int line, int column) { + Scope scope(e); + ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue()); + return e->memoryManager->allocObject<T>(v->isUndefined() ? e->errorClass : e->errorClassWithMessage, T::defaultPrototype(e), v, filename, line, column); +} + + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 98a4490211..66b2125a4f 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -70,14 +70,45 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, arg = mm->alloc<String>(mm, arg->d(), engine->newString(QString(0xfffe))); } } + nFormals = compiledFunction->nFormals; const quint32 *localsIndices = compiledFunction->localsTable(); for (quint32 i = 0; i < compiledFunction->nLocals; ++i) internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); + + activationRequired = compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject)); } Function::~Function() { } +void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> ¶meters) +{ + internalClass = engine->emptyClass; + + // iterate backwards, so we get the right ordering for duplicate names + Scope scope(engine); + ScopedString arg(scope); + for (int i = parameters.size() - 1; i >= 0; --i) { + arg = engine->newString(QString::fromUtf8(parameters.at(i))); + while (1) { + InternalClass *newClass = internalClass->addMember(arg, Attr_NotConfigurable); + if (newClass != internalClass) { + internalClass = newClass; + break; + } + // duplicate arguments, need some trick to store them + arg = engine->memoryManager->alloc<String>(engine->memoryManager, arg->d(), engine->newString(QString(0xfffe))); + } + } + nFormals = parameters.size(); + + const quint32 *localsIndices = compiledFunction->localsTable(); + for (quint32 i = 0; i < compiledFunction->nLocals; ++i) + internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); + + activationRequired = true; +} + QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 10a03bca94..534aa1b750 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -49,11 +49,16 @@ struct Q_QML_EXPORT Function { // first nArguments names in internalClass are the actual arguments InternalClass *internalClass; + uint nFormals; + bool activationRequired; Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function, ReturnedValue (*codePtr)(ExecutionEngine *, const uchar *)); ~Function(); + // used when dynamically assigning signal handlers (QQmlConnection) + void updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> ¶meters); + inline Heap::String *name() { return compilationUnit->runtimeStrings[compiledFunction->nameIndex]; } @@ -64,7 +69,7 @@ struct Q_QML_EXPORT Function { inline bool isNamedExpression() const { return compiledFunction->flags & CompiledData::Function::IsNamedExpression; } inline bool needsActivation() const - { return compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject)); } + { return activationRequired; } }; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 6412e65fa9..a94c3f6db5 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -63,8 +63,7 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(FunctionObject); Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, QV4::String *name, bool createProto) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) - , scope(scope->d()) + : scope(scope->d()) , function(Q_NULLPTR) { Scope s(scope->engine()); @@ -73,8 +72,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, QV4::String * } Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, Function *function, bool createProto) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) - , scope(scope->d()) + : scope(scope->d()) , function(Q_NULLPTR) { Scope s(scope->engine()); @@ -84,8 +82,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, Function *fun } Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const QString &name, bool createProto) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) - , scope(scope->d()) + : scope(scope->d()) , function(Q_NULLPTR) { Scope s(scope->engine()); @@ -95,8 +92,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const QString } Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto) - : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype()) - , scope(scope) + : scope(scope) , function(Q_NULLPTR) { Scope s(scope->engine); @@ -106,8 +102,7 @@ Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const QString &nam } Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const ReturnedValue name) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) - , scope(scope->d()) + : scope(scope->d()) , function(Q_NULLPTR) { Scope s(scope); @@ -117,8 +112,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const Returne } Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValue name) - : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype()) - , scope(scope) + : scope(scope) , function(Q_NULLPTR) { Scope s(scope->engine); @@ -127,15 +121,12 @@ Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValu f->init(n, false); } -Heap::FunctionObject::FunctionObject(InternalClass *ic, QV4::Object *prototype) - : Heap::Object(ic, prototype) - , scope(ic->engine->rootContext()->d()) +Heap::FunctionObject::FunctionObject() + : scope(internalClass->engine->rootContext()->d()) , function(Q_NULLPTR) { - Scope scope(ic->engine); - ScopedObject o(scope, this); - o->ensureMemberIndex(ic->engine, Index_Prototype); - memberData->data[Index_Prototype] = Encode::undefined(); + Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype); + *propertyData(Index_Prototype) = Encode::undefined(); } @@ -150,14 +141,14 @@ void FunctionObject::init(String *n, bool createProto) Scope s(internalClass()->engine); ScopedValue protectThis(s, this); - ensureMemberIndex(s.engine, Heap::FunctionObject::Index_Prototype); + Q_ASSERT(internalClass() && internalClass()->find(s.engine->id_prototype()) == Heap::FunctionObject::Index_Prototype); if (createProto) { ScopedObject proto(s, scope()->engine->newObject(s.engine->protoClass, s.engine->objectPrototype())); - proto->ensureMemberIndex(s.engine, Heap::FunctionObject::Index_ProtoConstructor); - proto->memberData()->data[Heap::FunctionObject::Index_ProtoConstructor] = this->asReturnedValue(); - memberData()->data[Heap::FunctionObject::Index_Prototype] = proto.asReturnedValue(); + Q_ASSERT(s.engine->protoClass->find(s.engine->id_constructor()) == Heap::FunctionObject::Index_ProtoConstructor); + *proto->propertyData(Heap::FunctionObject::Index_ProtoConstructor) = this->asReturnedValue(); + *propertyData(Heap::FunctionObject::Index_Prototype) = proto.asReturnedValue(); } else { - memberData()->data[Heap::FunctionObject::Index_Prototype] = Encode::undefined(); + *propertyData(Heap::FunctionObject::Index_Prototype) = Encode::undefined(); } ScopedValue v(s, n); @@ -202,10 +193,28 @@ Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *sco function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith || function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount || function->isNamedExpression()) - return scope->d()->engine->memoryManager->alloc<ScriptFunction>(scope, function); - return scope->d()->engine->memoryManager->alloc<SimpleScriptFunction>(scope, function, createProto); + return scope->d()->engine->memoryManager->allocObject<ScriptFunction>(scope, function); + return scope->d()->engine->memoryManager->allocObject<SimpleScriptFunction>(scope, function, createProto); } +Heap::FunctionObject *FunctionObject::createQmlFunction(QQmlContextData *qmlContext, QObject *scopeObject, Function *runtimeFunction, const QList<QByteArray> &signalParameters, QString *error) +{ + ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine); + QV4::Scope valueScope(engine); + ExecutionContext *global = valueScope.engine->rootContext(); + QV4::Scoped<QmlContext> wrapperContext(valueScope, global->newQmlContext(qmlContext, scopeObject)); + + if (!signalParameters.isEmpty()) { + if (error) + QQmlPropertyCache::signalParameterStringForJS(engine, signalParameters, error); + runtimeFunction->updateInternalClass(engine, signalParameters); + } + + QV4::ScopedFunctionObject function(valueScope, QV4::FunctionObject::createScriptFunction(wrapperContext, runtimeFunction)); + return function->d(); +} + + bool FunctionObject::isBinding() const { return d()->vtable() == QQmlBindingFunction::staticVTable(); @@ -240,7 +249,7 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) { Scope scope(static_cast<const Object *>(that)->engine()); Scoped<FunctionCtor> f(scope, static_cast<const FunctionCtor *>(that)); - ScopedContext ctx(scope, scope.engine->currentContext()); + QString arguments; QString body; if (callData->argc > 0) { @@ -251,7 +260,7 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) } body = callData->args[callData->argc - 1].toQString(); } - if (ctx->d()->engine->hasException) + if (scope.engine->hasException) return Encode::undefined(); QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1String("}"); @@ -281,7 +290,7 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit = isel->compile(); Function *vmf = compilationUnit->linkToEngine(scope.engine); - ScopedContext global(scope, scope.engine->rootContext()); + ExecutionContext *global = scope.engine->rootContext(); return FunctionObject::createScriptFunction(global, vmf)->asReturnedValue(); } @@ -293,8 +302,7 @@ ReturnedValue FunctionCtor::call(const Managed *that, CallData *callData) DEFINE_OBJECT_VTABLE(FunctionPrototype); -Heap::FunctionPrototype::FunctionPrototype(InternalClass *ic, QV4::Object *prototype) - : Heap::FunctionObject(ic, prototype) +Heap::FunctionPrototype::FunctionPrototype() { } @@ -392,12 +400,12 @@ ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) ScopedValue boundThis(scope, ctx->argument(0)); Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0); if (ctx->argc() > 1) { - boundArgs = MemberData::reallocate(scope.engine, 0, ctx->argc() - 1); + boundArgs = MemberData::allocate(scope.engine, ctx->argc() - 1); boundArgs->d()->size = ctx->argc() - 1; memcpy(boundArgs->data(), ctx->args() + 1, (ctx->argc() - 1)*sizeof(Value)); } - ScopedContext global(scope, scope.engine->rootContext()); + ExecutionContext *global = scope.engine->rootContext(); return BoundFunction::create(global, target, boundThis, boundArgs)->asReturnedValue(); } @@ -416,17 +424,18 @@ ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData) CHECK_STACK_LIMITS(v4); Scope scope(v4); + ExecutionContextSaver ctxSaver(scope); + Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); InternalClass *ic = scope.engine->emptyClass; ScopedObject proto(scope, f->protoForConstructor()); ScopedObject obj(scope, v4->newObject(ic, proto)); - ScopedContext context(scope, v4->currentContext()); callData->thisObject = obj.asReturnedValue(); - Scoped<CallContext> ctx(scope, context->newCallContext(f, callData)); + Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData)); + v4->pushContext(ctx); - ExecutionContextSaver ctxSaver(scope, context); ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); if (f->function()->compiledFunction->hasQmlDependencies()) @@ -448,12 +457,12 @@ ReturnedValue ScriptFunction::call(const Managed *that, CallData *callData) CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); - ScopedContext context(scope, v4->currentContext()); + ExecutionContextSaver ctxSaver(scope); - Scoped<CallContext> ctx(scope, context->newCallContext(f, callData)); + Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); + Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData)); + v4->pushContext(ctx); - ExecutionContextSaver ctxSaver(scope, context); ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); if (f->function()->compiledFunction->hasQmlDependencies()) @@ -465,7 +474,6 @@ ReturnedValue ScriptFunction::call(const Managed *that, CallData *callData) DEFINE_OBJECT_VTABLE(SimpleScriptFunction); Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, Function *function, bool createProto) - : Heap::FunctionObject(function->compilationUnit->engine->simpleScriptFunctionClass, function->compilationUnit->engine->functionPrototype()) { this->scope = scope->d(); @@ -482,9 +490,10 @@ Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, F f->init(name, createProto); f->defineReadonlyProperty(scope->d()->engine->id_length(), Primitive::fromInt32(f->formalParameterCount())); } else { - f->ensureMemberIndex(s.engine, Index_Length); - memberData->data[Index_Name] = function->name(); - memberData->data[Index_Length] = Primitive::fromInt32(f->formalParameterCount()); + Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()) == Index_Length); + Q_ASSERT(internalClass && internalClass->find(s.engine->id_name()) == Index_Name); + *propertyData(Index_Name) = function->name(); + *propertyData(Index_Length) = Primitive::fromInt32(f->formalParameterCount()); } if (scope->d()->strictMode) { @@ -504,14 +513,14 @@ ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *cal CHECK_STACK_LIMITS(v4); Scope scope(v4); + ExecutionContextSaver ctxSaver(scope); + Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); InternalClass *ic = scope.engine->emptyClass; ScopedObject proto(scope, f->protoForConstructor()); callData->thisObject = v4->newObject(ic, proto); - ExecutionContextSaver ctxSaver(scope, v4->currentContext()); - CallContext::Data ctx(v4); #ifndef QT_NO_DEBUG ctx.mm_data = 0; // make sure we don't run into the assertion in setVTable when allocating a context on the stack @@ -526,7 +535,8 @@ ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *cal ctx.locals = scope.alloc(f->varCount()); for (int i = callData->argc; i < (int)f->formalParameterCount(); ++i) callData->args[i] = Encode::undefined(); - Q_ASSERT(v4->currentContext() == &ctx); + v4->pushContext(&ctx); + Q_ASSERT(v4->current == &ctx); ScopedObject result(scope, Q_V4_PROFILE(v4, f->function())); @@ -546,9 +556,9 @@ ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); + ExecutionContextSaver ctxSaver(scope); - ExecutionContextSaver ctxSaver(scope, v4->currentContext()); + Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); CallContext::Data ctx(v4); #ifndef QT_NO_DEBUG @@ -564,7 +574,8 @@ ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData ctx.locals = scope.alloc(f->varCount()); for (int i = callData->argc; i < (int)f->formalParameterCount(); ++i) callData->args[i] = Encode::undefined(); - Q_ASSERT(v4->currentContext() == &ctx); + v4->pushContext(&ctx); + Q_ASSERT(v4->current == &ctx); ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); @@ -607,7 +618,7 @@ ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData) CHECK_STACK_LIMITS(v4); Scope scope(v4); - ExecutionContextSaver ctxSaver(scope, v4->currentContext()); + ExecutionContextSaver ctxSaver(scope); CallContext::Data ctx(v4); #ifndef QT_NO_DEBUG @@ -616,10 +627,10 @@ ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData) ctx.setVtable(CallContext::staticVTable()); ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context? ctx.callData = callData; - Q_ASSERT(v4->currentContext() == &ctx); - Scoped<CallContext> sctx(scope, &ctx); + v4->pushContext(&ctx); + Q_ASSERT(v4->current == &ctx); - return f->d()->code(sctx); + return f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext)); } ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callData) @@ -631,7 +642,7 @@ ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callDa CHECK_STACK_LIMITS(v4); Scope scope(v4); - ExecutionContextSaver ctxSaver(scope, v4->currentContext()); + ExecutionContextSaver ctxSaver(scope); CallContext::Data ctx(v4); #ifndef QT_NO_DEBUG @@ -640,10 +651,10 @@ ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callDa ctx.setVtable(CallContext::staticVTable()); ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context? ctx.callData = callData; - Q_ASSERT(v4->currentContext() == &ctx); - Scoped<CallContext> sctx(scope, &ctx); + v4->pushContext(&ctx); + Q_ASSERT(v4->current == &ctx); - return f->d()->code(sctx, f->d()->index); + return f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index); } DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 2c6a195746..182f06f74e 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -58,10 +58,10 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { FunctionObject(ExecutionContext *scope, const QString &name = QString(), bool createProto = false); FunctionObject(QV4::ExecutionContext *scope, const ReturnedValue name); FunctionObject(ExecutionContext *scope, const ReturnedValue name); - FunctionObject(InternalClass *ic, QV4::Object *prototype); + FunctionObject(); ~FunctionObject(); - unsigned int formalParameterCount() { return function ? function->compiledFunction->nFormals : 0; } + unsigned int formalParameterCount() { return function ? function->nFormals : 0; } unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } bool needsActivation() const { return function ? function->needsActivation() : false; } @@ -74,7 +74,7 @@ struct FunctionCtor : FunctionObject { }; struct FunctionPrototype : FunctionObject { - FunctionPrototype(InternalClass *ic, QV4::Object *prototype); + FunctionPrototype(); }; struct Q_QML_EXPORT BuiltinFunction : FunctionObject { @@ -115,6 +115,8 @@ struct Q_QML_EXPORT FunctionObject: Object { }; V4_OBJECT2(FunctionObject, Object) Q_MANAGED_TYPE(FunctionObject) + V4_INTERNALCLASS(functionClass) + V4_PROTOTYPE(functionPrototype) V4_NEEDS_DESTROY Heap::ExecutionContext *scope() const { return d()->scope; } @@ -134,8 +136,10 @@ struct Q_QML_EXPORT FunctionObject: Object { static ReturnedValue call(const Managed *that, CallData *d); static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true); + static Heap::FunctionObject *createQmlFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, + const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0); - ReturnedValue protoProperty() { return memberData()->data[Heap::FunctionObject::Index_Prototype].asReturnedValue(); } + ReturnedValue protoProperty() { return propertyData(Heap::FunctionObject::Index_Prototype)->asReturnedValue(); } bool needsActivation() const { return d()->needsActivation(); } bool strictMode() const { return d()->function ? d()->function->isStrict() : false; } @@ -178,7 +182,7 @@ struct Q_QML_EXPORT BuiltinFunction: FunctionObject { static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) { - return scope->engine()->memoryManager->alloc<BuiltinFunction>(scope, name, code); + return scope->engine()->memoryManager->allocObject<BuiltinFunction>(scope, name, code); } static ReturnedValue construct(const Managed *, CallData *); @@ -208,6 +212,7 @@ Heap::IndexedBuiltinFunction::IndexedBuiltinFunction(QV4::ExecutionContext *scop struct SimpleScriptFunction: FunctionObject { V4_OBJECT2(SimpleScriptFunction, FunctionObject) + V4_INTERNALCLASS(simpleScriptFunctionClass) static ReturnedValue construct(const Managed *, CallData *callData); static ReturnedValue call(const Managed *that, CallData *callData); @@ -228,7 +233,7 @@ struct BoundFunction: FunctionObject { static Heap::BoundFunction *create(ExecutionContext *scope, FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs) { - return scope->engine()->memoryManager->alloc<BoundFunction>(scope, target, boundThis, boundArgs); + return scope->engine()->memoryManager->allocObject<BoundFunction>(scope, target, boundThis, boundArgs); } Heap::FunctionObject *target() const { return d()->target; } diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index ec7b9b3f7d..110a2c9089 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -339,11 +339,10 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const ExecutionEngine *v4 = engine(); Scope scope(v4); + ExecutionContextSaver ctxSaver(scope); - ScopedContext parentContext(scope, v4->currentContext()); - ExecutionContextSaver ctxSaver(scope, parentContext); - - ScopedContext ctx(scope, parentContext.getPointer()); + ExecutionContext *currentContext = v4->currentContext; + ExecutionContext *ctx = currentContext; if (!directCall) { // the context for eval should be the global scope, so we fake a root @@ -358,10 +357,10 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const bool inheritContext = !ctx->d()->strictMode; Script script(ctx, code, QStringLiteral("eval code")); - script.strictMode = (directCall && parentContext->d()->strictMode); + script.strictMode = (directCall && currentContext->d()->strictMode); script.inheritContext = inheritContext; script.parse(); - if (scope.engine->hasException) + if (v4->hasException) return Encode::undefined(); Function *function = script.function(); diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index 138d76bf4a..a5336ee44f 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -149,6 +149,22 @@ Identifier *IdentifierTable::identifierImpl(const Heap::String *str) return str->identifier; } +Heap::String *IdentifierTable::stringFromIdentifier(Identifier *i) +{ + if (!i) + return 0; + + uint idx = i->hashValue % alloc; + while (1) { + Heap::String *e = entries[idx]; + Q_ASSERT(e); + if (e->identifier == i) + return e; + ++idx; + idx %= alloc; + } +} + Identifier *IdentifierTable::identifier(const QString &s) { return insertString(s)->identifier; diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h index 58f808b4d5..d91ce623c1 100644 --- a/src/qml/jsruntime/qv4identifiertable_p.h +++ b/src/qml/jsruntime/qv4identifiertable_p.h @@ -74,6 +74,8 @@ public: Identifier *identifierImpl(const Heap::String *str); + Heap::String *stringFromIdentifier(Identifier *i); + void mark(ExecutionEngine *e) { for (int i = 0; i < alloc; ++i) { Heap::String *entry = entries[i]; diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 2eb61081c7..90c6738c46 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -49,11 +49,12 @@ QT_BEGIN_NAMESPACE -QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QQmlContextData *context, - const QV4::Value &qmlglobal, const QV4::Value &callback) - : v4(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0), m_context(context) +QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, + QV4::QmlContext *qmlContext, const QV4::Value &callback) + : v4(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0) { - m_qmlglobal.set(engine, qmlglobal); + if (qmlContext) + m_qmlContext.set(engine, *qmlContext); if (callback.as<QV4::FunctionObject>()) m_callbackFunction.set(engine, callback); @@ -142,8 +143,8 @@ void QV4Include::finished() QString code = QString::fromUtf8(data); QmlIR::Document::removeScriptPragmas(code); - QV4::ScopedObject qmlglobal(scope, m_qmlglobal.value()); - QV4::Script script(v4, qmlglobal, code, m_url.toString()); + QV4::Scoped<QV4::QmlContext> qml(scope, m_qmlContext.value()); + QV4::Script script(v4, qml, code, m_url.toString()); script.parse(); if (!scope.engine->hasException) @@ -190,12 +191,10 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) QString localFile = QQmlFile::urlToLocalFileOrQrc(url); QV4::ScopedValue result(scope); - QV4::ScopedObject qmlcontextobject(scope, scope.engine->qmlContextObject()); + QV4::Scoped<QV4::QmlContext> qmlcontext(scope, scope.engine->qmlContext()); if (localFile.isEmpty()) { - QV4Include *i = new QV4Include(url, scope.engine, context, - qmlcontextobject, - callbackFunction); + QV4Include *i = new QV4Include(url, scope.engine, qmlcontext, callbackFunction); result = i->result(); } else { @@ -203,7 +202,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) if (const QQmlPrivate::CachedQmlUnit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url)) { QV4::CompiledData::CompilationUnit *jsUnit = cachedUnit->createCompilationUnit(); - script.reset(new QV4::Script(scope.engine, qmlcontextobject, jsUnit)); + script.reset(new QV4::Script(scope.engine, qmlcontext, jsUnit)); } else { QFile f(localFile); @@ -212,7 +211,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) QString code = QString::fromUtf8(data); QmlIR::Document::removeScriptPragmas(code); - script.reset(new QV4::Script(scope.engine, qmlcontextobject, code, url.toString())); + script.reset(new QV4::Script(scope.engine, qmlcontext, code, url.toString())); } } diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h index 5ef4442b03..3e3cf5e770 100644 --- a/src/qml/jsruntime/qv4include_p.h +++ b/src/qml/jsruntime/qv4include_p.h @@ -76,8 +76,7 @@ private Q_SLOTS: void finished(); private: - QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QQmlContextData *context, - const QV4::Value &qmlglobal, const QV4::Value &callback); + QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &callback); ~QV4Include(); QV4::ReturnedValue result(); @@ -95,8 +94,7 @@ private: QV4::PersistentValue m_callbackFunction; QV4::PersistentValue m_resultObject; - QQmlGuardedContextData m_context; - QV4::PersistentValue m_qmlglobal; + QV4::PersistentValue m_qmlContext; }; QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index a90e8e3689..8f0b1776d7 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -134,21 +134,64 @@ InternalClass::InternalClass(const QV4::InternalClass &other) Q_ASSERT(extensible); } +static void insertHoleIntoPropertyData(Object *object, int idx) +{ + int inlineSize = object->d()->inlineMemberSize; + int icSize = object->internalClass()->size; + int from = qMax(idx, inlineSize); + int to = from + 1; + if (from < icSize) + memmove(object->propertyData(to), object->propertyData(from), icSize - from - 1); + if (from == idx) + return; + if (inlineSize < icSize) + *object->propertyData(inlineSize) = *object->propertyData(inlineSize - 1); + from = idx; + to = from + 1; + if (from < inlineSize - 1) + memmove(object->propertyData(to), object->propertyData(from), inlineSize - from - 1); +} + +static void removeFromPropertyData(Object *object, int idx, bool accessor = false) +{ + int inlineSize = object->d()->inlineMemberSize; + int icSize = object->internalClass()->size; + int delta = (accessor ? 2 : 1); + int to = idx; + int from = to + delta; + if (from < inlineSize) { + memmove(object->propertyData(to), object->d()->propertyData(from), (inlineSize - from)*sizeof(Value)); + to = inlineSize - delta; + from = inlineSize; + } + if (to < inlineSize && from < icSize) { + Q_ASSERT(from >= inlineSize); + memcpy(object->propertyData(to), object->d()->propertyData(from), (inlineSize - to)*sizeof(Value)); + to = inlineSize; + from = inlineSize + delta; + } + if (from < icSize + delta) { + Q_ASSERT(to >= inlineSize && from > to); + memmove(object->propertyData(to), object->d()->propertyData(from), (icSize + delta - to)*sizeof(Value)); + } +} + void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index) { uint idx; - InternalClass *newClass = object->internalClass()->changeMember(string->identifier(), data, &idx); + InternalClass *oldClass = object->internalClass(); + InternalClass *newClass = oldClass->changeMember(string->identifier(), data, &idx); if (index) *index = idx; - if (newClass->size > object->internalClass()->size) { - Q_ASSERT(newClass->size == object->internalClass()->size + 1); - memmove(object->memberData()->data + idx + 2, object->memberData()->data + idx + 1, (object->internalClass()->size - idx - 1)*sizeof(Value)); - } else if (newClass->size < object->internalClass()->size) { - Q_ASSERT(newClass->size == object->internalClass()->size - 1); - memmove(object->memberData()->data + idx + 1, object->memberData()->data + idx + 2, (object->internalClass()->size - idx - 2)*sizeof(Value)); - } object->setInternalClass(newClass); + if (newClass->size > oldClass->size) { + Q_ASSERT(newClass->size == oldClass->size + 1); + insertHoleIntoPropertyData(object, idx + 1); + } else if (newClass->size < oldClass->size) { + Q_ASSERT(newClass->size == oldClass->size - 1); + removeFromPropertyData(object, idx + 1); + } } InternalClassTransition &InternalClass::lookupOrInsertTransition(const InternalClassTransition &t) @@ -286,6 +329,8 @@ void InternalClass::removeMember(Object *object, Identifier *id) Transition temp = { id, 0, -1 }; Transition &t = object->internalClass()->lookupOrInsertTransition(temp); + bool accessor = oldClass->propertyData.at(propIdx).isAccessor(); + if (t.lookup) { object->setInternalClass(t.lookup); } else { @@ -300,8 +345,10 @@ void InternalClass::removeMember(Object *object, Identifier *id) object->setInternalClass(newClass); } - // remove the entry in memberdata - memmove(object->memberData()->data + propIdx, object->memberData()->data + propIdx + 1, (object->internalClass()->size - propIdx)*sizeof(Value)); + Q_ASSERT(object->internalClass()->size == oldClass->size - (accessor ? 2 : 1)); + + // remove the entry in the property data + removeFromPropertyData(object, propIdx, accessor); t.lookup = object->internalClass(); Q_ASSERT(t.lookup); @@ -352,20 +399,26 @@ InternalClass *InternalClass::frozen() if (m_frozen) return m_frozen; - m_frozen = engine->emptyClass; + m_frozen = propertiesFrozen(); + m_frozen = m_frozen->nonExtensible(); + + m_frozen->m_frozen = m_frozen; + m_frozen->m_sealed = m_frozen; + return m_frozen; +} + +InternalClass *InternalClass::propertiesFrozen() const +{ + InternalClass *frozen = engine->emptyClass; for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (attrs.isEmpty()) continue; attrs.setWritable(false); attrs.setConfigurable(false); - m_frozen = m_frozen->addMember(nameMap.at(i), attrs); + frozen = frozen->addMember(nameMap.at(i), attrs); } - m_frozen = m_frozen->nonExtensible(); - - m_frozen->m_frozen = m_frozen; - m_frozen->m_sealed = m_frozen; - return m_frozen; + return frozen; } void InternalClass::destroy() diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 80590fe72e..342870fcd6 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -233,6 +233,7 @@ struct InternalClass : public QQmlJS::Managed { InternalClass *sealed(); InternalClass *frozen(); + InternalClass *propertiesFrozen() const; void destroy(); diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index f703e85399..f4f87f3aea 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -858,10 +858,9 @@ QString Stringify::JA(ArrayObject *a) } -Heap::JsonObject::JsonObject(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->objectPrototype()) +Heap::JsonObject::JsonObject() { - Scope scope(e); + Scope scope(internalClass->engine); ScopedObject o(scope, this); o->defineDefaultProperty(QStringLiteral("parse"), QV4::JsonObject::method_parse, 2); @@ -943,7 +942,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) ReturnedValue JsonObject::fromJsonValue(ExecutionEngine *engine, const QJsonValue &value) { if (value.isString()) - return engine->currentContext()->engine->newString(value.toString())->asReturnedValue(); + return engine->newString(value.toString())->asReturnedValue(); else if (value.isDouble()) return Encode(value.toDouble()); else if (value.isBool()) diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h index 1ad0e2c5de..61d44f206e 100644 --- a/src/qml/jsruntime/qv4jsonobject_p.h +++ b/src/qml/jsruntime/qv4jsonobject_p.h @@ -47,7 +47,7 @@ namespace QV4 { namespace Heap { struct JsonObject : Object { - JsonObject(ExecutionEngine *e); + JsonObject(); }; } diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 443427b024..d97abdb461 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -43,7 +43,7 @@ using namespace QV4; ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttributes *attrs) { ExecutionEngine *engine = o->engine(); - Identifier *name = engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]->identifier; + Identifier *name = engine->current->compilationUnit->runtimeStrings[nameIndex]->identifier; int i = 0; Heap::Object *obj = o->d(); while (i < Size && obj) { @@ -53,7 +53,8 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu if (index != UINT_MAX) { level = i; *attrs = obj->internalClass->propertyData.at(index); - return !attrs->isAccessor() ? obj->memberData->data[index].asReturnedValue() : Object::getValue(thisObject, obj->propertyAt(index), *attrs); + Value *v = obj->propertyData(index); + return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs); } obj = obj->prototype; @@ -65,7 +66,8 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu index = obj->internalClass->find(name); if (index != UINT_MAX) { *attrs = obj->internalClass->propertyData.at(index); - return !attrs->isAccessor() ? obj->memberData->data[index].asReturnedValue() : Object::getValue(thisObject, obj->propertyAt(index), *attrs); + Value *v = obj->propertyData(index); + return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs); } obj = obj->prototype; @@ -77,7 +79,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs { Heap::Object *obj = thisObject->d(); ExecutionEngine *engine = thisObject->engine(); - Identifier *name = engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]->identifier; + Identifier *name = engine->current->compilationUnit->runtimeStrings[nameIndex]->identifier; int i = 0; while (i < Size && obj) { classList[i] = obj->internalClass; @@ -86,7 +88,8 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs if (index != UINT_MAX) { level = i; *attrs = obj->internalClass->propertyData.at(index); - return !attrs->isAccessor() ? obj->memberData->data[index].asReturnedValue() : thisObject->getValue(obj->propertyAt(index), *attrs); + Value *v = obj->propertyData(index); + return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs); } obj = obj->prototype; @@ -98,7 +101,8 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs index = obj->internalClass->find(name); if (index != UINT_MAX) { *attrs = obj->internalClass->propertyData.at(index); - return !attrs->isAccessor() ? obj->memberData->data[index].asReturnedValue() : thisObject->getValue(obj->propertyAt(index), *attrs); + Value *v = obj->propertyData(index); + return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs); } obj = obj->prototype; @@ -165,7 +169,7 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con { uint idx = index.asArrayIndex(); if (idx == UINT_MAX || !object.isObject()) - return indexedGetterGeneric(l, object, index); + return indexedGetterFallback(l, object, index); Object *o = object.objectValue(); if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { @@ -251,7 +255,7 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va Q_ASSERT(object.isString()); proto = engine->stringPrototype(); Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]); if (name->equals(engine->id_length())) { // special case, as the property is on the object itself l->getter = stringLengthGetter; @@ -329,7 +333,7 @@ ReturnedValue Lookup::getterFallback(Lookup *l, ExecutionEngine *engine, const V QV4::ScopedObject o(scope, object.toObject(scope.engine)); if (!o) return Encode::undefined(); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]); return o->get(name); } @@ -340,7 +344,7 @@ ReturnedValue Lookup::getter0(Lookup *l, ExecutionEngine *engine, const Value &o // the internal class won't match Object *o = object.objectValue(); if (l->classList[0] == o->internalClass()) - return o->memberData()->data[l->index].asReturnedValue(); + return o->propertyData(l->index)->asReturnedValue(); } return getterTwoClasses(l, engine, object); } @@ -353,7 +357,7 @@ ReturnedValue Lookup::getter1(Lookup *l, ExecutionEngine *engine, const Value &o Object *o = object.objectValue(); if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) - return o->prototype()->memberData->data[l->index].asReturnedValue(); + return o->prototype()->propertyData(l->index)->asReturnedValue(); } return getterTwoClasses(l, engine, object); } @@ -369,7 +373,7 @@ ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &o if (l->classList[1] == p->internalClass) { p = p->prototype; if (l->classList[2] == p->internalClass) - return p->memberData->data[l->index].asReturnedValue(); + return p->propertyData(l->index)->asReturnedValue(); } } } @@ -384,9 +388,9 @@ ReturnedValue Lookup::getter0getter0(Lookup *l, ExecutionEngine *engine, const V // the internal class won't match Object *o = object.objectValue(); if (l->classList[0] == o->internalClass()) - return o->memberData()->data[l->index].asReturnedValue(); + return o->propertyData(l->index)->asReturnedValue(); if (l->classList[2] == o->internalClass()) - return o->memberData()->data[l->index2].asReturnedValue(); + return o->propertyData(l->index2)->asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); @@ -399,10 +403,10 @@ ReturnedValue Lookup::getter0getter1(Lookup *l, ExecutionEngine *engine, const V // the internal class won't match Object *o = object.objectValue(); if (l->classList[0] == o->internalClass()) - return o->memberData()->data[l->index].asReturnedValue(); + return o->propertyData(l->index)->asReturnedValue(); if (l->classList[2] == o->internalClass() && l->classList[3] == o->prototype()->internalClass) - return o->prototype()->memberData->data[l->index2].asReturnedValue(); + return o->prototype()->propertyData(l->index2)->asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); @@ -416,10 +420,10 @@ ReturnedValue Lookup::getter1getter1(Lookup *l, ExecutionEngine *engine, const V Object *o = object.objectValue(); if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) - return o->prototype()->memberData->data[l->index].asReturnedValue(); + return o->prototype()->propertyData(l->index)->asReturnedValue(); if (l->classList[2] == o->internalClass() && l->classList[3] == o->prototype()->internalClass) - return o->prototype()->memberData->data[l->index2].asReturnedValue(); + return o->prototype()->propertyData(l->index2)->asReturnedValue(); return getterFallback(l, engine, object); } l->getter = getterFallback; @@ -435,7 +439,7 @@ ReturnedValue Lookup::getterAccessor0(Lookup *l, ExecutionEngine *engine, const Object *o = object.objectValue(); if (l->classList[0] == o->internalClass()) { Scope scope(o->engine()); - ScopedFunctionObject getter(scope, o->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -457,7 +461,7 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const if (l->classList[0] == o->internalClass && l->classList[1] == o->prototype->internalClass) { Scope scope(o->internalClass->engine); - ScopedFunctionObject getter(scope, o->prototype->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->prototype->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -482,7 +486,7 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const o = o->prototype; if (l->classList[2] == o->internalClass) { Scope scope(o->internalClass->engine); - ScopedFunctionObject getter(scope, o->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -502,7 +506,7 @@ ReturnedValue Lookup::primitiveGetter0(Lookup *l, ExecutionEngine *engine, const if (object.type() == l->type) { Object *o = l->proto; if (l->classList[0] == o->internalClass()) - return o->memberData()->data[l->index].asReturnedValue(); + return o->propertyData(l->index)->asReturnedValue(); } l->getter = getterGeneric; return getterGeneric(l, engine, object); @@ -514,7 +518,7 @@ ReturnedValue Lookup::primitiveGetter1(Lookup *l, ExecutionEngine *engine, const Object *o = l->proto; if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) - return o->prototype()->memberData->data[l->index].asReturnedValue(); + return o->prototype()->propertyData(l->index)->asReturnedValue(); } l->getter = getterGeneric; return getterGeneric(l, engine, object); @@ -526,7 +530,7 @@ ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engin Object *o = l->proto; if (l->classList[0] == o->internalClass()) { Scope scope(o->engine()); - ScopedFunctionObject getter(scope, o->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -546,7 +550,7 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engin if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) { Scope scope(o->engine()); - ScopedFunctionObject getter(scope, o->prototype()->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -571,7 +575,7 @@ ReturnedValue Lookup::stringLengthGetter(Lookup *l, ExecutionEngine *engine, con ReturnedValue Lookup::arrayLengthGetter(Lookup *l, ExecutionEngine *engine, const Value &object) { if (const ArrayObject *a = object.as<ArrayObject>()) - return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].asReturnedValue(); + return a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->asReturnedValue(); l->getter = getterGeneric; return getterGeneric(l, engine, object); @@ -603,7 +607,7 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine) } } Scope scope(engine); - ScopedString n(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString n(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]); return engine->throwReferenceError(n); } @@ -611,7 +615,7 @@ ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionEngine *engine) { Object *o = engine->globalObject; if (l->classList[0] == o->internalClass()) - return o->memberData()->data[l->index].asReturnedValue(); + return o->propertyData(l->index)->asReturnedValue(); l->globalGetter = globalGetterGeneric; return globalGetterGeneric(l, engine); @@ -622,7 +626,7 @@ ReturnedValue Lookup::globalGetter1(Lookup *l, ExecutionEngine *engine) Object *o = engine->globalObject; if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) - return o->prototype()->memberData->data[l->index].asReturnedValue(); + return o->prototype()->propertyData(l->index)->asReturnedValue(); l->globalGetter = globalGetterGeneric; return globalGetterGeneric(l, engine); @@ -636,7 +640,7 @@ ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionEngine *engine) if (l->classList[1] == o->internalClass) { o = o->prototype; if (l->classList[2] == o->internalClass) { - return o->prototype->memberData->data[l->index].asReturnedValue(); + return o->prototype->propertyData(l->index)->asReturnedValue(); } } } @@ -649,7 +653,7 @@ ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionEngine *engine) Object *o = engine->globalObject; if (l->classList[0] == o->internalClass()) { Scope scope(o->engine()); - ScopedFunctionObject getter(scope, o->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -667,7 +671,7 @@ ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionEngine *engine) if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) { Scope scope(o->engine()); - ScopedFunctionObject getter(scope, o->prototype()->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -688,7 +692,7 @@ ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine) o = o->prototype; if (l->classList[2] == o->internalClass) { Scope scope(o->internalClass->engine); - ScopedFunctionObject getter(scope, o->propertyAt(l->index)->getter()); + ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -710,7 +714,7 @@ void Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, co o = RuntimeHelpers::convertToObject(scope.engine, object); if (!o) // type error return; - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]); o->put(name, value); return; } @@ -741,7 +745,7 @@ void Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, c QV4::Scope scope(engine); QV4::ScopedObject o(scope, object.toObject(scope.engine)); if (o) { - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]); o->put(name, value); } } @@ -750,7 +754,7 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Va { Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { - o->memberData()->data[l->index] = value; + *o->propertyData(l->index) = value; return; } @@ -762,10 +766,8 @@ void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, co Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { if (!o->prototype()) { - if (!o->memberData() || l->index >= o->memberData()->size) - o->ensureMemberIndex(l->index); - o->memberData()->data[l->index] = value; o->setInternalClass(l->classList[3]); + *o->propertyData(l->index) = value; return; } } @@ -780,10 +782,8 @@ void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, co if (o && o->internalClass() == l->classList[0]) { Heap::Object *p = o->prototype(); if (p && p->internalClass == l->classList[1]) { - if (!o->memberData() || l->index >= o->memberData()->size) - o->ensureMemberIndex(l->index); - o->memberData()->data[l->index] = value; o->setInternalClass(l->classList[3]); + *o->propertyData(l->index) = value; return; } } @@ -800,10 +800,8 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, co if (p && p->internalClass == l->classList[1]) { p = p->prototype; if (p && p->internalClass == l->classList[2]) { - if (!o->memberData() || l->index >= o->memberData()->size) - o->ensureMemberIndex(l->index); - o->memberData()->data[l->index] = value; o->setInternalClass(l->classList[3]); + *o->propertyData(l->index) = value; return; } } @@ -818,11 +816,11 @@ void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, c Object *o = object.as<Object>(); if (o) { if (o->internalClass() == l->classList[0]) { - o->memberData()->data[l->index] = value; + *o->propertyData(l->index) = value; return; } if (o->internalClass() == l->classList[1]) { - o->memberData()->data[l->index2] = value; + *o->propertyData(l->index2) = value; return; } } diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index bb7ee43b4e..e2de36d18e 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -88,29 +88,7 @@ QString Managed::className() const s = "RegExp"; break; case Type_ErrorObject: - switch (static_cast<Heap::ErrorObject *>(d())->errorType) { - case Heap::ErrorObject::Error: - s = "Error"; - break; - case Heap::ErrorObject::EvalError: - s = "EvalError"; - break; - case Heap::ErrorObject::RangeError: - s = "RangeError"; - break; - case Heap::ErrorObject::ReferenceError: - s = "ReferenceError"; - break; - case Heap::ErrorObject::SyntaxError: - s = "SyntaxError"; - break; - case Heap::ErrorObject::TypeError: - s = "TypeError"; - break; - case Heap::ErrorObject::URIError: - s = "URIError"; - break; - } + s = ErrorObject::className(static_cast<Heap::ErrorObject *>(d())->errorType); break; case Type_ArgumentsObject: s = "Arguments"; diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp index c498160c36..f1face007c 100644 --- a/src/qml/jsruntime/qv4mathobject.cpp +++ b/src/qml/jsruntime/qv4mathobject.cpp @@ -47,10 +47,9 @@ DEFINE_OBJECT_VTABLE(MathObject); static const double qt_PI = 2.0 * ::asin(1.0); -Heap::MathObject::MathObject(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->objectPrototype()) +Heap::MathObject::MathObject() { - Scope scope(e); + Scope scope(internalClass->engine); ScopedObject m(scope, this); m->defineReadonlyProperty(QStringLiteral("E"), Primitive::fromDouble(M_E)); diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h index 472b2020b1..ff4fb12ee6 100644 --- a/src/qml/jsruntime/qv4mathobject_p.h +++ b/src/qml/jsruntime/qv4mathobject_p.h @@ -42,7 +42,7 @@ namespace QV4 { namespace Heap { struct MathObject : Object { - MathObject(ExecutionEngine *e); + MathObject(); }; } diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index b3c0863e3e..ee3539c176 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -44,6 +44,7 @@ #include "qv4objectiterator_p.h" #include "qv4identifier_p.h" #include "qv4string_p.h" +#include "qv4identifiertable_p.h" #include <stdint.h> @@ -51,15 +52,25 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(Object); -Heap::Object::Object(InternalClass *internalClass, QV4::Object *prototype) - : internalClass(internalClass), - prototype(prototype ? prototype->d() : 0) +void Object::setInternalClass(InternalClass *ic) { - if (internalClass->size) { - Scope scope(internalClass->engine); - ScopedObject o(scope, this); - o->ensureMemberIndex(internalClass->engine, internalClass->size); - } + d()->internalClass = ic; + ensureMemberData(); +} + +void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const +{ + p->value = *propertyData(index); + *attrs = internalClass()->propertyData.at(index); + if (attrs->isAccessor()) + p->set = *propertyData(index + SetterOffset); +} + +void Object::setProperty(uint index, const Property *p) +{ + *propertyData(index) = p->value; + if (internalClass()->propertyData.at(index).isAccessor()) + *propertyData(index + SetterOffset) = p->set; } bool Object::setPrototype(Object *proto) @@ -81,28 +92,32 @@ void Object::put(ExecutionEngine *engine, const QString &name, const Value &valu put(n, value); } -ReturnedValue Object::getValue(const Value &thisObject, const Property *p, PropertyAttributes attrs) +ReturnedValue Object::getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs) { if (!attrs.isAccessor()) - return p->value.asReturnedValue(); - if (!p->getter()) + return v.asReturnedValue(); + const QV4::FunctionObject *f = v.as<FunctionObject>(); + if (!f) return Encode::undefined(); - Scope scope(p->getter()->internalClass->engine); - ScopedFunctionObject getter(scope, p->getter()); + Scope scope(f->engine()); ScopedCallData callData(scope); callData->thisObject = thisObject; - return getter->call(callData); + return f->call(callData); } -void Object::putValue(Property *pd, PropertyAttributes attrs, const Value &value) +void Object::putValue(uint memberIndex, const Value &value) { - if (internalClass()->engine->hasException) + QV4::InternalClass *ic = internalClass(); + if (ic->engine->hasException) return; + PropertyAttributes attrs = ic->propertyData[memberIndex]; + if (attrs.isAccessor()) { - if (Heap::FunctionObject *set = pd->setter()) { - Scope scope(set->internalClass->engine); + FunctionObject *set = propertyData(memberIndex + SetterOffset)->as<FunctionObject>(); + if (set) { + Scope scope(ic->engine); ScopedFunctionObject setter(scope, set); ScopedCallData callData(scope, 1); callData->args[0] = value; @@ -116,11 +131,11 @@ void Object::putValue(Property *pd, PropertyAttributes attrs, const Value &value if (!attrs.isWritable()) goto reject; - pd->value = value; + *propertyData(memberIndex) = value; return; reject: - if (engine()->currentContext()->strictMode) + if (engine()->current->strictMode) engine()->throwTypeError(); } @@ -137,7 +152,7 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Ca ExecutionEngine *e = engine(); Scope scope(e); ScopedString s(scope, e->newIdentifier(name)); - ScopedContext global(scope, e->rootContext()); + ExecutionContext *global = e->rootContext(); ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code)); function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(s, function); @@ -147,7 +162,7 @@ void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallConte { ExecutionEngine *e = engine(); Scope scope(e); - ScopedContext global(scope, e->rootContext()); + ExecutionContext *global = e->rootContext(); ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code)); function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(name, function); @@ -166,7 +181,7 @@ void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(CallCo ExecutionEngine *v4 = engine(); QV4::Scope scope(v4); ScopedProperty p(scope); - ScopedContext global(scope, scope.engine->rootContext()); + ExecutionContext *global = v4->rootContext(); p->setGetter(ScopedFunctionObject(scope, (getter ? BuiltinFunction::create(global, name, getter) : 0))); p->setSetter(ScopedFunctionObject(scope, (setter ? BuiltinFunction::create(global, name, setter) : 0))); insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); @@ -189,6 +204,12 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e) { Heap::Object *o = static_cast<Heap::Object *>(that); + if (o->inlineMemberSize) { + Value *v = o->propertyData(0); + for (uint i = 0; i < o->inlineMemberSize; ++i) + v[i].mark(e); + } + if (o->memberData) o->memberData->mark(e); if (o->arrayData) @@ -197,9 +218,11 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e) o->prototype->mark(e); } -void Object::ensureMemberIndex(uint idx) +void Object::ensureMemberData() { - d()->memberData = MemberData::reallocate(engine(), d()->memberData, idx); + QV4::InternalClass *ic = internalClass(); + if (ic->size > d()->inlineMemberSize) + d()->memberData = MemberData::reallocate(ic->engine, d()->memberData, ic->size - d()->inlineMemberSize); } void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes) @@ -207,15 +230,11 @@ void Object::insertMember(String *s, const Property *p, PropertyAttributes attri uint idx; InternalClass::addMember(this, s, attributes, &idx); - - ensureMemberIndex(internalClass()->size); - if (attributes.isAccessor()) { - Property *pp = propertyAt(idx); - pp->value = p->value; - pp->set = p->set; + *propertyData(idx + GetterOffset) = p->value; + *propertyData(idx + SetterOffset) = p->set; } else { - d()->memberData->data[idx] = p->value; + *propertyData(idx) = p->value; } } @@ -229,8 +248,11 @@ void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p uint member = internalClass()->find(name); if (member < UINT_MAX) { *attrs = internalClass()->propertyData[member]; - if (p) - p->copy(propertyAt(member), *attrs); + if (p) { + p->value = *propertyData(member); + if (attrs->isAccessor()) + p->set = *propertyData(member + SetterOffset); + } return; } @@ -261,47 +283,44 @@ void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p) } // Section 8.12.2 -Property *Object::__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const +Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs) { Q_ASSERT(name->asArrayIndex() == UINT_MAX); - const Heap::Object *o = d(); + Heap::Object *o = d(); while (o) { uint idx = o->internalClass->find(name); if (idx < UINT_MAX) { - if (attrs) - *attrs = o->internalClass->propertyData[idx]; - return const_cast<Property *>(o->propertyAt(idx)); + *attrs = o->internalClass->propertyData[idx]; + return o->propertyData(attrs->isAccessor() ? idx + SetterOffset : idx); } o = o->prototype; } - if (attrs) - *attrs = Attr_Invalid; + *attrs = Attr_Invalid; return 0; } -Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attrs) const +Value *Object::getValueOrSetter(uint index, PropertyAttributes *attrs) { - const Heap::Object *o = d(); + Heap::Object *o = d(); while (o) { Property *p = o->arrayData ? o->arrayData->getProperty(index) : 0; if (p) { *attrs = o->arrayData->attributes(index); - return p; + return attrs->isAccessor() ? &p->set : &p->value; } if (o->vtable()->type == Type_StringObject) { if (index < static_cast<const Heap::StringObject *>(o)->length()) { // this is an evil hack, but it works, as the method is only ever called from putIndexed, // where we don't use the returned pointer there for non writable attributes *attrs = (Attr_NotWritable|Attr_NotConfigurable); - return reinterpret_cast<Property *>(0x1); + return reinterpret_cast<Value *>(0x1); } } o = o->prototype; } - if (attrs) - *attrs = Attr_Invalid; + *attrs = Attr_Invalid; return 0; } @@ -466,7 +485,7 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value) { Scope scope(static_cast<Object *>(m)->engine()); ScopedObject o(scope, static_cast<Object *>(m)); - ScopedString name(scope, scope.engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, scope.engine->current->compilationUnit->runtimeStrings[l->nameIndex]); InternalClass *c = o->internalClass(); uint idx = c->find(name); @@ -475,12 +494,12 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value) l->classList[0] = o->internalClass(); l->index = idx; l->setter = Lookup::setter0; - o->memberData()->data[idx] = value; + *o->propertyData(idx) = value; return; } if (idx != UINT_MAX) { - o->putValue(o->propertyAt(idx), o->internalClass()->propertyData[idx], value); + o->putValue(idx, value); return; } } @@ -568,13 +587,15 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint * continue; } - Property *p = o->propertyAt(it->memberIndex); + int idx = it->memberIndex; PropertyAttributes a = o->internalClass()->propertyData[it->memberIndex]; ++it->memberIndex; if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { - name->setM(o->engine()->newString(n->string)); + name->setM(o->engine()->identifierTable->stringFromIdentifier(n)); *attrs = a; - pd->copy(p, a); + pd->value = *o->propertyData(idx); + if (a.isAccessor()) + pd->set = *o->propertyData(idx + SetterOffset); return; } } @@ -598,7 +619,7 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) const if (idx < UINT_MAX) { if (hasProperty) *hasProperty = true; - return getValue(o->propertyAt(idx), o->internalClass()->propertyData.at(idx)); + return getValue(*o->propertyData(idx), o->internalClass()->propertyData.at(idx)); } o = o->prototype(); @@ -637,7 +658,7 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const if (pd) { if (hasProperty) *hasProperty = true; - return getValue(pd, attrs); + return getValue(pd->value, attrs); } if (hasProperty) @@ -659,17 +680,17 @@ void Object::internalPut(String *name, const Value &value) name->makeIdentifier(engine()); uint member = internalClass()->find(name); - Property *pd = 0; + Value *v = 0; PropertyAttributes attrs; if (member < UINT_MAX) { - pd = propertyAt(member); attrs = internalClass()->propertyData[member]; + v = propertyData(attrs.isAccessor() ? member + SetterOffset : member); } // clause 1 - if (pd) { + if (v) { if (attrs.isAccessor()) { - if (pd->setter()) + if (v->as<FunctionObject>()) goto cont; goto reject; } else if (!attrs.isWritable()) @@ -685,7 +706,7 @@ void Object::internalPut(String *name, const Value &value) if (!ok) goto reject; } else { - pd->value = value; + *v = value; } return; } else if (!prototype()) { @@ -694,9 +715,9 @@ void Object::internalPut(String *name, const Value &value) } else { // clause 4 Scope scope(engine()); - if ((pd = ScopedObject(scope, prototype())->__getPropertyDescriptor__(name, &attrs))) { + if ((v = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs))) { if (attrs.isAccessor()) { - if (!pd->setter()) + if (!v->as<FunctionObject>()) goto reject; } else if (!isExtensible() || !attrs.isWritable()) { goto reject; @@ -709,11 +730,11 @@ void Object::internalPut(String *name, const Value &value) cont: // Clause 5 - if (pd && attrs.isAccessor()) { - Q_ASSERT(pd->setter() != 0); + if (v && attrs.isAccessor()) { + Q_ASSERT(v->as<FunctionObject>()); Scope scope(engine()); - ScopedFunctionObject setter(scope, pd->setter()); + ScopedFunctionObject setter(scope, *v); ScopedCallData callData(scope, 1); callData->args[0] = value; callData->thisObject = this; @@ -725,7 +746,7 @@ void Object::internalPut(String *name, const Value &value) return; reject: - if (engine()->currentContext()->strictMode) { + if (engine()->current->strictMode) { QString message = QStringLiteral("Cannot assign to read-only property \""); message += name->toQString(); message += QLatin1Char('\"'); @@ -740,26 +761,24 @@ void Object::internalPutIndexed(uint index, const Value &value) PropertyAttributes attrs; - Property *pd = arrayData() ? arrayData()->getProperty(index) : 0; - if (pd) - attrs = arrayData()->attributes(index); + Value *v = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : 0; - if (!pd && isStringObject()) { + if (!v && isStringObject()) { if (index < static_cast<StringObject *>(this)->length()) // not writable goto reject; } // clause 1 - if (pd) { + if (v) { if (attrs.isAccessor()) { - if (pd->setter()) + if (v->as<FunctionObject>()) goto cont; goto reject; } else if (!attrs.isWritable()) goto reject; else - pd->value = value; + *v = value; return; } else if (!prototype()) { if (!isExtensible()) @@ -767,9 +786,9 @@ void Object::internalPutIndexed(uint index, const Value &value) } else { // clause 4 Scope scope(engine()); - if ((pd = ScopedObject(scope, prototype())->__getPropertyDescriptor__(index, &attrs))) { + if ((v = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs))) { if (attrs.isAccessor()) { - if (!pd->setter()) + if (!v->as<FunctionObject>()) goto reject; } else if (!isExtensible() || !attrs.isWritable()) { goto reject; @@ -782,11 +801,11 @@ void Object::internalPutIndexed(uint index, const Value &value) cont: // Clause 5 - if (pd && attrs.isAccessor()) { - Q_ASSERT(pd->setter() != 0); + if (v && attrs.isAccessor()) { + Q_ASSERT(v->as<FunctionObject>()); Scope scope(engine()); - ScopedFunctionObject setter(scope, pd->setter()); + ScopedFunctionObject setter(scope, *v); ScopedCallData callData(scope, 1); callData->args[0] = value; callData->thisObject = this; @@ -798,7 +817,7 @@ void Object::internalPutIndexed(uint index, const Value &value) return; reject: - if (engine()->currentContext()->strictMode) + if (engine()->current->strictMode) engine()->throwTypeError(); } @@ -820,7 +839,7 @@ bool Object::internalDeleteProperty(String *name) InternalClass::removeMember(this, name->identifier()); return true; } - if (engine()->currentContext()->strictMode) + if (engine()->current->strictMode) engine()->throwTypeError(); return false; } @@ -838,7 +857,7 @@ bool Object::internalDeleteIndexedProperty(uint index) if (!ad || ad->vtable()->del(this, index)) return true; - if (engine()->currentContext()->strictMode) + if (engine()->current->strictMode) engine()->throwTypeError(); return false; } @@ -853,17 +872,16 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const Scope scope(engine); name->makeIdentifier(scope.engine); - Property *current; - PropertyAttributes *cattrs; uint memberIndex; if (isArrayObject() && name->equals(engine->id_length())) { Q_ASSERT(Heap::ArrayObject::LengthPropertyIndex == internalClass()->find(engine->id_length())); - Property *lp = propertyAt(Heap::ArrayObject::LengthPropertyIndex); - cattrs = internalClass()->propertyData.constData() + Heap::ArrayObject::LengthPropertyIndex; - if (attrs.isEmpty() || p->isSubset(attrs, lp, *cattrs)) + ScopedProperty lp(scope); + PropertyAttributes cattrs; + getProperty(Heap::ArrayObject::LengthPropertyIndex, lp, &cattrs); + if (attrs.isEmpty() || p->isSubset(attrs, lp, cattrs)) return true; - if (!cattrs->isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable()) + if (!cattrs.isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable()) goto reject; bool succeeded = true; if (attrs.type() == PropertyAttributes::Data) { @@ -876,8 +894,10 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const } succeeded = setArrayLength(l); } - if (attrs.hasWritable() && !attrs.isWritable()) - cattrs->setWritable(false); + if (attrs.hasWritable() && !attrs.isWritable()) { + cattrs.setWritable(false); + InternalClass::changeMember(this, engine->id_length(), cattrs); + } if (!succeeded) goto reject; return true; @@ -885,10 +905,8 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const // Clause 1 memberIndex = internalClass()->find(name); - current = (memberIndex < UINT_MAX) ? propertyAt(memberIndex) : 0; - cattrs = internalClass()->propertyData.constData() + memberIndex; - if (!current) { + if (memberIndex == UINT_MAX) { // clause 3 if (!isExtensible()) goto reject; @@ -902,7 +920,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const return __defineOwnProperty__(engine, memberIndex, name, p, attrs); reject: - if (engine->currentContext()->strictMode) + if (engine->current->strictMode) engine->throwTypeError(); return false; } @@ -918,7 +936,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, const Pr return defineOwnProperty2(engine, index, p, attrs); reject: - if (engine->currentContext()->strictMode) + if (engine->current->strictMode) engine->throwTypeError(); return false; } @@ -954,7 +972,7 @@ bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Prope return __defineOwnProperty__(engine, index, 0, p, attrs); reject: - if (engine->currentContext()->strictMode) + if (engine->current->strictMode) engine->throwTypeError(); return false; } @@ -965,13 +983,14 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * if (attrs.isEmpty()) return true; - Property *current = 0; + Scope scope(engine); + ScopedProperty current(scope); PropertyAttributes cattrs; if (member) { - current = propertyAt(index); + getProperty(index, current, &cattrs); cattrs = internalClass()->propertyData[index]; } else if (arrayData()) { - current = arrayData()->getProperty(index); + arrayData()->getProperty(index, current, &cattrs); cattrs = arrayData()->attributes(index); } @@ -1005,7 +1024,6 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * initSparseArray(); Q_ASSERT(arrayData()); setArrayAttributes(index, cattrs); - current = arrayData()->getProperty(index); } current->setGetter(0); current->setSetter(0); @@ -1016,7 +1034,6 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * if (!member) { // need to convert the array and the slot setArrayAttributes(index, cattrs); - current = arrayData()->getProperty(index); } current->value = Primitive::undefinedValue(); } @@ -1040,12 +1057,14 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * current->merge(cattrs, p, attrs); if (member) { InternalClass::changeMember(this, member, cattrs); + setProperty(index, current); } else { setArrayAttributes(index, cattrs); + arrayData()->setProperty(index, current); } return true; reject: - if (engine->currentContext()->strictMode) + if (engine->current->strictMode) engine->throwTypeError(); return false; } @@ -1135,11 +1154,11 @@ void Object::initSparseArray() DEFINE_OBJECT_VTABLE(ArrayObject); -Heap::ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list) - : Heap::Object(engine->arrayClass, engine->arrayPrototype()) +Heap::ArrayObject::ArrayObject(const QStringList &list) + : Heap::Object() { init(); - Scope scope(engine); + Scope scope(internalClass->engine); ScopedObject a(scope, this); // Converts a QStringList to JS. @@ -1150,19 +1169,19 @@ Heap::ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list) a->arrayReserve(len); ScopedValue v(scope); for (int ii = 0; ii < len; ++ii) - a->arrayPut(ii, (v = engine->newString(list.at(ii)))); + a->arrayPut(ii, (v = scope.engine->newString(list.at(ii)))); a->setArrayLengthUnchecked(len); } ReturnedValue ArrayObject::getLookup(const Managed *m, Lookup *l) { Scope scope(static_cast<const Object *>(m)->engine()); - ScopedString name(scope, scope.engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, scope.engine->current->compilationUnit->runtimeStrings[l->nameIndex]); if (name->equals(scope.engine->id_length())) { // special case, as the property is on the object itself l->getter = Lookup::arrayLengthGetter; const ArrayObject *a = static_cast<const ArrayObject *>(m); - return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].asReturnedValue(); + return a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->asReturnedValue(); } return Object::getLookup(m, l); } @@ -1170,9 +1189,9 @@ ReturnedValue ArrayObject::getLookup(const Managed *m, Lookup *l) uint ArrayObject::getLength(const Managed *m) { const ArrayObject *a = static_cast<const ArrayObject *>(m); - if (a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].isInteger()) - return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].integerValue(); - return Primitive::toUInt32(a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].doubleValue()); + if (a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->isInteger()) + return a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->integerValue(); + return Primitive::toUInt32(a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->doubleValue()); } QStringList ArrayObject::toQStringList() const diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index f129312819..58dab9691f 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -42,17 +42,19 @@ QT_BEGIN_NAMESPACE + namespace QV4 { namespace Heap { struct Object : Base { - inline Object(ExecutionEngine *engine); - Object(InternalClass *internal, QV4::Object *prototype); + inline Object() {} - const Property *propertyAt(uint index) const { return reinterpret_cast<const Property *>(memberData->data + index); } - Property *propertyAt(uint index) { return reinterpret_cast<Property *>(memberData->data + index); } + const Value *propertyData(uint index) const { if (index < inlineMemberSize) return reinterpret_cast<const Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; } + Value *propertyData(uint index) { if (index < inlineMemberSize) return reinterpret_cast<Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; } + uint inlineMemberOffset; + uint inlineMemberSize; InternalClass *internalClass; Pointer<Object> prototype; Pointer<MemberData> memberData; @@ -80,6 +82,13 @@ struct Object : Base { V4_MANAGED_SIZE_TEST \ QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m()); } +#define V4_INTERNALCLASS(c) \ + static QV4::InternalClass *defaultInternalClass(QV4::ExecutionEngine *e) \ + { return e->c; } +#define V4_PROTOTYPE(p) \ + static QV4::Object *defaultPrototype(QV4::ExecutionEngine *e) \ + { return e->p(); } + struct ObjectVTable { VTable vTable; @@ -124,21 +133,26 @@ const QV4::ObjectVTable classname::static_vtbl = \ struct Q_QML_EXPORT Object: Managed { V4_OBJECT2(Object, Object) Q_MANAGED_TYPE(Object) + V4_INTERNALCLASS(emptyClass) + V4_PROTOTYPE(objectPrototype) enum { - IsObject = true + IsObject = true, + GetterOffset = 0, + SetterOffset = 1 }; InternalClass *internalClass() const { return d()->internalClass; } - void setInternalClass(InternalClass *ic) { d()->internalClass = ic; } + void setInternalClass(InternalClass *ic); + + const Value *propertyData(uint index) const { return d()->propertyData(index); } + Value *propertyData(uint index) { return d()->propertyData(index); } - Heap::MemberData *memberData() { return d()->memberData; } - const Heap::MemberData *memberData() const { return d()->memberData; } Heap::ArrayData *arrayData() const { return d()->arrayData; } void setArrayData(ArrayData *a) { d()->arrayData = a->d(); } - const Property *propertyAt(uint index) const { return d()->propertyAt(index); } - Property *propertyAt(uint index) { return d()->propertyAt(index); } + void getProperty(uint index, Property *p, PropertyAttributes *attrs) const; + void setProperty(uint index, const Property *p); const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(d()->vtable()); } Heap::Object *prototype() const { return d()->prototype; } @@ -147,8 +161,8 @@ struct Q_QML_EXPORT Object: Managed { void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0); void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = 0); - Property *__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const; - Property *__getPropertyDescriptor__(uint index, PropertyAttributes *attrs) const; + Value *getValueOrSetter(String *name, PropertyAttributes *attrs); + Value *getValueOrSetter(uint index, PropertyAttributes *attrs); bool hasProperty(String *name) const; bool hasProperty(uint index) const; @@ -167,14 +181,14 @@ struct Q_QML_EXPORT Object: Managed { // void put(ExecutionEngine *engine, const QString &name, const Value &value); - static ReturnedValue getValue(const Value &thisObject, const Property *p, PropertyAttributes attrs); - ReturnedValue getValue(const Property *p, PropertyAttributes attrs) const { + static ReturnedValue getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs); + ReturnedValue getValue(const Value &v, PropertyAttributes attrs) const { Scope scope(this->engine()); ScopedValue t(scope, const_cast<Object *>(this)); - return getValue(t, p, attrs); + return getValue(t, v, attrs); } - void putValue(Property *pd, PropertyAttributes attrs, const Value &value); + void putValue(uint memberIndex, const Value &value); /* The spec default: Writable: true, Enumerable: false, Configurable: true */ void defineDefaultProperty(String *name, const Value &value) { @@ -189,10 +203,6 @@ struct Q_QML_EXPORT Object: Managed { void defineReadonlyProperty(const QString &name, const Value &value); void defineReadonlyProperty(String *name, const Value &value); - void ensureMemberIndex(QV4::ExecutionEngine *e, uint idx) { - d()->memberData = MemberData::reallocate(e, d()->memberData, idx); - } - void insertMember(String *s, const Value &v, PropertyAttributes attributes = Attr_Data) { Scope scope(engine()); ScopedProperty p(scope); @@ -269,7 +279,6 @@ public: return false; } - void ensureMemberIndex(uint idx); inline ReturnedValue get(String *name, bool *hasProperty = 0) const { return vtable()->get(this, name, hasProperty); } @@ -316,6 +325,8 @@ protected: static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); static uint getLength(const Managed *m); + void ensureMemberData(); + private: ReturnedValue internalGet(String *name, bool *hasProperty) const; ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const; @@ -330,39 +341,19 @@ private: namespace Heap { -inline Object::Object(ExecutionEngine *engine) - : internalClass(engine->emptyClass), - prototype(static_cast<Object *>(engine->objectPrototype()->m())) -{ -} - struct BooleanObject : Object { - BooleanObject(InternalClass *ic, QV4::Object *prototype) - : Object(ic, prototype), - b(false) - { - } - - BooleanObject(ExecutionEngine *engine, bool b) - : Object(engine->emptyClass, engine->booleanPrototype()), - b(b) - { - } + BooleanObject() {} + BooleanObject(bool b) + : b(b) + {} bool b; }; struct NumberObject : Object { - NumberObject(InternalClass *ic, QV4::Object *prototype) - : Object(ic, prototype), - value(0) - { - } - - NumberObject(ExecutionEngine *engine, double val) - : Object(engine->emptyClass, engine->numberPrototype()), - value(val) - { - } + NumberObject() {} + NumberObject(double val) + : value(val) + {} double value; }; @@ -371,15 +362,11 @@ struct ArrayObject : Object { LengthPropertyIndex = 0 }; - ArrayObject(ExecutionEngine *engine) - : Heap::Object(engine->arrayClass, engine->arrayPrototype()) - { init(); } - ArrayObject(ExecutionEngine *engine, const QStringList &list); - ArrayObject(InternalClass *ic, QV4::Object *prototype) - : Heap::Object(ic, prototype) + ArrayObject() { init(); } + ArrayObject(const QStringList &list); void init() - { memberData->data[LengthPropertyIndex] = Primitive::fromInt32(0); } + { *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); } }; } @@ -387,6 +374,7 @@ struct ArrayObject : Object { struct BooleanObject: Object { V4_OBJECT2(BooleanObject, Object) Q_MANAGED_TYPE(BooleanObject) + V4_PROTOTYPE(booleanPrototype) bool value() const { return d()->b; } @@ -395,6 +383,7 @@ struct BooleanObject: Object { struct NumberObject: Object { V4_OBJECT2(NumberObject, Object) Q_MANAGED_TYPE(NumberObject) + V4_PROTOTYPE(numberPrototype) double value() const { return d()->value; } }; @@ -402,6 +391,8 @@ struct NumberObject: Object { struct ArrayObject: Object { V4_OBJECT2(ArrayObject, Object) Q_MANAGED_TYPE(ArrayObject) + V4_INTERNALCLASS(arrayClass) + V4_PROTOTYPE(arrayPrototype) void init(ExecutionEngine *engine); @@ -415,7 +406,7 @@ struct ArrayObject: Object { inline void Object::setArrayLengthUnchecked(uint l) { if (isArrayObject()) - memberData()->data[Heap::ArrayObject::LengthPropertyIndex] = Primitive::fromUInt32(l); + *propertyData(Heap::ArrayObject::LengthPropertyIndex) = Primitive::fromUInt32(l); } inline void Object::push_back(const Value &v) @@ -438,10 +429,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a arrayData()->vtable()->reallocate(this, index + 1, false); } setArrayAttributes(index, attributes); - Property *pd = ArrayData::insert(this, index, attributes.isAccessor()); - pd->value = p->value; - if (attributes.isAccessor()) - pd->set = p->set; + ArrayData::insert(this, index, &p->value, attributes.isAccessor()); if (isArrayObject() && index >= getLength()) setArrayLengthUnchecked(index + 1); } @@ -453,8 +441,7 @@ inline void Object::arraySet(uint index, const Value &value) if (index > 0x1000 && index > 2*d()->arrayData->alloc) { initSparseArray(); } - Property *pd = ArrayData::insert(this, index); - pd->value = value; + ArrayData::insert(this, index, &value); if (isArrayObject() && index >= getLength()) setArrayLengthUnchecked(index + 1); } diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index 585f9f5c2e..7f97872092 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -144,7 +144,7 @@ ReturnedValue ObjectIterator::nextPropertyName(Value *value) if (attrs.isEmpty()) return Encode::null(); - *value = object->objectValue()->getValue(p, attrs); + *value = object->objectValue()->getValue(p->value, attrs); if (!!name) return name->asReturnedValue(); @@ -166,7 +166,7 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString(Value *value) if (attrs.isEmpty()) return Encode::null(); - *value = object->objectValue()->getValue(p, attrs); + *value = object->objectValue()->getValue(p->value, attrs); if (!!name) return name->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index bfe04b33aa..e34b641be9 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -67,7 +67,7 @@ struct Q_QML_EXPORT ObjectIterator namespace Heap { struct ForEachIteratorObject : Object { - ForEachIteratorObject(QV4::ExecutionEngine *engine, QV4::Object *o); + ForEachIteratorObject(QV4::Object *o); ObjectIterator it; Value workArea[2]; }; @@ -85,9 +85,8 @@ protected: }; inline -Heap::ForEachIteratorObject::ForEachIteratorObject(QV4::ExecutionEngine *engine, QV4::Object *o) - : Heap::Object(engine) - , it(engine, workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) +Heap::ForEachIteratorObject::ForEachIteratorObject(QV4::Object *o) + : it(internalClass->engine, workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) { } diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 1edf76e2de..df7441ef5d 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -108,7 +108,7 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) defineDefaultProperty(QStringLiteral("__defineGetter__"), method_defineGetter, 2); defineDefaultProperty(QStringLiteral("__defineSetter__"), method_defineSetter, 2); - ScopedContext global(scope, scope.engine->rootContext()); + ExecutionContext *global = v4->rootContext(); ScopedProperty p(scope); p->value = BuiltinFunction::create(global, v4->id___proto__(), method_get_proto); p->set = BuiltinFunction::create(global, v4->id___proto__(), method_set_proto); @@ -141,9 +141,9 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx) if (scope.hasException()) return Encode::undefined(); PropertyAttributes attrs; - Property desc; - O->getOwnProperty(name, &attrs, &desc); - return fromPropertyDescriptor(scope.engine, &desc, attrs); + ScopedProperty desc(scope); + O->getOwnProperty(name, &attrs, desc); + return fromPropertyDescriptor(scope.engine, desc, attrs); } ReturnedValue ObjectPrototype::method_getOwnPropertyNames(CallContext *context) @@ -222,7 +222,7 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx) if (attrs.isEmpty()) break; PropertyAttributes nattrs; - val = o->getValue(pd, attrs); + val = o->getValue(pd->value, attrs); toPropertyDescriptor(scope.engine, val, n, &nattrs); if (scope.engine->hasException) return Encode::undefined(); @@ -630,7 +630,7 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionEngine *engine, const Property *desc, PropertyAttributes attrs) { - if (!desc) + if (attrs.isEmpty()) return Encode::undefined(); Scope scope(engine); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 82e232d28c..ee294b3678 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -228,9 +228,8 @@ static QV4::ReturnedValue LoadProperty(QV4::ExecutionEngine *v4, QObject *object } } -Heap::QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object) - : Heap::Object(engine) - , object(object) +Heap::QObjectWrapper::QObjectWrapper(QObject *object) + : object(object) { } @@ -255,7 +254,7 @@ QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlCont return result; } -ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *n, QObjectWrapper::RevisionMode revisionMode, +ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty, bool includeImports) const { if (QQmlData::wasDeleted(d()->object)) { @@ -264,20 +263,18 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String return QV4::Encode::undefined(); } - QV4::Scope scope(engine()); - QV4::ScopedString name(scope, n); + ExecutionEngine *v4 = engine(); - if (name->equals(scope.engine->id_destroy()) || name->equals(scope.engine->id_toString())) { - int index = name->equals(scope.engine->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod; - ScopedContext global(scope, scope.engine->rootContext()); - QV4::ScopedValue method(scope, QV4::QObjectMethod::create(global, d()->object, index)); + if (name->equals(v4->id_destroy()) || name->equals(v4->id_toString())) { + int index = name->equals(v4->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod; if (hasProperty) *hasProperty = true; - return method->asReturnedValue(); + ExecutionContext *global = v4->rootContext(); + return QV4::QObjectMethod::create(global, d()->object, index); } QQmlPropertyData local; - QQmlPropertyData *result = findProperty(scope.engine, qmlContext, name, revisionMode, &local); + QQmlPropertyData *result = findProperty(v4, qmlContext, name, revisionMode, &local); if (!result) { if (includeImports && name->startsWithUpper()) { @@ -292,10 +289,10 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String if (r.scriptIndex != -1) { return QV4::Encode::undefined(); } else if (r.type) { - return QmlTypeWrapper::create(scope.engine, d()->object, + return QmlTypeWrapper::create(v4, d()->object, r.type, Heap::QmlTypeWrapper::ExcludeEnums); } else if (r.importNamespace) { - return QmlTypeWrapper::create(scope.engine, d()->object, + return QmlTypeWrapper::create(v4, d()->object, qmlContext->imports, r.importNamespace, Heap::QmlTypeWrapper::ExcludeEnums); } Q_ASSERT(!"Unreachable"); @@ -318,13 +315,11 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String if (hasProperty) *hasProperty = true; - return getProperty(scope.engine, d()->object, result); + return getProperty(v4, d()->object, result); } ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired) { - QV4::Scope scope(engine); - QQmlData::flushPendingBinding(object, property->coreIndex); if (property->isFunction() && !property->isVarProperty()) { @@ -333,24 +328,19 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje Q_ASSERT(vmemo); return vmemo->vmeMethod(property->coreIndex); } else if (property->isV4Function()) { - ScopedContext global(scope, scope.engine->qmlContext()); + Scope scope(engine); + ScopedContext global(scope, engine->qmlContext()); return QV4::QObjectMethod::create(global, object, property->coreIndex); } else if (property->isSignalHandler()) { - QV4::Scoped<QV4::QmlSignalHandler> handler(scope, scope.engine->memoryManager->alloc<QV4::QmlSignalHandler>(engine, object, property->coreIndex)); - - QV4::ScopedString connect(scope, engine->newIdentifier(QStringLiteral("connect"))); - QV4::ScopedString disconnect(scope, engine->newIdentifier(QStringLiteral("disconnect"))); - handler->put(connect, QV4::ScopedValue(scope, engine->functionPrototype()->get(connect))); - handler->put(disconnect, QV4::ScopedValue(scope, engine->functionPrototype()->get(disconnect))); - - return handler.asReturnedValue(); + QmlSignalHandler::initProto(engine); + return engine->memoryManager->allocObject<QV4::QmlSignalHandler>(object, property->coreIndex)->asReturnedValue(); } else { - ScopedContext global(scope, scope.engine->rootContext()); + ExecutionContext *global = engine->rootContext(); return QV4::QObjectMethod::create(global, object, property->coreIndex); } } - QQmlEnginePrivate *ep = scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : 0; + QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; if (property->hasAccessors()) { QQmlNotifier *n = 0; @@ -359,6 +349,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje if (ep && ep->propertyCapture && property->accessors->notifier) nptr = &n; + Scope scope(engine); QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(engine, object, *property, nptr)); if (captureRequired) { @@ -390,7 +381,6 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty) { - QV4::Scope scope(engine); if (QQmlData::wasDeleted(object)) { if (hasProperty) *hasProperty = false; @@ -403,6 +393,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC return QV4::Encode::null(); } + QV4::Scope scope(engine); QV4::Scoped<QObjectWrapper> wrapper(scope, wrap(engine, object)); if (!wrapper) { if (hasProperty) @@ -419,11 +410,7 @@ bool QObjectWrapper::setQmlProperty(ExecutionEngine *engine, QQmlContextData *qm return false; QQmlPropertyData local; - QQmlPropertyData *result = 0; - { - result = QQmlPropertyCache::property(engine->jsEngine(), object, name, qmlContext, local); - } - + QQmlPropertyData *result = QQmlPropertyCache::property(engine->jsEngine(), object, name, qmlContext, local); if (!result) return false; @@ -433,8 +420,6 @@ bool QObjectWrapper::setQmlProperty(ExecutionEngine *engine, QQmlContextData *qm return false; } - Scope scope(engine); - ScopedContext ctx(scope, engine->currentContext()); setProperty(engine, object, result, value); return true; } @@ -686,7 +671,7 @@ ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object) { if (engine->jsEngine()) QQmlData::ensurePropertyCache(engine->jsEngine(), object); - return (engine->memoryManager->alloc<QV4::QObjectWrapper>(engine, object))->asReturnedValue(); + return (engine->memoryManager->allocObject<QV4::QObjectWrapper>(object))->asReturnedValue(); } QV4::ReturnedValue QObjectWrapper::get(const Managed *m, String *name, bool *hasProperty) @@ -1037,19 +1022,18 @@ void QObjectWrapper::destroyObject(bool lastCall) if (!h->internalClass) return; // destroyObject already got called - QPointer<QObject> object = h->object; - if (object) { - QQmlData *ddata = QQmlData::get(object, false); + if (h->object) { + QQmlData *ddata = QQmlData::get(h->object, false); if (ddata) { - if (!object->parent() && !ddata->indestructible) { + if (!h->object->parent() && !ddata->indestructible) { if (ddata && ddata->ownContext && ddata->context) ddata->context->emitDestruction(); // This object is notionally destroyed now ddata->isQueuedForDeletion = true; if (lastCall) - delete object; + delete h->object; else - object->deleteLater(); + h->object->deleteLater(); } } } @@ -1061,9 +1045,6 @@ void QObjectWrapper::destroyObject(bool lastCall) DEFINE_OBJECT_VTABLE(QObjectWrapper); -// XXX TODO: Need to review all calls to QQmlEngine *engine() to confirm QObjects work -// correctly in a worker thread - namespace { template<typename A, typename B, typename C, typename D, typename E, @@ -1729,24 +1710,23 @@ QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine) ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, int index) { Scope valueScope(scope); - Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->alloc<QObjectMethod>(scope)); + Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->allocObject<QObjectMethod>(scope)); method->d()->object = object; if (QQmlData *ddata = QQmlData::get(object)) method->d()->propertyCache = ddata->propertyCache; method->d()->index = index; - method->d()->valueTypeWrapper = Primitive::undefinedValue(); return method.asReturnedValue(); } ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index) { Scope valueScope(scope); - Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->alloc<QObjectMethod>(scope)); + Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->allocObject<QObjectMethod>(scope)); method->d()->propertyCache = valueType->d()->propertyCache; method->d()->index = index; - method->d()->valueTypeWrapper = *valueType; + method->d()->valueTypeWrapper = valueType->d(); return method.asReturnedValue(); } @@ -1815,8 +1795,8 @@ ReturnedValue QObjectMethod::call(const Managed *m, CallData *callData) ReturnedValue QObjectMethod::callInternal(CallData *callData) const { - Scope scope(engine()); - ScopedContext context(scope, scope.engine->currentContext()); + ExecutionEngine *v4 = engine(); + ExecutionContext *context = v4->currentContext; if (d()->index == DestroyMethod) return method_destroy(context, callData->args, callData->argc); else if (d()->index == ToStringMethod) @@ -1824,11 +1804,10 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) const QQmlObjectOrGadget object(d()->object.data()); if (!d()->object) { - Scoped<QQmlValueTypeWrapper> wrapper(scope, d()->valueTypeWrapper); - if (!wrapper) + if (!d()->valueTypeWrapper) return Encode::undefined(); - object = QQmlObjectOrGadget(d()->propertyCache.data(), wrapper->d()->gadgetPtr); + object = QQmlObjectOrGadget(d()->propertyCache.data(), d()->valueTypeWrapper->gadgetPtr); } QQmlPropertyData method; @@ -1860,8 +1839,9 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) const } if (method.isV4Function()) { + Scope scope(v4); QV4::ScopedValue rv(scope, QV4::Primitive::undefinedValue()); - QQmlV4Function func(callData, rv, scope.engine); + QQmlV4Function func(callData, rv, v4); QQmlV4Function *funcptr = &func; void *args[] = { 0, &funcptr }; @@ -1871,31 +1851,46 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) const } if (!method.isOverload()) { - return CallPrecise(object, method, scope.engine, callData); + return CallPrecise(object, method, v4, callData); } else { - return CallOverloaded(object, method, scope.engine, callData, d()->propertyCache); + return CallOverloaded(object, method, v4, callData, d()->propertyCache); } } void QObjectMethod::markObjects(Heap::Base *that, ExecutionEngine *e) { QObjectMethod::Data *This = static_cast<QObjectMethod::Data*>(that); - This->valueTypeWrapper.mark(e); + if (This->valueTypeWrapper) + This->valueTypeWrapper->mark(e); FunctionObject::markObjects(that, e); } DEFINE_OBJECT_VTABLE(QObjectMethod); -Heap::QmlSignalHandler::QmlSignalHandler(QV4::ExecutionEngine *engine, QObject *object, int signalIndex) - : Heap::Object(engine) - , object(object) +Heap::QmlSignalHandler::QmlSignalHandler(QObject *object, int signalIndex) + : object(object) , signalIndex(signalIndex) { } DEFINE_OBJECT_VTABLE(QmlSignalHandler); +void QmlSignalHandler::initProto(ExecutionEngine *engine) +{ + if (engine->signalHandlerPrototype()->d()) + return; + + Scope scope(engine); + ScopedObject o(scope, engine->newObject()); + QV4::ScopedString connect(scope, engine->newIdentifier(QStringLiteral("connect"))); + QV4::ScopedString disconnect(scope, engine->newIdentifier(QStringLiteral("disconnect"))); + o->put(connect, QV4::ScopedValue(scope, engine->functionPrototype()->get(connect))); + o->put(disconnect, QV4::ScopedValue(scope, engine->functionPrototype()->get(disconnect))); + + engine->jsObjects[QV4::ExecutionEngine::SignalHandlerProto] = o->d(); +} + void MultiplyWrappedQObjectMap::insert(QObject *key, Heap::Object *value) { QV4::WeakValue v; diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index da24c81f40..1126013806 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -69,8 +69,10 @@ struct QObjectSlotDispatcher; namespace Heap { +struct QQmlValueTypeWrapper; + struct QObjectWrapper : Object { - QObjectWrapper(QV4::ExecutionEngine *engine, QObject *object); + QObjectWrapper(QObject *object); QPointer<QObject> object; }; @@ -80,13 +82,13 @@ struct QObjectMethod : FunctionObject { QQmlRefPointer<QQmlPropertyCache> propertyCache; int index; - Value valueTypeWrapper; + Pointer<QQmlValueTypeWrapper> valueTypeWrapper; const QMetaObject *metaObject(); }; struct QmlSignalHandler : Object { - QmlSignalHandler(QV4::ExecutionEngine *engine, QObject *object, int signalIndex); + QmlSignalHandler(QObject *object, int signalIndex); QPointer<QObject> object; int signalIndex; }; @@ -167,10 +169,13 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject struct QmlSignalHandler : public QV4::Object { V4_OBJECT2(QmlSignalHandler, QV4::Object) + V4_PROTOTYPE(signalHandlerPrototype) V4_NEEDS_DESTROY int signalIndex() const { return d()->signalIndex; } QObject *object() const { return d()->object.data(); } + + static void initProto(ExecutionEngine *v4); }; class MultiplyWrappedQObjectMap : public QObject, diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 329e5d2c56..1839ff17ab 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -62,35 +62,30 @@ Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyn using namespace QV4; DEFINE_OBJECT_VTABLE(RegExpObject); -DEFINE_OBJECT_VTABLE(RegExpPrototype); -Heap::RegExpObject::RegExpObject(InternalClass *ic, QV4::Object *prototype) - : Heap::Object(ic, prototype) +Heap::RegExpObject::RegExpObject() { - Scope scope(ic->engine); + Scope scope(internalClass->engine); Scoped<QV4::RegExpObject> o(scope, this); - o->d()->value = QV4::RegExp::create(ic->engine, QString(), false, false); + o->d()->value = QV4::RegExp::create(scope.engine, QString(), false, false); o->d()->global = false; - o->init(ic->engine); + o->initProperties(); } -Heap::RegExpObject::RegExpObject(QV4::ExecutionEngine *engine, QV4::RegExp *value, bool global) - : Heap::Object(engine->emptyClass, engine->regExpPrototype()) - , value(value->d()) +Heap::RegExpObject::RegExpObject(QV4::RegExp *value, bool global) + : value(value->d()) , global(global) { - Scope scope(engine); + Scope scope(internalClass->engine); Scoped<QV4::RegExpObject> o(scope, this); - o->init(engine); + o->initProperties(); } // Converts a QRegExp to a JS RegExp. // The conversion is not 100% exact since ECMA regexp and QRegExp // have different semantics/flags, but we try to do our best. -Heap::RegExpObject::RegExpObject(QV4::ExecutionEngine *engine, const QRegExp &re) - : Heap::Object(engine->emptyClass, engine->regExpPrototype()) +Heap::RegExpObject::RegExpObject(const QRegExp &re) { - value = 0; global = false; // Convert the pattern to a ECMAScript pattern. @@ -130,26 +125,21 @@ Heap::RegExpObject::RegExpObject(QV4::ExecutionEngine *engine, const QRegExp &re pattern = ecmaPattern; } - Scope scope(engine); + Scope scope(internalClass->engine); Scoped<QV4::RegExpObject> o(scope, this); - o->d()->value = QV4::RegExp::create(engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false); + o->d()->value = QV4::RegExp::create(scope.engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false); - o->init(engine); + o->initProperties(); } -void RegExpObject::init(ExecutionEngine *engine) +void RegExpObject::initProperties() { - Scope scope(engine); - ScopedObject protectThis(scope, this); + *propertyData(Index_LastIndex) = Primitive::fromInt32(0); - ScopedString lastIndex(scope, engine->newIdentifier(QStringLiteral("lastIndex"))); - ScopedValue v(scope, Primitive::fromInt32(0)); - insertMember(lastIndex, v, Attr_NotEnumerable|Attr_NotConfigurable); - if (!this->value()) - return; + Q_ASSERT(value()); - QString p = this->value()->pattern; + QString p = value()->pattern; if (p.isEmpty()) { p = QStringLiteral("(?:)"); } else { @@ -157,10 +147,10 @@ void RegExpObject::init(ExecutionEngine *engine) p.replace('/', QLatin1String("\\/")); } - defineReadonlyProperty(QStringLiteral("source"), (v = engine->newString(p))); - defineReadonlyProperty(QStringLiteral("global"), Primitive::fromBoolean(global())); - defineReadonlyProperty(QStringLiteral("ignoreCase"), Primitive::fromBoolean(this->value()->ignoreCase)); - defineReadonlyProperty(QStringLiteral("multiline"), Primitive::fromBoolean(this->value()->multiLine)); + *propertyData(Index_Source) = engine()->newString(p); + *propertyData(Index_Global) = Primitive::fromBoolean(global()); + *propertyData(Index_IgnoreCase) = Primitive::fromBoolean(value()->ignoreCase); + *propertyData(Index_Multiline) = Primitive::fromBoolean(value()->multiLine); } @@ -172,10 +162,10 @@ void RegExpObject::markObjects(Heap::Base *that, ExecutionEngine *e) Object::markObjects(that, e); } -Property *RegExpObject::lastIndexProperty() +Value *RegExpObject::lastIndexProperty() { Q_ASSERT(0 == internalClass()->find(engine()->id_lastIndex())); - return propertyAt(0); + return propertyData(0); } // Converts a JS RegExp to a QRegExp. @@ -239,17 +229,16 @@ void Heap::RegExpCtor::clearLastMatch() ReturnedValue RegExpCtor::construct(const Managed *m, CallData *callData) { Scope scope(static_cast<const Object *>(m)->engine()); - ScopedContext ctx(scope, scope.engine->currentContext()); ScopedValue r(scope, callData->argument(0)); ScopedValue f(scope, callData->argument(1)); Scoped<RegExpObject> re(scope, r); if (re) { if (!f->isUndefined()) - return ctx->engine()->throwTypeError(); + return scope.engine->throwTypeError(); Scoped<RegExp> regexp(scope, re->value()); - return Encode(ctx->d()->engine->newRegExpObject(regexp, re->global())); + return Encode(scope.engine->newRegExpObject(regexp, re->global())); } QString pattern; @@ -274,16 +263,16 @@ ReturnedValue RegExpCtor::construct(const Managed *m, CallData *callData) } else if (str.at(i) == QLatin1Char('m') && !multiLine) { multiLine = true; } else { - return ctx->engine()->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor")); + return scope.engine->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor")); } } } - Scoped<RegExp> regexp(scope, RegExp::create(ctx->d()->engine, pattern, ignoreCase, multiLine)); + Scoped<RegExp> regexp(scope, RegExp::create(scope.engine, pattern, ignoreCase, multiLine)); if (!regexp->isValid()) - return ctx->engine()->throwSyntaxError(QStringLiteral("Invalid regular expression")); + return scope.engine->throwSyntaxError(QStringLiteral("Invalid regular expression")); - return Encode(ctx->d()->engine->newRegExpObject(regexp, global)); + return Encode(scope.engine->newRegExpObject(regexp, global)); } ReturnedValue RegExpCtor::call(const Managed *that, CallData *callData) @@ -354,9 +343,9 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) return Encode::undefined(); QString s = arg->stringValue()->toQString(); - int offset = r->global() ? r->lastIndexProperty()->value.toInt32() : 0; + int offset = r->global() ? r->lastIndexProperty()->toInt32() : 0; if (offset < 0 || offset > s.length()) { - r->lastIndexProperty()->value = Primitive::fromInt32(0); + *r->lastIndexProperty() = Primitive::fromInt32(0); return Encode::null(); } @@ -367,7 +356,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) regExpCtor->d()->clearLastMatch(); if (result == -1) { - r->lastIndexProperty()->value = Primitive::fromInt32(0); + *r->lastIndexProperty() = Primitive::fromInt32(0); return Encode::null(); } @@ -383,8 +372,8 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) array->arrayPut(i, v); } array->setArrayLengthUnchecked(len); - array->memberData()->data[Index_ArrayIndex] = Primitive::fromInt32(result); - array->memberData()->data[Index_ArrayInput] = arg; + *array->propertyData(Index_ArrayIndex) = Primitive::fromInt32(result); + *array->propertyData(Index_ArrayInput) = arg; RegExpCtor::Data *dd = regExpCtor->d(); dd->lastMatch = array; @@ -393,7 +382,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) dd->lastMatchEnd = matchOffsets[1]; if (r->global()) - r->lastIndexProperty()->value = Primitive::fromInt32(matchOffsets[1]); + *r->lastIndexProperty() = Primitive::fromInt32(matchOffsets[1]); return array.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index 29d20614de..4f803df9c8 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -57,9 +57,9 @@ namespace QV4 { namespace Heap { struct RegExpObject : Object { - RegExpObject(InternalClass *ic, QV4::Object *prototype); - RegExpObject(QV4::ExecutionEngine *engine, QV4::RegExp *value, bool global); - RegExpObject(QV4::ExecutionEngine *engine, const QRegExp &re); + RegExpObject(); + RegExpObject(QV4::RegExp *value, bool global); + RegExpObject(const QRegExp &re); Pointer<RegExp> value; bool global; @@ -74,16 +74,13 @@ struct RegExpCtor : FunctionObject { void clearLastMatch(); }; -struct RegExpPrototype : RegExpObject -{ - inline RegExpPrototype(ExecutionEngine *e); -}; - } struct RegExpObject: Object { V4_OBJECT2(RegExpObject, Object) Q_MANAGED_TYPE(RegExpObject) + V4_INTERNALCLASS(regExpObjectClass) + V4_PROTOTYPE(regExpPrototype) // needs to be compatible with the flags in qv4jsir_p.h enum Flags { @@ -93,6 +90,11 @@ struct RegExpObject: Object { }; enum { + Index_LastIndex = 0, + Index_Source = 1, + Index_Global = 2, + Index_IgnoreCase = 3, + Index_Multiline = 4, Index_ArrayIndex = Heap::ArrayObject::LengthPropertyIndex + 1, Index_ArrayInput = Index_ArrayIndex + 1 }; @@ -100,9 +102,9 @@ struct RegExpObject: Object { Heap::RegExp *value() const { return d()->value; } bool global() const { return d()->global; } - void init(ExecutionEngine *engine); + void initProperties(); - Property *lastIndexProperty(); + Value *lastIndexProperty(); QRegExp toQRegExp() const; QString toString() const; QString source() const; @@ -128,8 +130,6 @@ struct RegExpCtor: FunctionObject struct RegExpPrototype: RegExpObject { - V4_OBJECT2(RegExpPrototype, RegExpObject) - void init(ExecutionEngine *engine, Object *ctor); static ReturnedValue method_exec(CallContext *ctx); @@ -145,11 +145,6 @@ struct RegExpPrototype: RegExpObject static ReturnedValue method_get_rightContext(CallContext *ctx); }; -inline Heap::RegExpPrototype::RegExpPrototype(ExecutionEngine *e) - : RegExpObject(e->emptyClass, e->objectPrototype()) -{ -} - } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 9316223696..0d7a1851b8 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -268,10 +268,9 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix) ReturnedValue Runtime::closure(ExecutionEngine *engine, int functionId) { - QV4::Function *clos = engine->currentContext()->compilationUnit->runtimeFunctions[functionId]; + QV4::Function *clos = engine->current->compilationUnit->runtimeFunctions[functionId]; Q_ASSERT(clos); - Scope scope(engine); - return FunctionObject::createScriptFunction(ScopedContext(scope, engine->currentContext()), clos)->asReturnedValue(); + return FunctionObject::createScriptFunction(engine->currentContext, clos)->asReturnedValue(); } ReturnedValue Runtime::deleteElement(ExecutionEngine *engine, const Value &base, const Value &index) @@ -292,7 +291,7 @@ ReturnedValue Runtime::deleteElement(ExecutionEngine *engine, const Value &base, ReturnedValue Runtime::deleteMember(ExecutionEngine *engine, const Value &base, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); return deleteMemberString(engine, base, name); } @@ -308,9 +307,8 @@ ReturnedValue Runtime::deleteMemberString(ExecutionEngine *engine, const Value & ReturnedValue Runtime::deleteName(ExecutionEngine *engine, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); - ScopedContext ctx(scope, engine->currentContext()); - return Encode(ctx->deleteProperty(name)); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); + return Encode(engine->currentContext->deleteProperty(name)); } QV4::ReturnedValue Runtime::instanceof(ExecutionEngine *engine, const Value &left, const Value &right) @@ -566,7 +564,7 @@ QV4::ReturnedValue Runtime::addString(ExecutionEngine *engine, const Value &left void Runtime::setProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); ScopedObject o(scope, object.toObject(engine)); if (!o) return; @@ -663,15 +661,14 @@ ReturnedValue Runtime::foreachNextPropertyName(const Value &foreach_iterator) void Runtime::setActivationProperty(ExecutionEngine *engine, int nameIndex, const Value &value) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); - ScopedContext ctx(scope, engine->currentContext()); - ctx->setProperty(name, value); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); + engine->currentContext->setProperty(name, value); } ReturnedValue Runtime::getProperty(ExecutionEngine *engine, const Value &object, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); ScopedObject o(scope, object); if (o) @@ -691,9 +688,8 @@ ReturnedValue Runtime::getProperty(ExecutionEngine *engine, const Value &object, ReturnedValue Runtime::getActivationProperty(ExecutionEngine *engine, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); - ScopedContext ctx(scope, engine->currentContext()); - return ctx->getProperty(name); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); + return engine->currentContext->getProperty(name); } #endif // V4_BOOTSTRAP @@ -909,12 +905,12 @@ ReturnedValue Runtime::callGlobalLookup(ExecutionEngine *engine, uint index, Cal Scope scope(engine); Q_ASSERT(callData->thisObject.isUndefined()); - Lookup *l = engine->currentContext()->lookups + index; + Lookup *l = engine->current->lookups + index; ScopedFunctionObject o(scope, l->globalGetter(l, engine)); if (!o) return engine->throwTypeError(); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]); if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) return static_cast<EvalFunction *>(o.getPointer())->evalCall(callData, true); @@ -926,11 +922,10 @@ ReturnedValue Runtime::callActivationProperty(ExecutionEngine *engine, int nameI { Q_ASSERT(callData->thisObject.isUndefined()); Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); ScopedObject base(scope); - ScopedContext ctx(scope, engine->currentContext()); - ScopedValue func(scope, ctx->getPropertyAndBase(name, base.getRef())); + ScopedValue func(scope, engine->currentContext->getPropertyAndBase(name, base.getRef())); if (scope.engine->hasException) return Encode::undefined(); @@ -980,7 +975,7 @@ ReturnedValue Runtime::callQmlContextObjectProperty(ExecutionEngine *engine, int ReturnedValue Runtime::callProperty(ExecutionEngine *engine, int nameIndex, CallData *callData) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); ScopedObject baseObject(scope, callData->thisObject); if (!baseObject) { Q_ASSERT(!callData->thisObject.isEmpty()); @@ -1006,7 +1001,7 @@ ReturnedValue Runtime::callProperty(ExecutionEngine *engine, int nameIndex, Call ReturnedValue Runtime::callPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData) { - Lookup *l = engine->currentContext()->lookups + index; + Lookup *l = engine->current->lookups + index; Value v; v = l->getter(l, engine, callData->thisObject); if (!v.isObject()) @@ -1046,7 +1041,7 @@ ReturnedValue Runtime::constructGlobalLookup(ExecutionEngine *engine, uint index Scope scope(engine); Q_ASSERT(callData->thisObject.isUndefined()); - Lookup *l = engine->currentContext()->lookups + index; + Lookup *l = engine->current->lookups + index; ScopedObject f(scope, l->globalGetter(l, engine)); if (!f) return engine->throwTypeError(); @@ -1058,9 +1053,8 @@ ReturnedValue Runtime::constructGlobalLookup(ExecutionEngine *engine, uint index ReturnedValue Runtime::constructActivationProperty(ExecutionEngine *engine, int nameIndex, CallData *callData) { Scope scope(engine); - ScopedContext ctx(scope, engine->currentContext()); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); - ScopedValue func(scope, ctx->getProperty(name)); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); + ScopedValue func(scope, engine->currentContext->getProperty(name)); if (scope.engine->hasException) return Encode::undefined(); @@ -1084,7 +1078,7 @@ ReturnedValue Runtime::constructProperty(ExecutionEngine *engine, int nameIndex, { Scope scope(engine); ScopedObject thisObject(scope, callData->thisObject.toObject(engine)); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); if (scope.engine->hasException) return Encode::undefined(); @@ -1097,7 +1091,7 @@ ReturnedValue Runtime::constructProperty(ExecutionEngine *engine, int nameIndex, ReturnedValue Runtime::constructPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData) { - Lookup *l = engine->currentContext()->lookups + index; + Lookup *l = engine->current->lookups + index; Value v; v = l->getter(l, engine, callData->thisObject); if (!v.isObject()) @@ -1145,9 +1139,8 @@ ReturnedValue Runtime::typeofValue(ExecutionEngine *engine, const Value &value) QV4::ReturnedValue Runtime::typeofName(ExecutionEngine *engine, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); - ScopedContext ctx(scope, engine->currentContext()); - ScopedValue prop(scope, ctx->getProperty(name)); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); + ScopedValue prop(scope, engine->currentContext->getProperty(name)); // typeof doesn't throw. clear any possible exception scope.engine->hasException = false; return Runtime::typeofValue(engine, prop); @@ -1156,7 +1149,7 @@ QV4::ReturnedValue Runtime::typeofName(ExecutionEngine *engine, int nameIndex) QV4::ReturnedValue Runtime::typeofMember(ExecutionEngine *engine, const Value &base, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); ScopedObject obj(scope, base.toObject(engine)); if (scope.engine->hasException) return Encode::undefined(); @@ -1175,14 +1168,6 @@ QV4::ReturnedValue Runtime::typeofElement(ExecutionEngine *engine, const Value & return Runtime::typeofValue(engine, prop); } -void Runtime::pushWithScope(const Value &o, ExecutionEngine *engine) -{ - Scope scope(engine); - ScopedObject obj(scope, o.toObject(engine)); - ScopedContext ctx(scope, engine->currentContext()); - ctx->newWithContext(obj); -} - ReturnedValue Runtime::unwindException(ExecutionEngine *engine) { if (!engine->hasException) @@ -1190,45 +1175,47 @@ ReturnedValue Runtime::unwindException(ExecutionEngine *engine) return engine->catchException(0); } +/* The next three methods are a bit tricky. They can't open up a Scope, as that + * would mess up the pushing of the context. + * + * Instead the push/pop pair acts as a non local scope. + */ +void Runtime::pushWithScope(const Value &o, ExecutionEngine *engine) +{ + engine->pushContext(engine->currentContext->newWithContext(o.toObject(engine))); + Q_ASSERT(engine->jsStackTop = engine->currentContext + 2); +} + void Runtime::pushCatchScope(NoThrowEngine *engine, int exceptionVarNameIndex) { - Scope scope(engine); - ScopedValue v(scope, engine->catchException(0)); - ScopedString exceptionVarName(scope, engine->currentContext()->compilationUnit->runtimeStrings[exceptionVarNameIndex]); - ScopedContext ctx(scope, engine->currentContext()); - ctx->newCatchContext(exceptionVarName, v); + ExecutionContext *c = engine->currentContext; + engine->pushContext(c->newCatchContext(c->d()->compilationUnit->runtimeStrings[exceptionVarNameIndex], engine->catchException(0))); + Q_ASSERT(engine->jsStackTop = engine->currentContext + 2); } void Runtime::popScope(ExecutionEngine *engine) { + Q_ASSERT(engine->jsStackTop = engine->currentContext + 2); engine->popContext(); + engine->jsStackTop -= 2; } void Runtime::declareVar(ExecutionEngine *engine, bool deletable, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); - ScopedContext ctx(scope, engine->currentContext()); - ctx->createMutableBinding(name, deletable); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); + engine->currentContext->createMutableBinding(name, deletable); } ReturnedValue Runtime::arrayLiteral(ExecutionEngine *engine, Value *values, uint length) { - Scope scope(engine); - ScopedArrayObject a(scope, engine->newArrayObject()); - - if (length) { - a->arrayReserve(length); - a->arrayPut(0, values, length); - a->setArrayLengthUnchecked(length); - } - return a.asReturnedValue(); + return engine->newArrayObject(values, length)->asReturnedValue(); } ReturnedValue Runtime::objectLiteral(ExecutionEngine *engine, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags) { Scope scope(engine); - QV4::InternalClass *klass = engine->currentContext()->compilationUnit->runtimeClasses[classId]; + QV4::InternalClass *klass = engine->current->compilationUnit->runtimeClasses[classId]; ScopedObject o(scope, engine->newObject(klass, engine->objectPrototype())); { @@ -1238,7 +1225,7 @@ ReturnedValue Runtime::objectLiteral(ExecutionEngine *engine, const QV4::Value * } for (uint i = 0; i < klass->size; ++i) - o->memberData()->data[i] = *args++; + *o->propertyData(i) = *args++; if (arrayValueCount > 0) { ScopedValue entry(scope); @@ -1269,10 +1256,10 @@ ReturnedValue Runtime::objectLiteral(ExecutionEngine *engine, const QV4::Value * QV4::ReturnedValue Runtime::setupArgumentsObject(ExecutionEngine *engine) { - Q_ASSERT(engine->currentContext()->type == Heap::ExecutionContext::Type_CallContext); - Scope scope(engine); - Scoped<CallContext> c(scope, static_cast<Heap::CallContext *>(engine->currentContext())); - return (engine->memoryManager->alloc<ArgumentsObject>(c))->asReturnedValue(); + Q_ASSERT(engine->current->type == Heap::ExecutionContext::Type_CallContext); + QV4::CallContext *c = static_cast<QV4::CallContext *>(engine->currentContext); + QV4::InternalClass *ic = c->d()->strictMode ? engine->strictArgumentsObjectClass : engine->argumentsObjectClass; + return engine->memoryManager->allocObject<ArgumentsObject>(ic, engine->objectPrototype(), c)->asReturnedValue(); } #endif // V4_BOOTSTRAP @@ -1363,7 +1350,7 @@ ReturnedValue Runtime::getQmlContext(NoThrowEngine *engine) ReturnedValue Runtime::regexpLiteral(ExecutionEngine *engine, int id) { - return engine->currentContext()->compilationUnit->runtimeRegularExpressions[id].asReturnedValue(); + return engine->current->compilationUnit->runtimeRegularExpressions[id].asReturnedValue(); } ReturnedValue Runtime::getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired) @@ -1459,13 +1446,13 @@ ReturnedValue Runtime::getQmlImportedScripts(NoThrowEngine *engine) QV4::ReturnedValue Runtime::getQmlSingleton(QV4::NoThrowEngine *engine, int nameIndex) { Scope scope(engine); - ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]); return engine->qmlSingletonWrapper(name); } void Runtime::convertThisToObject(ExecutionEngine *engine) { - Value *t = &engine->currentContext()->callData->thisObject; + Value *t = &engine->current->callData->thisObject; if (t->isObject()) return; if (t->isNullOrUndefined()) { diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index e19aeaf882..0c79897015 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -54,18 +54,12 @@ struct ScopedValue; struct Scope { inline Scope(ExecutionContext *ctx) : engine(ctx->d()->engine) -#ifndef QT_NO_DEBUG - , size(0) -#endif { mark = engine->jsStackTop; } explicit Scope(ExecutionEngine *e) : engine(e) -#ifndef QT_NO_DEBUG - , size(0) -#endif { mark = engine->jsStackTop; } @@ -73,6 +67,7 @@ struct Scope { ~Scope() { #ifndef QT_NO_DEBUG Q_ASSERT(engine->jsStackTop >= mark); + Q_ASSERT(engine->currentContext < mark); memset(mark, 0, (engine->jsStackTop - mark)*sizeof(Value)); #endif #ifdef V4_USE_VALGRIND @@ -82,9 +77,6 @@ struct Scope { } Value *alloc(int nValues) { -#ifndef QT_NO_DEBUG - size += nValues; -#endif return engine->jsAlloca(nValues); } @@ -94,9 +86,6 @@ struct Scope { ExecutionEngine *engine; Value *mark; -#ifndef QT_NO_DEBUG - mutable int size; -#endif private: Q_DISABLE_COPY(Scope) @@ -108,18 +97,12 @@ struct ScopedValue { ptr = scope.engine->jsStackTop++; ptr->setRawValue(0); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } ScopedValue(const Scope &scope, const Value &v) { ptr = scope.engine->jsStackTop++; *ptr = v; -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } ScopedValue(const Scope &scope, Heap::Base *o) @@ -129,27 +112,18 @@ struct ScopedValue #if QT_POINTER_SIZE == 4 ptr->setTag(QV4::Value::Managed_Type); #endif -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } ScopedValue(const Scope &scope, Managed *m) { ptr = scope.engine->jsStackTop++; ptr->setRawValue(m->asReturnedValue()); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } ScopedValue(const Scope &scope, const ReturnedValue &v) { ptr = scope.engine->jsStackTop++; ptr->setRawValue(v); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } ScopedValue &operator=(const Value &v) { @@ -213,18 +187,12 @@ struct Scoped #if QT_POINTER_SIZE == 4 ptr->setTag(QV4::Value::Managed_Type); #endif -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, const Value &v) { ptr = scope.engine->jsStackTop++; setPointer(v.as<T>()); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, Heap::Base *o) { @@ -232,69 +200,45 @@ struct Scoped v = o; ptr = scope.engine->jsStackTop++; setPointer(v.as<T>()); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, const ScopedValue &v) { ptr = scope.engine->jsStackTop++; setPointer(v.ptr->as<T>()); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, const Value &v, _Convert) { ptr = scope.engine->jsStackTop++; ptr->setRawValue(value_convert<T>(scope.engine, v)); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, const Value *v) { ptr = scope.engine->jsStackTop++; setPointer(v ? v->as<T>() : 0); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, T *t) { ptr = scope.engine->jsStackTop++; setPointer(t); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, typename T::Data *t) { ptr = scope.engine->jsStackTop++; *ptr = t; -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, const ReturnedValue &v) { ptr = scope.engine->jsStackTop++; setPointer(QV4::Value::fromReturnedValue(v).as<T>()); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped(const Scope &scope, const ReturnedValue &v, _Convert) { ptr = scope.engine->jsStackTop++; ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v))); -#ifndef QT_NO_DEBUG - ++scope.size; -#endif } Scoped<T> &operator=(Heap::Base *o) { @@ -414,29 +358,18 @@ struct ScopedProperty struct ExecutionContextSaver { ExecutionEngine *engine; - Value *savedContext; + ExecutionContext *savedContext; - ExecutionContextSaver(Scope &scope, ExecutionContext *context) - : engine(context->d()->engine) - , savedContext(scope.alloc(1)) + ExecutionContextSaver(Scope &scope) + : engine(scope.engine) { - savedContext->setM(context->d()); -#if QT_POINTER_SIZE == 4 - savedContext->setTag(QV4::Value::Managed_Type); -#endif - } - ExecutionContextSaver(Scope &scope, Heap::ExecutionContext *context) - : engine(context->engine) - , savedContext(scope.alloc(1)) - { - savedContext->setM(context); -#if QT_POINTER_SIZE == 4 - savedContext->setTag(QV4::Value::Managed_Type); -#endif + savedContext = engine->currentContext; } ~ExecutionContextSaver() { - engine->current = static_cast<Heap::ExecutionContext *>(savedContext->heapObject()); + Q_ASSERT(engine->jsStackTop > engine->currentContext); + engine->currentContext = savedContext; + engine->current = savedContext->d(); } }; diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 7067d10e22..7f2f22780e 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -59,11 +59,15 @@ namespace QV4 { namespace Heap { struct CompilationUnitHolder : Object { - inline CompilationUnitHolder(ExecutionEngine *engine, CompiledData::CompilationUnit *unit); + inline CompilationUnitHolder(CompiledData::CompilationUnit *unit); QQmlRefPointer<CompiledData::CompilationUnit> unit; }; +struct QmlBindingWrapper : FunctionObject { + QmlBindingWrapper(QV4::QmlContext *scope, Function *f); +}; + } struct CompilationUnitHolder : public Object @@ -73,12 +77,17 @@ struct CompilationUnitHolder : public Object }; inline -Heap::CompilationUnitHolder::CompilationUnitHolder(ExecutionEngine *engine, CompiledData::CompilationUnit *unit) - : Heap::Object(engine) - , unit(unit) +Heap::CompilationUnitHolder::CompilationUnitHolder(CompiledData::CompilationUnit *unit) + : unit(unit) { } +struct QmlBindingWrapper : FunctionObject { + V4_OBJECT2(QmlBindingWrapper, FunctionObject) + + static ReturnedValue call(const Managed *that, CallData *callData); +}; + } QT_END_NAMESPACE @@ -88,7 +97,7 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlBindingWrapper); DEFINE_OBJECT_VTABLE(CompilationUnitHolder); -Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::QmlContextWrapper *qml) +Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::QmlContext *scope, Function *f) : Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false) { Q_ASSERT(scope->inUse()); @@ -96,12 +105,6 @@ Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Functio function = f; if (function) function->compilationUnit->addref(); - - Scope s(scope); - Scoped<QV4::QmlBindingWrapper> protectThis(s, this); - - this->scope = scope->newQmlContext(qml); - internalClass->engine->popContext(); } ReturnedValue QmlBindingWrapper::call(const Managed *that, CallData *callData) @@ -113,65 +116,33 @@ ReturnedValue QmlBindingWrapper::call(const Managed *that, CallData *callData) CHECK_STACK_LIMITS(v4); Scope scope(v4); + ExecutionContextSaver ctxSaver(scope); + QV4::Function *f = This->function(); if (!f) return QV4::Encode::undefined(); - ScopedContext context(scope, v4->currentContext()); - Scoped<CallContext> ctx(scope, context->newCallContext(This, callData)); + Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(This, callData)); + v4->pushContext(ctx); - ExecutionContextSaver ctxSaver(scope, context); ScopedValue result(scope, Q_V4_PROFILE(v4, f)); return result->asReturnedValue(); } -static ReturnedValue signalParameterGetter(QV4::CallContext *ctx, uint parameterIndex) -{ - QV4::Scope scope(ctx); - QV4::Scoped<CallContext> signalEmittingContext(scope, ctx->d()->parent.cast<Heap::CallContext>()); - Q_ASSERT(signalEmittingContext && signalEmittingContext->d()->type >= QV4::Heap::ExecutionContext::Type_SimpleCallContext); - return signalEmittingContext->argument(parameterIndex); -} - -Heap::FunctionObject *QmlBindingWrapper::createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, Function *runtimeFunction, const QList<QByteArray> &signalParameters, QString *error) -{ - ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine); - QV4::Scope valueScope(engine); - QV4::Scoped<QmlContextWrapper> qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine, qmlContext, scopeObject)); - ScopedContext global(valueScope, valueScope.engine->rootContext()); - QV4::Scoped<QmlContext> wrapperContext(valueScope, global->newQmlContext(qmlScopeObject)); - engine->popContext(); - - if (!signalParameters.isEmpty()) { - if (error) - QQmlPropertyCache::signalParameterStringForJS(engine, signalParameters, error); - QV4::ScopedProperty p(valueScope); - QV4::ScopedString s(valueScope); - int index = 0; - foreach (const QByteArray ¶m, signalParameters) { - QV4::ScopedFunctionObject g(valueScope, engine->memoryManager->alloc<QV4::IndexedBuiltinFunction>(wrapperContext, index++, signalParameterGetter)); - p->setGetter(g); - p->setSetter(0); - s = engine->newString(QString::fromUtf8(param)); - qmlScopeObject->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable); - } - } - - QV4::ScopedFunctionObject function(valueScope, QV4::FunctionObject::createScriptFunction(wrapperContext, runtimeFunction)); - return function->d(); -} - -Script::Script(ExecutionEngine *v4, Object *qml, CompiledData::CompilationUnit *compilationUnit) +Script::Script(ExecutionEngine *v4, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit) : line(0), column(0), scope(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false) - , qml(v4, qml), vmFunction(0), parseAsBinding(true) + , vmFunction(0), parseAsBinding(true) { + if (qml) + qmlContext.set(v4, *qml); + parsed = true; vmFunction = compilationUnit ? compilationUnit->linkToEngine(v4) : 0; if (vmFunction) { Scope valueScope(v4); - ScopedObject holder(valueScope, v4->memoryManager->alloc<CompilationUnitHolder>(v4, compilationUnit)); + ScopedObject holder(valueScope, v4->memoryManager->allocObject<CompilationUnitHolder>(compilationUnit)); compilationUnitHolder.set(v4, holder); } } @@ -242,7 +213,7 @@ void Script::parse() isel->setUseFastLookups(false); QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = isel->compile(); vmFunction = compilationUnit->linkToEngine(v4); - ScopedObject holder(valueScope, v4->memoryManager->alloc<CompilationUnitHolder>(v4, compilationUnit)); + ScopedObject holder(valueScope, v4->memoryManager->allocObject<CompilationUnitHolder>(compilationUnit)); compilationUnitHolder.set(v4, holder); } @@ -263,10 +234,10 @@ ReturnedValue Script::run() QV4::ExecutionEngine *engine = scope->engine(); QV4::Scope valueScope(engine); - if (qml.isUndefined()) { + if (qmlContext.isUndefined()) { TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction); - ExecutionContextSaver ctxSaver(valueScope, scope); + ExecutionContextSaver ctxSaver(valueScope); ContextStateSaver stateSaver(valueScope, scope); scope->d()->strictMode = vmFunction->isStrict(); scope->d()->lookups = vmFunction->compilationUnit->runtimeLookups; @@ -274,8 +245,8 @@ ReturnedValue Script::run() return Q_V4_PROFILE(engine, vmFunction); } else { - Scoped<QmlContextWrapper> qmlObj(valueScope, qml.value()); - ScopedFunctionObject f(valueScope, engine->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj)); + Scoped<QmlContext> qml(valueScope, qmlContext.value()); + ScopedFunctionObject f(valueScope, engine->memoryManager->allocObject<QmlBindingWrapper>(qml, vmFunction)); ScopedCallData callData(valueScope); callData->thisObject = Primitive::undefinedValue(); return f->call(callData); @@ -352,15 +323,15 @@ ReturnedValue Script::qmlBinding() parse(); ExecutionEngine *v4 = scope->engine(); Scope valueScope(v4); - Scoped<QmlContextWrapper> qmlObj(valueScope, qml.value()); - ScopedObject v(valueScope, v4->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj)); + Scoped<QmlContext> qml(valueScope, qmlContext.value()); + ScopedObject v(valueScope, v4->memoryManager->allocObject<QmlBindingWrapper>(qml, vmFunction)); return v.asReturnedValue(); } -QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject) +QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext) { QV4::Scope scope(engine); - QV4::Script qmlScript(engine, scopeObject, script, QString()); + QV4::Script qmlScript(engine, qmlContext, script, QString()); qmlScript.parse(); QV4::ScopedValue result(scope); diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index fad011f88a..63e8239342 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -36,6 +36,7 @@ #include "qv4global_p.h" #include "qv4engine_p.h" #include "qv4functionobject_p.h" +#include "qv4context_p.h" #include <QQmlError> @@ -85,32 +86,19 @@ struct ContextStateSaver { } }; -namespace Heap { -struct QmlBindingWrapper : Heap::FunctionObject { - QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::QmlContextWrapper *qml); -}; - -} - -struct Q_QML_EXPORT QmlBindingWrapper : FunctionObject { - V4_OBJECT2(QmlBindingWrapper, FunctionObject) - - static ReturnedValue call(const Managed *that, CallData *callData); - - static Heap::FunctionObject *createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, - const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0); -}; - struct Q_QML_EXPORT Script { Script(ExecutionContext *scope, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) : sourceFile(source), line(line), column(column), sourceCode(sourceCode) , scope(scope), strictMode(false), inheritContext(false), parsed(false) , vmFunction(0), parseAsBinding(false) {} - Script(ExecutionEngine *engine, Object *qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) + Script(ExecutionEngine *engine, QmlContext *qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) : sourceFile(source), line(line), column(column), sourceCode(sourceCode) , scope(engine->rootContext()), strictMode(false), inheritContext(true), parsed(false) - , qml(engine, qml), vmFunction(0), parseAsBinding(true) {} - Script(ExecutionEngine *engine, Object *qml, CompiledData::CompilationUnit *compilationUnit); + , vmFunction(0), parseAsBinding(true) { + if (qml) + qmlContext.set(engine, *qml); + } + Script(ExecutionEngine *engine, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit); ~Script(); QString sourceFile; int line; @@ -120,7 +108,7 @@ struct Q_QML_EXPORT Script { bool strictMode; bool inheritContext; bool parsed; - QV4::PersistentValue qml; + QV4::PersistentValue qmlContext; QV4::PersistentValue compilationUnitHolder; Function *vmFunction; bool parseAsBinding; @@ -134,7 +122,7 @@ struct Q_QML_EXPORT Script { static QQmlRefPointer<CompiledData::CompilationUnit> precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors = 0, QQmlJS::Directives *directivesCollector = 0); - static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject); + static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext); }; } diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 23bbcc60e1..36ee848d00 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -207,8 +207,8 @@ namespace Heap { template <typename Container> struct QQmlSequence : Object { - QQmlSequence(QV4::ExecutionEngine *engine, const Container &container); - QQmlSequence(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex); + QQmlSequence(const Container &container); + QQmlSequence(QObject *object, int propertyIndex); mutable Container container; QPointer<QObject> object; @@ -223,6 +223,7 @@ struct QQmlSequence : public QV4::Object { V4_OBJECT2(QQmlSequence<Container>, QV4::Object) Q_MANAGED_TYPE(QmlSequence) + V4_PROTOTYPE(sequencePrototype) V4_NEEDS_DESTROY public: @@ -543,26 +544,24 @@ public: template <typename Container> -Heap::QQmlSequence<Container>::QQmlSequence(QV4::ExecutionEngine *engine, const Container &container) - : Heap::Object(engine->emptyClass, engine->sequencePrototype()) - , container(container) +Heap::QQmlSequence<Container>::QQmlSequence(const Container &container) + : container(container) , propertyIndex(-1) , isReference(false) { - QV4::Scope scope(engine); + QV4::Scope scope(internalClass->engine); QV4::Scoped<QV4::QQmlSequence<Container> > o(scope, this); o->setArrayType(Heap::ArrayData::Custom); o->init(); } template <typename Container> -Heap::QQmlSequence<Container>::QQmlSequence(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex) - : Heap::Object(engine->emptyClass, engine->sequencePrototype()) - , object(object) +Heap::QQmlSequence<Container>::QQmlSequence(QObject *object, int propertyIndex) + : object(object) , propertyIndex(propertyIndex) , isReference(true) { - QV4::Scope scope(engine); + QV4::Scope scope(internalClass->engine); QV4::Scoped<QV4::QQmlSequence<Container> > o(scope, this); o->setArrayType(Heap::ArrayData::Custom); o->loadReference(); @@ -644,7 +643,7 @@ bool SequencePrototype::isSequenceType(int sequenceTypeId) #define NEW_REFERENCE_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \ if (sequenceType == qMetaTypeId<SequenceType>()) { \ - QV4::ScopedObject obj(scope, engine->memoryManager->alloc<QQml##ElementTypeName##List>(engine, object, propertyIndex)); \ + QV4::ScopedObject obj(scope, engine->memoryManager->allocObject<QQml##ElementTypeName##List>(object, propertyIndex)); \ return obj.asReturnedValue(); \ } else @@ -662,7 +661,7 @@ ReturnedValue SequencePrototype::newSequence(QV4::ExecutionEngine *engine, int s #define NEW_COPY_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \ if (sequenceType == qMetaTypeId<SequenceType>()) { \ - QV4::ScopedObject obj(scope, engine->memoryManager->alloc<QQml##ElementTypeName##List>(engine, v.value<SequenceType >())); \ + QV4::ScopedObject obj(scope, engine->memoryManager->allocObject<QQml##ElementTypeName##List>(v.value<SequenceType >())); \ return obj.asReturnedValue(); \ } else diff --git a/src/qml/jsruntime/qv4sparsearray.cpp b/src/qml/jsruntime/qv4sparsearray.cpp index 01f94eeac6..bb1d3aeb69 100644 --- a/src/qml/jsruntime/qv4sparsearray.cpp +++ b/src/qml/jsruntime/qv4sparsearray.cpp @@ -246,15 +246,12 @@ void SparseArray::deleteNode(SparseArrayNode *z) x->setParent(y->parent()); if (root == y) root = x; - else if (y->parent()->left == y) { + else if (y->parent()->left == y) y->parent()->left = x; - if (x) - x->size_left += y->size_left; - } else { + else y->parent()->right = x; - if (x) - x->size_left += y->size_left; - } + if (x && x == y->right) + x->size_left += y->size_left; y->size_left = 0; } if (y->color() != SparseArrayNode::Red) { diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 9fbafa7ded..757ec6c6bf 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -67,25 +67,17 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(StringObject); -Heap::StringObject::StringObject(InternalClass *ic, QV4::Object *prototype) - : Heap::Object(ic, prototype) +Heap::StringObject::StringObject() { Q_ASSERT(vtable() == QV4::StringObject::staticVTable()); - string = ic->engine->newString(); - - Scope scope(ic->engine); - ScopedObject s(scope, this); - s->defineReadonlyProperty(ic->engine->id_length(), Primitive::fromInt32(0)); + string = internalClass->engine->id_empty()->d(); + *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); } -Heap::StringObject::StringObject(ExecutionEngine *engine, const QV4::String *str) - : Heap::Object(engine->emptyClass, engine->stringPrototype()) +Heap::StringObject::StringObject(const QV4::String *str) { string = str->d(); - - Scope scope(engine); - ScopedObject s(scope, this); - s->defineReadonlyProperty(engine->id_length(), Primitive::fromUInt32(length())); + *propertyData(LengthPropertyIndex) = Primitive::fromInt32(length()); } Heap::String *Heap::StringObject::getIndex(uint index) const @@ -98,7 +90,7 @@ Heap::String *Heap::StringObject::getIndex(uint index) const uint Heap::StringObject::length() const { - return string->toQString().length(); + return string->len; } bool StringObject::deleteIndexedProperty(Managed *m, uint index) @@ -109,7 +101,7 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index) Q_ASSERT(!!o); if (index < static_cast<uint>(o->d()->string->toQString().length())) { - if (v4->currentContext()->strictMode) + if (v4->current->strictMode) v4->throwTypeError(); return false; } @@ -511,7 +503,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) offset = qMax(offset + 1, matchOffsets[oldSize + 1]); } if (regExp->global()) - regExp->lastIndexProperty()->value = Primitive::fromUInt32(0); + *regExp->lastIndexProperty() = Primitive::fromUInt32(0); numStringMatches = nMatchOffsets / (regExp->value()->captureCount() * 2); numCaptures = regExp->value()->captureCount(); } else { diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index aa56a79bc3..86d77c726a 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -44,8 +44,12 @@ namespace QV4 { namespace Heap { struct StringObject : Object { - StringObject(InternalClass *ic, QV4::Object *prototype); - StringObject(ExecutionEngine *engine, const QV4::String *string); + enum { + LengthPropertyIndex = 0 + }; + + StringObject(); + StringObject(const QV4::String *string); String *string; Heap::String *getIndex(uint index) const; @@ -61,6 +65,8 @@ struct StringCtor : FunctionObject { struct StringObject: Object { V4_OBJECT2(StringObject, Object) Q_MANAGED_TYPE(StringObject) + V4_INTERNALCLASS(stringClass) + V4_PROTOTYPE(stringPrototype) Heap::String *getIndex(uint index) const { return d()->getIndex(index); diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index f06eeb08b9..b45bbb713c 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -216,11 +216,11 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) if (l != len) scope.engine->throwRangeError(QStringLiteral("Non integer length for typed array.")); uint byteLength = len * operations[that->d()->type].bytesPerElement; - Scoped<ArrayBuffer> buffer(scope, scope.engine->memoryManager->alloc<ArrayBuffer>(scope.engine, byteLength)); + Scoped<ArrayBuffer> buffer(scope, scope.engine->newArrayBuffer(byteLength)); if (scope.engine->hasException) return Encode::undefined(); - Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); array->d()->buffer = buffer->d(); array->d()->byteLength = byteLength; array->d()->byteOffset = 0; @@ -236,11 +236,11 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) uint byteLength = typedArray->d()->byteLength; uint destByteLength = byteLength*destElementSize/srcElementSize; - Scoped<ArrayBuffer> newBuffer(scope, scope.engine->memoryManager->alloc<ArrayBuffer>(scope.engine, destByteLength)); + Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(destByteLength)); if (scope.engine->hasException) return Encode::undefined(); - Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); array->d()->buffer = newBuffer->d(); array->d()->byteLength = destByteLength; array->d()->byteOffset = 0; @@ -290,7 +290,7 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) byteLength = (uint)l; } - Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); array->d()->buffer = buffer->d(); array->d()->byteLength = byteLength; array->d()->byteOffset = byteOffset; @@ -305,11 +305,11 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) return scope.engine->throwTypeError(); uint elementSize = operations[that->d()->type].bytesPerElement; - Scoped<ArrayBuffer> newBuffer(scope, scope.engine->memoryManager->alloc<ArrayBuffer>(scope.engine, l * elementSize)); + Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(l * elementSize)); if (scope.engine->hasException) return Encode::undefined(); - Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); array->d()->buffer = newBuffer->d(); array->d()->byteLength = l * elementSize; array->d()->byteOffset = 0; @@ -335,13 +335,17 @@ ReturnedValue TypedArrayCtor::call(const Managed *that, CallData *callData) return construct(that, callData); } -Heap::TypedArray::TypedArray(ExecutionEngine *e, Type t) - : Heap::Object(e->emptyClass, e->typedArrayPrototype + t), - type(operations + t), +Heap::TypedArray::TypedArray(Type t) + : type(operations + t), arrayType(t) { } +Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type t) +{ + return e->memoryManager->allocObject<TypedArray>(e->emptyClass, e->typedArrayPrototype + t, t); +} + void TypedArray::markObjects(Heap::Base *that, ExecutionEngine *e) { static_cast<TypedArray::Data *>(that)->buffer->mark(e); @@ -383,7 +387,7 @@ void TypedArray::putIndexed(Managed *m, uint index, const Value &value) return; reject: - if (scope.engine->currentContext()->strictMode) + if (scope.engine->current->strictMode) scope.engine->throwTypeError(); } diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index 8e1090dcd2..74ee285da4 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -69,7 +69,7 @@ struct TypedArray : Object { NTypes }; - TypedArray(ExecutionEngine *e, Type t); + TypedArray(Type t); const TypedArrayOperations *type; Pointer<ArrayBuffer> buffer; @@ -85,7 +85,7 @@ struct TypedArrayCtor : FunctionObject { }; struct TypedArrayPrototype : Object { - inline TypedArrayPrototype(ExecutionEngine *e, TypedArray::Type t); + inline TypedArrayPrototype(TypedArray::Type t); TypedArray::Type type; }; @@ -96,6 +96,8 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object { V4_OBJECT2(TypedArray, Object) + static Heap::TypedArray *create(QV4::ExecutionEngine *e, Heap::TypedArray::Type t); + uint byteLength() const { return d()->byteLength; } @@ -142,9 +144,8 @@ struct TypedArrayPrototype : Object }; inline -Heap::TypedArrayPrototype::TypedArrayPrototype(ExecutionEngine *e, TypedArray::Type t) - : Heap::Object(e) - , type(t) +Heap::TypedArrayPrototype::TypedArrayPrototype(TypedArray::Type t) + : type(t) { } diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 6305e6dfbb..14094878d8 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -85,8 +85,8 @@ struct Q_QML_PRIVATE_EXPORT Value Q_ALWAYS_INLINE quint64 val() const { return _val; } Q_ALWAYS_INLINE void setVal(quint64 v) { _val = v; } - Q_ALWAYS_INLINE void setValue(quint32 v) { setTagValue(tag(), v); } - Q_ALWAYS_INLINE void setTag(quint32 t) { setTagValue(t, value()); } + Q_ALWAYS_INLINE void setValue(quint32 v) { memcpy(&_val, &v, 4); } + Q_ALWAYS_INLINE void setTag(quint32 t) { memcpy(4 + (quint8 *)&_val, &t, 4); } #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN static inline int valueOffset() { return 0; } diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index f9e26efe71..4609373cc9 100644 --- a/src/qml/jsruntime/qv4variantobject.cpp +++ b/src/qml/jsruntime/qv4variantobject.cpp @@ -43,12 +43,15 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(VariantObject); -Heap::VariantObject::VariantObject(QV4::ExecutionEngine *engine, const QVariant &value) - : Heap::Object(engine->emptyClass, engine->variantPrototype()) +Heap::VariantObject::VariantObject() +{ +} + +Heap::VariantObject::VariantObject(const QVariant &value) { data = value; if (isScarce()) - engine->scarceResources.insert(this); + internalClass->engine->scarceResources.insert(this); } bool VariantObject::Data::isScarce() const diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h index b19f12bb98..4680912354 100644 --- a/src/qml/jsruntime/qv4variantobject_p.h +++ b/src/qml/jsruntime/qv4variantobject_p.h @@ -60,10 +60,8 @@ namespace Heap { struct VariantObject : Object, public ExecutionEngine::ScarceResourceData { - VariantObject(InternalClass *ic, QV4::Object *prototype) - : Object(ic, prototype) - {} - VariantObject(QV4::ExecutionEngine *engine, const QVariant &value); + VariantObject(); + VariantObject(const QVariant &value); ~VariantObject() { if (isScarce()) node.remove(); @@ -77,6 +75,7 @@ struct VariantObject : Object, public ExecutionEngine::ScarceResourceData struct VariantObject : Object { V4_OBJECT2(VariantObject, Object) + V4_PROTOTYPE(variantPrototype) V4_NEEDS_DESTROY void addVmePropertyReference(); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 0edd7378a7..68f996c4c7 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -375,8 +375,8 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code const uchar *exceptionHandler = 0; QV4::Scope scope(engine); - QV4::ScopedContext context(scope, engine->currentContext()); - engine->currentContext()->lineNumber = -1; + QV4::ExecutionContext *context = engine->currentContext; + engine->current->lineNumber = -1; #ifdef DO_TRACE_INSTR qDebug("Starting VME with context=%p and code=%p", context, code); @@ -650,18 +650,18 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope) Runtime::pushCatchScope(static_cast<QV4::NoThrowEngine*>(engine), instr.name); - context = engine->currentContext(); + context = engine->currentContext; MOTH_END_INSTR(CallBuiltinPushCatchScope) MOTH_BEGIN_INSTR(CallBuiltinPushScope) Runtime::pushWithScope(VALUE(instr.arg), engine); - context = engine->currentContext(); + context = engine->currentContext; CHECK_EXCEPTION; MOTH_END_INSTR(CallBuiltinPushScope) MOTH_BEGIN_INSTR(CallBuiltinPopScope) Runtime::popScope(engine); - context = engine->currentContext(); + context = engine->currentContext; MOTH_END_INSTR(CallBuiltinPopScope) MOTH_BEGIN_INSTR(CallBuiltinForeachIteratorObject) @@ -889,7 +889,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(Ret) MOTH_BEGIN_INSTR(Debug) - engine->currentContext()->lineNumber = instr.lineNumber; + engine->current->lineNumber = instr.lineNumber; QV4::Debugging::Debugger *debugger = context->engine()->debugger; if (debugger && debugger->pauseAtNextOpportunity()) debugger->maybeBreakAtInstruction(); @@ -898,7 +898,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(Debug) MOTH_BEGIN_INSTR(Line) - engine->currentContext()->lineNumber = instr.lineNumber; + engine->current->lineNumber = instr.lineNumber; if (qt_v4IsDebugging) qt_v4CheckForBreak(context, scopes, scopeDepth); MOTH_END_INSTR(Line) |