diff options
Diffstat (limited to 'src/qml/jsruntime')
72 files changed, 910 insertions, 751 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index 519c87d0c4..4bc877bd9d 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -41,7 +41,8 @@ SOURCES += \ $$PWD/qv4qobjectwrapper.cpp \ $$PWD/qv4arraybuffer.cpp \ $$PWD/qv4typedarray.cpp \ - $$PWD/qv4dataview.cpp + $$PWD/qv4dataview.cpp \ + $$PWD/qv4vme_moth.cpp qtConfig(qml-debug): SOURCES += $$PWD/qv4profiling.cpp @@ -94,14 +95,8 @@ HEADERS += \ $$PWD/qv4profiling_p.h \ $$PWD/qv4arraybuffer_p.h \ $$PWD/qv4typedarray_p.h \ - $$PWD/qv4dataview_p.h - -qtConfig(qml-interpreter) { - HEADERS += \ - $$PWD/qv4vme_moth_p.h - SOURCES += \ - $$PWD/qv4vme_moth.cpp -} + $$PWD/qv4dataview_p.h \ + $$PWD/qv4vme_moth_p.h } diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp index f7b9e8acef..c4eddb6b2a 100644 --- a/src/qml/jsruntime/qv4arraybuffer.cpp +++ b/src/qml/jsruntime/qv4arraybuffer.cpp @@ -96,7 +96,7 @@ void Heap::ArrayBuffer::init(size_t length) Object::init(); data = QTypedArrayData<char>::allocate(length + 1); if (!data) { - data = 0; + data = nullptr; internalClass->engine->throwRangeError(QStringLiteral("ArrayBuffer: out of memory")); return; } @@ -152,7 +152,7 @@ void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor) ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); ctor->defineDefaultProperty(QStringLiteral("isView"), ArrayBufferCtor::method_isView, 1); defineDefaultProperty(engine->id_constructor(), (o = ctor)); - defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); + defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, nullptr); defineDefaultProperty(QStringLiteral("slice"), method_slice, 2); defineDefaultProperty(QStringLiteral("toString"), method_toString, 0); } diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h index e236a23d1f..59e78ee85f 100644 --- a/src/qml/jsruntime/qv4arraybuffer_p.h +++ b/src/qml/jsruntime/qv4arraybuffer_p.h @@ -93,8 +93,8 @@ struct Q_QML_PRIVATE_EXPORT ArrayBuffer : Object QByteArray asByteArray() const; uint byteLength() const { return d()->byteLength(); } - char *data() { detach(); return d()->data ? d()->data->data() : 0; } - const char *constData() { detach(); return d()->data ? d()->data->data() : 0; } + char *data() { detach(); return d()->data ? d()->data->data() : nullptr; } + const char *constData() { detach(); return d()->data ? d()->data->data() : nullptr; } private: void detach(); diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index 390840fb1e..30c8527f21 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -50,7 +50,7 @@ using namespace QV4; QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON const QV4::VTable QV4::ArrayData::static_vtbl = { - 0, + nullptr, 0, 0, QV4::ArrayData::IsExecutionContext, @@ -69,7 +69,7 @@ const QV4::VTable QV4::ArrayData::static_vtbl = { const ArrayVTable SimpleArrayData::static_vtbl = { - DEFINE_MANAGED_VTABLE_INT(SimpleArrayData, 0), + DEFINE_MANAGED_VTABLE_INT(SimpleArrayData, nullptr), Heap::ArrayData::Simple, SimpleArrayData::reallocate, SimpleArrayData::get, @@ -85,7 +85,7 @@ const ArrayVTable SimpleArrayData::static_vtbl = const ArrayVTable SparseArrayData::static_vtbl = { - DEFINE_MANAGED_VTABLE_INT(SparseArrayData, 0), + DEFINE_MANAGED_VTABLE_INT(SparseArrayData, nullptr), Heap::ArrayData::Sparse, SparseArrayData::reallocate, SparseArrayData::get, @@ -170,7 +170,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt newData->setType(newType); if (d) newData->d()->needsMark = d->d()->needsMark; - newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->d()->values.values + alloc) : 0); + newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->d()->values.values + alloc) : nullptr); o->setArrayData(newData); if (d) { @@ -203,12 +203,11 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt if (d && d->type() == Heap::ArrayData::Sparse) { Heap::SparseArrayData *old = static_cast<Heap::SparseArrayData *>(d->d()); sparse->sparse = old->sparse; - old->sparse = 0; - sparse->freeList = old->freeList; - lastFree = &sparse->freeList; + old->sparse = nullptr; + lastFree = &sparse->sparse->freeList; } else { sparse->sparse = new SparseArray; - lastFree = &sparse->freeList; + lastFree = &sparse->sparse->freeList; storeValue(lastFree, 0); for (uint i = 0; i < toCopy; ++i) { if (!sparse->values[i].isEmpty()) { @@ -228,10 +227,10 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt sparse->values.values[i].setEmpty(); lastFree = &sparse->values.values[i].rawValueRef(); } - storeValue(lastFree, UINT_MAX); } + storeValue(lastFree, UINT_MAX); - Q_ASSERT(Value::fromReturnedValue(sparse->freeList).isEmpty()); + Q_ASSERT(Value::fromReturnedValue(sparse->sparse->freeList).isEmpty()); // ### Could explicitly free the old data } @@ -373,12 +372,12 @@ void SparseArrayData::free(Heap::ArrayData *d, uint idx) Value *v = d->values.values + idx; if (d->attrs && d->attrs[idx].isAccessor()) { // double slot, free both. Order is important, so we have a double slot for allocation again afterwards. - v[1].setEmpty(Value::fromReturnedValue(d->freeList).emptyValue()); + v[1].setEmpty(Value::fromReturnedValue(d->sparse->freeList).emptyValue()); v[0].setEmpty(idx + 1); } else { - v->setEmpty(Value::fromReturnedValue(d->freeList).emptyValue()); + v->setEmpty(Value::fromReturnedValue(d->sparse->freeList).emptyValue()); } - d->freeList = Primitive::emptyValue(idx).asReturnedValue(); + d->sparse->freeList = Primitive::emptyValue(idx).asReturnedValue(); if (d->attrs) d->attrs[idx].clear(); } @@ -395,12 +394,12 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot) Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Sparse); Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (doubleSlot) { - ReturnedValue *last = &dd->freeList; + ReturnedValue *last = &dd->sparse->freeList; while (1) { if (Value::fromReturnedValue(*last).value() == UINT_MAX) { reallocate(o, dd->values.alloc + 2, true); dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); - last = &dd->freeList; + last = &dd->sparse->freeList; Q_ASSERT(Value::fromReturnedValue(*last).value() != UINT_MAX); } @@ -417,14 +416,14 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot) last = &dd->values.values[Value::fromReturnedValue(*last).value()].rawValueRef(); } } else { - if (Value::fromReturnedValue(dd->freeList).value() == UINT_MAX) { + if (Value::fromReturnedValue(dd->sparse->freeList).value() == UINT_MAX) { reallocate(o, dd->values.alloc + 1, false); dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } - uint idx = Value::fromReturnedValue(dd->freeList).value(); + uint idx = Value::fromReturnedValue(dd->sparse->freeList).value(); Q_ASSERT(idx != UINT_MAX); - dd->freeList = dd->values[idx].asReturnedValue(); - Q_ASSERT(Value::fromReturnedValue(dd->freeList).isEmpty()); + dd->sparse->freeList = dd->values[idx].asReturnedValue(); + Q_ASSERT(Value::fromReturnedValue(dd->sparse->freeList).isEmpty()); if (dd->attrs) dd->attrs[idx] = Attr_Data; return idx; @@ -479,14 +478,14 @@ bool SparseArrayData::del(Object *o, uint index) if (isAccessor) { // free up both indices - dd->values.values[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); + dd->values.values[pidx + 1].setEmpty(Value::fromReturnedValue(dd->sparse->freeList).emptyValue()); dd->values.values[pidx].setEmpty(pidx + 1); } else { Q_ASSERT(dd->type == Heap::ArrayData::Sparse); - dd->values.values[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); + dd->values.values[pidx].setEmpty(Value::fromReturnedValue(dd->sparse->freeList).emptyValue()); } - dd->freeList = Primitive::emptyValue(pidx).asReturnedValue(); + dd->sparse->freeList = Primitive::emptyValue(pidx).asReturnedValue(); dd->sparse->erase(n); return true; } @@ -780,7 +779,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c if (!sparse->sparse()->nEntries()) return; - thisObject->setArrayData(0); + thisObject->setArrayData(nullptr); ArrayData::realloc(thisObject, Heap::ArrayData::Simple, sparse->sparse()->nEntries(), sparse->attrs() ? true : false); Heap::SimpleArrayData *d = thisObject->d()->arrayData.cast<Heap::SimpleArrayData>(); diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index db9db5a220..9356670b6d 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -95,7 +95,6 @@ namespace Heap { Member(class, NoMark, ushort, needsMark) \ Member(class, NoMark, uint, offset) \ Member(class, NoMark, PropertyAttributes *, attrs) \ - Member(class, NoMark, ReturnedValue, freeList) \ Member(class, NoMark, SparseArray *, sparse) \ Member(class, ValueArray, ValueArray, values) @@ -142,7 +141,7 @@ DECLARE_HEAP_OBJECT(ArrayData, Base) { uint mappedIndex(uint index) const; }; -V4_ASSERT_IS_TRIVIAL(ArrayData) +Q_STATIC_ASSERT(std::is_trivial< ArrayData >::value); struct SimpleArrayData : public ArrayData { uint mappedIndex(uint index) const { index += offset; if (index >= values.alloc) index -= values.alloc; return index; } @@ -157,7 +156,7 @@ struct SimpleArrayData : public ArrayData { return attrs ? attrs[i] : Attr_Data; } }; -V4_ASSERT_IS_TRIVIAL(SimpleArrayData) +Q_STATIC_ASSERT(std::is_trivial< SimpleArrayData >::value); struct SparseArrayData : public ArrayData { void destroy() { @@ -264,8 +263,6 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData V4_INTERNALCLASS(SparseArrayData) V4_NEEDS_DESTROY - ReturnedValue &freeList() { return d()->freeList; } - ReturnedValue freeList() const { return d()->freeList; } SparseArray *sparse() const { return d()->sparse; } void setSparse(SparseArray *s) { d()->sparse = s; } @@ -334,7 +331,7 @@ ArrayData::Index ArrayData::getValueOrSetter(uint index, PropertyAttributes *att uint idx = mappedIndex(index); if (idx == UINT_MAX) { *attrs = Attr_Invalid; - return { 0, 0 }; + return { nullptr, 0 }; } *attrs = attributes(index); diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 00d816fe91..020e519e74 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -302,7 +302,7 @@ ReturnedValue ExecutionContext::getProperty(String *name) ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) { - base->setM(0); + base->setM(nullptr); name->makeIdentifier(); Heap::ExecutionContext *ctx = d(); diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 4efd0bc899..512bfa06d8 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -143,7 +143,7 @@ DECLARE_HEAP_OBJECT(ExecutionContext, Base) { quint8 padding_[4]; #endif }; -V4_ASSERT_IS_TRIVIAL(ExecutionContext) +Q_STATIC_ASSERT(std::is_trivial< ExecutionContext >::value); Q_STATIC_ASSERT(sizeof(ExecutionContext) == sizeof(Base) + sizeof(ExecutionContextData) + QT_POINTER_SIZE); Q_STATIC_ASSERT(std::is_standard_layout<ExecutionContextData>::value); @@ -170,7 +170,7 @@ DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) { } void setArg(uint index, Value v); }; -V4_ASSERT_IS_TRIVIAL(CallContext) +Q_STATIC_ASSERT(std::is_trivial< CallContext >::value); Q_STATIC_ASSERT(std::is_standard_layout<CallContextData>::value); Q_STATIC_ASSERT(offsetof(CallContextData, function) == 0); //### The following size check fails on Win8. With the ValueArray at the end of the @@ -190,7 +190,7 @@ DECLARE_HEAP_OBJECT(CatchContext, ExecutionContext) { void init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue); }; -V4_ASSERT_IS_TRIVIAL(CatchContext) +Q_STATIC_ASSERT(std::is_trivial< CatchContext >::value); } @@ -246,12 +246,12 @@ struct CatchContext : public ExecutionContext inline CallContext *ExecutionContext::asCallContext() { - return d()->type == Heap::ExecutionContext::Type_CallContext ? static_cast<CallContext *>(this) : 0; + return d()->type == Heap::ExecutionContext::Type_CallContext ? static_cast<CallContext *>(this) : nullptr; } inline const CallContext *ExecutionContext::asCallContext() const { - return d()->type == Heap::ExecutionContext::Type_CallContext ? static_cast<const CallContext *>(this) : 0; + return d()->type == Heap::ExecutionContext::Type_CallContext ? static_cast<const CallContext *>(this) : nullptr; } } // namespace QV4 diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp index 397ef1cfec..d894d909ff 100644 --- a/src/qml/jsruntime/qv4dataview.cpp +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -88,9 +88,9 @@ void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor) ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(3)); ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); defineDefaultProperty(engine->id_constructor(), (o = ctor)); - defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0); - defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); - defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); + defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, nullptr); + defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, nullptr); + defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, nullptr); defineDefaultProperty(QStringLiteral("getInt8"), method_getChar<signed char>, 0); defineDefaultProperty(QStringLiteral("getUint8"), method_getChar<unsigned char>, 0); diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index b8392d27e9..bc9b3013d1 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -328,7 +328,7 @@ static inline double DaylightSavingTA(double t) // t is a UTC time static inline double DaylightSavingTA(double t) { struct tm tmtm; -#if defined(_MSC_VER) && _MSC_VER >= 1400 +#if defined(Q_CC_MSVC) __time64_t tt = (__time64_t)(t / msPerSecond); // _localtime_64_s returns non-zero on failure if (_localtime64_s(&tmtm, &tt) != 0) @@ -854,7 +854,7 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor) ScopedString us(scope, engine->newIdentifier(toUtcString)); ScopedString gs(scope, engine->newIdentifier(toGmtString)); ExecutionContext *global = engine->rootContext(); - ScopedFunctionObject toUtcGmtStringFn(scope, BuiltinFunction::create(global, us, method_toUTCString)); + ScopedFunctionObject toUtcGmtStringFn(scope, FunctionObject::createBuiltinFunction(global, us, method_toUTCString)); toUtcGmtStringFn->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0)); defineDefaultProperty(us, toUtcGmtStringFn); defineDefaultProperty(gs, toUtcGmtStringFn); diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index a4ab0a27ed..2b9a580288 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -101,7 +101,7 @@ struct DateObject: Object { template<> inline const DateObject *Value::as() const { - return isManaged() && m()->vtable()->type == Managed::Type_DateObject ? static_cast<const DateObject *>(this) : 0; + return isManaged() && m()->vtable()->type == Managed::Type_DateObject ? static_cast<const DateObject *>(this) : nullptr; } struct DateCtor: FunctionObject diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h index 61a55964ab..9b41bb6e7a 100644 --- a/src/qml/jsruntime/qv4debugging_p.h +++ b/src/qml/jsruntime/qv4debugging_p.h @@ -78,7 +78,7 @@ class Q_QML_EXPORT Debugger : public QObject Q_OBJECT public: - virtual ~Debugger() {} + ~Debugger() override {} virtual bool pauseAtNextOpportunity() const = 0; virtual void maybeBreakAtInstruction() = 0; virtual void enteringFunction() = 0; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index c57f39f61c..5f59e1e809 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -101,7 +101,7 @@ using namespace QV4; static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1); -ReturnedValue throwTypeError(const BuiltinFunction *b, CallData *) +ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int) { return b->engine()->throwTypeError(); } @@ -127,13 +127,16 @@ ExecutionEngine::ExecutionEngine() , bumperPointerAllocator(new WTF::BumpPointerAllocator) , jsStack(new WTF::PageAllocation) , gcStack(new WTF::PageAllocation) - , globalCode(0) - , v8Engine(0) - , argumentsAccessors(0) + , globalCode(nullptr) + , v8Engine(nullptr) + , argumentsAccessors(nullptr) , nArgumentsAccessors(0) , m_engineId(engineSerial.fetchAndAddOrdered(1)) - , regExpCache(0) - , m_multiplyWrappedQObjects(0) + , regExpCache(nullptr) + , m_multiplyWrappedQObjects(nullptr) +#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP) + , m_canAllocateExecutableMemory(OSAllocator::canAllocateExecutableMemory()) +#endif { memoryManager = new QV4::MemoryManager(this); @@ -168,6 +171,15 @@ ExecutionEngine::ExecutionEngine() /* writable */ true, /* executable */ false, /* includesGuardPages */ true); + { + bool ok = false; + jitCallCountThreshold = qEnvironmentVariableIntValue("QV4_JIT_CALL_THRESHOLD", &ok); + if (!ok) + jitCallCountThreshold = 3; + if (qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER")) + jitCallCountThreshold = std::numeric_limits<int>::max(); + } + exceptionValue = jsAlloca(1); globalObject = static_cast<Object *>(jsAlloca(1)); jsObjects = jsAlloca(NJSObjects); @@ -188,6 +200,7 @@ ExecutionEngine::ExecutionEngine() internalClasses[Class_SimpleArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable()); internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable()); internalClasses[Class_ExecutionContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable()); + internalClasses[Class_QmlContext] = internalClasses[EngineBase::Class_ExecutionContext]->changeVTable(QV4::QmlContext::staticVTable()); internalClasses[Class_CallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable()); jsStrings[String_Empty] = newIdentifier(QString()); @@ -230,6 +243,7 @@ ExecutionEngine::ExecutionEngine() InternalClass *ic = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable()); jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic); internalClasses[Class_Object] = ic->changePrototype(objectPrototype()->d()); + internalClasses[EngineBase::Class_QmlContextWrapper] = internalClasses[Class_Object]->changeVTable(QV4::QQmlContextWrapper::staticVTable()); ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype()); Q_ASSERT(ic->prototype); @@ -275,8 +289,6 @@ ExecutionEngine::ExecutionEngine() ic = ic->changeVTable(ScriptFunction::staticVTable()); internalClasses[EngineBase::Class_ScriptFunction] = ic->addMember(id_length(), Attr_ReadOnly, &index); Q_ASSERT(index == Heap::ScriptFunction::Index_Length); - internalClasses[EngineBase::Class_BuiltinFunction] = ic->changeVTable(BuiltinFunction::staticVTable()); - Q_ASSERT(index == Heap::ScriptFunction::Index_Length); internalClasses[EngineBase::Class_ObjectProto] = internalClasses[Class_Object]->addMember(id_constructor(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor); @@ -302,7 +314,7 @@ ExecutionEngine::ExecutionEngine() internalClasses[EngineBase::Class_RegExpExecArray] = ic->addMember(id_input(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayInput); - ic = newInternalClass(ErrorObject::staticVTable(), 0); + ic = newInternalClass(ErrorObject::staticVTable(), nullptr); ic = ic->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_Stack); ic = ic->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index); @@ -320,7 +332,7 @@ ExecutionEngine::ExecutionEngine() internalClasses[EngineBase::Class_ErrorProto] = ic->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); + jsObjects[GetStack_Function] = FunctionObject::createBuiltinFunction(rootContext(), str = newIdentifier(QStringLiteral("stack")), ErrorObject::method_get_stack); getStackFunction()->defineReadonlyProperty(id_length(), Primitive::fromInt32(0)); jsObjects[ErrorProto] = memoryManager->allocObject<ErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto], objectPrototype()); @@ -384,8 +396,8 @@ ExecutionEngine::ExecutionEngine() 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; + jsObjects[ValueTypeProto] = (Heap::Base *) nullptr; + jsObjects[SignalHandlerProto] = (Heap::Base *) nullptr; for (int i = 0; i < Heap::TypedArray::NTypes; ++i) { static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocObject<TypedArrayCtor>(global, Heap::TypedArray::Type(i)); @@ -442,8 +454,8 @@ ExecutionEngine::ExecutionEngine() ScopedString pi(scope, newIdentifier(piString)); ScopedString pf(scope, newIdentifier(pfString)); ExecutionContext *global = rootContext(); - ScopedFunctionObject parseIntFn(scope, BuiltinFunction::create(global, pi, GlobalFunctions::method_parseInt)); - ScopedFunctionObject parseFloatFn(scope, BuiltinFunction::create(global, pf, GlobalFunctions::method_parseFloat)); + ScopedFunctionObject parseIntFn(scope, FunctionObject::createBuiltinFunction(global, pi, GlobalFunctions::method_parseInt)); + ScopedFunctionObject parseFloatFn(scope, FunctionObject::createBuiltinFunction(global, pf, GlobalFunctions::method_parseFloat)); parseIntFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(2)); parseFloatFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(1)); globalObject->defineDefaultProperty(piString, parseIntFn); @@ -462,13 +474,13 @@ ExecutionEngine::ExecutionEngine() globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1); ScopedString name(scope, newString(QStringLiteral("thrower"))); - jsObjects[ThrowerObject] = BuiltinFunction::create(global, name, ::throwTypeError); + jsObjects[ThrowerObject] = FunctionObject::createBuiltinFunction(global, name, ::throwTypeError); } ExecutionEngine::~ExecutionEngine() { delete m_multiplyWrappedQObjects; - m_multiplyWrappedQObjects = 0; + m_multiplyWrappedQObjects = nullptr; delete identifierTable; delete memoryManager; @@ -519,7 +531,7 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other) InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype) { - return internalClasses[EngineBase::Class_Empty]->changeVTable(vtable)->changePrototype(prototype ? prototype->d() : 0); + return internalClasses[EngineBase::Class_Empty]->changeVTable(vtable)->changePrototype(prototype ? prototype->d() : nullptr); } Heap::Object *ExecutionEngine::newObject() @@ -721,18 +733,18 @@ Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o) Heap::QmlContext *ExecutionEngine::qmlContext() const { if (!currentStackFrame) - return 0; + return nullptr; Heap::ExecutionContext *ctx = currentContext()->d(); if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer) - return 0; + return nullptr; while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext) ctx = ctx->outer; Q_ASSERT(ctx); if (ctx->type != Heap::ExecutionContext::Type_QmlContext) - return 0; + return nullptr; return static_cast<Heap::QmlContext *>(ctx); } @@ -741,7 +753,7 @@ QObject *ExecutionEngine::qmlScopeObject() const { Heap::QmlContext *ctx = qmlContext(); if (!ctx) - return 0; + return nullptr; return ctx->qml()->scopeObject; } @@ -771,7 +783,7 @@ QQmlContextData *ExecutionEngine::callingQmlContext() const { Heap::QmlContext *ctx = qmlContext(); if (!ctx) - return 0; + return nullptr; return ctx->qml()->context->contextData(); } @@ -868,14 +880,14 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) CppStackFrame *f = currentStackFrame; while (f) { if (f->v4Function) { - base.setUrl(f->v4Function->sourceFile()); + base = f->v4Function->finalUrl(); break; } f = f->parent; } if (base.isEmpty() && globalCode) - base.setUrl(globalCode->sourceFile()); + base = globalCode->finalUrl(); if (base.isEmpty()) return src; @@ -898,7 +910,7 @@ void ExecutionEngine::requireArgumentsAccessors(int n) nArgumentsAccessors = qMax(8, n); argumentsAccessors = new Property[nArgumentsAccessors]; if (oldAccessors) { - memcpy(argumentsAccessors, oldAccessors, oldSize*sizeof(Property)); + memcpy(static_cast<void *>(argumentsAccessors), static_cast<const void *>(oldAccessors), oldSize*sizeof(Property)); delete [] oldAccessors; } ExecutionContext *global = rootContext(); @@ -1079,7 +1091,7 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError() typedef QSet<QV4::Heap::Object *> V4ObjectSet; static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects); static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value); -static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects = 0); +static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects = nullptr); static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value, const QByteArray &targetType, void **result); @@ -1093,7 +1105,7 @@ static QV4::ReturnedValue variantToJS(QV4::ExecutionEngine *v4, const QVariant & QVariant ExecutionEngine::toVariant(const Value &value, int typeHint, bool createJSValueForObjects) { - return ::toVariant(this, value, typeHint, createJSValueForObjects, 0); + return ::toVariant(this, value, typeHint, createJSValueForObjects, nullptr); } @@ -1457,7 +1469,7 @@ static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVarian // Returns the value if conversion succeeded, an empty handle otherwise. QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data) { - Q_ASSERT(data != 0); + Q_ASSERT(data != nullptr); // check if it's one of the types we know switch (QMetaType::Type(type)) { @@ -1545,13 +1557,9 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data) return 0; } -bool ExecutionEngine::canJIT() +ReturnedValue ExecutionEngine::global() { -#ifdef V4_ENABLE_JIT - return true; -#else - return false; -#endif + return globalObject->asReturnedValue(); } // Converts a JS value to a meta-type. @@ -1734,7 +1742,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) QByteArray className = name.left(name.size()-1); QV4::ScopedObject p(scope, proto.getPointer()); if (QObject *qobject = qtObjectFromJS(this, p)) - canCast = qobject->qt_metacast(className) != 0; + canCast = qobject->qt_metacast(className) != nullptr; } if (canCast) { QByteArray varTypeName = QMetaType::typeName(var.userType()); @@ -1748,7 +1756,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) } } } else if (value->isNull() && name.endsWith('*')) { - *reinterpret_cast<void* *>(data) = 0; + *reinterpret_cast<void* *>(data) = nullptr; return true; } else if (type == qMetaTypeId<QJSValue>()) { *reinterpret_cast<QJSValue*>(data) = QJSValue(this, value->asReturnedValue()); @@ -1776,7 +1784,7 @@ static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &va static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value) { if (!value.isObject()) - return 0; + return nullptr; QV4::Scope scope(engine); QV4::Scoped<QV4::VariantObject> v(scope, value); @@ -1789,7 +1797,7 @@ static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &v } QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, value); if (!wrapper) - return 0; + return nullptr; return wrapper->object(); } diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 346f290feb..5edf89f720 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -56,7 +56,9 @@ #include <private/qintrusivelist_p.h> #include "qv4enginebase_p.h" + #ifndef V4_BOOTSTRAP +# include "qv4function_p.h" # include <private/qv8engine_p.h> # include <private/qv4compileddata_p.h> #endif @@ -85,6 +87,7 @@ namespace CompiledData { struct CompilationUnit; } +struct Function; struct InternalClass; struct InternalClassPool; @@ -365,6 +368,9 @@ public: // but any time a QObject is wrapped a second time in another engine, we have to do // bookkeeping. MultiplyWrappedQObjectMap *m_multiplyWrappedQObjects; +#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP) + const bool m_canAllocateExecutableMemory; +#endif int internalClassIdCount = 0; @@ -453,7 +459,7 @@ public: StackTrace exceptionStackTrace; ReturnedValue throwError(const Value &value); - ReturnedValue catchException(StackTrace *trace = 0); + ReturnedValue catchException(StackTrace *trace = nullptr); ReturnedValue throwError(const QString &message); ReturnedValue throwSyntaxError(const QString &message); @@ -481,13 +487,28 @@ public: bool checkStackLimits(); - static bool canJIT(); + bool canJIT(Function *f = nullptr) + { +#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP) + if (!m_canAllocateExecutableMemory) + return false; + if (f) + return f->interpreterCallCount >= jitCallCountThreshold; + return true; +#else + Q_UNUSED(f); + return false; +#endif + } + + QV4::ReturnedValue global(); private: #if QT_CONFIG(qml_debug) QScopedPointer<QV4::Debugging::Debugger> m_debugger; QScopedPointer<QV4::Profiling::Profiler> m_profiler; #endif + int jitCallCountThreshold; }; // This is a trick to tell the code generators that functions taking a NoThrowContext won't diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index e0f5f3ffb1..59fb4a564a 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -101,7 +101,6 @@ struct Q_QML_EXPORT EngineBase { Class_FunctionObject, Class_StringObject, Class_ScriptFunction, - Class_BuiltinFunction, Class_ObjectProto, Class_RegExp, Class_RegExpObject, @@ -111,6 +110,8 @@ struct Q_QML_EXPORT EngineBase { Class_ErrorObject, Class_ErrorObjectWithMessage, Class_ErrorProto, + Class_QmlContextWrapper, + Class_QmlContext, NClasses }; InternalClass *internalClasses[NClasses]; diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index a5ee0eb886..6b578e8c38 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -180,7 +180,7 @@ struct ErrorObject: Object { template<> inline const ErrorObject *Value::as() const { - return isManaged() && m()->vtable()->isErrorObject ? reinterpret_cast<const ErrorObject *>(this) : 0; + return isManaged() && m()->vtable()->isErrorObject ? reinterpret_cast<const ErrorObject *>(this) : nullptr; } struct EvalErrorObject: ErrorObject { @@ -322,7 +322,7 @@ struct URIErrorPrototype : ErrorObject inline SyntaxErrorObject *ErrorObject::asSyntaxError() { - return d()->errorType == QV4::Heap::ErrorObject::SyntaxError ? static_cast<SyntaxErrorObject *>(this) : 0; + return d()->errorType == QV4::Heap::ErrorObject::SyntaxError ? static_cast<SyntaxErrorObject *>(this) : nullptr; } diff --git a/src/qml/jsruntime/qv4executableallocator.cpp b/src/qml/jsruntime/qv4executableallocator.cpp index 64ac1267ce..6f04a712e6 100644 --- a/src/qml/jsruntime/qv4executableallocator.cpp +++ b/src/qml/jsruntime/qv4executableallocator.cpp @@ -159,7 +159,7 @@ ExecutableAllocator::~ExecutableAllocator() ExecutableAllocator::Allocation *ExecutableAllocator::allocate(size_t size) { QMutexLocker locker(&mutex); - Allocation *allocation = 0; + Allocation *allocation = nullptr; // Code is best aligned to 16-byte boundaries. size = WTF::roundUpToMultipleOf(16, size); @@ -217,7 +217,7 @@ void ExecutableAllocator::free(Allocation *allocation) if (!merged) freeAllocations.insert(allocation->size, allocation); - allocation = 0; + allocation = nullptr; if (!chunk->firstAllocation->next) { freeAllocations.remove(chunk->firstAllocation->size, chunk->firstAllocation); @@ -235,7 +235,7 @@ ExecutableAllocator::ChunkOfPages *ExecutableAllocator::chunkForAllocation(Alloc if (it != chunks.begin()) --it; if (it == chunks.end()) - return 0; + return nullptr; return *it; } diff --git a/src/qml/jsruntime/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h index dad02d9560..19eaed8723 100644 --- a/src/qml/jsruntime/qv4executableallocator_p.h +++ b/src/qml/jsruntime/qv4executableallocator_p.h @@ -82,11 +82,8 @@ public: struct Allocation { Allocation() - : addr(0) - , size(0) + : size(0) , free(true) - , next(0) - , prev(0) {} void *start() const; @@ -103,16 +100,16 @@ public: bool mergeNext(ExecutableAllocator *allocator); bool mergePrevious(ExecutableAllocator *allocator); - quintptr addr; #ifndef QT_NO_BITFIELDS + quintptr addr = 0; uint size : 31; // More than 2GB of function code? nah :) uint free : 1; #else uint size = 31; // More than 2GB of function code? nah :) uint free = 1; #endif - Allocation *next; - Allocation *prev; + Allocation *next = nullptr; + Allocation *prev = nullptr; }; // for debugging / unit-testing @@ -122,13 +119,12 @@ public: struct ChunkOfPages { ChunkOfPages() - : pages(0) - , firstAllocation(0) + {} ~ChunkOfPages(); - WTF::PageAllocation *pages; - Allocation *firstAllocation; + WTF::PageAllocation *pages = nullptr; + Allocation *firstAllocation = nullptr; bool contains(Allocation *alloc) const; }; diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 0e61be5115..4c8c790ca7 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -83,6 +83,7 @@ struct Q_QML_EXPORT Function { // first nArguments names in internalClass are the actual arguments InternalClass *internalClass; uint nFormals; + int interpreterCallCount = 0; bool hasQmlDependencies; Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function, Code codePtr); @@ -95,6 +96,7 @@ struct Q_QML_EXPORT Function { return compilationUnit->runtimeStrings[compiledFunction->nameIndex]; } inline QString sourceFile() const { return compilationUnit->fileName(); } + inline QUrl finalUrl() const { return compilationUnit->finalUrl(); } inline bool usesArgumentsObject() const { return compiledFunction->flags & CompiledData::Function::UsesArgumentsObject; } inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 4293d43791..a8c1640767 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -232,7 +232,7 @@ ReturnedValue FunctionCtor::callAsConstructor(const FunctionObject *f, const Val if (!fe) return scope.engine->throwSyntaxError(QLatin1String("Parse error")); - Compiler::Module module(scope.engine->debugger() != 0); + Compiler::Module module(scope.engine->debugger() != nullptr); Compiler::JSUnitGenerator jsGenerator(&module); RuntimeCodegen cg(scope.engine, &jsGenerator, false); @@ -351,7 +351,7 @@ ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Valu return scope.engine->throwTypeError(); ScopedValue boundThis(scope, argc ? argv[0] : Primitive::undefinedValue()); - Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0); + Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)nullptr); if (argc > 1) { boundArgs = MemberData::allocate(scope.engine, argc - 1); boundArgs->d()->values.size = argc - 1; @@ -430,27 +430,6 @@ InternalClass *ScriptFunction::classForConstructor() const return ic; } -DEFINE_OBJECT_VTABLE(BuiltinFunction); - -void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(const QV4::BuiltinFunction *, CallData *)) -{ - Heap::FunctionObject::init(scope, name); - this->code = code; -} - -ReturnedValue BuiltinFunction::callAsConstructor(const QV4::FunctionObject *f, const Value *, int) -{ - return f->engine()->throwTypeError(); -} - -ReturnedValue BuiltinFunction::call(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc) -{ - const BuiltinFunction *f = static_cast<const BuiltinFunction *>(fo); - Scope scope(f->engine()); - JSCallData callData(scope, argc, argv, thisObject); - return f->d()->code(f, callData.callData()); -} - DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction); DEFINE_OBJECT_VTABLE(BoundFunction); @@ -461,7 +440,7 @@ void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject Scope s(scope); Heap::FunctionObject::init(scope, QStringLiteral("__bound function__")); this->target.set(s.engine, target->d()); - this->boundArgs.set(s.engine, boundArgs ? boundArgs->d() : 0); + this->boundArgs.set(s.engine, boundArgs ? boundArgs->d() : nullptr); this->boundThis.set(scope->engine(), boundThis); ScopedObject f(s, this); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index d61006a6b0..d6066ec648 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -61,7 +61,6 @@ struct QQmlSourceLocation; namespace QV4 { -struct BuiltinFunction; struct IndexedBuiltinFunction; struct JSCallData; @@ -84,8 +83,8 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) { Index_ProtoConstructor = 0 }; - void init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(const QV4::FunctionObject *, const Value *thisObject, const Value *argv, int argc)); - void init(QV4::ExecutionContext *scope, QV4::String *name = 0, bool createProto = false); + Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(const QV4::FunctionObject *, const Value *thisObject, const Value *argv, int argc)); + void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr, bool createProto = false); void init(QV4::ExecutionContext *scope, QV4::Function *function, bool createProto = false); void init(QV4::ExecutionContext *scope, const QString &name, bool createProto = false); void init(); @@ -105,13 +104,8 @@ struct FunctionPrototype : FunctionObject { void init(); }; -struct Q_QML_EXPORT BuiltinFunction : FunctionObject { - void init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(const QV4::BuiltinFunction *, CallData *)); - ReturnedValue (*code)(const QV4::BuiltinFunction *, CallData *); -}; - -struct IndexedBuiltinFunction : BuiltinFunction { - inline void init(QV4::ExecutionContext *scope, uint index, ReturnedValue (*code)(const QV4::BuiltinFunction *, CallData *)); +struct IndexedBuiltinFunction : FunctionObject { + inline void init(QV4::ExecutionContext *scope, uint index, ReturnedValue (*code)(const QV4::FunctionObject *, const Value *, const Value *, int)); uint index; }; @@ -170,6 +164,11 @@ struct Q_QML_EXPORT FunctionObject: Object { static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function); + static Heap::FunctionObject *createBuiltinFunction(ExecutionContext *scope, String *name, + ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)) + { + return scope->engine()->memoryManager->allocObject<FunctionObject>(scope, name, code); + } bool strictMode() const { return d()->function ? d()->function->isStrict() : false; } bool isBinding() const; @@ -180,7 +179,7 @@ struct Q_QML_EXPORT FunctionObject: Object { template<> inline const FunctionObject *Value::as() const { - return isManaged() && m()->vtable()->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : 0; + return isManaged() && m()->vtable()->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : nullptr; } @@ -204,34 +203,16 @@ struct FunctionPrototype: FunctionObject static ReturnedValue method_bind(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); }; -struct Q_QML_EXPORT BuiltinFunction : FunctionObject { - V4_OBJECT2(BuiltinFunction, FunctionObject) - V4_INTERNALCLASS(BuiltinFunction) - - static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(const BuiltinFunction *, CallData *)) - { - return scope->engine()->memoryManager->allocObject<BuiltinFunction>(scope, name, code); - } - - static Heap::FunctionObject *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)) - { - return scope->engine()->memoryManager->allocObject<FunctionObject>(scope, name, code); - } - - static ReturnedValue callAsConstructor(const FunctionObject *, const Value *argv, int argc); - static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); -}; - -struct IndexedBuiltinFunction: BuiltinFunction +struct IndexedBuiltinFunction : FunctionObject { - V4_OBJECT2(IndexedBuiltinFunction, BuiltinFunction) + V4_OBJECT2(IndexedBuiltinFunction, FunctionObject) }; void Heap::IndexedBuiltinFunction::init(QV4::ExecutionContext *scope, uint index, - ReturnedValue (*code)(const QV4::BuiltinFunction *, CallData *)) + ReturnedValue (*code)(const QV4::FunctionObject *, const Value *thisObject, const Value *argv, int argc)) { Heap::FunctionObject::init(scope); - this->code = code; + this->jsCall = code; this->index = index; } diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 29eddc864d..382dd9b7e1 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -76,9 +76,6 @@ namespace std { inline bool isinf(double d) { return !_finite(d) && !_isnan(d); } inline bool isnan(double d) { return !!_isnan(d); } inline bool isfinite(double d) { return _finite(d); } -#if _MSC_VER < 1800 -inline bool signbit(double d) { return _copysign(1.0, d) < 0; } -#endif } // namespace std @@ -95,7 +92,7 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD)) # define V4_ENABLE_JIT #elif defined(Q_PROCESSOR_X86_64) && (QT_POINTER_SIZE == 8) \ - && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)) + && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)) # define V4_ENABLE_JIT #elif defined(Q_PROCESSOR_ARM_32) && (QT_POINTER_SIZE == 4) # if defined(thumb2) || defined(__thumb2__) || ((defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4) @@ -104,7 +101,7 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } # define V4_ENABLE_JIT # endif #elif defined(Q_PROCESSOR_ARM_64) && (QT_POINTER_SIZE == 8) -# if defined(Q_OS_LINUX) +# if defined(Q_OS_LINUX) || defined(Q_OS_QNX) # define V4_ENABLE_JIT # endif //#elif defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX) @@ -211,7 +208,6 @@ struct StringObject; struct ArrayObject; struct DateObject; struct FunctionObject; -struct BuiltinFunction; struct ErrorObject; struct ArgumentsObject; struct Managed; diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 3214a716e8..f419ab53fe 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -375,12 +375,12 @@ ReturnedValue EvalFunction::evalCall(const Value *, const Value *argv, int argc, if (function->isStrict() || isStrict) { ScopedFunctionObject e(scope, FunctionObject::createScriptFunction(ctx, function)); ScopedValue thisObject(scope, directCall ? scope.engine->currentStackFrame->thisObject() : scope.engine->globalObject->asReturnedValue()); - return e->call(thisObject, 0, 0); + return e->call(thisObject, nullptr, 0); } ScopedValue thisObject(scope, scope.engine->currentStackFrame->thisObject()); - return function->call(thisObject, 0, 0, ctx); + return function->call(thisObject, nullptr, 0, ctx); } @@ -507,7 +507,7 @@ ReturnedValue GlobalFunctions::method_parseFloat(const FunctionObject *b, const QByteArray ba = trimmed.toLatin1(); bool ok; const char *begin = ba.constData(); - const char *end = 0; + const char *end = nullptr; double d = qstrtod(begin, &end, &ok); if (end - begin == 0) RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN())); // 3 diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp index e35f72b820..c122bcb51a 100644 --- a/src/qml/jsruntime/qv4identifier.cpp +++ b/src/qml/jsruntime/qv4identifier.cpp @@ -75,13 +75,13 @@ IdentifierHashData::IdentifierHashData(IdentifierHashData *other) memcpy(entries, other->entries, alloc*sizeof(IdentifierHashEntry)); } -IdentifierHashBase::IdentifierHashBase(ExecutionEngine *engine) +IdentifierHash::IdentifierHash(ExecutionEngine *engine) { d = new IdentifierHashData(3); d->identifierTable = engine->identifierTable; } -void IdentifierHashBase::detach() +void IdentifierHash::detach() { if (!d || d->refCount == 1) return; @@ -92,7 +92,7 @@ void IdentifierHashBase::detach() } -IdentifierHashEntry *IdentifierHashBase::addEntry(const Identifier *identifier) +IdentifierHashEntry *IdentifierHash::addEntry(const Identifier *identifier) { // fill up to max 50% bool grow = (d->alloc <= d->size*2); @@ -129,16 +129,16 @@ IdentifierHashEntry *IdentifierHashBase::addEntry(const Identifier *identifier) return d->entries + idx; } -const IdentifierHashEntry *IdentifierHashBase::lookup(const Identifier *identifier) const +const IdentifierHashEntry *IdentifierHash::lookup(const Identifier *identifier) const { if (!d) - return 0; + return nullptr; Q_ASSERT(d->entries); uint idx = identifier->hashValue % d->alloc; while (1) { if (!d->entries[idx].identifier) - return 0; + return nullptr; if (d->entries[idx].identifier == identifier) return d->entries + idx; ++idx; @@ -146,17 +146,17 @@ const IdentifierHashEntry *IdentifierHashBase::lookup(const Identifier *identifi } } -const IdentifierHashEntry *IdentifierHashBase::lookup(const QString &str) const +const IdentifierHashEntry *IdentifierHash::lookup(const QString &str) const { if (!d) - return 0; + return nullptr; Q_ASSERT(d->entries); uint hash = String::createHashValue(str.constData(), str.length(), nullptr); uint idx = hash % d->alloc; while (1) { if (!d->entries[idx].identifier) - return 0; + return nullptr; if (d->entries[idx].identifier->string == str) return d->entries + idx; ++idx; @@ -164,22 +164,22 @@ const IdentifierHashEntry *IdentifierHashBase::lookup(const QString &str) const } } -const IdentifierHashEntry *IdentifierHashBase::lookup(String *str) const +const IdentifierHashEntry *IdentifierHash::lookup(String *str) const { if (!d) - return 0; + return nullptr; if (str->d()->identifier) return lookup(str->d()->identifier); return lookup(str->toQString()); } -const Identifier *IdentifierHashBase::toIdentifier(const QString &str) const +const Identifier *IdentifierHash::toIdentifier(const QString &str) const { Q_ASSERT(d); return d->identifierTable->identifier(str); } -const Identifier *IdentifierHashBase::toIdentifier(Heap::String *str) const +const Identifier *IdentifierHash::toIdentifier(Heap::String *str) const { Q_ASSERT(d); return d->identifierTable->identifier(str); diff --git a/src/qml/jsruntime/qv4identifier_p.h b/src/qml/jsruntime/qv4identifier_p.h index 2695bbc875..82346d5f68 100644 --- a/src/qml/jsruntime/qv4identifier_p.h +++ b/src/qml/jsruntime/qv4identifier_p.h @@ -73,13 +73,7 @@ struct Identifier struct IdentifierHashEntry { const Identifier *identifier; - union { - int value; - void *pointer; - }; - static int get(const IdentifierHashEntry *This, int *) { return This ? This->value : -1; } - static bool get(const IdentifierHashEntry *This, bool *) { return This != 0; } - static void *get(const IdentifierHashEntry *This, void **) { return This ? This->pointer : 0; } + int value; }; struct IdentifierHashData @@ -98,26 +92,30 @@ struct IdentifierHashData IdentifierHashEntry *entries; }; -struct IdentifierHashBase +struct IdentifierHash { - IdentifierHashData *d; + IdentifierHashData *d = nullptr; - IdentifierHashBase() : d(0) {} - IdentifierHashBase(ExecutionEngine *engine); - inline IdentifierHashBase(const IdentifierHashBase &other); - inline ~IdentifierHashBase(); - inline IdentifierHashBase &operator=(const IdentifierHashBase &other); + IdentifierHash() {} + IdentifierHash(ExecutionEngine *engine); + inline IdentifierHash(const IdentifierHash &other); + inline ~IdentifierHash(); + inline IdentifierHash &operator=(const IdentifierHash &other); bool isEmpty() const { return !d; } inline int count() const; - bool contains(const Identifier *i) const; - bool contains(const QString &str) const; - bool contains(String *str) const; void detach(); + void add(const QString &str, int value); + void add(Heap::String *str, int value); + + inline int value(const QString &str) const; + inline int value(String *str) const; + QString findId(int value) const; + protected: IdentifierHashEntry *addEntry(const Identifier *i); const IdentifierHashEntry *lookup(const Identifier *identifier) const; @@ -128,43 +126,20 @@ protected: }; -template<typename T> -struct IdentifierHash : public IdentifierHashBase -{ - IdentifierHash() - : IdentifierHashBase() {} - IdentifierHash(ExecutionEngine *engine) - : IdentifierHashBase(engine) {} - inline IdentifierHash(const IdentifierHash<T> &other) - : IdentifierHashBase(other) {} - inline ~IdentifierHash() {} - inline IdentifierHash &operator=(const IdentifierHash<T> &other) { - IdentifierHashBase::operator =(other); - return *this; - } - - void add(const QString &str, const T &value); - void add(Heap::String *str, const T &value); - - inline T value(const QString &str) const; - inline T value(String *str) const; - QString findId(T value) const; -}; - -inline IdentifierHashBase::IdentifierHashBase(const IdentifierHashBase &other) +inline IdentifierHash::IdentifierHash(const IdentifierHash &other) { d = other.d; if (d) d->refCount.ref(); } -inline IdentifierHashBase::~IdentifierHashBase() +inline IdentifierHash::~IdentifierHash() { if (d && !d->refCount.deref()) delete d; } -IdentifierHashBase &IdentifierHashBase::operator=(const IdentifierHashBase &other) +IdentifierHash &IdentifierHash::operator=(const IdentifierHash &other) { if (other.d) other.d->refCount.ref(); @@ -174,60 +149,45 @@ IdentifierHashBase &IdentifierHashBase::operator=(const IdentifierHashBase &othe return *this; } -inline int IdentifierHashBase::count() const +inline int IdentifierHash::count() const { return d ? d->size : 0; } -inline bool IdentifierHashBase::contains(const Identifier *i) const -{ - return lookup(i) != 0; -} - -inline bool IdentifierHashBase::contains(const QString &str) const -{ - return lookup(str) != 0; -} - -inline bool IdentifierHashBase::contains(String *str) const -{ - return lookup(str) != 0; -} - -template<typename T> -void IdentifierHash<T>::add(const QString &str, const T &value) +inline +void IdentifierHash::add(const QString &str, int value) { IdentifierHashEntry *e = addEntry(toIdentifier(str)); e->value = value; } -template<typename T> -void IdentifierHash<T>::add(Heap::String *str, const T &value) +inline +void IdentifierHash::add(Heap::String *str, int value) { IdentifierHashEntry *e = addEntry(toIdentifier(str)); e->value = value; } -template<typename T> -inline T IdentifierHash<T>::value(const QString &str) const +inline int IdentifierHash::value(const QString &str) const { - return IdentifierHashEntry::get(lookup(str), (T*)0); + const IdentifierHashEntry *e = lookup(str); + return e ? e->value : -1; } -template<typename T> -inline T IdentifierHash<T>::value(String *str) const +inline int IdentifierHash::value(String *str) const { - return IdentifierHashEntry::get(lookup(str), (T*)0); + const IdentifierHashEntry *e = lookup(str); + return e ? e->value : -1; } -template<typename T> -QString IdentifierHash<T>::findId(T value) const +inline +QString IdentifierHash::findId(int value) const { IdentifierHashEntry *e = d->entries; IdentifierHashEntry *end = e + d->alloc; while (e < end) { - if (e->identifier && IdentifierHashEntry::get(e, (T*)0) == value) + if (e->identifier && e->value == value) return e->identifier->string; ++e; } diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index 3def6defbf..b77f9478d3 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -142,7 +142,7 @@ Identifier *IdentifierTable::identifierImpl(const Heap::String *str) return str->identifier; uint hash = str->hashValue(); if (str->subtype == Heap::String::StringType_ArrayIndex) - return 0; + return nullptr; uint idx = hash % alloc; while (Heap::String *e = entries[idx]) { @@ -161,7 +161,7 @@ Identifier *IdentifierTable::identifierImpl(const Heap::String *str) Heap::String *IdentifierTable::stringFromIdentifier(Identifier *i) { if (!i) - return 0; + return nullptr; uint idx = i->hashValue % alloc; while (1) { diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 3e04ed63df..aaf5e3b857 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -61,7 +61,7 @@ QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &callback) : v4(engine), m_url(url) #if QT_CONFIG(qml_network) - , m_redirectCount(0), m_network(0) , m_reply(0) + , m_redirectCount(0), m_network(nullptr) , m_reply(nullptr) #endif { if (qmlContext) @@ -88,7 +88,7 @@ QV4Include::~QV4Include() { #if QT_CONFIG(qml_network) delete m_reply; - m_reply = 0; + m_reply = nullptr; #endif } @@ -196,10 +196,10 @@ void QV4Include::finished() /* Documented in qv8engine.cpp */ -QV4::ReturnedValue QV4Include::method_include(const QV4::BuiltinFunction *b, QV4::CallData *callData) +QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *argv, int argc) { QV4::Scope scope(b); - if (!callData->argc()) + if (!argc) RETURN_UNDEFINED(); QQmlContextData *context = scope.engine->callingQmlContext(); @@ -208,11 +208,11 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::BuiltinFunction *b, QV4 RETURN_RESULT(scope.engine->throwError(QString::fromUtf8("Qt.include(): Can only be called from JavaScript files"))); QV4::ScopedValue callbackFunction(scope, QV4::Primitive::undefinedValue()); - if (callData->argc() >= 2 && callData->args[1].as<QV4::FunctionObject>()) - callbackFunction = callData->args[1]; + if (argc >= 2 && argv[1].as<QV4::FunctionObject>()) + callbackFunction = argv[1]; #if QT_CONFIG(qml_network) - QUrl url(scope.engine->resolvedUrl(callData->args[0].toQStringNoThrow())); + QUrl url(scope.engine->resolvedUrl(argv[0].toQStringNoThrow())); if (scope.engine->qmlEngine() && scope.engine->qmlEngine()->urlInterceptor()) url = scope.engine->qmlEngine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::JavaScriptFile); @@ -227,21 +227,7 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::BuiltinFunction *b, QV4 } else { QScopedPointer<QV4::Script> script; - - if (const QQmlPrivate::CachedQmlUnit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url)) { - QV4::CompiledData::CompilationUnit *jsUnit = cachedUnit->createCompilationUnit(); - script.reset(new QV4::Script(scope.engine, qmlcontext, jsUnit)); - } else { - QFile f(localFile); - - if (f.open(QIODevice::ReadOnly)) { - QByteArray data = f.readAll(); - QString code = QString::fromUtf8(data); - QmlIR::Document::removeScriptPragmas(code); - - script.reset(new QV4::Script(scope.engine, qmlcontext, code, url.toString())); - } - } + script.reset(QV4::Script::createFromFileOrCache(scope.engine, qmlcontext, localFile, url)); if (!script.isNull()) { script->parse(); diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h index 68537ba2e8..8015722afc 100644 --- a/src/qml/jsruntime/qv4include_p.h +++ b/src/qml/jsruntime/qv4include_p.h @@ -77,7 +77,7 @@ public: Exception = 3 }; - static QV4::ReturnedValue method_include(const QV4::BuiltinFunction *, QV4::CallData *callData); + static QV4::ReturnedValue method_include(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc); private Q_SLOTS: void finished(); diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index d439884ca2..9da854e7d7 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -105,10 +105,10 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize) InternalClass::InternalClass(ExecutionEngine *engine) : engine(engine) - , vtable(0) - , prototype(0) - , m_sealed(0) - , m_frozen(0) + , vtable(nullptr) + , prototype(nullptr) + , m_sealed(nullptr) + , m_frozen(nullptr) , size(0) , extensible(true) { @@ -124,8 +124,8 @@ InternalClass::InternalClass(const QV4::InternalClass &other) , propertyTable(other.propertyTable) , nameMap(other.nameMap) , propertyData(other.propertyData) - , m_sealed(0) - , m_frozen(0) + , m_sealed(nullptr) + , m_frozen(nullptr) , size(other.size) , extensible(other.extensible) , isUsedAsProto(other.isUsedAsProto) @@ -149,6 +149,9 @@ static void removeFromPropertyData(Object *object, int idx, bool accessor = fals int size = o->internalClass->size; for (int i = idx; i < size; ++i) o->setProperty(v4, i, *o->propertyData(i + (accessor ? 2 : 1))); + o->setProperty(v4, size, Primitive::undefinedValue()); + if (accessor) + o->setProperty(v4, size + 1, Primitive::undefinedValue()); } void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index) @@ -220,7 +223,7 @@ InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto) Q_ASSERT(prototype != proto); Q_ASSERT(!proto || proto->internalClass->isUsedAsProto); - Transition temp = { { nullptr }, 0, Transition::PrototypeChange }; + Transition temp = { { nullptr }, nullptr, Transition::PrototypeChange }; temp.prototype = proto; Transition &t = lookupOrInsertTransition(temp); @@ -484,7 +487,7 @@ void InternalClass::destroy() destroyStack.pop_back(); if (!next->engine) continue; - next->engine = 0; + next->engine = nullptr; next->propertyTable.~PropertyHash(); next->nameMap.~SharedInternalClassData<Identifier *>(); next->propertyData.~SharedInternalClassData<PropertyAttributes>(); diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 546073dcf5..b689272006 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -277,10 +277,10 @@ struct InternalClass : public QQmlJS::Managed { } static void addMember(Object *object, String *string, PropertyAttributes data, uint *index); - Q_REQUIRED_RESULT InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0); - Q_REQUIRED_RESULT InternalClass *addMember(Identifier *identifier, PropertyAttributes data, uint *index = 0); - Q_REQUIRED_RESULT InternalClass *changeMember(Identifier *identifier, PropertyAttributes data, uint *index = 0); - static void changeMember(Object *object, String *string, PropertyAttributes data, uint *index = 0); + Q_REQUIRED_RESULT InternalClass *addMember(String *string, PropertyAttributes data, uint *index = nullptr); + Q_REQUIRED_RESULT InternalClass *addMember(Identifier *identifier, PropertyAttributes data, uint *index = nullptr); + Q_REQUIRED_RESULT InternalClass *changeMember(Identifier *identifier, PropertyAttributes data, uint *index = nullptr); + static void changeMember(Object *object, String *string, PropertyAttributes data, uint *index = nullptr); static void removeMember(Object *object, Identifier *id); uint find(const String *string); uint find(const Identifier *id) diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h index 6d641bf9c5..c676b57c51 100644 --- a/src/qml/jsruntime/qv4jscall_p.h +++ b/src/qml/jsruntime/qv4jscall_p.h @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE namespace QV4 { struct JSCallData { - JSCallData(const Scope &scope, int argc = 0, const Value *argv = 0, const Value *thisObject = 0) + JSCallData(const Scope &scope, int argc = 0, const Value *argv = nullptr, const Value *thisObject = nullptr) : scope(scope), argc(argc) { if (thisObject) @@ -124,7 +124,7 @@ struct ScopedStackFrame { return; frame.jsFrame = reinterpret_cast<CallData *>(scope.alloc(sizeof(CallData)/sizeof(Value))); frame.jsFrame->context = context; - frame.v4Function = frame.parent ? frame.parent->v4Function : 0; + frame.v4Function = frame.parent ? frame.parent->v4Function : nullptr; scope.engine->currentStackFrame = &frame; } ~ScopedStackFrame() { diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 5e580b8b4d..99666806be 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -634,7 +634,7 @@ struct Stringify return false; } - Stringify(ExecutionEngine *e) : v4(e), replacerFunction(0), propertyList(0), propertyListSize(0) {} + Stringify(ExecutionEngine *e) : v4(e), replacerFunction(nullptr), propertyList(nullptr), propertyListSize(0) {} QString Str(const QString &key, const Value &v); QString JA(ArrayObject *a); @@ -884,12 +884,12 @@ void Heap::JsonObject::init() } -ReturnedValue JsonObject::method_parse(const BuiltinFunction *b, CallData *callData) +ReturnedValue JsonObject::method_parse(const FunctionObject *b, const Value *, const Value *argv, int argc) { ExecutionEngine *v4 = b->engine(); QString jtext; - if (callData->argc() > 0) - jtext = callData->args[0].toQString(); + if (argc > 0) + jtext = argv[0].toQString(); DEBUG << "parsing source = " << jtext; JsonParser parser(v4, jtext.constData(), jtext.length()); @@ -903,12 +903,12 @@ ReturnedValue JsonObject::method_parse(const BuiltinFunction *b, CallData *callD return result; } -ReturnedValue JsonObject::method_stringify(const BuiltinFunction *b, CallData *callData) +ReturnedValue JsonObject::method_stringify(const FunctionObject *b, const Value *, const Value *argv, int argc) { Scope scope(b); Stringify stringify(scope.engine); - ScopedObject o(scope, callData->argument(1)); + ScopedObject o(scope, argc > 1 ? argv[1] : Primitive::undefinedValue()); if (o) { stringify.replacerFunction = o->as<FunctionObject>(); if (o->isArrayObject()) { @@ -920,11 +920,11 @@ ReturnedValue JsonObject::method_stringify(const BuiltinFunction *b, CallData *c if (v->as<NumberObject>() || v->as<StringObject>() || v->isNumber()) *v = v->toString(scope.engine); if (!v->isString()) { - v->setM(0); + v->setM(nullptr); } else { for (uint j = 0; j <i; ++j) { if (stringify.propertyList[j].m() == v->m()) { - v->setM(0); + v->setM(nullptr); break; } } @@ -933,7 +933,7 @@ ReturnedValue JsonObject::method_stringify(const BuiltinFunction *b, CallData *c } } - ScopedValue s(scope, callData->argument(2)); + ScopedValue s(scope, argc > 2 ? argv[2] : Primitive::undefinedValue()); if (NumberObject *n = s->as<NumberObject>()) s = Encode(n->value()); else if (StringObject *so = s->as<StringObject>()) @@ -946,7 +946,7 @@ ReturnedValue JsonObject::method_stringify(const BuiltinFunction *b, CallData *c } - ScopedValue arg0(scope, callData->argument(0)); + ScopedValue arg0(scope, argc ? argv[0] : Primitive::undefinedValue()); QString result = stringify.Str(QString(), arg0); if (result.isEmpty() || scope.engine->hasException) RETURN_UNDEFINED(); diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h index 19dba14aef..7d9f204910 100644 --- a/src/qml/jsruntime/qv4jsonobject_p.h +++ b/src/qml/jsruntime/qv4jsonobject_p.h @@ -88,8 +88,8 @@ private: typedef QSet<ObjectItem> V4ObjectSet; public: - static ReturnedValue method_parse(const BuiltinFunction *, CallData *callData); - static ReturnedValue method_stringify(const BuiltinFunction *, CallData *callData); + static ReturnedValue method_parse(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_stringify(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue fromJsonValue(ExecutionEngine *engine, const QJsonValue &value); static ReturnedValue fromJsonObject(ExecutionEngine *engine, const QJsonObject &object); diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index 200380eda0..b50e5f0355 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -46,7 +46,7 @@ using namespace QV4; const VTable Managed::static_vtbl = { - 0, + nullptr, 0, 0, Managed::IsExecutionContext, @@ -58,15 +58,15 @@ const VTable Managed::static_vtbl = 0, Managed::MyType, "Managed", - 0, - 0 /*markObjects*/, + nullptr, + nullptr /*markObjects*/, isEqualTo }; QString Managed::className() const { - const char *s = 0; + const char *s = nullptr; switch (Type(d()->vtable()->type)) { case Type_Invalid: case Type_String: diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index f81dcf9479..092c61b81c 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -93,7 +93,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} dptr->_checkIsInitialized(); \ return dptr; \ } \ - V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass) + Q_STATIC_ASSERT(std::is_trivial< QV4::Heap::DataClass >::value); #define V4_MANAGED(DataClass, superClass) \ private: \ diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp index 252ec345d9..0c18d908de 100644 --- a/src/qml/jsruntime/qv4mathobject.cpp +++ b/src/qml/jsruntime/qv4mathobject.cpp @@ -277,7 +277,7 @@ ReturnedValue MathObject::method_pow(const FunctionObject *, const Value *, cons ReturnedValue MathObject::method_random(const FunctionObject *, const Value *, const Value *, int) { - RETURN_RESULT(Encode(QRandomGenerator::getReal())); + RETURN_RESULT(Encode(QRandomGenerator::global()->generateDouble())); } ReturnedValue MathObject::method_round(const FunctionObject *, const Value *, const Value *argv, int argc) diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 3e231d693b..ac9671254d 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -65,7 +65,7 @@ namespace Heap { DECLARE_HEAP_OBJECT(MemberData, Base) { DECLARE_MARKOBJECTS(MemberData); }; -V4_ASSERT_IS_TRIVIAL(MemberData) +Q_STATIC_ASSERT(std::is_trivial< MemberData >::value); } @@ -79,7 +79,7 @@ struct MemberData : Managed Value *slot; void set(EngineBase *e, Value newVal) { - WriteBarrier::write(e, base, slot, newVal); + WriteBarrier::write(e, base, slot->data_ptr(), newVal.asReturnedValue()); } const Value *operator->() const { return slot; } const Value &operator*() const { return *slot; } @@ -93,7 +93,7 @@ struct MemberData : Managed inline uint size() const { return d()->values.size; } - static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0); + static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = nullptr); }; } diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index b4034fd196..8e9bf794a9 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -94,7 +94,7 @@ void Heap::Object::setUsedAsProto() bool Object::setPrototype(Object *proto) { - Heap::Object *p = proto ? proto->d() : 0; + Heap::Object *p = proto ? proto->d() : nullptr; Heap::Object *pp = p; while (pp) { if (pp == d()) @@ -156,34 +156,13 @@ void Object::defineDefaultProperty(const QString &name, const Value &value) defineDefaultProperty(s, value); } -void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(const BuiltinFunction *, CallData *), int argumentCount) -{ - ExecutionEngine *e = engine(); - Scope scope(e); - ScopedString s(scope, e->newIdentifier(name)); - ExecutionContext *global = e->rootContext(); - ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code)); - function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount)); - defineDefaultProperty(s, function); -} - -void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(const BuiltinFunction *, CallData *), int argumentCount) -{ - ExecutionEngine *e = engine(); - Scope scope(e); - ExecutionContext *global = e->rootContext(); - ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code)); - function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount)); - defineDefaultProperty(name, function); -} - void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount) { ExecutionEngine *e = engine(); Scope scope(e); ScopedString s(scope, e->newIdentifier(name)); ExecutionContext *global = e->rootContext(); - ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code)); + ScopedFunctionObject function(scope, FunctionObject::createBuiltinFunction(global, s, code)); function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(s, function); } @@ -193,32 +172,11 @@ void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(const Fun ExecutionEngine *e = engine(); Scope scope(e); ExecutionContext *global = e->rootContext(); - ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code)); + ScopedFunctionObject function(scope, FunctionObject::createBuiltinFunction(global, name, code)); function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(name, function); } -void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(const BuiltinFunction *, CallData *), - ReturnedValue (*setter)(const BuiltinFunction *, CallData *)) -{ - ExecutionEngine *e = engine(); - Scope scope(e); - ScopedString s(scope, e->newIdentifier(name)); - defineAccessorProperty(s, getter, setter); -} - -void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(const BuiltinFunction *, CallData *), - ReturnedValue (*setter)(const BuiltinFunction *, CallData *)) -{ - ExecutionEngine *v4 = engine(); - QV4::Scope scope(v4); - ScopedProperty p(scope); - 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); -} - void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(const FunctionObject *, const Value *, const Value *, int), ReturnedValue (*setter)(const FunctionObject *, const Value *, const Value *, int)) { @@ -235,8 +193,8 @@ void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(const QV4::Scope scope(v4); ScopedProperty p(scope); 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))); + p->setGetter(ScopedFunctionObject(scope, (getter ? FunctionObject::createBuiltinFunction(global, name, getter) : nullptr))); + p->setSetter(ScopedFunctionObject(scope, (setter ? FunctionObject::createBuiltinFunction(global, name, setter) : nullptr))); insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); } @@ -268,11 +226,6 @@ void Object::defineReadonlyConfigurableProperty(String *name, const Value &value insertMember(name, value, Attr_ReadOnly_ButConfigurable); } -void Object::markObjects(Heap::Base *base, MarkStack *stack) -{ - Heap::Object::markObjects(base, stack); -} - void Heap::Object::markObjects(Heap::Base *b, MarkStack *stack) { Object *o = static_cast<Object *>(b); @@ -368,7 +321,7 @@ MemberData::Index Object::getValueOrSetter(String *name, PropertyAttributes *att o = o->prototype(); } *attrs = Attr_Invalid; - return { 0, 0 }; + return { nullptr, nullptr }; } ArrayData::Index Object::getValueOrSetter(uint index, PropertyAttributes *attrs) @@ -393,7 +346,7 @@ ArrayData::Index Object::getValueOrSetter(uint index, PropertyAttributes *attrs) o = o->prototype(); } *attrs = Attr_Invalid; - return { 0, 0 }; + return { nullptr, 0 }; } bool Object::hasProperty(String *name) const @@ -531,7 +484,7 @@ bool Object::deleteIndexedProperty(Managed *m, uint index) void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *pd, PropertyAttributes *attrs) { Object *o = static_cast<Object *>(m); - name->setM(0); + name->setM(nullptr); *index = UINT_MAX; if (o->arrayData()) { @@ -555,7 +508,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint * return; } } - it->arrayNode = 0; + it->arrayNode = nullptr; it->arrayIndex = UINT_MAX; } // dense arrays @@ -675,7 +628,7 @@ bool Object::internalPut(String *name, const Value &value) name->makeIdentifier(); Identifier *id = name->identifier(); - MemberData::Index memberIndex{0, 0}; + MemberData::Index memberIndex{nullptr, nullptr}; uint member = internalClass()->find(id); PropertyAttributes attrs; if (member < UINT_MAX) { @@ -751,7 +704,7 @@ bool Object::internalPutIndexed(uint index, const Value &value) PropertyAttributes attrs; - ArrayData::Index arrayIndex = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : ArrayData::Index{ 0, 0 }; + ArrayData::Index arrayIndex = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : ArrayData::Index{ nullptr, 0 }; if (arrayIndex.isNull() && isStringObject()) { if (index < static_cast<StringObject *>(this)->length()) @@ -945,7 +898,7 @@ bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Prope return true; } - return __defineOwnProperty__(engine, index, 0, p, attrs); + return __defineOwnProperty__(engine, index, nullptr, p, attrs); } bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *member, const Property *p, PropertyAttributes attrs) @@ -996,8 +949,8 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * Q_ASSERT(arrayData()); setArrayAttributes(index, cattrs); } - current->setGetter(0); - current->setSetter(0); + current->setGetter(nullptr); + current->setSetter(nullptr); } else { // 9c cattrs.setType(PropertyAttributes::Data); @@ -1069,7 +1022,6 @@ void Object::copyArrayData(Object *other) Heap::ArrayData *od = other->d()->arrayData; Heap::ArrayData *dd = d()->arrayData; dd->sparse = new SparseArray(*od->sparse); - dd->freeList = od->freeList; } else { Heap::ArrayData *dd = d()->arrayData; dd->values.size = other->d()->arrayData->values.size; diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 66177617f7..1731ae3c76 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -64,8 +64,6 @@ QT_BEGIN_NAMESPACE namespace QV4 { -struct BuiltinFunction; - namespace Heap { #define ObjectMembers(class, Member) \ @@ -87,12 +85,12 @@ DECLARE_EXPORTED_HEAP_OBJECT(Object, Base) { void setInlineProperty(ExecutionEngine *e, uint index, Value v) { Q_ASSERT(index < vtable()->nInlineProperties); Value *prop = reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index; - WriteBarrier::write(e, this, prop, v); + WriteBarrier::write(e, this, prop->data_ptr(), v.asReturnedValue()); } void setInlineProperty(ExecutionEngine *e, uint index, Heap::Base *b) { Q_ASSERT(index < vtable()->nInlineProperties); Value *prop = reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index; - WriteBarrier::write(e, this, prop, b); + WriteBarrier::write(e, this, prop->data_ptr(), b->asReturnedValue()); } QV4::MemberData::Index writablePropertyData(uint index) { @@ -153,7 +151,7 @@ DECLARE_EXPORTED_HEAP_OBJECT(Object, Base) { dptr->_checkIsInitialized(); \ return dptr; \ } \ - V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); + Q_STATIC_ASSERT(std::is_trivial< QV4::Heap::DataClass >::value); #define V4_PROTOTYPE(p) \ static QV4::Object *defaultPrototype(QV4::ExecutionEngine *e) \ @@ -238,8 +236,8 @@ struct Q_QML_EXPORT Object: Managed { Heap::Object *prototype() const { return d()->prototype(); } bool setPrototype(Object *proto); - void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0); - void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = 0); + void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = nullptr); + void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = nullptr); MemberData::Index getValueOrSetter(String *name, PropertyAttributes *attrs); ArrayData::Index getValueOrSetter(uint index, PropertyAttributes *attrs); @@ -273,16 +271,8 @@ struct Q_QML_EXPORT Object: Managed { insertMember(name, value, Attr_Data|Attr_NotEnumerable); } void defineDefaultProperty(const QString &name, const Value &value); - // old calling convention - void defineDefaultProperty(const QString &name, ReturnedValue (*code)(const BuiltinFunction *, CallData *), int argumentCount = 0); - void defineDefaultProperty(String *name, ReturnedValue (*code)(const BuiltinFunction *, CallData *), int argumentCount = 0); - // new calling convention void defineDefaultProperty(const QString &name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount = 0); void defineDefaultProperty(String *name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount = 0); - void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(const BuiltinFunction *, CallData *), - ReturnedValue (*setter)(const BuiltinFunction *, CallData *)); - void defineAccessorProperty(String *name, ReturnedValue (*getter)(const BuiltinFunction *, CallData *), - ReturnedValue (*setter)(const BuiltinFunction *, CallData *)); void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(const FunctionObject *, const Value *, const Value *, int), ReturnedValue (*setter)(const FunctionObject *, const Value *, const Value *, int)); void defineAccessorProperty(String *name, ReturnedValue (*getter)(const FunctionObject *, const Value *, const Value *, int), @@ -308,8 +298,6 @@ struct Q_QML_EXPORT Object: Managed { // Array handling public: - static void markObjects(Heap::Base *base, MarkStack *stack); - void copyArrayData(Object *other); bool setArrayLength(uint newLen); @@ -358,8 +346,8 @@ public: } void initSparseArray(); - SparseArrayNode *sparseBegin() { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->begin() : 0; } - SparseArrayNode *sparseEnd() { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->end() : 0; } + SparseArrayNode *sparseBegin() { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->begin() : nullptr; } + SparseArrayNode *sparseEnd() { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->end() : nullptr; } inline bool protoHasArray() { Scope scope(engine()); @@ -372,9 +360,9 @@ public: return false; } - inline ReturnedValue get(String *name, bool *hasProperty = 0) const + inline ReturnedValue get(String *name, bool *hasProperty = nullptr) const { return vtable()->get(this, name, hasProperty); } - inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) const + inline ReturnedValue getIndexed(uint idx, bool *hasProperty = nullptr) const { return vtable()->getIndexed(this, idx, hasProperty); } // use the set variants instead, to customize throw behavior @@ -563,7 +551,7 @@ inline void Object::arraySet(uint index, const Value &value) template<> inline const ArrayObject *Value::as() const { - return isManaged() && m()->vtable()->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : 0; + return isManaged() && m()->vtable()->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : nullptr; } #ifndef V4_BOOTSTRAP diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index 0394c704f9..7bf7e1aa04 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -47,8 +47,8 @@ using namespace QV4; void ObjectIterator::init(const Object *o) { - object->setM(o ? o->m() : 0); - current->setM(o ? o->m() : 0); + object->setM(o ? o->m() : nullptr); + current->setM(o ? o->m() : nullptr); if (object->as<ArgumentsObject>()) { Scope scope(engine); @@ -58,7 +58,7 @@ void ObjectIterator::init(const Object *o) void ObjectIterator::next(Value *name, uint *index, Property *pd, PropertyAttributes *attrs) { - name->setM(0); + name->setM(nullptr); *index = UINT_MAX; if (!object->as<Object>()) { @@ -100,7 +100,7 @@ void ObjectIterator::next(Value *name, uint *index, Property *pd, PropertyAttrib if (flags & WithProtoChain) current->setM(co->prototype()); else - current->setM(0); + current->setM(nullptr); arrayIndex = 0; memberIndex = 0; diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index 30a6ad3025..744d16301a 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -73,7 +73,7 @@ struct Q_QML_EXPORT ObjectIteratorData uint memberIndex; uint flags; }; -V4_ASSERT_IS_TRIVIAL(ObjectIteratorData) +Q_STATIC_ASSERT(std::is_trivial< ObjectIteratorData >::value); struct Q_QML_EXPORT ObjectIterator: ObjectIteratorData { @@ -101,7 +101,7 @@ struct Q_QML_EXPORT ObjectIterator: ObjectIteratorData init(o); } - void next(Value *name, uint *index, Property *pd, PropertyAttributes *attributes = 0); + void next(Value *name, uint *index, Property *pd, PropertyAttributes *attributes = nullptr); ReturnedValue nextPropertyName(Value *value); ReturnedValue nextPropertyNameAsString(Value *value); ReturnedValue nextPropertyNameAsString(); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 5eef757ce9..b998b78520 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -121,8 +121,8 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) 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); + p->value = FunctionObject::createBuiltinFunction(global, v4->id___proto__(), method_get_proto); + p->set = FunctionObject::createBuiltinFunction(global, v4->id___proto__(), method_set_proto); insertMember(v4->id___proto__(), p, Attr_Accessor|Attr_NotEnumerable); } @@ -638,7 +638,7 @@ ReturnedValue ObjectPrototype::method_set_proto(const FunctionObject *b, const V THROW_TYPE_ERROR(); if (argv[0].isNull()) { - o->setPrototype(0); + o->setPrototype(nullptr); RETURN_UNDEFINED(); } diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 0b31c971f9..7fc74173e3 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -68,6 +68,22 @@ Page *getPage(Value *val) { return reinterpret_cast<Page *>(reinterpret_cast<quintptr>(val) & ~((quintptr)(WTF::pageSize() - 1))); } +QML_NEARLY_ALWAYS_INLINE void insertInFront(PersistentValueStorage *storage, Page *p) +{ + p->header.next = reinterpret_cast<Page *>(storage->firstPage); + p->header.prev = reinterpret_cast<Page **>(&storage->firstPage); + if (p->header.next) + p->header.next->header.prev = &p->header.next; + storage->firstPage = p; +} + +QML_NEARLY_ALWAYS_INLINE void unlink(Page *p) +{ + if (p->header.prev) + *p->header.prev = p->header.next; + if (p->header.next) + p->header.next->header.prev = p->header.prev; +} Page *allocatePage(PersistentValueStorage *storage) { @@ -78,19 +94,14 @@ Page *allocatePage(PersistentValueStorage *storage) p->header.engine = storage->engine; p->header.alloc = page; - p->header.next = reinterpret_cast<Page *>(storage->firstPage); - p->header.prev = reinterpret_cast<Page **>(&storage->firstPage); p->header.refCount = 0; p->header.freeList = 0; - if (p->header.next) - p->header.next->header.prev = &p->header.next; + insertInFront(storage, p); for (int i = 0; i < kEntriesPerPage - 1; ++i) { p->values[i].setEmpty(i + 1); } p->values[kEntriesPerPage - 1].setEmpty(-1); - storage->firstPage = p; - return p; } @@ -161,7 +172,7 @@ Value &PersistentValueStorage::Iterator::operator *() PersistentValueStorage::PersistentValueStorage(ExecutionEngine *engine) : engine(engine), - firstPage(0) + firstPage(nullptr) { } @@ -174,9 +185,9 @@ PersistentValueStorage::~PersistentValueStorage() p->values[i] = Encode::undefined(); } Page *n = p->header.next; - p->header.engine = 0; - p->header.prev = 0; - p->header.next = 0; + p->header.engine = nullptr; + p->header.prev = nullptr; + p->header.next = nullptr; Q_ASSERT(p->header.refCount); p = n; } @@ -195,6 +206,12 @@ Value *PersistentValueStorage::allocate() Value *v = p->values + p->header.freeList; p->header.freeList = v->int_32(); + + if (p->header.freeList != -1 && p != firstPage) { + unlink(p); + insertInFront(this, p); + } + ++p->header.refCount; v->setRawValue(Encode::undefined()); @@ -237,16 +254,13 @@ ExecutionEngine *PersistentValueStorage::getEngine(Value *v) void PersistentValueStorage::freePage(void *page) { Page *p = static_cast<Page *>(page); - if (p->header.prev) - *p->header.prev = p->header.next; - if (p->header.next) - p->header.next->header.prev = p->header.prev; + unlink(p); p->header.alloc.deallocate(); } PersistentValue::PersistentValue(const PersistentValue &other) - : val(0) + : val(nullptr) { if (other.val) { val = other.engine()->memoryManager->m_persistentValues->allocate(); @@ -267,7 +281,7 @@ PersistentValue::PersistentValue(ExecutionEngine *engine, ReturnedValue value) } PersistentValue::PersistentValue(ExecutionEngine *engine, Object *object) - : val(0) + : val(nullptr) { if (!object) return; @@ -344,7 +358,7 @@ void PersistentValue::set(ExecutionEngine *engine, Heap::Base *obj) } WeakValue::WeakValue(const WeakValue &other) - : val(0) + : val(nullptr) { if (other.val) { allocVal(other.engine()); @@ -404,6 +418,6 @@ void WeakValue::free() PersistentValueStorage::free(val); } - val = 0; + val = nullptr; } diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h index 1f838f5531..55e8eefcb7 100644 --- a/src/qml/jsruntime/qv4persistent_p.h +++ b/src/qml/jsruntime/qv4persistent_p.h @@ -81,7 +81,7 @@ struct Q_QML_EXPORT PersistentValueStorage Value &operator *(); }; Iterator begin() { return Iterator(firstPage, 0); } - Iterator end() { return Iterator(0, 0); } + Iterator end() { return Iterator(nullptr, 0); } static ExecutionEngine *getEngine(Value *v); @@ -94,7 +94,7 @@ private: class Q_QML_EXPORT PersistentValue { public: - PersistentValue() : val(0) {} + PersistentValue() {} PersistentValue(const PersistentValue &other); PersistentValue &operator=(const PersistentValue &other); PersistentValue &operator=(const WeakValue &other); @@ -117,19 +117,19 @@ public: } Managed *asManaged() const { if (!val) - return 0; + return nullptr; return val->managed(); } template<typename T> T *as() const { if (!val) - return 0; + return nullptr; return val->as<T>(); } ExecutionEngine *engine() const { if (!val) - return 0; + return nullptr; return PersistentValueStorage::getEngine(val); } @@ -137,18 +137,18 @@ public: bool isNullOrUndefined() const { return !val || val->isNullOrUndefined(); } void clear() { PersistentValueStorage::free(val); - val = 0; + val = nullptr; } bool isEmpty() { return !val; } private: - Value *val; + Value *val = nullptr; }; class Q_QML_EXPORT WeakValue { public: - WeakValue() : val(0) {} + WeakValue() {} WeakValue(const WeakValue &other); WeakValue(ExecutionEngine *engine, const Value &value); WeakValue &operator=(const WeakValue &other); @@ -183,19 +183,19 @@ public: } Managed *asManaged() const { if (!val) - return 0; + return nullptr; return val->managed(); } template <typename T> T *as() const { if (!val) - return 0; + return nullptr; return val->as<T>(); } ExecutionEngine *engine() const { if (!val) - return 0; + return nullptr; return PersistentValueStorage::getEngine(val); } @@ -206,7 +206,7 @@ public: void markOnce(MarkStack *markStack); private: - Value *val; + Value *val = nullptr; private: Q_NEVER_INLINE void allocVal(ExecutionEngine *engine); diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index bedcb5b164..5fd200efc1 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -120,7 +120,8 @@ void Profiler::startProfiling(quint64 features) if (features & (1 << FeatureMemoryAllocation)) { qint64 timestamp = m_timer.nsecsElapsed(); MemoryAllocationProperties heap = {timestamp, - (qint64)m_engine->memoryManager->getAllocatedMem(), + (qint64)m_engine->memoryManager->getAllocatedMem() - + (qint64)m_engine->memoryManager->getLargeItemsMem(), HeapPage}; m_memory_data.append(heap); MemoryAllocationProperties small = {timestamp, diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index 8a24c71815..e8c154e4e7 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -59,12 +59,18 @@ #if !QT_CONFIG(qml_debug) +#define Q_V4_PROFILE_ALLOC(engine, size, type) (!engine) +#define Q_V4_PROFILE_DEALLOC(engine, size, type) (!engine) QT_BEGIN_NAMESPACE namespace QV4 { namespace Profiling { class Profiler {}; +class FunctionCallProfiler { +public: + FunctionCallProfiler(ExecutionEngine *, Function *) {} +}; } } @@ -72,6 +78,16 @@ QT_END_NAMESPACE #else +#define Q_V4_PROFILE_ALLOC(engine, size, type)\ + (engine->profiler() &&\ + (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\ + engine->profiler()->trackAlloc(size, type) : false) + +#define Q_V4_PROFILE_DEALLOC(engine, size, type) \ + (engine->profiler() &&\ + (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\ + engine->profiler()->trackDealloc(size, type) : false) + QT_BEGIN_NAMESPACE namespace QV4 { @@ -123,7 +139,7 @@ struct MemoryAllocationProperties { class FunctionCall { public: - FunctionCall() : m_function(0), m_start(0), m_end(0) + FunctionCall() : m_function(nullptr), m_start(0), m_end(0) { Q_ASSERT_X(false, Q_FUNC_INFO, "Cannot construct a function call without function"); } FunctionCall(Function *function, qint64 start, qint64 end) : @@ -211,16 +227,24 @@ public: bool trackAlloc(size_t size, MemoryType type) { - MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), (qint64)size, type}; - m_memory_data.append(allocation); - return true; + if (size) { + MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), (qint64)size, type}; + m_memory_data.append(allocation); + return true; + } else { + return false; + } } bool trackDealloc(size_t size, MemoryType type) { - MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), -(qint64)size, type}; - m_memory_data.append(allocation); - return true; + if (size) { + MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), -(qint64)size, type}; + m_memory_data.append(allocation); + return true; + } else { + return false; + } } quint64 featuresEnabled; @@ -252,7 +276,7 @@ public: // It's enough to ref() the function in the destructor as it will probably not disappear while // it's executing ... FunctionCallProfiler(ExecutionEngine *engine, Function *f) - : profiler(0) + : profiler(nullptr) { Profiler *p = engine->profiler(); if (Q_UNLIKELY(p) && (p->featuresEnabled & (1 << Profiling::FeatureFunctionCall))) { diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h index 2a5b6f7f74..7cb106c424 100644 --- a/src/qml/jsruntime/qv4property_p.h +++ b/src/qml/jsruntime/qv4property_p.h @@ -84,7 +84,7 @@ struct Property { inline Heap::FunctionObject *getter() const { return reinterpret_cast<Heap::FunctionObject *>(value.heapObject()); } inline Heap::FunctionObject *setter() const { return reinterpret_cast<Heap::FunctionObject *>(set.heapObject()); } inline void setGetter(FunctionObject *g) { value = reinterpret_cast<Managed *>(g); } - inline void setSetter(FunctionObject *s) { set = (s ? reinterpret_cast<Managed *>(s) : 0); } + inline void setSetter(FunctionObject *s) { set = (s ? reinterpret_cast<Managed *>(s) : nullptr); } void copy(const Property *other, PropertyAttributes attrs) { value = other->value; @@ -92,7 +92,7 @@ struct Property { set = other->set; } - explicit Property() { value = Encode::undefined(); set = Value::fromHeapObject(0); } + explicit Property() { value = Encode::undefined(); set = Value::fromHeapObject(nullptr); } Property(Heap::FunctionObject *getter, Heap::FunctionObject *setter) { value.setM(reinterpret_cast<Heap::Base *>(getter)); set.setM(reinterpret_cast<Heap::Base *>(setter)); diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 5a165b2309..040f060476 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -108,8 +108,8 @@ ReturnedValue QQmlContextWrapper::get(const Managed *m, String *name, bool *hasP return result->asReturnedValue(); } - // Its possible we could delay the calculation of the "actual" context (in the case - // of sub contexts) until it is definately needed. + // It's possible we could delay the calculation of the "actual" context (in the case + // of sub contexts) until it is definitely needed. QQmlContextData *context = resource->getContext(); QQmlContextData *expressionContext = context; @@ -138,7 +138,9 @@ ReturnedValue QQmlContextWrapper::get(const Managed *m, String *name, bool *hasP *hasProperty = true; if (r.scriptIndex != -1) { QV4::ScopedObject scripts(scope, context->importedScripts.valueRef()); - return scripts->getIndexed(r.scriptIndex); + if (scripts) + return scripts->getIndexed(r.scriptIndex); + return QV4::Encode::null(); } else if (r.type.isValid()) { return QQmlTypeWrapper::create(v4, scopeObject, r.type); } else if (r.importNamespace) { @@ -154,7 +156,7 @@ ReturnedValue QQmlContextWrapper::get(const Managed *m, String *name, bool *hasP while (context) { // Search context properties - const QV4::IdentifierHash<int> &properties = context->propertyNames(); + const QV4::IdentifierHash &properties = context->propertyNames(); if (properties.count()) { int propertyIdx = properties.value(name); @@ -200,7 +202,7 @@ ReturnedValue QQmlContextWrapper::get(const Managed *m, String *name, bool *hasP return result->asReturnedValue(); } } - scopeObject = 0; + scopeObject = nullptr; // Search context object @@ -248,8 +250,8 @@ bool QQmlContextWrapper::put(Managed *m, String *name, const Value &value) return Object::put(m, name, value); } - // Its possible we could delay the calculation of the "actual" context (in the case - // of sub contexts) until it is definately needed. + // It's possible we could delay the calculation of the "actual" context (in the case + // of sub contexts) until it is definitely needed. QQmlContextData *context = wrapper->getContext(); QQmlContextData *expressionContext = context; @@ -261,7 +263,7 @@ bool QQmlContextWrapper::put(Managed *m, String *name, const Value &value) QObject *scopeObject = wrapper->getScopeObject(); while (context) { - const QV4::IdentifierHash<int> &properties = context->propertyNames(); + const QV4::IdentifierHash &properties = context->propertyNames(); // Search context properties if (properties.count() && properties.value(name) != -1) return false; @@ -270,7 +272,7 @@ bool QQmlContextWrapper::put(Managed *m, String *name, const Value &value) if (scopeObject && QV4::QObjectWrapper::setQmlProperty(v4, context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, value)) return true; - scopeObject = 0; + scopeObject = nullptr; // Search context object if (context->contextObject && @@ -310,7 +312,7 @@ Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, cons context->isInternal = true; context->isJSContext = true; - Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QQmlContextWrapper>(context, (QObject*)0)); + Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QQmlContextWrapper>(context, (QObject*)nullptr)); qml->d()->isNullWrapper = true; qml->setReadOnly(false); diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index a1df5cb95f..647bef7fc1 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -91,6 +91,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object { V4_OBJECT2(QQmlContextWrapper, Object) V4_NEEDS_DESTROY + V4_INTERNALCLASS(QmlContextWrapper) inline QObject *getScopeObject() const { return d()->scopeObject; } inline QQmlContextData *getContext() const { return *d()->context; } @@ -104,6 +105,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object struct Q_QML_EXPORT QmlContext : public ExecutionContext { V4_MANAGED(QmlContext, ExecutionContext) + V4_INTERNALCLASS(QmlContext) static Heap::QmlContext *createWorkerContext(QV4::ExecutionContext *parent, const QUrl &source, Value *sendFunction); static Heap::QmlContext *create(QV4::ExecutionContext *parent, QQmlContextData *context, QObject *scopeObject); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 6d7d929b61..c1bbe2a330 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -99,7 +99,7 @@ QPair<QObject *, int> QObjectMethod::extractQtMethod(const QV4::FunctionObject * return qMakePair(method->object(), method->methodIndex()); } - return qMakePair((QObject *)0, -1); + return qMakePair((QObject *)nullptr, -1); } static QPair<QObject *, int> extractQtSignal(const Value &value) @@ -116,7 +116,7 @@ static QPair<QObject *, int> extractQtSignal(const Value &value) return qMakePair(handler->object(), handler->signalIndex()); } - return qMakePair((QObject *)0, -1); + return qMakePair((QObject *)nullptr, -1); } static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object, @@ -126,7 +126,7 @@ static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object QV4::Scope scope(v4); if (property.isQObject()) { - QObject *rv = 0; + QObject *rv = nullptr; property.readProperty(object, &rv); return QV4::QObjectWrapper::wrap(v4, rv); } else if (property.isQList()) { @@ -194,7 +194,7 @@ static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object "'%s::%s'", p.typeName(), object->metaObject()->className(), p.name()); return QV4::Encode::undefined(); } else { - QVariant v(property.propType(), (void *)0); + QVariant v(property.propType(), (void *)nullptr); property.readProperty(object, v.data()); return scope.engine->fromVariant(v); } @@ -217,7 +217,7 @@ QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QObject Q_UNUSED(revisionMode); QQmlData *ddata = QQmlData::get(o, false); - QQmlPropertyData *result = 0; + QQmlPropertyData *result = nullptr; if (ddata && ddata->propertyCache) result = ddata->propertyCache->property(name, o, qmlContext); else @@ -249,7 +249,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje } } - QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; + QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr; if (captureRequired && ep && ep->propertyCapture && !property->isConstant()) ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex()); @@ -335,6 +335,11 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje if (!ddata) return QV4::Encode::undefined(); + if (Q_UNLIKELY(!ddata->propertyCache)) { + ddata->propertyCache = QQmlEnginePrivate::get(engine)->cache(object->metaObject()); + ddata->propertyCache->addref(); + } + QQmlPropertyCache *cache = ddata->propertyCache; Q_ASSERT(cache); QQmlPropertyData *property = cache->property(propertyIndex); @@ -434,7 +439,7 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP return; } - QQmlBinding *newBinding = 0; + QQmlBinding *newBinding = nullptr; QV4::Scope scope(engine); QV4::ScopedFunctionObject f(scope, value); if (f) { @@ -496,9 +501,9 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP QMetaObject::metacall(object, QMetaObject::WriteProperty, property->coreIndex(), argv); if (value.isNull() && property->isQObject()) { - PROPERTY_STORE(QObject*, 0); + PROPERTY_STORE(QObject*, nullptr); } else if (value.isUndefined() && property->isResettable()) { - void *a[] = { 0 }; + void *a[] = { nullptr }; QMetaObject::metacall(object, QMetaObject::ResetProperty, property->coreIndex(), a); } else if (value.isUndefined() && property->propType() == qMetaTypeId<QVariant>()) { PROPERTY_STORE(QVariant, QVariant()); @@ -531,7 +536,7 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP Q_ASSERT(vmemo); vmemo->setVMEProperty(property->coreIndex(), value); } else if (property->propType() == qMetaTypeId<QQmlScriptString>() && (value.isUndefined() || value.isPrimitive())) { - QQmlScriptString ss(value.toQStringNoThrow(), 0 /* context */, object); + QQmlScriptString ss(value.toQStringNoThrow(), nullptr /* context */, object); if (value.isNumber()) { ss.d->numberValue = value.toNumber(); ss.d->isNumberLiteral = true; @@ -549,7 +554,7 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP QQmlContextData *callingQmlContext = scope.engine->callingQmlContext(); if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) { - const char *valueType = 0; + const char *valueType = nullptr; if (v.userType() == QVariant::Invalid) valueType = "null"; else valueType = QMetaType::typeName(v.userType()); @@ -590,7 +595,7 @@ ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *ob } else { // If this object is tainted, we have to check to see if it is in our // tainted object list - ScopedObject alternateWrapper(scope, (Object *)0); + ScopedObject alternateWrapper(scope, (Object *)nullptr); if (engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object) alternateWrapper = engine->m_multiplyWrappedQObjects->value(object); @@ -715,6 +720,10 @@ bool QObjectWrapper::put(Managed *m, String *name, const Value &value) PropertyAttributes QObjectWrapper::query(const Managed *m, String *name) { const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m); + const QObject *thatObject = that->d()->object(); + if (QQmlData::wasDeleted(thatObject)) + return QV4::Object::query(m, name); + ExecutionEngine *engine = that->engine(); QQmlContextData *qmlContext = engine->callingQmlContext(); QQmlPropertyData local; @@ -732,7 +741,7 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()"); static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()"); - name->setM(0); + name->setM(nullptr); *index = UINT_MAX; QObjectWrapper *that = static_cast<QObjectWrapper*>(m); @@ -809,7 +818,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase break; QQmlMetaObject::ArgTypeStorage storage; - int *argsTypes = QQmlMetaObject(r).methodParameterTypes(This->signalIndex, &storage, 0); + int *argsTypes = QQmlMetaObject(r).methodParameterTypes(This->signalIndex, &storage, nullptr); int argCount = argsTypes ? argsTypes[0]:0; @@ -838,7 +847,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase QQmlEnginePrivate::get(qmlEngine)->warning(error); } else { QMessageLogger(error.url().toString().toLatin1().constData(), - error.line(), 0).warning().noquote() + error.line(), nullptr).warning().noquote() << error.toString(); } } @@ -900,14 +909,14 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase } // namespace QV4 -ReturnedValue QObjectWrapper::method_connect(const BuiltinFunction *b, CallData *callData) +ReturnedValue QObjectWrapper::method_connect(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { QV4::Scope scope(b); - if (callData->argc() == 0) + if (argc == 0) THROW_GENERIC_ERROR("Function.prototype.connect: no arguments given"); - QPair<QObject *, int> signalInfo = extractQtSignal(callData->thisObject); + QPair<QObject *, int> signalInfo = extractQtSignal(*thisObject); QObject *signalObject = signalInfo.first; int signalIndex = signalInfo.second; // in method range, not signal range! @@ -921,25 +930,25 @@ ReturnedValue QObjectWrapper::method_connect(const BuiltinFunction *b, CallData THROW_GENERIC_ERROR("Function.prototype.connect: this object is not a signal"); QV4::ScopedFunctionObject f(scope); - QV4::ScopedValue thisObject (scope, QV4::Encode::undefined()); + QV4::ScopedValue object (scope, QV4::Encode::undefined()); - if (callData->argc() == 1) { - f = callData->args[0]; - } else if (callData->argc() >= 2) { - thisObject = callData->args[0]; - f = callData->args[1]; + if (argc == 1) { + f = argv[0]; + } else if (argc >= 2) { + object = argv[0]; + f = argv[1]; } if (!f) THROW_GENERIC_ERROR("Function.prototype.connect: target is not a function"); - if (!thisObject->isUndefined() && !thisObject->isObject()) + if (!object->isUndefined() && !object->isObject()) THROW_GENERIC_ERROR("Function.prototype.connect: target this is not an object"); QV4::QObjectSlotDispatcher *slot = new QV4::QObjectSlotDispatcher; slot->signalIndex = signalIndex; - slot->thisObject.set(scope.engine, thisObject); + slot->thisObject.set(scope.engine, object); slot->function.set(scope.engine, f); if (QQmlData *ddata = QQmlData::get(signalObject)) { @@ -952,14 +961,14 @@ ReturnedValue QObjectWrapper::method_connect(const BuiltinFunction *b, CallData RETURN_UNDEFINED(); } -ReturnedValue QObjectWrapper::method_disconnect(const BuiltinFunction *b, CallData *callData) +ReturnedValue QObjectWrapper::method_disconnect(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { QV4::Scope scope(b); - if (callData->argc() == 0) + if (argc == 0) THROW_GENERIC_ERROR("Function.prototype.disconnect: no arguments given"); - QPair<QObject *, int> signalInfo = extractQtSignal(callData->thisObject); + QPair<QObject *, int> signalInfo = extractQtSignal(*thisObject); QObject *signalObject = signalInfo.first; int signalIndex = signalInfo.second; @@ -975,11 +984,11 @@ ReturnedValue QObjectWrapper::method_disconnect(const BuiltinFunction *b, CallDa QV4::ScopedFunctionObject functionValue(scope); QV4::ScopedValue functionThisValue(scope, QV4::Encode::undefined()); - if (callData->argc() == 1) { - functionValue = callData->args[0]; - } else if (callData->argc() >= 2) { - functionThisValue = callData->args[0]; - functionValue = callData->args[1]; + if (argc == 1) { + functionValue = argv[0]; + } else if (argc >= 2) { + functionThisValue = argv[0]; + functionValue = argv[1]; } if (!functionValue) @@ -1048,8 +1057,8 @@ void QObjectWrapper::destroyObject(bool lastCall) if (ddata && ddata->ownContext) { Q_ASSERT(ddata->ownContext == ddata->context); ddata->ownContext->emitDestruction(); - ddata->ownContext = 0; - ddata->context = 0; + ddata->ownContext = nullptr; + ddata->context = nullptr; } // This object is notionally destroyed now ddata->isQueuedForDeletion = true; @@ -1177,14 +1186,14 @@ static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index } else { - void *args[] = { 0 }; + void *args[] = { nullptr }; object.metacall(callType, index, args); return Encode::undefined(); } } -/*! +/* Returns the match score for converting \a actual to be of type \a conversionType. A zero score means "perfect match" whereas a higher score is worse. @@ -1341,7 +1350,7 @@ static inline int QMetaObject_methods(const QMetaObject *metaObject) return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount; } -/*! +/* Returns the next related method, if one, or 0. */ static const QQmlPropertyData * RelatedMethod(const QQmlObjectOrGadget &object, @@ -1350,7 +1359,7 @@ static const QQmlPropertyData * RelatedMethod(const QQmlObjectOrGadget &object, const QQmlPropertyCache *propertyCache) { if (!current->isOverload()) - return 0; + return nullptr; Q_ASSERT(!current->overrideIndexIsProperty()); @@ -1368,7 +1377,7 @@ static const QQmlPropertyData * RelatedMethod(const QQmlObjectOrGadget &object, // If we've been called before with the same override index, then // we can't go any further... if (&dummy == current && dummy.coreIndex() == current->overrideIndex()) - return 0; + return nullptr; QMetaMethod method = mo->method(current->overrideIndex()); dummy.load(method); @@ -1403,7 +1412,7 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ if (data.hasArguments()) { - int *args = 0; + int *args = nullptr; QQmlMetaObject::ArgTypeStorage storage; if (data.isConstructor()) @@ -1426,12 +1435,12 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ } else { - return CallMethod(object, data.coreIndex(), returnType, 0, 0, engine, callArgs, callType); + return CallMethod(object, data.coreIndex(), returnType, 0, nullptr, engine, callArgs, callType); } } -/*! +/* Resolve the overloaded method to call. The algorithm works conceptually like this: 1. Resolve the set of overloads it is *possible* to call. Impossible overloads include those that have too many parameters or have parameters @@ -1463,9 +1472,9 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const do { QQmlMetaObject::ArgTypeStorage storage; int methodArgumentCount = 0; - int *methodArgTypes = 0; + int *methodArgTypes = nullptr; if (attempt->hasArguments()) { - int *args = object.methodParameterTypes(attempt->coreIndex(), &storage, 0); + int *args = object.methodParameterTypes(attempt->coreIndex(), &storage, nullptr); if (!args) // Must be an unknown argument continue; @@ -1493,7 +1502,7 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const if (bestParameterScore == 0 && bestMatchScore == 0) break; // We can't get better than that - } while ((attempt = RelatedMethod(object, attempt, dummy, propertyCache)) != 0); + } while ((attempt = RelatedMethod(object, attempt, dummy, propertyCache)) != nullptr); if (best.isValid()) { return CallPrecise(object, best, engine, callArgs, callType); @@ -1560,7 +1569,7 @@ void *CallArgument::dataPtr() return stdVectorQModelIndexPtr; else if (type != 0) return (void *)&allocData; - return 0; + return nullptr; } void CallArgument::initAsType(int callType) @@ -1578,7 +1587,7 @@ void CallArgument::initAsType(int callType) callType == QMetaType::Float) { type = callType; } else if (callType == QMetaType::QObjectStar) { - qobjectPtr = 0; + qobjectPtr = nullptr; type = callType; } else if (callType == QMetaType::QString) { qstringPtr = new (&allocData) QString(); @@ -1603,7 +1612,7 @@ void CallArgument::initAsType(int callType) jsonValuePtr = new (&allocData) QJsonValue(); } else { type = -1; - qvariantPtr = new (&allocData) QVariant(callType, (void *)0); + qvariantPtr = new (&allocData) QVariant(callType, (void *)nullptr); } } @@ -1655,7 +1664,7 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q qstringPtr = new (&allocData) QString(value.toQStringNoThrow()); type = callType; } else if (callType == QMetaType::QObjectStar) { - qobjectPtr = 0; + qobjectPtr = nullptr; if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) qobjectPtr = qobjectWrapper->object(); else if (const QV4::QQmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QQmlTypeWrapper>()) @@ -1672,14 +1681,14 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q uint length = array->getLength(); for (uint ii = 0; ii < length; ++ii) { - QObject *o = 0; + QObject *o = nullptr; qobjectWrapper = array->getIndexed(ii); if (!!qobjectWrapper) o = qobjectWrapper->object(); qlistPtr->append(o); } } else { - QObject *o = 0; + QObject *o = nullptr; if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) o = qobjectWrapper->object(); qlistPtr->append(o); @@ -1736,7 +1745,7 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q qvariantPtr = new (&allocData) QVariant(); type = -1; - QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; + QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr; QVariant v = scope.engine->toVariant(value, callType); if (v.userType() == callType) { @@ -1749,12 +1758,12 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q if (!mo.isNull()) { QObject *obj = ep->toQObject(v); - if (obj != 0 && !QQmlMetaObject::canConvert(obj, mo)) - obj = 0; + if (obj != nullptr && !QQmlMetaObject::canConvert(obj, mo)) + obj = nullptr; *qvariantPtr = QVariant(callType, &obj); } else { - *qvariantPtr = QVariant(callType, (void *)0); + *qvariantPtr = QVariant(callType, (void *)nullptr); } } } @@ -1953,7 +1962,7 @@ ReturnedValue QObjectMethod::callInternal(const Value *thisObject, const Value * QQmlV4Function func(callData, rv, v4); QQmlV4Function *funcptr = &func; - void *args[] = { 0, &funcptr }; + void *args[] = { nullptr, &funcptr }; object.metacall(QMetaObject::InvokeMetaMethod, method.coreIndex(), args); return rv->asReturnedValue(); @@ -2083,11 +2092,11 @@ ReturnedValue QMetaObjectWrapper::callOverloadedConstructor(QV4::ExecutionEngine for (int i = 0; i < numberOfConstructors; i++) { const QQmlPropertyData & attempt = d()->constructors[i]; + QQmlMetaObject::ArgTypeStorage storage; int methodArgumentCount = 0; - int *methodArgTypes = 0; + int *methodArgTypes = nullptr; if (attempt.hasArguments()) { - QQmlMetaObject::ArgTypeStorage storage; - int *args = object.constructorParameterTypes(attempt.coreIndex(), &storage, 0); + int *args = object.constructorParameterTypes(attempt.coreIndex(), &storage, nullptr); if (!args) // Must be an unknown argument continue; diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index c00e82e4fa..1455acc1b3 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -166,8 +166,8 @@ struct Q_QML_EXPORT QObjectWrapper : public Object QObject *object() const { return d()->object(); } - ReturnedValue getQmlProperty(QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = 0, bool includeImports = false) const; - static ReturnedValue getQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = 0); + ReturnedValue getQmlProperty(QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = nullptr, bool includeImports = false) const; + static ReturnedValue getQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = nullptr); static bool setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value); @@ -198,8 +198,8 @@ protected: static PropertyAttributes query(const Managed *, String *name); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); - static ReturnedValue method_connect(const BuiltinFunction *, CallData *callData); - static ReturnedValue method_disconnect(const BuiltinFunction *, CallData *callData); + static ReturnedValue method_connect(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_disconnect(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); private: Q_NEVER_INLINE static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object); diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index fb49def317..d99536829b 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -48,7 +48,7 @@ RegExpCache::~RegExpCache() { for (RegExpCache::Iterator it = begin(), e = end(); it != e; ++it) { if (RegExp *re = it.value().as<RegExp>()) - re->d()->cache = 0; + re->d()->cache = nullptr; } } @@ -82,7 +82,7 @@ Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bo return result->d(); Scope scope(engine); - Scoped<RegExp> result(scope, engine->memoryManager->alloc<RegExp>(pattern, ignoreCase, multiline, global)); + Scoped<RegExp> result(scope, engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline, global)); result->d()->cache = cache; cachedValue.set(engine, result); @@ -90,7 +90,7 @@ Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bo return result->d(); } -void Heap::RegExp::init(const QString &pattern, bool ignoreCase, bool multiline, bool global) +void Heap::RegExp::init(ExecutionEngine *engine, const QString &pattern, bool ignoreCase, bool multiline, bool global) { Base::init(); this->pattern = new QString(pattern); @@ -100,13 +100,13 @@ void Heap::RegExp::init(const QString &pattern, bool ignoreCase, bool multiline, valid = false; - const char* error = 0; + const char* error = nullptr; JSC::Yarr::YarrPattern yarrPattern(WTF::String(pattern), ignoreCase, multiLine, &error); if (error) return; subPatternCount = yarrPattern.m_numSubpatterns; #if ENABLE(YARR_JIT) - if (!yarrPattern.m_containsBackreferences) { + if (!yarrPattern.m_containsBackreferences && engine->canJIT()) { jitCode = new JSC::Yarr::YarrCodeBlock; JSC::JSGlobalData dummy(internalClass->engine->regExpAllocator); JSC::Yarr::jitCompile(yarrPattern, JSC::Yarr::Char16, &dummy, *jitCode); diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h index 498468e165..56454f73d3 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -76,7 +76,7 @@ struct RegExpCacheKey; namespace Heap { struct RegExp : Base { - void init(const QString& pattern, bool ignoreCase, bool multiline, bool global); + void init(ExecutionEngine *engine, const QString& pattern, bool ignoreCase, bool multiline, bool global); void destroy(); QString *pattern; @@ -100,7 +100,7 @@ struct RegExp : Base { int captureCount() const { return subPatternCount + 1; } }; -V4_ASSERT_IS_TRIVIAL(RegExp) +Q_STATIC_ASSERT(std::is_trivial< RegExp >::value); } diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index f95719b25f..000e2c3a7e 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -283,25 +283,25 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor) ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(2)); // Properties deprecated in the spec but required by "the web" :( - ctor->defineAccessorProperty(QStringLiteral("lastMatch"), method_get_lastMatch_n<0>, 0); - ctor->defineAccessorProperty(QStringLiteral("$&"), method_get_lastMatch_n<0>, 0); - ctor->defineAccessorProperty(QStringLiteral("$1"), method_get_lastMatch_n<1>, 0); - ctor->defineAccessorProperty(QStringLiteral("$2"), method_get_lastMatch_n<2>, 0); - ctor->defineAccessorProperty(QStringLiteral("$3"), method_get_lastMatch_n<3>, 0); - ctor->defineAccessorProperty(QStringLiteral("$4"), method_get_lastMatch_n<4>, 0); - ctor->defineAccessorProperty(QStringLiteral("$5"), method_get_lastMatch_n<5>, 0); - ctor->defineAccessorProperty(QStringLiteral("$6"), method_get_lastMatch_n<6>, 0); - ctor->defineAccessorProperty(QStringLiteral("$7"), method_get_lastMatch_n<7>, 0); - ctor->defineAccessorProperty(QStringLiteral("$8"), method_get_lastMatch_n<8>, 0); - ctor->defineAccessorProperty(QStringLiteral("$9"), method_get_lastMatch_n<9>, 0); - ctor->defineAccessorProperty(QStringLiteral("lastParen"), method_get_lastParen, 0); - ctor->defineAccessorProperty(QStringLiteral("$+"), method_get_lastParen, 0); - ctor->defineAccessorProperty(QStringLiteral("input"), method_get_input, 0); - ctor->defineAccessorProperty(QStringLiteral("$_"), method_get_input, 0); - ctor->defineAccessorProperty(QStringLiteral("leftContext"), method_get_leftContext, 0); - ctor->defineAccessorProperty(QStringLiteral("$`"), method_get_leftContext, 0); - ctor->defineAccessorProperty(QStringLiteral("rightContext"), method_get_rightContext, 0); - ctor->defineAccessorProperty(QStringLiteral("$'"), method_get_rightContext, 0); + ctor->defineAccessorProperty(QStringLiteral("lastMatch"), method_get_lastMatch_n<0>, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$&"), method_get_lastMatch_n<0>, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$1"), method_get_lastMatch_n<1>, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$2"), method_get_lastMatch_n<2>, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$3"), method_get_lastMatch_n<3>, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$4"), method_get_lastMatch_n<4>, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$5"), method_get_lastMatch_n<5>, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$6"), method_get_lastMatch_n<6>, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$7"), method_get_lastMatch_n<7>, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$8"), method_get_lastMatch_n<8>, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$9"), method_get_lastMatch_n<9>, nullptr); + ctor->defineAccessorProperty(QStringLiteral("lastParen"), method_get_lastParen, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$+"), method_get_lastParen, nullptr); + ctor->defineAccessorProperty(QStringLiteral("input"), method_get_input, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$_"), method_get_input, nullptr); + ctor->defineAccessorProperty(QStringLiteral("leftContext"), method_get_leftContext, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$`"), method_get_leftContext, nullptr); + ctor->defineAccessorProperty(QStringLiteral("rightContext"), method_get_rightContext, nullptr); + ctor->defineAccessorProperty(QStringLiteral("$'"), method_get_rightContext, nullptr); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(QStringLiteral("exec"), method_exec, 1); @@ -343,7 +343,7 @@ ReturnedValue RegExpPrototype::execFirstMatch(const FunctionObject *b, const Val if (r->value()->captureCount()) { int start = matchOffsets[0]; int end = matchOffsets[1]; - retVal = (start != -1) ? scope.engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined(); + retVal = (start != -1) ? scope.engine->memoryManager->alloc<ComplexString>(str->d(), start, end - start)->asReturnedValue() : Encode::undefined(); } RegExpCtor::Data *dd = regExpCtor->d(); @@ -394,7 +394,7 @@ ReturnedValue RegExpPrototype::method_exec(const FunctionObject *b, const Value for (int i = 0; i < len; ++i) { int start = matchOffsets[i * 2]; int end = matchOffsets[i * 2 + 1]; - v = (start != -1) ? scope.engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined(); + v = (start != -1) ? scope.engine->memoryManager->alloc<ComplexString>(str->d(), start, end - start)->asReturnedValue() : Encode::undefined(); array->arrayPut(i, v); } array->setArrayLengthUnchecked(len); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 240fba7905..04cad8ddb7 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -382,11 +382,11 @@ double RuntimeHelpers::stringToNumber(const QString &string) { const QStringRef s = QStringRef(&string).trimmed(); if (s.startsWith(QLatin1String("0x")) || s.startsWith(QLatin1String("0X"))) - return s.toLong(0, 16); + return s.toLong(nullptr, 16); bool ok; QByteArray ba = s.toLatin1(); const char *begin = ba.constData(); - const char *end = 0; + const char *end = nullptr; double d = qstrtod(begin, &end, &ok); if (end - begin != ba.size()) { if (ba == "Infinity" || ba == "+Infinity") @@ -457,7 +457,7 @@ Heap::Object *RuntimeHelpers::convertToObject(ExecutionEngine *engine, const Val case Value::Undefined_Type: case Value::Null_Type: engine->throwTypeError(); - return 0; + return nullptr; case Value::Boolean_Type: return engine->newBooleanObject(value.booleanValue()); case Value::Managed_Type: @@ -532,7 +532,7 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu if (!sright->d()->length()) return sleft->asReturnedValue(); MemoryManager *mm = engine->memoryManager; - return (mm->alloc<String>(sleft->d(), sright->d()))->asReturnedValue(); + return (mm->alloc<ComplexString>(sleft->d(), sright->d()))->asReturnedValue(); } double x = RuntimeHelpers::toNumber(pleft); double y = RuntimeHelpers::toNumber(pright); @@ -604,6 +604,14 @@ static Q_NEVER_INLINE ReturnedValue getElementFallback(ExecutionEngine *engine, return o->get(name); } +/* load element: + + Managed *m = object.heapObject(); + if (m) + return m->internalClass->getIndexed(m, index); + return getIndexedFallback(object, index); +*/ + ReturnedValue Runtime::method_loadElement(ExecutionEngine *engine, const Value &object, const Value &index) { uint idx = 0; @@ -672,7 +680,7 @@ bool Runtime::method_storeElement(ExecutionEngine *engine, const Value &object, ReturnedValue Runtime::method_foreachIterator(ExecutionEngine *engine, const Value &in) { Scope scope(engine); - ScopedObject o(scope, (Object *)0); + ScopedObject o(scope, (Object *)nullptr); if (!in.isNullOrUndefined()) o = in.toObject(engine); return engine->newForEachIteratorObject(o)->asReturnedValue(); @@ -1090,6 +1098,37 @@ ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &fu return static_cast<const FunctionObject &>(func).call(nullptr, argv, argc); } +ReturnedValue Runtime::method_callQmlScopeObjectProperty(ExecutionEngine *engine, Value *base, + int propertyIndex, Value *argv, int argc) +{ + Scope scope(engine); + ScopedFunctionObject fo(scope, method_loadQmlScopeObjectProperty(engine, *base, propertyIndex, + /*captureRequired*/true)); + if (!fo) { + QString error = QStringLiteral("Property '%1' of scope object is not a function").arg(propertyIndex); + return engine->throwTypeError(error); + } + + QObject *qmlScopeObj = static_cast<QmlContext *>(base)->d()->qml()->scopeObject; + ScopedValue qmlScopeValue(scope, QObjectWrapper::wrap(engine, qmlScopeObj)); + return fo->call(qmlScopeValue, argv, argc); +} + +ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engine, Value *base, + int propertyIndex, Value *argv, int argc) +{ + Scope scope(engine); + ScopedFunctionObject fo(scope, method_loadQmlContextObjectProperty(engine, *base, propertyIndex, + /*captureRequired*/true)); + if (!fo) { + QString error = QStringLiteral("Property '%1' of context object is not a function").arg(propertyIndex); + return engine->throwTypeError(error); + } + + QObject *qmlContextObj = static_cast<QmlContext *>(base)->d()->qml()->context->contextData()->contextObject; + ScopedValue qmlContextValue(scope, QObjectWrapper::wrap(engine, qmlContextObj)); + return fo->call(qmlContextValue, argv, argc); +} ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &function, Value *argv, int argc) { @@ -1160,7 +1199,7 @@ ReturnedValue Runtime::method_createCatchContext(ExecutionContext *parent, int e { ExecutionEngine *e = parent->engine(); return parent->newCatchContext(e->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex], - e->catchException(0))->asReturnedValue(); + e->catchException(nullptr))->asReturnedValue(); } void Runtime::method_declareVar(ExecutionEngine *engine, bool deletable, int nameIndex) @@ -1260,7 +1299,7 @@ ReturnedValue Runtime::method_loadQmlIdObject(ExecutionEngine *engine, const Val if (!context || index >= (uint)context->idValueCount) return Encode::undefined(); - QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; + QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr; if (ep && ep->propertyCapture) ep->propertyCapture->captureProperty(&context->idValues[index].bindings); diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index ea31dfd08b..2956a4a463 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -188,6 +188,8 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> { F(ReturnedValue, loadQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \ F(ReturnedValue, loadQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \ F(ReturnedValue, loadQmlIdObject, (ExecutionEngine *engine, const Value &context, uint index)) \ + F(ReturnedValue, callQmlScopeObjectProperty, (ExecutionEngine *engine, Value *base, int propertyIndex, Value *argv, int argc)) \ + F(ReturnedValue, callQmlContextObjectProperty, (ExecutionEngine *engine, Value *base, int propertyIndex, Value *argv, int argc)) \ \ F(void, storeQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \ F(void, storeQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \ diff --git a/src/qml/jsruntime/qv4runtimecodegen.cpp b/src/qml/jsruntime/qv4runtimecodegen.cpp index 9c115099b5..fe18ddf9ed 100644 --- a/src/qml/jsruntime/qv4runtimecodegen.cpp +++ b/src/qml/jsruntime/qv4runtimecodegen.cpp @@ -49,15 +49,16 @@ void RuntimeCodegen::generateFromFunctionExpression(const QString &fileName, { _module = module; _module->fileName = fileName; - _context = 0; + _module->finalUrl = fileName; + _context = nullptr; Compiler::ScanFunctions scan(this, sourceCode, Compiler::GlobalCode); // fake a global environment - scan.enterEnvironment(0, Compiler::FunctionCode); + scan.enterEnvironment(nullptr, Compiler::FunctionCode); scan(ast); scan.leaveEnvironment(); - int index = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0); + int index = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : nullptr); _module->rootContext = _module->functions.at(index); } diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index afb5c21d36..bb20f384b3 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -209,7 +209,7 @@ struct Scoped enum ConvertType { Convert }; QML_NEARLY_ALWAYS_INLINE void setPointer(const Managed *p) { - ptr->setM(p ? p->m() : 0); + ptr->setM(p ? p->m() : nullptr); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope) @@ -244,7 +244,7 @@ struct Scoped QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value *v) { ptr = scope.engine->jsAlloca(1); - setPointer(v ? v->as<T>() : 0); + setPointer(v ? v->as<T>() : nullptr); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, T *t) @@ -290,7 +290,7 @@ struct Scoped return *this; } Scoped<T> &operator=(Value *v) { - setPointer(v ? v->as<T>() : 0); + setPointer(v ? v->as<T>() : nullptr); return *this; } diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 901f2574da..bb6608bec0 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -62,14 +62,14 @@ using namespace QV4; Script::Script(ExecutionEngine *v4, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit) : line(1), column(0), context(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false) - , compilationUnit(compilationUnit), vmFunction(0), parseAsBinding(true) + , compilationUnit(compilationUnit), vmFunction(nullptr), parseAsBinding(true) { if (qml) qmlContext.set(v4, *qml); parsed = true; - vmFunction = compilationUnit ? compilationUnit->linkToEngine(v4) : 0; + vmFunction = compilationUnit ? compilationUnit->linkToEngine(v4) : nullptr; } Script::~Script() @@ -88,7 +88,7 @@ void Script::parse() ExecutionEngine *v4 = context->engine(); Scope valueScope(v4); - Module module(v4->debugger() != 0); + Module module(v4->debugger() != nullptr); Engine ee, *engine = ⅇ Lexer lexer(engine); @@ -121,7 +121,7 @@ void Script::parse() RuntimeCodegen cg(v4, &jsGenerator, strictMode); if (inheritContext) cg.setUseFastLookups(false); - cg.generateFromProgram(sourceFile, sourceCode, program, &module, compilationMode); + cg.generateFromProgram(sourceFile, sourceFile, sourceCode, program, &module, compilationMode); if (v4->hasException) return; @@ -149,10 +149,10 @@ ReturnedValue Script::run() if (qmlContext.isUndefined()) { TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction); - return vmFunction->call(engine->globalObject, 0, 0, context); + return vmFunction->call(engine->globalObject, nullptr, 0, context); } else { Scoped<QmlContext> qml(valueScope, qmlContext.value()); - return vmFunction->call(0, 0, 0, qml); + return vmFunction->call(nullptr, nullptr, 0, qml); } } @@ -164,8 +164,8 @@ Function *Script::function() } QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compiler::Module *module, Compiler::JSUnitGenerator *unitGenerator, - const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors, - Directives *directivesCollector) + const QString &fileName, const QString &finalUrl, const QString &source, + QList<QQmlError> *reportedErrors, Directives *directivesCollector) { using namespace QV4::Compiler; using namespace QQmlJS::AST; @@ -184,12 +184,12 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compi const auto diagnosticMessages = parser.diagnosticMessages(); for (const DiagnosticMessage &m : diagnosticMessages) { if (m.isWarning()) { - qWarning("%s:%d : %s", qPrintable(url.toString()), m.loc.startLine, qPrintable(m.message)); + qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message)); continue; } QQmlError error; - error.setUrl(url); + error.setUrl(QUrl(fileName)); error.setDescription(m.message); error.setLine(m.loc.startLine); error.setColumn(m.loc.startColumn); @@ -199,29 +199,50 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compi if (!errors.isEmpty()) { if (reportedErrors) *reportedErrors << errors; - return 0; + return nullptr; } Program *program = AST::cast<Program *>(parser.rootNode()); if (!program) { // if parsing was successful, and we have no program, then // we're done...: - return 0; + return nullptr; } Codegen cg(unitGenerator, /*strict mode*/false); cg.setUseFastLookups(false); - cg.generateFromProgram(url.toString(), source, program, module, GlobalCode); + cg.generateFromProgram(fileName, finalUrl, source, program, module, GlobalCode); errors = cg.qmlErrors(); if (!errors.isEmpty()) { if (reportedErrors) *reportedErrors << errors; - return 0; + return nullptr; } return cg.generateCompilationUnit(/*generate unit data*/false); } +Script *Script::createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl) +{ + if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(originalUrl)) { + QQmlRefPointer<QV4::CompiledData::CompilationUnit> jsUnit; + jsUnit.adopt(new QV4::CompiledData::CompilationUnit(cachedUnit)); + return new QV4::Script(engine, qmlContext, jsUnit); + } + + QFile f(fileName); + if (!f.open(QIODevice::ReadOnly)) + return nullptr; + + QByteArray data = f.readAll(); + QString sourceCode = QString::fromUtf8(data); + QmlIR::Document::removeScriptPragmas(sourceCode); + + auto result = new QV4::Script(engine, qmlContext, sourceCode, originalUrl.toString()); + result->parse(); + return result; +} + QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext) { QV4::Scope scope(engine); diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index 158d21c69d..24291b9aa6 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -68,11 +68,11 @@ struct Q_QML_EXPORT Script { Script(ExecutionContext *scope, QV4::Compiler::CompilationMode mode, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) : sourceFile(source), line(line), column(column), sourceCode(sourceCode) , context(scope), strictMode(false), inheritContext(false), parsed(false), compilationMode(mode) - , vmFunction(0), parseAsBinding(false) {} + , vmFunction(nullptr), parseAsBinding(false) {} 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) , context(engine->rootContext()), strictMode(false), inheritContext(true), parsed(false) - , vmFunction(0), parseAsBinding(true) { + , vmFunction(nullptr), parseAsBinding(true) { if (qml) qmlContext.set(engine, *qml); } @@ -97,8 +97,11 @@ struct Q_QML_EXPORT Script { Function *function(); - static QQmlRefPointer<CompiledData::CompilationUnit> precompile(QV4::Compiler::Module *module, Compiler::JSUnitGenerator *unitGenerator, const QUrl &url, const QString &source, - QList<QQmlError> *reportedErrors = 0, QQmlJS::Directives *directivesCollector = 0); + static QQmlRefPointer<CompiledData::CompilationUnit> precompile( + QV4::Compiler::Module *module, Compiler::JSUnitGenerator *unitGenerator, + const QString &fileName, const QString &finalUrl, const QString &source, + QList<QQmlError> *reportedErrors = nullptr, QQmlJS::Directives *directivesCollector = nullptr); + static Script *createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl); 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 78cd7529d8..7d29d0b517 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -340,7 +340,7 @@ public: void containerAdvanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) { - name->setM(0); + name->setM(nullptr); *index = UINT_MAX; if (d()->isReference) { @@ -420,11 +420,10 @@ public: ScopedFunctionObject compare(scope, m_compareFn); if (!compare) return m_v4->throwTypeError(); - JSCallData jsCallData(scope, 2); - jsCallData->args[0] = convertElementToValue(m_v4, lhs); - jsCallData->args[1] = convertElementToValue(m_v4, rhs); - *jsCallData->thisObject = m_v4->globalObject; - QV4::ScopedValue result(scope, compare->call(jsCallData)); + Value *argv = scope.alloc(2); + argv[0] = convertElementToValue(m_v4, lhs); + argv[1] = convertElementToValue(m_v4, rhs); + QV4::ScopedValue result(scope, compare->call(m_v4->globalObject, argv, 2)); return result->toNumber() < 0; } @@ -433,7 +432,7 @@ public: const QV4::Value *m_compareFn; }; - void sort(const BuiltinFunction *, Scope &scope, CallData *callData) + void sort(const FunctionObject *f, const Value *, const Value *argv, int argc) { if (d()->isReference) { if (!d()->object) @@ -441,8 +440,8 @@ public: loadReference(); } - if (callData->argc() == 1 && callData->args[0].as<FunctionObject>()) { - CompareFunctor cf(scope.engine, callData->args[0]); + if (argc == 1 && argv[0].as<FunctionObject>()) { + CompareFunctor cf(f->engine(), argv[0]); std::sort(d()->container->begin(), d()->container->end(), cf); } else { DefaultCompareFunctor cf; @@ -453,10 +452,10 @@ public: storeReference(); } - static QV4::ReturnedValue method_get_length(const BuiltinFunction *b, CallData *callData) + static QV4::ReturnedValue method_get_length(const FunctionObject *b, const Value *thisObject, const Value *, int) { QV4::Scope scope(b); - QV4::Scoped<QQmlSequence<Container> > This(scope, callData->thisObject.as<QQmlSequence<Container> >()); + QV4::Scoped<QQmlSequence<Container>> This(scope, thisObject->as<QQmlSequence<Container> >()); if (!This) THROW_TYPE_ERROR(); @@ -468,14 +467,14 @@ public: RETURN_RESULT(Encode(qint32(This->d()->container->size()))); } - static QV4::ReturnedValue method_set_length(const BuiltinFunction *b, CallData *callData) + static QV4::ReturnedValue method_set_length(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc) { - QV4::Scope scope(b); - QV4::Scoped<QQmlSequence<Container> > This(scope, callData->thisObject.as<QQmlSequence<Container> >()); + QV4::Scope scope(f); + QV4::Scoped<QQmlSequence<Container>> This(scope, thisObject->as<QQmlSequence<Container> >()); if (!This) THROW_TYPE_ERROR(); - quint32 newLength = callData->args[0].toUInt32(); + quint32 newLength = argc ? argv[0].toUInt32() : 0; /* Qt containers have int (rather than uint) allowable indexes. */ if (newLength > INT_MAX) { generateWarning(scope.engine, QLatin1String("Index out of range during length set")); @@ -536,7 +535,7 @@ public: { Q_ASSERT(d()->object); Q_ASSERT(d()->isReference); - void *a[] = { d()->container, 0 }; + void *a[] = { d()->container, nullptr }; QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->propertyIndex, a); } @@ -546,7 +545,7 @@ public: Q_ASSERT(d()->isReference); int status = -1; QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding; - void *a[] = { d()->container, 0, &status, &flags }; + void *a[] = { d()->container, nullptr, &status, &flags }; QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a); } @@ -652,24 +651,24 @@ void SequencePrototype::init() } #undef REGISTER_QML_SEQUENCE_METATYPE -ReturnedValue SequencePrototype::method_valueOf(const BuiltinFunction *f, CallData *callData) +ReturnedValue SequencePrototype::method_valueOf(const FunctionObject *f, const Value *thisObject, const Value *, int) { - return Encode(callData->thisObject.toString(f->engine())); + return Encode(thisObject->toString(f->engine())); } -ReturnedValue SequencePrototype::method_sort(const BuiltinFunction *b, CallData *callData) +ReturnedValue SequencePrototype::method_sort(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { Scope scope(b); - QV4::ScopedObject o(scope, callData->thisObject); + QV4::ScopedObject o(scope, thisObject); if (!o || !o->isListType()) THROW_TYPE_ERROR(); - if (callData->argc() >= 2) + if (argc >= 2) return o.asReturnedValue(); #define CALL_SORT(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue) \ if (QQml##SequenceElementTypeName##List *s = o->as<QQml##SequenceElementTypeName##List>()) { \ - s->sort(b, scope, callData); \ + s->sort(b, thisObject, argv, argc); \ } else FOREACH_QML_SEQUENCE_TYPE(CALL_SORT) diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h index 169a48c2f9..e9bef2f604 100644 --- a/src/qml/jsruntime/qv4sequenceobject_p.h +++ b/src/qml/jsruntime/qv4sequenceobject_p.h @@ -68,8 +68,8 @@ struct SequencePrototype : public QV4::Object V4_PROTOTYPE(arrayPrototype) void init(); - static ReturnedValue method_valueOf(const BuiltinFunction *f, CallData *callData); - static ReturnedValue method_sort(const BuiltinFunction *, CallData *callData); + static ReturnedValue method_valueOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_sort(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static bool isSequenceType(int sequenceTypeId); static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded); diff --git a/src/qml/jsruntime/qv4sparsearray.cpp b/src/qml/jsruntime/qv4sparsearray.cpp index 8f6aa6723c..2a3e28bf63 100644 --- a/src/qml/jsruntime/qv4sparsearray.cpp +++ b/src/qml/jsruntime/qv4sparsearray.cpp @@ -89,20 +89,20 @@ const SparseArrayNode *SparseArrayNode::previousNode() const SparseArrayNode *SparseArrayNode::copy(SparseArray *d) const { - SparseArrayNode *n = d->createNode(size_left, 0, false); + SparseArrayNode *n = d->createNode(size_left, nullptr, false); n->value = value; n->setColor(color()); if (left) { n->left = left->copy(d); n->left->setParent(n); } else { - n->left = 0; + n->left = nullptr; } if (right) { n->right = right->copy(d); n->right->setParent(n); } else { - n->right = 0; + n->right = nullptr; } return n; } @@ -119,7 +119,7 @@ void SparseArray::rotateLeft(SparseArrayNode *x) SparseArrayNode *&root = header.left; SparseArrayNode *y = x->right; x->right = y->left; - if (y->left != 0) + if (y->left != nullptr) y->left->setParent(x); y->setParent(x->parent()); if (x == root) @@ -146,7 +146,7 @@ void SparseArray::rotateRight(SparseArrayNode *x) SparseArrayNode *&root = header.left; SparseArrayNode *y = x->left; x->left = y->right; - if (y->right != 0) + if (y->right != nullptr) y->right->setParent(x); y->setParent(x->parent()); if (x == root) @@ -209,7 +209,7 @@ void SparseArray::deleteNode(SparseArrayNode *z) SparseArrayNode *y = z; SparseArrayNode *x; SparseArrayNode *x_parent; - if (y->left == 0) { + if (y->left == nullptr) { x = y->right; if (y == mostLeftNode) { if (x) @@ -217,11 +217,11 @@ void SparseArray::deleteNode(SparseArrayNode *z) else mostLeftNode = y->parent(); } - } else if (y->right == 0) { + } else if (y->right == nullptr) { x = y->left; } else { y = y->right; - while (y->left != 0) + while (y->left != nullptr) y = y->left; x = y->right; } @@ -261,7 +261,7 @@ void SparseArray::deleteNode(SparseArrayNode *z) y->size_left = 0; } if (y->color() != SparseArrayNode::Red) { - while (x != root && (x == 0 || x->color() == SparseArrayNode::Black)) { + while (x != root && (x == nullptr || x->color() == SparseArrayNode::Black)) { if (x == x_parent->left) { SparseArrayNode *w = x_parent->right; if (w->color() == SparseArrayNode::Red) { @@ -270,13 +270,13 @@ void SparseArray::deleteNode(SparseArrayNode *z) rotateLeft(x_parent); w = x_parent->right; } - if ((w->left == 0 || w->left->color() == SparseArrayNode::Black) && - (w->right == 0 || w->right->color() == SparseArrayNode::Black)) { + if ((w->left == nullptr || w->left->color() == SparseArrayNode::Black) && + (w->right == nullptr || w->right->color() == SparseArrayNode::Black)) { w->setColor(SparseArrayNode::Red); x = x_parent; x_parent = x_parent->parent(); } else { - if (w->right == 0 || w->right->color() == SparseArrayNode::Black) { + if (w->right == nullptr || w->right->color() == SparseArrayNode::Black) { if (w->left) w->left->setColor(SparseArrayNode::Black); w->setColor(SparseArrayNode::Red); @@ -298,13 +298,13 @@ void SparseArray::deleteNode(SparseArrayNode *z) rotateRight(x_parent); w = x_parent->left; } - if ((w->right == 0 || w->right->color() == SparseArrayNode::Black) && - (w->left == 0 || w->left->color() == SparseArrayNode::Black)) { + if ((w->right == nullptr || w->right->color() == SparseArrayNode::Black) && + (w->left == nullptr || w->left->color() == SparseArrayNode::Black)) { w->setColor(SparseArrayNode::Red); x = x_parent; x_parent = x_parent->parent(); } else { - if (w->left == 0 || w->left->color() == SparseArrayNode::Black) { + if (w->left == nullptr || w->left->color() == SparseArrayNode::Black) { if (w->right) w->right->setColor(SparseArrayNode::Black); w->setColor(SparseArrayNode::Red); @@ -363,8 +363,8 @@ SparseArrayNode *SparseArray::createNode(uint sl, SparseArrayNode *parent, bool Q_CHECK_PTR(node); node->p = (quintptr)parent; - node->left = 0; - node->right = 0; + node->left = nullptr; + node->right = nullptr; node->size_left = sl; node->value = UINT_MAX; ++numEntries; @@ -395,21 +395,23 @@ void SparseArray::freeTree(SparseArrayNode *root, int alignment) SparseArray::SparseArray() : numEntries(0) { + freeList = Primitive::emptyValue(UINT_MAX).asReturnedValue(); header.p = 0; - header.left = 0; - header.right = 0; + header.left = nullptr; + header.right = nullptr; mostLeftNode = &header; } SparseArray::SparseArray(const SparseArray &other) { header.p = 0; - header.right = 0; + header.right = nullptr; if (other.header.left) { header.left = other.header.left->copy(this); header.left->setParent(&header); recalcMostLeftNode(); } + freeList = other.freeList; } SparseArrayNode *SparseArray::insert(uint akey) diff --git a/src/qml/jsruntime/qv4sparsearray_p.h b/src/qml/jsruntime/qv4sparsearray_p.h index 2e4ac883f2..51869b259f 100644 --- a/src/qml/jsruntime/qv4sparsearray_p.h +++ b/src/qml/jsruntime/qv4sparsearray_p.h @@ -109,7 +109,7 @@ struct SparseArrayNode inline SparseArrayNode *SparseArrayNode::lowerBound(uint akey) { SparseArrayNode *n = this; - SparseArrayNode *last = 0; + SparseArrayNode *last = nullptr; while (n) { if (akey <= n->size_left) { last = n; @@ -126,7 +126,7 @@ inline SparseArrayNode *SparseArrayNode::lowerBound(uint akey) inline SparseArrayNode *SparseArrayNode::upperBound(uint akey) { SparseArrayNode *n = this; - SparseArrayNode *last = 0; + SparseArrayNode *last = nullptr; while (n) { if (akey < n->size_left) { last = n; @@ -150,6 +150,8 @@ struct Q_QML_EXPORT SparseArray } SparseArray(const SparseArray &other); + + ReturnedValue freeList; private: SparseArray &operator=(const SparseArray &other); @@ -221,7 +223,7 @@ inline SparseArrayNode *SparseArray::findNode(uint akey) const } } - return 0; + return nullptr; } inline uint SparseArray::pop_front() diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index b38b01c9f7..447992ebec 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -55,9 +55,16 @@ using namespace QV4; void Heap::String::markObjects(Heap::Base *that, MarkStack *markStack) { String *s = static_cast<String *>(that); - if (s->largestSubLength) { - s->left->mark(markStack); - s->right->mark(markStack); + if (s->subtype < StringType_Complex) + return; + + ComplexString *cs = static_cast<ComplexString *>(s); + if (cs->subtype == StringType_AddedString) { + cs->left->mark(markStack); + cs->right->mark(markStack); + } else { + Q_ASSERT(cs->subtype == StringType_SubString); + cs->left->mark(markStack); } } @@ -84,37 +91,45 @@ void Heap::String::init(const QString &t) text = const_cast<QString &>(t).data_ptr(); text->ref.ref(); - identifier = 0; - stringHash = UINT_MAX; - largestSubLength = 0; - len = text->size; } -void Heap::String::init(String *l, String *r) +void Heap::ComplexString::init(String *l, String *r) { Base::init(); - subtype = String::StringType_Unknown; + subtype = String::StringType_AddedString; left = l; right = r; - stringHash = UINT_MAX; - largestSubLength = qMax(l->largestSubLength, r->largestSubLength); - len = l->len + r->len; - Q_ASSERT(largestSubLength <= len); - - if (!l->largestSubLength && l->len > largestSubLength) - largestSubLength = l->len; - if (!r->largestSubLength && r->len > largestSubLength) - largestSubLength = r->len; + len = left->length() + right->length(); + if (left->subtype >= StringType_Complex) + largestSubLength = static_cast<ComplexString *>(left)->largestSubLength; + else + largestSubLength = left->length(); + if (right->subtype >= StringType_Complex) + largestSubLength = qMax(largestSubLength, static_cast<ComplexString *>(right)->largestSubLength); + else + largestSubLength = qMax(largestSubLength, right->length()); // make sure we don't get excessive depth in our strings if (len > 256 && len >= 2*largestSubLength) simplifyString(); } +void Heap::ComplexString::init(Heap::String *ref, int from, int len) +{ + Q_ASSERT(ref->length() >= from + len); + Base::init(); + + subtype = String::StringType_SubString; + + left = ref; + this->from = from; + this->len = len; +} + void Heap::String::destroy() { - if (!largestSubLength) { + if (text) { internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(-text->size) * (int)sizeof(QChar)); if (!text->ref.deref()) QStringData::deallocate(text); @@ -126,7 +141,7 @@ uint String::toUInt(bool *ok) const { *ok = true; - if (subtype() == Heap::String::StringType_Unknown) + if (subtype() >= Heap::String::StringType_Unknown) d()->createHashValue(); if (subtype() == Heap::String::StringType_ArrayIndex) return d()->stringHash; @@ -142,15 +157,15 @@ uint String::toUInt(bool *ok) const void String::makeIdentifierImpl() const { - if (d()->largestSubLength) + if (!d()->text) d()->simplifyString(); - Q_ASSERT(!d()->largestSubLength); + Q_ASSERT(d()->text); engine()->identifierTable->identifier(this); } void Heap::String::simplifyString() const { - Q_ASSERT(largestSubLength); + Q_ASSERT(!text); int l = length(); QString result(l, Qt::Uninitialized); @@ -158,9 +173,33 @@ void Heap::String::simplifyString() const append(this, ch); text = result.data_ptr(); text->ref.ref(); - identifier = 0; - largestSubLength = 0; + const ComplexString *cs = static_cast<const ComplexString *>(this); + identifier = nullptr; + cs->left = cs->right = nullptr; + internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(text->size) * (qptrdiff)sizeof(QChar)); + subtype = StringType_Unknown; +} + +bool Heap::String::startsWithUpper() const +{ + if (subtype == StringType_AddedString) + return static_cast<const Heap::ComplexString *>(this)->left->startsWithUpper(); + + const Heap::String *str = this; + int offset = 0; + if (subtype == StringType_SubString) { + const ComplexString *cs = static_cast<const Heap::ComplexString *>(this); + if (!cs->len) + return false; + // simplification here is not ideal, but hopefully not a common case. + if (cs->left->subtype >= Heap::String::StringType_Complex) + cs->left->simplifyString(); + str = cs->left; + offset = cs->from; + } + Q_ASSERT(str->subtype < Heap::String::StringType_Complex); + return str->text->size > offset && QChar::isUpper(str->text->data()[offset]); } void Heap::String::append(const String *data, QChar *ch) @@ -173,11 +212,16 @@ void Heap::String::append(const String *data, QChar *ch) const String *item = worklist.back(); worklist.pop_back(); - if (item->largestSubLength) { - worklist.push_back(item->right); - worklist.push_back(item->left); + if (item->subtype == StringType_AddedString) { + const ComplexString *cs = static_cast<const ComplexString *>(item); + worklist.push_back(cs->right); + worklist.push_back(cs->left); + } else if (item->subtype == StringType_SubString) { + const ComplexString *cs = static_cast<const ComplexString *>(item); + memcpy(ch, cs->left->toQString().constData() + cs->from, cs->len*sizeof(QChar)); + ch += cs->len; } else { - memcpy(ch, item->text->data(), item->text->size * sizeof(QChar)); + memcpy(static_cast<void *>(ch), static_cast<const void *>(item->text->data()), item->text->size * sizeof(QChar)); ch += item->text->size; } } @@ -185,9 +229,9 @@ void Heap::String::append(const String *data, QChar *ch) void Heap::String::createHashValue() const { - if (largestSubLength) + if (!text) simplifyString(); - Q_ASSERT(!largestSubLength); + Q_ASSERT(text); const QChar *ch = reinterpret_cast<const QChar *>(text->data()); const QChar *end = ch + text->size; stringHash = QV4::String::calculateHashValue(ch, end, &subtype); diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 85345aca4d..5466cc274d 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -67,35 +67,32 @@ namespace Heap { struct Q_QML_PRIVATE_EXPORT String : Base { static void markObjects(Heap::Base *that, MarkStack *markStack); enum StringType { - StringType_Unknown, StringType_Regular, - StringType_ArrayIndex + StringType_ArrayIndex, + StringType_Unknown, + StringType_AddedString, + StringType_SubString, + StringType_Complex = StringType_AddedString }; #ifndef V4_BOOTSTRAP void init(const QString &text); - void init(String *l, String *n); void destroy(); void simplifyString() const; - int length() const { - Q_ASSERT((largestSubLength && - (len == left->len + right->len)) || - len == (uint)text->size); - return len; - } + int length() const; std::size_t retainedTextSize() const { - return largestSubLength ? 0 : (std::size_t(text->size) * sizeof(QChar)); + return subtype >= StringType_Complex ? 0 : (std::size_t(text->size) * sizeof(QChar)); } void createHashValue() const; inline unsigned hashValue() const { - if (subtype == StringType_Unknown) + if (subtype >= StringType_Unknown) createHashValue(); - Q_ASSERT(!largestSubLength); + Q_ASSERT(subtype < StringType_Complex); return stringHash; } inline QString toQString() const { - if (largestSubLength) + if (subtype >= StringType_Complex) simplifyString(); QStringDataPtr ptr = { text }; text->ref.ref(); @@ -106,7 +103,7 @@ struct Q_QML_PRIVATE_EXPORT String : Base { return true; if (hashValue() != other->hashValue()) return false; - Q_ASSERT(!largestSubLength); + Q_ASSERT(subtype < StringType_Complex); if (identifier && identifier == other->identifier) return true; if (subtype == Heap::String::StringType_ArrayIndex && other->subtype == Heap::String::StringType_ArrayIndex) @@ -115,23 +112,37 @@ struct Q_QML_PRIVATE_EXPORT String : Base { return toQString() == other->toQString(); } - union { - mutable QStringData *text; - mutable String *left; - }; - union { - mutable Identifier *identifier; - mutable String *right; - }; + bool startsWithUpper() const; + + mutable QStringData *text; + mutable Identifier *identifier; mutable uint subtype; mutable uint stringHash; - mutable uint largestSubLength; - uint len; private: static void append(const String *data, QChar *ch); #endif }; -V4_ASSERT_IS_TRIVIAL(String) +Q_STATIC_ASSERT(std::is_trivial< String >::value); + +#ifndef V4_BOOTSTRAP +struct ComplexString : String { + void init(String *l, String *n); + void init(String *ref, int from, int len); + mutable String *left; + mutable String *right; + union { + mutable int largestSubLength; + int from; + }; + int len; +}; +Q_STATIC_ASSERT(std::is_trivial< ComplexString >::value); + +inline +int String::length() const { + return text ? text->size : static_cast<const ComplexString *>(this)->len; +} +#endif } @@ -167,9 +178,9 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { return d()->hashValue(); } uint asArrayIndex() const { - if (subtype() == Heap::String::StringType_Unknown) + if (subtype() >= Heap::String::StringType_Unknown) d()->createHashValue(); - Q_ASSERT(!d()->largestSubLength); + Q_ASSERT(d()->subtype < Heap::String::StringType_Complex); if (subtype() == Heap::String::StringType_ArrayIndex) return d()->stringHash; return UINT_MAX; @@ -197,12 +208,7 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { return calculateHashValue(ch, end, subtype); } - bool startsWithUpper() const { - const String::Data *l = d(); - while (l->largestSubLength) - l = l->left; - return l->text->size && QChar::isUpper(l->text->data()[0]); - } + bool startsWithUpper() const { return d()->startsWithUpper(); } Identifier *identifier() const { return d()->identifier; } @@ -216,7 +222,7 @@ public: private: static inline uint toUInt(const QChar *ch) { return ch->unicode(); } - static inline uint toUInt(const char *ch) { return *ch; } + static inline uint toUInt(const char *ch) { return static_cast<unsigned char>(*ch); } template <typename T> static inline uint toArrayIndex(const T *ch, const T *end) @@ -263,12 +269,22 @@ public: } }; +#ifndef V4_BOOTSTRAP +struct ComplexString : String { + typedef QV4::Heap::ComplexString Data; + QV4::Heap::ComplexString *d_unchecked() const { return static_cast<QV4::Heap::ComplexString *>(m()); } + QV4::Heap::ComplexString *d() const { + QV4::Heap::ComplexString *dptr = d_unchecked(); + dptr->_checkIsInitialized(); + return dptr; + } +}; + template<> inline const String *Value::as() const { - return isManaged() && m()->vtable()->isString ? static_cast<const String *>(this) : 0; + return isManaged() && m()->vtable()->isString ? static_cast<const String *>(this) : nullptr; } -#ifndef V4_BOOTSTRAP template<> inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v) { diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index efab51ec53..e5a02fdc22 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -86,13 +86,13 @@ Heap::String *Heap::StringObject::getIndex(uint index) const { QString str = string->toQString(); if (index >= (uint)str.length()) - return 0; + return nullptr; return internalClass->engine->newString(str.mid(index, 1)); } uint Heap::StringObject::length() const { - return string->len; + return string->length(); } bool StringObject::deleteIndexedProperty(Managed *m, uint index) @@ -109,7 +109,7 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index) void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) { - name->setM(0); + name->setM(nullptr); StringObject *s = static_cast<StringObject *>(m); uint slen = s->d()->string->toQString().length(); if (it->arrayIndex <= slen) { @@ -200,6 +200,15 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("trim"), method_trim); } +static Heap::String *thisAsString(ExecutionEngine *v4, const Value *thisObject) +{ + if (String *s = thisObject->stringValue()) + return s->d(); + if (const StringObject *thisString = thisObject->as<StringObject>()) + return thisString->d()->string; + return thisObject->toString(v4); +} + static QString getThisString(ExecutionEngine *v4, const Value *thisObject) { if (String *s = thisObject->stringValue()) @@ -649,11 +658,13 @@ ReturnedValue StringPrototype::method_search(const FunctionObject *b, const Valu ReturnedValue StringPrototype::method_slice(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { ExecutionEngine *v4 = b->engine(); - const QString text = getThisString(v4, thisObject); + Scope scope(v4); + ScopedString s(scope, thisAsString(v4, thisObject)); if (v4->hasException) return QV4::Encode::undefined(); + Q_ASSERT(s); - const double length = text.length(); + const double length = s->d()->length(); double start = argc ? argv[0].toInteger() : 0; double end = (argc < 2 || argv[1].isUndefined()) @@ -673,7 +684,7 @@ ReturnedValue StringPrototype::method_slice(const FunctionObject *b, const Value const int intEnd = int(end); int count = qMax(0, intEnd - intStart); - return Encode(v4->newString(text.mid(intStart, count))); + return Encode(v4->memoryManager->alloc<ComplexString>(s->d(), intStart, count)); } ReturnedValue StringPrototype::method_split(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) @@ -706,7 +717,7 @@ ReturnedValue StringPrototype::method_split(const FunctionObject *b, const Value Scoped<RegExpObject> re(scope, separatorValue); if (re) { if (re->value()->pattern->isEmpty()) { - re = (RegExpObject *)0; + re = (RegExpObject *)nullptr; separatorValue = scope.engine->newString(); } } diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 4ba31f9b6e..ea1532b8ce 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -399,10 +399,10 @@ void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor) ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); ctor->defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Primitive::fromInt32(operations[ctor->d()->type].bytesPerElement)); defineDefaultProperty(engine->id_constructor(), (o = ctor)); - defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0); - defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); - defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); - defineAccessorProperty(QStringLiteral("length"), method_get_length, 0); + defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, nullptr); + defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, nullptr); + defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, nullptr); + defineAccessorProperty(QStringLiteral("length"), method_get_length, nullptr); defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Primitive::fromInt32(operations[ctor->d()->type].bytesPerElement)); defineDefaultProperty(QStringLiteral("set"), method_set, 1); @@ -514,7 +514,7 @@ ReturnedValue TypedArrayPrototype::method_set(const FunctionObject *b, const Val RETURN_UNDEFINED(); } - char *srcCopy = 0; + char *srcCopy = nullptr; if (buffer->d() == srcBuffer->d()) { // same buffer, need to take a temporary copy, to not run into problems srcCopy = new char[srcTypedArray->d()->byteLength]; diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 52d9f23afd..97ed13cd91 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -57,6 +57,8 @@ #include "qv4global_p.h" #include <private/qv4heap_p.h> +#include <private/qnumeric_p.h> + QT_BEGIN_NAMESPACE namespace QV4 { @@ -322,6 +324,8 @@ public: return d; } QML_NEARLY_ALWAYS_INLINE void setDouble(double d) { + if (qt_is_nan(d)) + d = qt_qnan(); memcpy(&_val, &d, 8); _val ^= NaNEncodeMask; Q_ASSERT(isDouble()); @@ -422,7 +426,7 @@ public: template <typename T> const T *as() const { if (!isManaged()) - return 0; + return nullptr; Q_ASSERT(m()->vtable()); #if !defined(QT_NO_QOBJECT_CHECK) @@ -434,7 +438,7 @@ public: return static_cast<const T *>(this); vt = vt->parent; } - return 0; + return nullptr; } template <typename T> T *as() { @@ -457,6 +461,7 @@ public: uint asArrayLength(bool *ok) const; #endif + ReturnedValue *data_ptr() { return &_val; } ReturnedValue asReturnedValue() const { return _val; } static Value fromReturnedValue(ReturnedValue val) { Value v; v._val = val; return v; } @@ -469,7 +474,7 @@ public: Value &operator=(ReturnedValue v) { _val = v; return *this; } Value &operator=(Managed *m) { if (!m) { - setM(0); + setM(nullptr); } else { _val = reinterpret_cast<Value *>(m)->_val; } @@ -483,7 +488,7 @@ public: template<typename T> Value &operator=(const Scoped<T> &t); }; -V4_ASSERT_IS_TRIVIAL(Value) +Q_STATIC_ASSERT(std::is_trivial< Value >::value); inline void Value::mark(MarkStack *markStack) { @@ -792,6 +797,94 @@ inline double Value::toInteger() const } +template <size_t o> +struct HeapValue : Value { + static Q_CONSTEXPR size_t offset = o; + Heap::Base *base() { + Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base)); + Q_ASSERT(base->inUse()); + return base; + } + + void set(EngineBase *e, const Value &newVal) { + WriteBarrier::write(e, base(), data_ptr(), newVal.asReturnedValue()); + } + void set(EngineBase *e, Heap::Base *b) { + WriteBarrier::write(e, base(), data_ptr(), b->asReturnedValue()); + } +}; + +template <size_t o> +struct ValueArray { + static Q_CONSTEXPR size_t offset = o; + uint size; + uint alloc; + Value values[1]; + + Heap::Base *base() { + Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base)); + Q_ASSERT(base->inUse()); + return base; + } + + void set(EngineBase *e, uint index, Value v) { + WriteBarrier::write(e, base(), values[index].data_ptr(), v.asReturnedValue()); + } + void set(EngineBase *e, uint index, Heap::Base *b) { + WriteBarrier::write(e, base(), values[index].data_ptr(), b->asReturnedValue()); + } + inline const Value &operator[] (uint index) const { + Q_ASSERT(index < alloc); + return values[index]; + } + inline const Value *data() const { + return values; + } + + void insertData(EngineBase *e, uint index, Value v) { + for (uint i = size - 1; i > index; --i) { + values[i] = values[i - 1]; + } + set(e, index, v); + } + void removeData(EngineBase *e, uint index, int n = 1) { + Q_UNUSED(e); + for (uint i = index; i < size - n; ++i) { + values[i] = values[i + n]; + } + } + + void mark(MarkStack *markStack) { + Value *v = values; + const Value *end = v + alloc; + if (alloc > 32*1024) { + // drain from time to time to avoid overflows in the js stack + Heap::Base **currentBase = markStack->top; + while (v < end) { + v->mark(markStack); + ++v; + if (markStack->top >= currentBase + 32*1024) { + Heap::Base **oldBase = markStack->base; + markStack->base = currentBase; + markStack->drain(); + markStack->base = oldBase; + } + } + } else { + while (v < end) { + v->mark(markStack); + ++v; + } + } + } +}; + +// It's really important that the offset of values in this structure is +// constant across all architecture, otherwise JIT cross-compiled code will +// have wrong offsets between host and target. +Q_STATIC_ASSERT(offsetof(ValueArray<0>, values) == 8); + + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index 00be90b3c2..bee17e0390 100644 --- a/src/qml/jsruntime/qv4variantobject.cpp +++ b/src/qml/jsruntime/qv4variantobject.cpp @@ -113,17 +113,17 @@ void VariantPrototype::init() defineDefaultProperty(engine()->id_toString(), method_toString, 0); } -ReturnedValue VariantPrototype::method_preserve(const BuiltinFunction *, CallData *callData) +ReturnedValue VariantPrototype::method_preserve(const FunctionObject *, const Value *thisObject, const Value *, int) { - VariantObject *o = callData->thisObject.as<QV4::VariantObject>(); + const VariantObject *o = thisObject->as<QV4::VariantObject>(); if (o && o->d()->isScarce()) o->d()->addVmePropertyReference(); RETURN_UNDEFINED(); } -ReturnedValue VariantPrototype::method_destroy(const BuiltinFunction *, CallData *callData) +ReturnedValue VariantPrototype::method_destroy(const FunctionObject *, const Value *thisObject, const Value *, int) { - VariantObject *o = callData->thisObject.as<QV4::VariantObject>(); + const VariantObject *o = thisObject->as<QV4::VariantObject>(); if (o) { if (o->d()->isScarce()) o->d()->addVmePropertyReference(); @@ -132,10 +132,10 @@ ReturnedValue VariantPrototype::method_destroy(const BuiltinFunction *, CallData RETURN_UNDEFINED(); } -ReturnedValue VariantPrototype::method_toString(const BuiltinFunction *b, CallData *callData) +ReturnedValue VariantPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int) { ExecutionEngine *v4 = b->engine(); - VariantObject *o = callData->thisObject.as<QV4::VariantObject>(); + const VariantObject *o = thisObject->as<QV4::VariantObject>(); if (!o) RETURN_UNDEFINED(); QString result = o->d()->data().toString(); @@ -147,9 +147,9 @@ ReturnedValue VariantPrototype::method_toString(const BuiltinFunction *b, CallDa return Encode(v4->newString(result)); } -ReturnedValue VariantPrototype::method_valueOf(const BuiltinFunction *b, CallData *callData) +ReturnedValue VariantPrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int) { - VariantObject *o = callData->thisObject.as<QV4::VariantObject>(); + const VariantObject *o = thisObject->as<QV4::VariantObject>(); if (o) { QVariant v = o->d()->data(); switch (v.type()) { @@ -170,7 +170,7 @@ ReturnedValue VariantPrototype::method_valueOf(const BuiltinFunction *b, CallDat break; } } - return callData->thisObject.asReturnedValue(); + return thisObject->asReturnedValue(); } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h index 07b3310e91..62fa7ff9a8 100644 --- a/src/qml/jsruntime/qv4variantobject_p.h +++ b/src/qml/jsruntime/qv4variantobject_p.h @@ -108,10 +108,10 @@ public: V4_PROTOTYPE(objectPrototype) void init(); - static ReturnedValue method_preserve(const BuiltinFunction *, CallData *callData); - static ReturnedValue method_destroy(const BuiltinFunction *, CallData *callData); - static ReturnedValue method_toString(const BuiltinFunction *, CallData *callData); - static ReturnedValue method_valueOf(const BuiltinFunction *, CallData *callData); + static ReturnedValue method_preserve(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_destroy(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_valueOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); }; } diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index bc1cb8caa7..bd07473176 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -492,6 +492,7 @@ static bool compareEqualInt(Value &accumulator, Value lhs, int rhs) if (val.isDouble()) \ d = val.doubleValue(); \ else { \ + STORE_ACC(); \ d = val.toNumberImpl(); \ CHECK_EXCEPTION; \ } \ @@ -552,17 +553,17 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject, Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling QV4::Debugging::Debugger *debugger = engine->debugger(); - - const uchar *exceptionHandler = 0; + const uchar *exceptionHandler = nullptr; QV4::Value &accumulator = frame.jsFrame->accumulator; QV4::ReturnedValue acc = Encode::undefined(); #ifdef V4_ENABLE_JIT - static const bool forceInterpreter = qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER"); - if (function->jittedCode == nullptr) { - if (ExecutionEngine::canJIT() && debugger == nullptr && !forceInterpreter) + if (function->jittedCode == nullptr && debugger == nullptr) { + if (engine->canJIT(function)) QV4::JIT::BaselineJIT(function).generate(); + else + ++function->interpreterCallCount; } #endif // V4_ENABLE_JIT @@ -634,7 +635,7 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject, MOTH_BEGIN_INSTR(StoreLocal) CHECK_EXCEPTION; auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m()); - QV4::WriteBarrier::write(engine, cc, cc->locals.values + index, ACC); + QV4::WriteBarrier::write(engine, cc, cc->locals.values[index].data_ptr(), acc); MOTH_END_INSTR(StoreLocal) MOTH_BEGIN_INSTR(LoadScopedLocal) @@ -645,7 +646,7 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject, MOTH_BEGIN_INSTR(StoreScopedLocal) CHECK_EXCEPTION; auto cc = getScope(stack, scope); - QV4::WriteBarrier::write(engine, cc, cc->locals.values + index, ACC); + QV4::WriteBarrier::write(engine, cc, cc->locals.values[index].data_ptr(), acc); MOTH_END_INSTR(StoreScopedLocal) MOTH_BEGIN_INSTR(LoadRuntimeString) @@ -839,6 +840,18 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject, CHECK_EXCEPTION; MOTH_END_INSTR(CallGlobalLookup) + MOTH_BEGIN_INSTR(CallScopeObjectProperty) + STORE_IP(); + acc = Runtime::method_callQmlScopeObjectProperty(engine, stack + base, name, stack + argv, argc); + CHECK_EXCEPTION; + MOTH_END_INSTR(CallScopeObjectProperty) + + MOTH_BEGIN_INSTR(CallContextObjectProperty) + STORE_IP(); + acc = Runtime::method_callQmlContextObjectProperty(engine, stack + base, name, stack + argv, argc); + CHECK_EXCEPTION; + MOTH_END_INSTR(CallContextObjectProperty) + MOTH_BEGIN_INSTR(SetExceptionHandler) exceptionHandler = offset ? code + offset : nullptr; MOTH_END_INSTR(SetExceptionHandler) @@ -1145,14 +1158,13 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject, MOTH_BEGIN_INSTR(CmpInstanceOf) // 11.8.6, 5: rval must be an Object - const Object *rhs = Primitive::fromReturnedValue(acc).as<Object>(); - if (Q_UNLIKELY(!rhs)) { + if (Q_UNLIKELY(!Primitive::fromReturnedValue(acc).isObject())) { acc = engine->throwTypeError(); goto catchException; } // 11.8.6, 7: call "HasInstance", which we term instanceOf, and return the result. - acc = rhs->instanceOf(STACK_VALUE(lhs)); + acc = Primitive::fromReturnedValue(acc).objectValue()->instanceOf(STACK_VALUE(lhs)); CHECK_EXCEPTION; MOTH_END_INSTR(CmpInstanceOf) @@ -1294,9 +1306,9 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject, MOTH_END_INSTR(BitXor) MOTH_BEGIN_INSTR(UShr) - uint l = STACK_VALUE(lhs).toUInt32(); + VALUE_TO_INT(l, STACK_VALUE(lhs)); VALUE_TO_INT(a, ACC); - acc = Encode(l >> uint(a & 0x1f)); + acc = Encode(static_cast<uint>(l) >> uint(a & 0x1f)); MOTH_END_INSTR(UShr) MOTH_BEGIN_INSTR(Shr) @@ -1345,12 +1357,12 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject, goto functionExit; MOTH_END_INSTR(Ret) -#if QT_CONFIG(qml_debug) MOTH_BEGIN_INSTR(Debug) +#if QT_CONFIG(qml_debug) STORE_IP(); debug_slowPath(engine); - MOTH_END_INSTR(Debug) #endif // QT_CONFIG(qml_debug) + MOTH_END_INSTR(Debug) MOTH_BEGIN_INSTR(LoadQmlContext) STACK_VALUE(result) = Runtime::method_loadQmlContext(static_cast<QV4::NoThrowEngine*>(engine)); diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h index dbf9ed3550..3b7723ca7e 100644 --- a/src/qml/jsruntime/qv4vme_moth_p.h +++ b/src/qml/jsruntime/qv4vme_moth_p.h @@ -53,8 +53,6 @@ #include <private/qv4global_p.h> -QT_REQUIRE_CONFIG(qml_interpreter); - QT_BEGIN_NAMESPACE namespace QV4 { |