diff options
author | Liang Qi <liang.qi@qt.io> | 2016-10-18 08:33:26 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-10-18 08:33:26 +0200 |
commit | f04c2c40fd7ee91e5cbff2ca4df0fdc30dfbbcd5 (patch) | |
tree | 4e96d097987deb8d4d1a963e911dcbd1641a8502 /src/qml | |
parent | 0da811cdfebdae1d96c99fe681e6a776e73d2f7f (diff) | |
parent | e76ed6a2655894bd671ee7397a15f2e57cfc8d33 (diff) |
Merge remote-tracking branch 'origin/5.8' into dev
Conflicts:
src/qml/jsruntime/qv4variantobject.cpp
src/qml/types/qquickworkerscript.cpp
src/quick/scenegraph/util/qsgdefaultpainternode_p.h
tools/qmljs/qmljs.cpp
Change-Id: I876242714ec8c046238d8fd673a5ace2455b2b59
Diffstat (limited to 'src/qml')
125 files changed, 1533 insertions, 984 deletions
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri index e49f5c40a5..a63de67b4c 100644 --- a/src/qml/compiler/compiler.pri +++ b/src/qml/compiler/compiler.pri @@ -25,8 +25,6 @@ SOURCES += \ HEADERS += \ $$PWD/qqmltypecompiler_p.h \ - $$PWD/qv4isel_moth_p.h \ - $$PWD/qv4instr_moth_p.h \ $$PWD/qqmlpropertycachecreator_p.h \ $$PWD/qqmlpropertyvalidator_p.h \ $$PWD/qv4compilationunitmapper_p.h @@ -34,8 +32,6 @@ HEADERS += \ SOURCES += \ $$PWD/qqmltypecompiler.cpp \ - $$PWD/qv4instr_moth.cpp \ - $$PWD/qv4isel_moth.cpp \ $$PWD/qqmlpropertycachecreator.cpp \ $$PWD/qqmlpropertyvalidator.cpp \ $$PWD/qv4compilationunitmapper.cpp @@ -43,4 +39,14 @@ SOURCES += \ unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp +qtConfig(qml-interpreter) { + HEADERS += \ + $$PWD/qv4instr_moth_p.h \ + $$PWD/qv4isel_moth_p.h + SOURCES += \ + $$PWD/qv4instr_moth.cpp \ + $$PWD/qv4isel_moth.cpp +} + + } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index ae8677138e..fe18024070 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -71,7 +71,7 @@ QT_BEGIN_NAMESPACE // Bump this whenever the compiler data structures change in an incompatible way. -#define QV4_DATA_STRUCTURE_VERSION 0x04 +#define QV4_DATA_STRUCTURE_VERSION 0x05 class QIODevice; class QQmlPropertyCache; @@ -202,6 +202,8 @@ struct String } }; +// Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties +// for unaligned access. The ordering of the fields is also from largest to smallest. struct Function { enum Flags : unsigned int { @@ -212,6 +214,11 @@ struct Function HasCatchOrWith = 0x10 }; + // Absolute offset into file where the code for this function is located. Only used when the function + // is serialized. + LEUInt64 codeOffset; + LEUInt64 codeSize; + LEUInt32 nameIndex; LEUInt32 nFormals; LEUInt32 formalsOffset; @@ -229,11 +236,6 @@ struct Function LEUInt32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index) // Qml Extensions End - // Absolute offset into file where the code for this function is located. Only used when the function - // is serialized. - LEUInt64 codeOffset; - LEUInt64 codeSize; - // quint32 formalsIndex[nFormals] // quint32 localsIndex[nLocals] // quint32 offsetForInnerFunctions[nInnerFunctions] diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index beb43376ee..b83bcdb83b 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -50,12 +50,13 @@ // // We mean it. // - -#include <QtCore/qglobal.h> +#include <private/qv4global_p.h> #include <private/qv4value_p.h> #include <private/qv4function_p.h> #include <private/qv4runtime_p.h> +QT_REQUIRE_CONFIG(qml_interpreter); + QT_BEGIN_NAMESPACE #ifdef QT_NO_QML_DEBUGGER diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h index 9699555670..afe5fe342e 100644 --- a/src/qml/compiler/qv4isel_moth_p.h +++ b/src/qml/compiler/qv4isel_moth_p.h @@ -59,6 +59,8 @@ #include <private/qv4value_p.h> #include "qv4instr_moth_p.h" +QT_REQUIRE_CONFIG(qml_interpreter); + QT_BEGIN_NAMESPACE namespace QV4 { diff --git a/src/qml/configure.json b/src/qml/configure.json new file mode 100644 index 0000000000..d22ba3b8f0 --- /dev/null +++ b/src/qml/configure.json @@ -0,0 +1,37 @@ +{ + "module": "qml", + "depends": [ + "core-private", + "network-private" + ], + + "commandline": { + "options": { + "qml-interpreter": "boolean", + "qml-network": "boolean" + } + }, + + "features": { + "qml-interpreter": { + "label": "QML interpreter", + "purpose": "Support for the QML interpreter", + "output": [ "privateFeature" ] + }, + "qml-network": { + "label": "QML network support", + "purpose": "Provides network transparency for QML", + "output": [ "publicFeature" ] + } + }, + + "summary": [ + { + "section": "Qt QML", + "entries": [ + "qml-interpreter", + "qml-network" + ] + } + ] +} diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp index 386fb60b3a..b2c4b139ee 100644 --- a/src/qml/debugger/qqmldebug.cpp +++ b/src/qml/debugger/qqmldebug.cpp @@ -169,4 +169,22 @@ bool QQmlDebuggingEnabler::startDebugConnector(const QString &pluginName, return connector ? connector->open(configuration) : false; } +enum { HookCount = 3 }; + +// Only add to the end, and bump version if you do. +quintptr Q_QML_EXPORT qtDeclarativeHookData[] = { + // Version of this Array. Bump if you add to end. + 1, + + // Number of entries in this array. + HookCount, + + // TypeInformationVersion, an integral value, bumped whenever private + // object sizes or member offsets that are used in Qt Creator's + // data structure "pretty printing" change. + 2 +}; + +Q_STATIC_ASSERT(HookCount == sizeof(qtDeclarativeHookData) / sizeof(qtDeclarativeHookData[0])); + QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlmemoryprofiler.cpp b/src/qml/debugger/qqmlmemoryprofiler.cpp index 60f6d96eaf..53d4e7ab21 100644 --- a/src/qml/debugger/qqmlmemoryprofiler.cpp +++ b/src/qml/debugger/qqmlmemoryprofiler.cpp @@ -38,18 +38,11 @@ ****************************************************************************/ #include "qqmlmemoryprofiler_p.h" -#include <QUrl> QT_BEGIN_NAMESPACE -enum LibraryState -{ - Unloaded, - Failed, - Loaded -}; -static LibraryState state = Unloaded; +QQmlMemoryScope::LibraryState QQmlMemoryScope::state = QQmlMemoryScope::Unloaded; typedef void (qmlmemprofile_stats)(int *allocCount, int *bytesAllocated); typedef void (qmlmemprofile_clear)(); @@ -73,7 +66,7 @@ static qmlmemprofile_is_enabled *memprofile_is_enabled; extern QFunctionPointer qt_linux_find_symbol_sys(const char *symbol); #endif -static bool openLibrary() +bool QQmlMemoryScope::doOpenLibrary() { #if defined(Q_OS_LINUX) && !defined(QT_NO_LIBRARY) if (state == Unloaded) { @@ -97,28 +90,22 @@ static bool openLibrary() return state == Loaded; } -QQmlMemoryScope::QQmlMemoryScope(const QUrl &url) - : QQmlMemoryScope(url.path().toUtf8().constData()) -{ -} - -QQmlMemoryScope::QQmlMemoryScope(const char *string) : pushed(false) +void QQmlMemoryScope::init(const char *string) { - if (openLibrary() && memprofile_is_enabled()) { + if (memprofile_is_enabled()) { memprofile_push_location(string, 0); pushed = true; } } -QQmlMemoryScope::~QQmlMemoryScope() +void QQmlMemoryScope::done() { - if (pushed) - memprofile_pop_location(); + memprofile_pop_location(); } bool QQmlMemoryProfiler::isEnabled() { - if (openLibrary()) + if (QQmlMemoryScope::openLibrary()) return memprofile_is_enabled(); return false; @@ -126,31 +113,31 @@ bool QQmlMemoryProfiler::isEnabled() void QQmlMemoryProfiler::enable() { - if (openLibrary()) + if (QQmlMemoryScope::openLibrary()) memprofile_enable(); } void QQmlMemoryProfiler::disable() { - if (openLibrary()) + if (QQmlMemoryScope::openLibrary()) memprofile_disable(); } void QQmlMemoryProfiler::clear() { - if (openLibrary()) + if (QQmlMemoryScope::openLibrary()) memprofile_clear(); } void QQmlMemoryProfiler::stats(int *allocCount, int *bytesAllocated) { - if (openLibrary()) + if (QQmlMemoryScope::openLibrary()) memprofile_stats(allocCount, bytesAllocated); } void QQmlMemoryProfiler::save(const char *filename) { - if (openLibrary()) + if (QQmlMemoryScope::openLibrary()) memprofile_save(filename); } diff --git a/src/qml/debugger/qqmlmemoryprofiler_p.h b/src/qml/debugger/qqmlmemoryprofiler_p.h index 59f08704ca..fb71c999c3 100644 --- a/src/qml/debugger/qqmlmemoryprofiler_p.h +++ b/src/qml/debugger/qqmlmemoryprofiler_p.h @@ -52,6 +52,7 @@ // #include <private/qtqmlglobal_p.h> +#include <QUrl> QT_BEGIN_NAMESPACE @@ -62,16 +63,53 @@ QT_BEGIN_NAMESPACE #else -class QUrl; - class Q_QML_PRIVATE_EXPORT QQmlMemoryScope { public: - explicit QQmlMemoryScope(const QUrl &url); - explicit QQmlMemoryScope(const char *string); - ~QQmlMemoryScope(); + explicit QQmlMemoryScope(const QUrl &url) + : pushed(false) + { + if (Q_UNLIKELY(openLibrary())) + init(url.path().toUtf8().constData()); + } + + explicit QQmlMemoryScope(const char *string) + : pushed(false) + { + if (Q_UNLIKELY(openLibrary())) + init(string); + } + + ~QQmlMemoryScope() + { + if (Q_UNLIKELY(pushed)) + done(); + } + + enum LibraryState + { + Unloaded, + Failed, + Loaded + }; + + static bool openLibrary() + { + if (Q_LIKELY(state == Loaded)) + return true; + if (state == Failed) + return false; + + return doOpenLibrary(); + } private: + Q_NEVER_INLINE void init(const char *string); + Q_NEVER_INLINE void done(); + Q_NEVER_INLINE static bool doOpenLibrary(); + + static LibraryState state; + bool pushed; }; diff --git a/src/qml/doc/src/cppclasses/topic.qdoc b/src/qml/doc/src/cppclasses/topic.qdoc index ddb29fbb14..133f9bc72c 100644 --- a/src/qml/doc/src/cppclasses/topic.qdoc +++ b/src/qml/doc/src/cppclasses/topic.qdoc @@ -91,7 +91,7 @@ at run-time using a QQmlComponent. An instance of the QQmlComponent class can be created in C++ directly, or via the \l{QtQml::Qt::createComponent()} {Qt.createComponent()} function in imperative QML code. Arbitrary expressions can be calculated in C++ via the QQmlExpression class, and such expressions -can interact directly the QML context. +can interact directly with the QML context. \section2 The QQmlComponent Class @@ -106,7 +106,7 @@ how to use QQmlComponent. The QQmlExpression class provides a way for clients to evaluate JavaScript expressions from C++, using a particular QML evaluation context. This allows -clients to access QML objects by id, for example. The result of evaluation +clients to access QML objects by id, for example. The result of the evaluation is returned as a QVariant, and the conversion rules are defined by the QML engine. diff --git a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc index f5aea0b01a..ed0d049564 100644 --- a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc +++ b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc @@ -71,7 +71,7 @@ type that is supported by the QML engine. By default, the engine supports a number of Qt C++ types and can automatically convert them as appropriately when used from QML. Additionally, C++ classes that are \l{Registering C++ types with the QML type system}{registered} with -the QML type system can be can be used as data types, as can their enums if +the QML type system can be used as data types, as can their enums if appropriately registered. See \l{qtqml-cppintegration-data.html}{Data Type Conversion Between QML and C++} for further information. diff --git a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc index 4b4b25796c..03a7ddfb19 100644 --- a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc +++ b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc @@ -43,7 +43,8 @@ For example, below is a document that declares a \l Rectangle with a child \l Mo import QtQuick 2.0 Rectangle { - width: 100; height: 100 + property int side: 100 + width: side; height: side color: "red" MouseArea { @@ -87,7 +88,7 @@ For example, the root object type in the \c SquareButton.qml file above is \l Re import QtQuick 2.0 Column { - SquareButton { width: 50; height: 50 } + SquareButton { side: 50 } SquareButton { x: 50; color: "blue" } SquareButton { radius: 10 } } @@ -112,7 +113,8 @@ Rectangle { root.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1) } - width: 100; height: 100 + property int side: 100 + width: side; height: side color: "red" MouseArea { diff --git a/src/qml/doc/src/qmllanguageref/documents/scope.qdoc b/src/qml/doc/src/qmllanguageref/documents/scope.qdoc index 3e3bbaca98..eaf1747a6d 100644 --- a/src/qml/doc/src/qmllanguageref/documents/scope.qdoc +++ b/src/qml/doc/src/qmllanguageref/documents/scope.qdoc @@ -105,7 +105,7 @@ ListView { \section1 Binding Scope Object -An object which has a \l{Property Binding}{property binding} is known has the +An object which has a \l{Property Binding}{property binding} is known as the binding's \e{scope object}. In the following example, the \l Item object is the binding's scope object. diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc index 3692605c18..030eb72b5f 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc @@ -191,7 +191,7 @@ which was then imported by the client), then a property of type \section3 Assigning Values to Property Attributes -The value of a property of an object instance may specified in two separate ways: +The value of a property of an object instance may be specified in two separate ways: \list \li a value assignment on initialization \li an imperative value assignment @@ -724,7 +724,8 @@ Rectangle { signal activated(real xPosition, real yPosition) signal deactivated - width: 100; height: 100 + property int side: 100 + width: side; height: side MouseArea { anchors.fill: parent diff --git a/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc b/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc index 602b202ed4..4a022f2b0b 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc @@ -187,7 +187,8 @@ Rectangle { signal activated(real xPosition, real yPosition) - width: 100; height: 100 + property int side: 100 + width: side; height: side MouseArea { anchors.fill: parent diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 5e05f14192..e1acc33f82 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -196,8 +196,30 @@ void Assembler::generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBl generateCJumpOnCompare(NotEqual, reg, TrustedImm32(0), currentBlock, trueBlock, falseBlock); } -void Assembler::generateCJumpOnCompare(RelationalCondition cond, RegisterID left,TrustedImm32 right, - IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock, +#ifdef QV4_USE_64_BIT_VALUE_ENCODING +void Assembler::generateCJumpOnCompare(RelationalCondition cond, + RegisterID left, + TrustedImm64 right, + IR::BasicBlock *currentBlock, + IR::BasicBlock *trueBlock, + IR::BasicBlock *falseBlock) +{ + if (trueBlock == _nextBlock) { + Jump target = branch64(invert(cond), left, right); + addPatch(falseBlock, target); + } else { + Jump target = branch64(cond, left, right); + addPatch(trueBlock, target); + jumpToBlock(currentBlock, falseBlock); + } +} +#endif + +void Assembler::generateCJumpOnCompare(RelationalCondition cond, + RegisterID left, + TrustedImm32 right, + IR::BasicBlock *currentBlock, + IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock) { if (trueBlock == _nextBlock) { @@ -210,8 +232,11 @@ void Assembler::generateCJumpOnCompare(RelationalCondition cond, RegisterID left } } -void Assembler::generateCJumpOnCompare(RelationalCondition cond, RegisterID left, RegisterID right, - IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock, +void Assembler::generateCJumpOnCompare(RelationalCondition cond, + RegisterID left, + RegisterID right, + IR::BasicBlock *currentBlock, + IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock) { if (trueBlock == _nextBlock) { @@ -408,9 +433,8 @@ Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRe // not an int, check if it's a double: isNoInt.link(this); #ifdef QV4_USE_64_BIT_VALUE_ENCODING - and32(Assembler::TrustedImm32(Value::IsDouble_Mask), Assembler::ScratchRegister); - Assembler::Jump isNoDbl = branch32(Assembler::Equal, Assembler::ScratchRegister, - Assembler::TrustedImm32(0)); + rshift32(TrustedImm32(Value::IsDoubleTag_Shift), ScratchRegister); + Assembler::Jump isNoDbl = branch32(Equal, ScratchRegister, TrustedImm32(0)); #else and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister); Assembler::Jump isNoDbl = branch32(Assembler::Equal, Assembler::ScratchRegister, diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 7d4d90882a..94478cd9cd 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -319,6 +319,11 @@ public: void addPatch(DataLabelPtr patch, IR::BasicBlock *target); void generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); +#ifdef QV4_USE_64_BIT_VALUE_ENCODING + void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, TrustedImm64 right, + IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock, + IR::BasicBlock *falseBlock); +#endif void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, TrustedImm32 right, IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 12b1eb4473..515b8aea4d 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -686,7 +686,7 @@ void InstructionSelection::loadString(const QString &str, IR::Expr *target) #else _as->store32(Assembler::ReturnValueRegister, destAddr); destAddr.offset += 4; - _as->store32(Assembler::TrustedImm32(QV4::Value::Managed_Type), destAddr); + _as->store32(Assembler::TrustedImm32(QV4::Value::Managed_Type_Internal), destAddr); #endif } @@ -948,7 +948,7 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target) tag = QV4::Value::Integer_Type_Internal; break; default: - tag = QV4::Value::Undefined_Type; + tag = 31337; // bogus value Q_UNREACHABLE(); } _as->store32(Assembler::TrustedImm32(tag), addr); @@ -1092,7 +1092,7 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *targe // not an int, check if it's NOT a double: isNoInt.link(_as); #ifdef QV4_USE_64_BIT_VALUE_ENCODING - _as->and32(Assembler::TrustedImm32(Value::IsDouble_Mask), Assembler::ScratchRegister); + _as->rshift32(Assembler::TrustedImm32(Value::IsDoubleTag_Shift), Assembler::ScratchRegister); Assembler::Jump isDbl = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); #else @@ -1183,10 +1183,15 @@ void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *targe _as->load64(addr, Assembler::ScratchRegister); _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister); - // check if it's a number - _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsNumber_Shift), Assembler::ScratchRegister); - Assembler::Jump isInt = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(1)); - Assembler::Jump fallback = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); + // check if it's integer convertible + _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsIntegerConvertible_Shift), Assembler::ScratchRegister); + Assembler::Jump isIntConvertible = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(3)); + + // nope, not integer convertible, so check for a double: + _as->urshift64(Assembler::TrustedImm32( + QV4::Value::IsDoubleTag_Shift - QV4::Value::IsIntegerConvertible_Shift), + Assembler::ScratchRegister); + Assembler::Jump fallback = _as->branch32(Assembler::GreaterThan, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); // it's a double _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister); @@ -1201,7 +1206,7 @@ void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *targe generateRuntimeCall(Assembler::ReturnValueRegister, toInt, _as->loadAddress(Assembler::ScratchRegister, source)); - isInt.link(_as); + isIntConvertible.link(_as); success.link(_as); IR::Temp *targetTemp = target->asTemp(); if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { @@ -1396,7 +1401,7 @@ void InstructionSelection::visitCJump(IR::CJump *s) Address temp = _as->loadAddress(Assembler::ScratchRegister, s->cond); Address tag = temp; tag.offset += QV4::Value::tagOffset(); - Assembler::Jump booleanConversion = _as->branch32(Assembler::NotEqual, tag, Assembler::TrustedImm32(QV4::Value::Boolean_Type)); + Assembler::Jump booleanConversion = _as->branch32(Assembler::NotEqual, tag, Assembler::TrustedImm32(QV4::Value::Boolean_Type_Internal)); Address data = temp; data.offset += QV4::Value::valueOffset(); @@ -1563,7 +1568,7 @@ void InstructionSelection::visitRet(IR::Ret *s) tag = QV4::Value::Boolean_Type_Internal; break; default: - tag = QV4::Value::Undefined_Type; + tag = 31337; // bogus value Q_UNREACHABLE(); } _as->or64(Assembler::TrustedImm64(tag << 32), @@ -1744,9 +1749,9 @@ void InstructionSelection::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *tr { Q_ASSERT(binop->op == IR::OpStrictEqual || binop->op == IR::OpStrictNotEqual); - if (visitCJumpStrictNullUndefined(IR::NullType, binop, trueBlock, falseBlock)) + if (visitCJumpStrictNull(binop, trueBlock, falseBlock)) return; - if (visitCJumpStrictNullUndefined(IR::UndefinedType, binop, trueBlock, falseBlock)) + if (visitCJumpStrictUndefined(binop, trueBlock, falseBlock)) return; if (visitCJumpStrictBool(binop, trueBlock, falseBlock)) return; @@ -1762,16 +1767,14 @@ void InstructionSelection::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *tr } // Only load the non-null temp. -bool InstructionSelection::visitCJumpStrictNullUndefined(IR::Type nullOrUndef, IR::Binop *binop, - IR::BasicBlock *trueBlock, - IR::BasicBlock *falseBlock) +bool InstructionSelection::visitCJumpStrictNull(IR::Binop *binop, + IR::BasicBlock *trueBlock, + IR::BasicBlock *falseBlock) { - Q_ASSERT(nullOrUndef == IR::NullType || nullOrUndef == IR::UndefinedType); - IR::Expr *varSrc = 0; - if (binop->left->type == IR::VarType && binop->right->type == nullOrUndef) + if (binop->left->type == IR::VarType && binop->right->type == IR::NullType) varSrc = binop->left; - else if (binop->left->type == nullOrUndef && binop->right->type == IR::VarType) + else if (binop->left->type == IR::NullType && binop->right->type == IR::VarType) varSrc = binop->right; if (!varSrc) return false; @@ -1782,7 +1785,7 @@ bool InstructionSelection::visitCJumpStrictNullUndefined(IR::Type nullOrUndef, I } if (IR::Const *c = varSrc->asConst()) { - if (c->type == nullOrUndef) + if (c->type == IR::NullType) _as->jumpToBlock(_block, trueBlock); else _as->jumpToBlock(_block, falseBlock); @@ -1795,9 +1798,54 @@ bool InstructionSelection::visitCJumpStrictNullUndefined(IR::Type nullOrUndef, I _as->load32(tagAddr, tagReg); Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal - : Assembler::NotEqual; - const Assembler::TrustedImm32 tag(nullOrUndef == IR::NullType ? int(QV4::Value::Null_Type_Internal) - : int(QV4::Value::Undefined_Type)); + : Assembler::NotEqual; + const Assembler::TrustedImm32 tag(QV4::Value::Null_Type_Internal); + _as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock); + return true; +} + +bool InstructionSelection::visitCJumpStrictUndefined(IR::Binop *binop, + IR::BasicBlock *trueBlock, + IR::BasicBlock *falseBlock) +{ + IR::Expr *varSrc = 0; + if (binop->left->type == IR::VarType && binop->right->type == IR::UndefinedType) + varSrc = binop->left; + else if (binop->left->type == IR::UndefinedType && binop->right->type == IR::VarType) + varSrc = binop->right; + if (!varSrc) + return false; + + if (varSrc->asTemp() && varSrc->asTemp()->kind == IR::Temp::PhysicalRegister) { + _as->jumpToBlock(_block, falseBlock); + return true; + } + + if (IR::Const *c = varSrc->asConst()) { + if (c->type == IR::UndefinedType) + _as->jumpToBlock(_block, trueBlock); + else + _as->jumpToBlock(_block, falseBlock); + return true; + } + + Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal + : Assembler::NotEqual; + const Assembler::RegisterID tagReg = Assembler::ScratchRegister; +#ifdef QV4_USE_64_BIT_VALUE_ENCODING + Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, varSrc); + _as->load64(addr, tagReg); + const Assembler::TrustedImm64 tag(0); +#else // !QV4_USE_64_BIT_VALUE_ENCODING + Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc); + _as->load32(tagAddr, tagReg); + Assembler::Jump j = _as->branch32(Assembler::invert(cond), tagReg, Assembler::TrustedImm32(0)); + _as->addPatch(falseBlock, j); + + tagAddr.offset += 4; + _as->load32(tagAddr, tagReg); + const Assembler::TrustedImm32 tag(QV4::Value::Managed_Type_Internal); +#endif _as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock); return true; } @@ -1888,10 +1936,14 @@ bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Bin if (binop->op == IR::OpNotEqual) qSwap(trueBlock, falseBlock); Assembler::Jump isNull = _as->branch32(Assembler::Equal, tagReg, Assembler::TrustedImm32(int(QV4::Value::Null_Type_Internal))); - Assembler::Jump isUndefined = _as->branch32(Assembler::Equal, tagReg, Assembler::TrustedImm32(int(QV4::Value::Undefined_Type))); + Assembler::Jump isNotUndefinedTag = _as->branch32(Assembler::NotEqual, tagReg, Assembler::TrustedImm32(int(QV4::Value::Managed_Type_Internal))); + tagAddr.offset -= 4; + _as->load32(tagAddr, tagReg); + Assembler::Jump isNotUndefinedValue = _as->branch32(Assembler::NotEqual, tagReg, Assembler::TrustedImm32(0)); _as->addPatch(trueBlock, isNull); - _as->addPatch(trueBlock, isUndefined); - _as->jumpToBlock(_block, falseBlock); + _as->addPatch(falseBlock, isNotUndefinedTag); + _as->addPatch(falseBlock, isNotUndefinedValue); + _as->jumpToBlock(_block, trueBlock); return true; } diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index 1742ff9a36..5c693e0736 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/src/qml/jit/qv4isel_masm_p.h @@ -172,8 +172,8 @@ protected: bool visitCJumpSInt32(IR::AluOp op, IR::Expr *left, IR::Expr *right, IR::BasicBlock *iftrue, IR::BasicBlock *iffalse); void visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); - bool visitCJumpStrictNullUndefined(IR::Type nullOrUndef, IR::Binop *binop, - IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); + bool visitCJumpStrictNull(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); + bool visitCJumpStrictUndefined(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); bool visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); bool visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp index 86c7554924..ce472ce7e5 100644 --- a/src/qml/jsapi/qjsvalueiterator.cpp +++ b/src/qml/jsapi/qjsvalueiterator.cpp @@ -103,11 +103,11 @@ QJSValueIterator::QJSValueIterator(const QJSValue& object) return; QV4::Scope scope(v4); QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); - it->d()->it.flags = QV4::ObjectIterator::NoFlags; + it->d()->it().flags = QV4::ObjectIterator::NoFlags; QV4::ScopedString nm(scope); QV4::Property nextProperty; QV4::PropertyAttributes nextAttributes; - it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &nextProperty, &nextAttributes); + it->d()->it().next(nm.getRef(), &d_ptr->nextIndex, &nextProperty, &nextAttributes); d_ptr->nextName.set(v4, nm.asReturnedValue()); } @@ -157,7 +157,7 @@ bool QJSValueIterator::next() QV4::ScopedString nm(scope); QV4::Property nextProperty; QV4::PropertyAttributes nextAttributes; - it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &nextProperty, &nextAttributes); + it->d()->it().next(nm.getRef(), &d_ptr->nextIndex, &nextProperty, &nextAttributes); d_ptr->nextName.set(v4, nm.asReturnedValue()); return d_ptr->currentName.as<QV4::String>() || d_ptr->currentIndex != UINT_MAX; } @@ -231,11 +231,11 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object) QV4::ScopedObject o(scope, QJSValuePrivate::getValue(&object)); d_ptr->iterator.set(v4, v4->newForEachIteratorObject(o)); QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); - it->d()->it.flags = QV4::ObjectIterator::NoFlags; + it->d()->it().flags = QV4::ObjectIterator::NoFlags; QV4::ScopedString nm(scope); QV4::Property nextProperty; QV4::PropertyAttributes nextAttributes; - it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &nextProperty, &nextAttributes); + it->d()->it().next(nm.getRef(), &d_ptr->nextIndex, &nextProperty, &nextAttributes); d_ptr->nextName.set(v4, nm.asReturnedValue()); return *this; } diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index 63cf8779d2..4343924436 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -38,7 +38,6 @@ SOURCES += \ $$PWD/qv4sequenceobject.cpp \ $$PWD/qv4include.cpp \ $$PWD/qv4qobjectwrapper.cpp \ - $$PWD/qv4vme_moth.cpp \ $$PWD/qv4arraybuffer.cpp \ $$PWD/qv4typedarray.cpp \ $$PWD/qv4dataview.cpp @@ -87,12 +86,18 @@ HEADERS += \ $$PWD/qv4sequenceobject_p.h \ $$PWD/qv4include_p.h \ $$PWD/qv4qobjectwrapper_p.h \ - $$PWD/qv4vme_moth_p.h \ $$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 +} + } diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 156c21ca66..0dfdf25158 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -45,9 +45,10 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(ArgumentsObject); -Heap::ArgumentsObject::ArgumentsObject(QV4::CallContext *context) - : fullyCreated(false) +void Heap::ArgumentsObject::init(QV4::CallContext *context) { + Object::init(); + fullyCreated = false; this->context = context->d(); Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable()); diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 6ccfd89fd4..37a8d0a94a 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -60,12 +60,12 @@ namespace QV4 { namespace Heap { struct ArgumentsGetterFunction : FunctionObject { - inline ArgumentsGetterFunction(QV4::ExecutionContext *scope, uint index); + inline void init(QV4::ExecutionContext *scope, uint index); uint index; }; struct ArgumentsSetterFunction : FunctionObject { - inline ArgumentsSetterFunction(QV4::ExecutionContext *scope, uint index); + inline void init(QV4::ExecutionContext *scope, uint index); uint index; }; @@ -75,7 +75,7 @@ struct ArgumentsObject : Object { CalleePropertyIndex = 1, CallerPropertyIndex = 3 }; - ArgumentsObject(QV4::CallContext *context); + void init(QV4::CallContext *context); Pointer<CallContext> context; bool fullyCreated; Pointer<MemberData> mappedArguments; @@ -91,11 +91,11 @@ struct ArgumentsGetterFunction: FunctionObject static void call(const Managed *that, Scope &scope, CallData *d); }; -inline -Heap::ArgumentsGetterFunction::ArgumentsGetterFunction(QV4::ExecutionContext *scope, uint index) - : Heap::FunctionObject(scope) - , index(index) +inline void +Heap::ArgumentsGetterFunction::init(QV4::ExecutionContext *scope, uint index) { + Heap::FunctionObject::init(scope); + this->index = index; } struct ArgumentsSetterFunction: FunctionObject @@ -106,11 +106,11 @@ struct ArgumentsSetterFunction: FunctionObject static void call(const Managed *that, Scope &scope, CallData *callData); }; -inline -Heap::ArgumentsSetterFunction::ArgumentsSetterFunction(QV4::ExecutionContext *scope, uint index) - : Heap::FunctionObject(scope) - , index(index) +inline void +Heap::ArgumentsSetterFunction::init(QV4::ExecutionContext *scope, uint index) { + Heap::FunctionObject::init(scope); + this->index = index; } diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp index 34c7746684..23075aa78c 100644 --- a/src/qml/jsruntime/qv4arraybuffer.cpp +++ b/src/qml/jsruntime/qv4arraybuffer.cpp @@ -46,9 +46,9 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(ArrayBufferCtor); DEFINE_OBJECT_VTABLE(ArrayBuffer); -Heap::ArrayBufferCtor::ArrayBufferCtor(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, QStringLiteral("ArrayBuffer")) +void Heap::ArrayBufferCtor::init(QV4::ExecutionContext *scope) { + Heap::FunctionObject::init(scope, QStringLiteral("ArrayBuffer")); } void ArrayBufferCtor::construct(const Managed *m, Scope &scope, CallData *callData) @@ -94,8 +94,9 @@ ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx) } -Heap::ArrayBuffer::ArrayBuffer(size_t length) +void Heap::ArrayBuffer::init(size_t length) { + Object::init(); data = QTypedArrayData<char>::allocate(length + 1); if (!data) { data = 0; @@ -106,16 +107,18 @@ Heap::ArrayBuffer::ArrayBuffer(size_t length) memset(data->data(), 0, length + 1); } -Heap::ArrayBuffer::ArrayBuffer(const QByteArray& array) - : data(const_cast<QByteArray&>(array).data_ptr()) +void Heap::ArrayBuffer::init(const QByteArray& array) { + Object::init(); + data = const_cast<QByteArray&>(array).data_ptr(); data->ref.ref(); } -Heap::ArrayBuffer::~ArrayBuffer() +void Heap::ArrayBuffer::destroy() { if (!data->ref.deref()) QTypedArrayData<char>::deallocate(data); + Object::destroy(); } QByteArray ArrayBuffer::asByteArray() const diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h index b552cef9f1..bc56d1ea31 100644 --- a/src/qml/jsruntime/qv4arraybuffer_p.h +++ b/src/qml/jsruntime/qv4arraybuffer_p.h @@ -60,13 +60,13 @@ namespace QV4 { namespace Heap { struct ArrayBufferCtor : FunctionObject { - ArrayBufferCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; struct Q_QML_PRIVATE_EXPORT ArrayBuffer : Object { - ArrayBuffer(size_t length); - ArrayBuffer(const QByteArray& array); - ~ArrayBuffer(); + void init(size_t length); + void init(const QByteArray& array); + void destroy(); QTypedArrayData<char> *data; uint byteLength() const { return data->size; } diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index 74c83b1940..bfeb3d4699 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -46,6 +46,8 @@ using namespace QV4; +QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON + const QV4::VTable QV4::ArrayData::static_vtbl = { 0, QV4::ArrayData::IsExecutionContext, @@ -94,13 +96,15 @@ const ArrayVTable SparseArrayData::static_vtbl = SparseArrayData::length }; +QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF + Q_STATIC_ASSERT(sizeof(Heap::ArrayData) == sizeof(Heap::SimpleArrayData)); Q_STATIC_ASSERT(sizeof(Heap::ArrayData) == sizeof(Heap::SparseArrayData)); static Q_ALWAYS_INLINE void storeValue(ReturnedValue *target, uint value) { Value v; - v.setTagValue(Value::fromReturnedValue(*target).tag(), value); + v.setEmpty(value); *target = v.asReturnedValue(); } @@ -189,6 +193,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt } else { sparse->sparse = new SparseArray; lastFree = &sparse->freeList; + storeValue(lastFree, 0); for (uint i = 0; i < toCopy; ++i) { if (!sparse->arrayData[i].isEmpty()) { SparseArrayNode *n = sparse->sparse->insert(i); @@ -209,6 +214,8 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt } storeValue(lastFree, UINT_MAX); } + + Q_ASSERT(Value::fromReturnedValue(sparse->freeList).isEmpty()); // ### Could explicitly free the old data } @@ -357,12 +364,12 @@ void SparseArrayData::free(Heap::ArrayData *d, uint idx) Value *v = d->arrayData + idx; if (d->attrs && d->attrs[idx].isAccessor()) { // double slot, free both. Order is important, so we have a double slot for allocation again afterwards. - v[1].setTagValue(Value::Empty_Type, Value::fromReturnedValue(d->freeList).value()); - v[0].setTagValue(Value::Empty_Type, idx + 1); + v[1].setEmpty(Value::fromReturnedValue(d->freeList).emptyValue()); + v[0].setEmpty(idx + 1); } else { - v->setTagValue(Value::Empty_Type, Value::fromReturnedValue(d->freeList).value()); + v->setEmpty(Value::fromReturnedValue(d->freeList).emptyValue()); } - d->freeList = idx; + d->freeList = Primitive::emptyValue(idx).asReturnedValue(); if (d->attrs) d->attrs[idx].clear(); } @@ -400,9 +407,9 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot) Q_ASSERT(dd->arrayData[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value()); if (dd->arrayData[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) { // found two slots in a row - uint idx = Value::fromReturnedValue(*last).uint_32(); + uint idx = Value::fromReturnedValue(*last).emptyValue(); Value lastV = Value::fromReturnedValue(*last); - lastV.setTagValue(lastV.tag(), dd->arrayData[lastV.value() + 1].value()); + lastV.setEmpty(dd->arrayData[lastV.emptyValue() + 1].value()); *last = lastV.rawValue(); dd->attrs[idx] = Attr_Accessor; return idx; @@ -416,7 +423,8 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot) } uint idx = Value::fromReturnedValue(dd->freeList).value(); Q_ASSERT(idx != UINT_MAX); - dd->freeList = dd->arrayData[idx].uint_32(); + dd->freeList = dd->arrayData[idx].asReturnedValue(); + Q_ASSERT(Value::fromReturnedValue(dd->freeList).isEmpty()); if (dd->attrs) dd->attrs[idx] = Attr_Data; return idx; @@ -471,13 +479,14 @@ bool SparseArrayData::del(Object *o, uint index) if (isAccessor) { // free up both indices - dd->arrayData[pidx + 1].setTagValue(Value::Empty_Type, Value::fromReturnedValue(dd->freeList).value()); - dd->arrayData[pidx].setTagValue(Value::Undefined_Type, pidx + 1); + dd->arrayData[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); + dd->arrayData[pidx].setEmpty(pidx + 1); } else { - dd->arrayData[pidx].setTagValue(Value::Empty_Type, Value::fromReturnedValue(dd->freeList).value()); + Q_ASSERT(dd->type == Heap::ArrayData::Sparse); + dd->arrayData[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); } - dd->freeList = pidx; + dd->freeList = Primitive::emptyValue(pidx).asReturnedValue(); dd->sparse->erase(n); return true; } diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index d7ee4798b0..24b948f01e 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -133,7 +133,7 @@ struct ArrayData : public Base { } }; -Q_STATIC_ASSERT(std::is_trivial<ArrayData>::value); +V4_ASSERT_IS_TRIVIAL(ArrayData) struct SimpleArrayData : public ArrayData { uint mappedIndex(uint index) const { return (index + offset) % alloc; } @@ -153,10 +153,13 @@ struct SimpleArrayData : public ArrayData { return attrs ? attrs[i] : Attr_Data; } }; -Q_STATIC_ASSERT(std::is_trivial<SimpleArrayData>::value); +V4_ASSERT_IS_TRIVIAL(SimpleArrayData) struct SparseArrayData : public ArrayData { - inline ~SparseArrayData(); + void destroy() { + delete sparse; + ArrayData::destroy(); + } uint mappedIndex(uint index) const { SparseArrayNode *n = sparse->findNode(index); @@ -287,11 +290,6 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData namespace Heap { -inline SparseArrayData::~SparseArrayData() -{ - delete sparse; -} - void ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs) { Property *pd = getProperty(index); diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 4d15c6c137..659ede7552 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -49,9 +49,9 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(ArrayCtor); -Heap::ArrayCtor::ArrayCtor(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, QStringLiteral("Array")) +void Heap::ArrayCtor::init(QV4::ExecutionContext *scope) { + Heap::FunctionObject::init(scope, QStringLiteral("Array")); } void ArrayCtor::construct(const Managed *m, Scope &scope, CallData *callData) @@ -186,6 +186,10 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) { Scope scope(ctx); ScopedValue arg(scope, ctx->argument(0)); + ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + + if (!instance) + return ctx->d()->engine->newString()->asReturnedValue(); QString r4; if (arg->isUndefined()) @@ -193,8 +197,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) else r4 = arg->toQString(); - ScopedObject self(scope, ctx->thisObject()); - ScopedValue length(scope, self->get(ctx->d()->engine->id_length())); + ScopedValue length(scope, instance->get(ctx->d()->engine->id_length())); const quint32 r2 = length->isUndefined() ? 0 : length->toUInt32(); if (!r2) @@ -203,7 +206,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) QString R; // ### FIXME - if (ArrayObject *a = self->as<ArrayObject>()) { + if (ArrayObject *a = instance->as<ArrayObject>()) { ScopedValue e(scope); for (uint i = 0; i < a->getLength(); ++i) { if (i) @@ -220,7 +223,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) // crazy! // ScopedString name(scope, ctx->d()->engine->newString(QStringLiteral("0"))); - ScopedValue r6(scope, self->get(name)); + ScopedValue r6(scope, instance->get(name)); if (!r6->isNullOrUndefined()) R = r6->toQString(); @@ -229,7 +232,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) R += r4; name = Primitive::fromDouble(k).toString(scope.engine); - r12 = self->get(name); + r12 = instance->get(name); if (scope.hasException()) return Encode::undefined(); diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h index f49ed76b02..9a05bb8681 100644 --- a/src/qml/jsruntime/qv4arrayobject_p.h +++ b/src/qml/jsruntime/qv4arrayobject_p.h @@ -61,7 +61,7 @@ namespace QV4 { namespace Heap { struct ArrayCtor : FunctionObject { - ArrayCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; } diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp index 57c54e15c4..8047993266 100644 --- a/src/qml/jsruntime/qv4booleanobject.cpp +++ b/src/qml/jsruntime/qv4booleanobject.cpp @@ -45,9 +45,9 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(BooleanCtor); DEFINE_OBJECT_VTABLE(BooleanObject); -Heap::BooleanCtor::BooleanCtor(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, QStringLiteral("Boolean")) +void Heap::BooleanCtor::init(QV4::ExecutionContext *scope) { + Heap::FunctionObject::init(scope, QStringLiteral("Boolean")); } void BooleanCtor::construct(const Managed *, Scope &scope, CallData *callData) diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h index 17543e33e0..4c2f3c09e7 100644 --- a/src/qml/jsruntime/qv4booleanobject_p.h +++ b/src/qml/jsruntime/qv4booleanobject_p.h @@ -61,7 +61,7 @@ namespace QV4 { namespace Heap { struct BooleanCtor : FunctionObject { - BooleanCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; } diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index ffedf737ce..0b42288ccc 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -128,7 +128,7 @@ struct ExecutionContext : Base { bool strictMode : 8; int lineNumber; }; -Q_STATIC_ASSERT(std::is_trivial<ExecutionContext>::value); +V4_ASSERT_IS_TRIVIAL(ExecutionContext) struct CallContext : ExecutionContext { static CallContext createOnStack(ExecutionEngine *v4); @@ -145,20 +145,20 @@ struct CallContext : ExecutionContext { Value *locals; Pointer<Object> activation; }; -Q_STATIC_ASSERT(std::is_trivial<CallContext>::value); +V4_ASSERT_IS_TRIVIAL(CallContext) struct GlobalContext : ExecutionContext { void init(ExecutionEngine *engine); Pointer<Object> global; }; -Q_STATIC_ASSERT(std::is_trivial<GlobalContext>::value); +V4_ASSERT_IS_TRIVIAL(GlobalContext) struct CatchContext : ExecutionContext { void init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue); Pointer<String> exceptionVarName; Value exceptionValue; }; -Q_STATIC_ASSERT(std::is_trivial<CatchContext>::value); +V4_ASSERT_IS_TRIVIAL(CatchContext) struct WithContext : ExecutionContext { void init(ExecutionContext *outerContext, Object *with) @@ -175,7 +175,7 @@ struct WithContext : ExecutionContext { Pointer<Object> withObject; }; -Q_STATIC_ASSERT(std::is_trivial<WithContext>::value); +V4_ASSERT_IS_TRIVIAL(WithContext) struct QmlContextWrapper; diff --git a/src/qml/jsruntime/qv4context_p_p.h b/src/qml/jsruntime/qv4context_p_p.h index 0da9f678ed..ca8dc0b518 100644 --- a/src/qml/jsruntime/qv4context_p_p.h +++ b/src/qml/jsruntime/qv4context_p_p.h @@ -69,7 +69,7 @@ QObject *QmlContext::qmlScope() const QQmlContextData *QmlContext::qmlContext() const { - return d()->qml->context; + return *d()->qml->context; } void QmlContext::takeContextOwnership() { diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp index fac3d5316c..db8376272d 100644 --- a/src/qml/jsruntime/qv4dataview.cpp +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -49,9 +49,9 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(DataViewCtor); DEFINE_OBJECT_VTABLE(DataView); -Heap::DataViewCtor::DataViewCtor(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, QStringLiteral("DataView")) +void Heap::DataViewCtor::init(QV4::ExecutionContext *scope) { + Heap::FunctionObject::init(scope, QStringLiteral("DataView")); } void DataViewCtor::construct(const Managed *, Scope &scope, CallData *callData) diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h index f996a4c2f1..246124394a 100644 --- a/src/qml/jsruntime/qv4dataview_p.h +++ b/src/qml/jsruntime/qv4dataview_p.h @@ -60,11 +60,11 @@ namespace QV4 { namespace Heap { struct DataViewCtor : FunctionObject { - DataViewCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; struct DataView : Object { - DataView() {} + void init() { Object::init(); } Pointer<ArrayBuffer> buffer; uint byteLength; uint byteOffset; diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 04358fe3b5..4f3138a452 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -634,13 +634,15 @@ static double getLocalTZA() DEFINE_OBJECT_VTABLE(DateObject); -Heap::DateObject::DateObject(const QDateTime &date) +void Heap::DateObject::init(const QDateTime &date) { + Object::init(); this->date = date.isValid() ? date.toMSecsSinceEpoch() : qt_qnan(); } -Heap::DateObject::DateObject(const QTime &time) +void Heap::DateObject::init(const QTime &time) { + Object::init(); if (!time.isValid()) { date = qt_qnan(); return; @@ -668,9 +670,9 @@ QDateTime DateObject::toQDateTime() const DEFINE_OBJECT_VTABLE(DateCtor); -Heap::DateCtor::DateCtor(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, QStringLiteral("Date")) +void Heap::DateCtor::init(QV4::ExecutionContext *scope) { + Heap::FunctionObject::init(scope, QStringLiteral("Date")); } void DateCtor::construct(const Managed *, Scope &scope, CallData *callData) diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index c67acdcfa2..2d0648396e 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -63,24 +63,26 @@ namespace QV4 { namespace Heap { struct DateObject : Object { - DateObject() + void init() { + Object::init(); date = qt_qnan(); } - DateObject(const Value &date) + void init(const Value &date) { + Object::init(); this->date = date.toNumber(); } - DateObject(const QDateTime &date); - double date; + void init(const QDateTime &date); + void init(const QTime &time); - DateObject(const QTime &time); + double date; }; struct DateCtor : FunctionObject { - DateCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; } diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index fea6bbbd70..7265952f72 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -86,7 +86,9 @@ #include "qv4isel_masm_p.h" #endif // V4_ENABLE_JIT +#if QT_CONFIG(qml_interpreter) #include "qv4isel_moth_p.h" +#endif #if USE(PTHREADS) # include <pthread.h> @@ -160,6 +162,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) MemoryManager::GCBlocker gcBlocker(memoryManager); if (!factory) { +#if QT_CONFIG(qml_interpreter) bool jitDisabled = true; #ifdef V4_ENABLE_JIT @@ -180,6 +183,9 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) "very slow. Visit https://wiki.qt.io/V4 to learn about possible " "solutions for your platform."); } +#else + factory = new JIT::ISelFactory; +#endif } iselFactory.reset(factory); @@ -744,7 +750,7 @@ QQmlContextData *ExecutionEngine::callingQmlContext() const if (!ctx) return 0; - return ctx->qml->context.contextData(); + return ctx->qml->context->contextData(); } QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const @@ -920,7 +926,7 @@ ReturnedValue ExecutionEngine::throwError(const Value &value) QV4::Scope scope(this); QV4::Scoped<ErrorObject> error(scope, value); if (!!error) - exceptionStackTrace = error->d()->stackTrace; + exceptionStackTrace = *error->d()->stackTrace; else exceptionStackTrace = stackTrace(); @@ -1079,7 +1085,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int QV4::Scope scope(e); if (const QV4::VariantObject *v = value.as<QV4::VariantObject>()) - return v->d()->data; + return v->d()->data(); if (typeHint == QVariant::Bool) return QVariant(value.toBoolean()); @@ -1153,7 +1159,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return str; } if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>()) - return ld->d()->locale; + return *ld->d()->locale; if (const QV4::DateObject *d = value.as<DateObject>()) return d->toQDateTime(); if (const ArrayBuffer *d = value.as<ArrayBuffer>()) @@ -1693,7 +1699,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) return true; if (value->as<QV4::VariantObject>() && name.endsWith('*')) { int valueType = QMetaType::type(name.left(name.size()-1)); - QVariant &var = value->as<QV4::VariantObject>()->d()->data; + QVariant &var = value->as<QV4::VariantObject>()->d()->data(); if (valueType == var.userType()) { // We have T t, T* is requested, so return &t. *reinterpret_cast<void* *>(data) = var.data(); @@ -1705,7 +1711,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) while (proto) { bool canCast = false; if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) { - const QVariant &v = vo->d()->data; + const QVariant &v = vo->d()->data(); canCast = (type == v.userType()) || (valueType && (valueType == v.userType())); } else if (proto->as<QV4::QObjectWrapper>()) { @@ -1760,7 +1766,7 @@ static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const Value &value) QV4::Scoped<QV4::VariantObject> v(scope, value); if (v) { - QVariant variant = v->d()->data; + QVariant variant = v->d()->data(); int type = variant.userType(); if (type == QMetaType::QObjectStar) return *reinterpret_cast<QObject* const *>(variant.constData()); diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 3763bf2613..597ded6ae1 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -67,8 +67,11 @@ using namespace QV4; -Heap::ErrorObject::ErrorObject() +void Heap::ErrorObject::init() { + Object::init(); + stackTrace = nullptr; + Scope scope(internalClass->engine); Scoped<QV4::ErrorObject> e(scope, this); @@ -81,8 +84,9 @@ Heap::ErrorObject::ErrorObject() *propertyData(QV4::ErrorObject::Index_LineNumber) = Encode::undefined(); } -Heap::ErrorObject::ErrorObject(const Value &message, ErrorType t) +void Heap::ErrorObject::init(const Value &message, ErrorType t) { + Object::init(); errorType = t; Scope scope(internalClass->engine); @@ -91,18 +95,19 @@ Heap::ErrorObject::ErrorObject(const Value &message, ErrorType t) *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); - e->d()->stackTrace = scope.engine->stackTrace(); - if (!e->d()->stackTrace.isEmpty()) { - *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace.at(0).source); - *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace.at(0).line); + e->d()->stackTrace = new StackTrace(scope.engine->stackTrace()); + if (!e->d()->stackTrace->isEmpty()) { + *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace->at(0).source); + *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace->at(0).line); } if (!message.isUndefined()) *propertyData(QV4::ErrorObject::Index_Message) = message; } -Heap::ErrorObject::ErrorObject(const Value &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t) +void Heap::ErrorObject::init(const Value &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t) { + Object::init(); errorType = t; Scope scope(internalClass->engine); @@ -111,16 +116,16 @@ Heap::ErrorObject::ErrorObject(const Value &message, const QString &fileName, in *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); - e->d()->stackTrace = scope.engine->stackTrace(); + e->d()->stackTrace = new StackTrace(scope.engine->stackTrace()); StackFrame frame; frame.source = fileName; frame.line = line; frame.column = column; - e->d()->stackTrace.prepend(frame); + e->d()->stackTrace->prepend(frame); - if (!e->d()->stackTrace.isEmpty()) { - *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace.at(0).source); - *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace.at(0).line); + if (!e->d()->stackTrace->isEmpty()) { + *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace->at(0).source); + *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace->at(0).line); } if (!message.isUndefined()) @@ -156,10 +161,10 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx) return ctx->engine()->throwTypeError(); if (!This->d()->stack) { QString trace; - for (int i = 0; i < This->d()->stackTrace.count(); ++i) { + for (int i = 0; i < This->d()->stackTrace->count(); ++i) { if (i > 0) trace += QLatin1Char('\n'); - const StackFrame &frame = This->d()->stackTrace[i]; + const StackFrame &frame = This->d()->stackTrace->at(i); trace += frame.function + QLatin1Char('@') + frame.source; if (frame.line >= 0) trace += QLatin1Char(':') + QString::number(frame.line); @@ -181,44 +186,44 @@ DEFINE_OBJECT_VTABLE(ErrorObject); DEFINE_OBJECT_VTABLE(SyntaxErrorObject); -Heap::SyntaxErrorObject::SyntaxErrorObject(const Value &msg) - : Heap::ErrorObject(msg, SyntaxError) +void Heap::SyntaxErrorObject::init(const Value &msg) { + Heap::ErrorObject::init(msg, SyntaxError); } -Heap::SyntaxErrorObject::SyntaxErrorObject(const Value &msg, const QString &fileName, int lineNumber, int columnNumber) - : Heap::ErrorObject(msg, fileName, lineNumber, columnNumber, SyntaxError) +void Heap::SyntaxErrorObject::init(const Value &msg, const QString &fileName, int lineNumber, int columnNumber) { + Heap::ErrorObject::init(msg, fileName, lineNumber, columnNumber, SyntaxError); } -Heap::EvalErrorObject::EvalErrorObject(const Value &message) - : Heap::ErrorObject(message, EvalError) +void Heap::EvalErrorObject::init(const Value &message) { + Heap::ErrorObject::init(message, EvalError); } -Heap::RangeErrorObject::RangeErrorObject(const Value &message) - : Heap::ErrorObject(message, RangeError) +void Heap::RangeErrorObject::init(const Value &message) { + Heap::ErrorObject::init(message, RangeError); } -Heap::ReferenceErrorObject::ReferenceErrorObject(const Value &message) - : Heap::ErrorObject(message, ReferenceError) +void Heap::ReferenceErrorObject::init(const Value &message) { + Heap::ErrorObject::init(message, ReferenceError); } -Heap::ReferenceErrorObject::ReferenceErrorObject(const Value &msg, const QString &fileName, int lineNumber, int columnNumber) - : Heap::ErrorObject(msg, fileName, lineNumber, columnNumber, ReferenceError) +void Heap::ReferenceErrorObject::init(const Value &msg, const QString &fileName, int lineNumber, int columnNumber) { + Heap::ErrorObject::init(msg, fileName, lineNumber, columnNumber, ReferenceError); } -Heap::TypeErrorObject::TypeErrorObject(const Value &message) - : Heap::ErrorObject(message, TypeError) +void Heap::TypeErrorObject::init(const Value &message) { + Heap::ErrorObject::init(message, TypeError); } -Heap::URIErrorObject::URIErrorObject(const Value &message) - : Heap::ErrorObject(message, URIError) +void Heap::URIErrorObject::init(const Value &message) { + Heap::ErrorObject::init(message, URIError); } DEFINE_OBJECT_VTABLE(ErrorCtor); @@ -229,14 +234,14 @@ DEFINE_OBJECT_VTABLE(SyntaxErrorCtor); DEFINE_OBJECT_VTABLE(TypeErrorCtor); DEFINE_OBJECT_VTABLE(URIErrorCtor); -Heap::ErrorCtor::ErrorCtor(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, QStringLiteral("Error")) +void Heap::ErrorCtor::init(QV4::ExecutionContext *scope) { + Heap::FunctionObject::init(scope, QStringLiteral("Error")); } -Heap::ErrorCtor::ErrorCtor(QV4::ExecutionContext *scope, const QString &name) - : Heap::FunctionObject(scope, name) +void Heap::ErrorCtor::init(QV4::ExecutionContext *scope, const QString &name) { + Heap::FunctionObject::init(scope, name); } void ErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) @@ -250,9 +255,9 @@ void ErrorCtor::call(const Managed *that, Scope &scope, CallData *callData) static_cast<const Object *>(that)->construct(scope, callData); } -Heap::EvalErrorCtor::EvalErrorCtor(QV4::ExecutionContext *scope) - : Heap::ErrorCtor(scope, QStringLiteral("EvalError")) +void Heap::EvalErrorCtor::init(QV4::ExecutionContext *scope) { + Heap::ErrorCtor::init(scope, QStringLiteral("EvalError")); } void EvalErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) @@ -261,9 +266,9 @@ void EvalErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) scope.result = ErrorObject::create<EvalErrorObject>(scope.engine, v); } -Heap::RangeErrorCtor::RangeErrorCtor(QV4::ExecutionContext *scope) - : Heap::ErrorCtor(scope, QStringLiteral("RangeError")) +void Heap::RangeErrorCtor::init(QV4::ExecutionContext *scope) { + Heap::ErrorCtor::init(scope, QStringLiteral("RangeError")); } void RangeErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) @@ -272,9 +277,9 @@ void RangeErrorCtor::construct(const Managed *, Scope &scope, CallData *callData scope.result = ErrorObject::create<RangeErrorObject>(scope.engine, v); } -Heap::ReferenceErrorCtor::ReferenceErrorCtor(QV4::ExecutionContext *scope) - : Heap::ErrorCtor(scope, QStringLiteral("ReferenceError")) +void Heap::ReferenceErrorCtor::init(QV4::ExecutionContext *scope) { + Heap::ErrorCtor::init(scope, QStringLiteral("ReferenceError")); } void ReferenceErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) @@ -283,9 +288,9 @@ void ReferenceErrorCtor::construct(const Managed *, Scope &scope, CallData *call scope.result = ErrorObject::create<ReferenceErrorObject>(scope.engine, v); } -Heap::SyntaxErrorCtor::SyntaxErrorCtor(QV4::ExecutionContext *scope) - : Heap::ErrorCtor(scope, QStringLiteral("SyntaxError")) +void Heap::SyntaxErrorCtor::init(QV4::ExecutionContext *scope) { + Heap::ErrorCtor::init(scope, QStringLiteral("SyntaxError")); } void SyntaxErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) @@ -294,9 +299,9 @@ void SyntaxErrorCtor::construct(const Managed *, Scope &scope, CallData *callDat scope.result = ErrorObject::create<SyntaxErrorObject>(scope.engine, v); } -Heap::TypeErrorCtor::TypeErrorCtor(QV4::ExecutionContext *scope) - : Heap::ErrorCtor(scope, QStringLiteral("TypeError")) +void Heap::TypeErrorCtor::init(QV4::ExecutionContext *scope) { + Heap::ErrorCtor::init(scope, QStringLiteral("TypeError")); } void TypeErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) @@ -305,9 +310,9 @@ void TypeErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) scope.result = ErrorObject::create<TypeErrorObject>(scope.engine, v); } -Heap::URIErrorCtor::URIErrorCtor(QV4::ExecutionContext *scope) - : Heap::ErrorCtor(scope, QStringLiteral("URIError")) +void Heap::URIErrorCtor::init(QV4::ExecutionContext *scope) { + Heap::ErrorCtor::init(scope, QStringLiteral("URIError")); } void URIErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 42a3d05d9f..42a6e0b4b1 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -73,68 +73,72 @@ struct ErrorObject : Object { URIError }; - ErrorObject(); - ErrorObject(const Value &message, ErrorType t = Error); - ErrorObject(const Value &message, const QString &fileName, int line, int column, ErrorType t = Error); + void init(); + void init(const Value &message, ErrorType t = Error); + void init(const Value &message, const QString &fileName, int line, int column, ErrorType t = Error); + void destroy() { + delete stackTrace; + Object::destroy(); + } ErrorType errorType; - StackTrace stackTrace; + StackTrace *stackTrace; Pointer<String> stack; }; struct EvalErrorObject : ErrorObject { - EvalErrorObject(const Value &message); + void init(const Value &message); }; struct RangeErrorObject : ErrorObject { - RangeErrorObject(const Value &message); + void init(const Value &message); }; struct ReferenceErrorObject : ErrorObject { - ReferenceErrorObject(const Value &message); - ReferenceErrorObject(const Value &msg, const QString &fileName, int lineNumber, int columnNumber); + void init(const Value &message); + void init(const Value &msg, const QString &fileName, int lineNumber, int columnNumber); }; struct SyntaxErrorObject : ErrorObject { - SyntaxErrorObject(const Value &message); - SyntaxErrorObject(const Value &msg, const QString &fileName, int lineNumber, int columnNumber); + void init(const Value &message); + void init(const Value &msg, const QString &fileName, int lineNumber, int columnNumber); }; struct TypeErrorObject : ErrorObject { - TypeErrorObject(const Value &message); + void init(const Value &message); }; struct URIErrorObject : ErrorObject { - URIErrorObject(const Value &message); + void init(const Value &message); }; struct ErrorCtor : Heap::FunctionObject { - ErrorCtor(QV4::ExecutionContext *scope); - ErrorCtor(QV4::ExecutionContext *scope, const QString &name); + void init(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope, const QString &name); }; struct EvalErrorCtor : ErrorCtor { - EvalErrorCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; struct RangeErrorCtor : ErrorCtor { - RangeErrorCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; struct ReferenceErrorCtor : ErrorCtor { - ReferenceErrorCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; struct SyntaxErrorCtor : ErrorCtor { - SyntaxErrorCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; struct TypeErrorCtor : ErrorCtor { - TypeErrorCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; struct URIErrorCtor : ErrorCtor { - URIErrorCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; } diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 300e538d3d..caabee322a 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -73,7 +73,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, } // duplicate arguments, need some trick to store them MemoryManager *mm = engine->memoryManager; - arg = mm->alloc<String>(mm, arg->d(), engine->newString(QString(0xfffe)), true); + arg = mm->alloc<String>(mm, arg->d(), engine->newString(QString(0xfffe))); } } nFormals = compiledFunction->nFormals; @@ -105,7 +105,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr break; } // duplicate arguments, need some trick to store them - arg = engine->memoryManager->alloc<String>(engine->memoryManager, arg->d(), engine->newString(QString(0xfffe)), true); + arg = engine->memoryManager->alloc<String>(engine->memoryManager, arg->d(), engine->newString(QString(0xfffe))); } } nFormals = parameters.size(); diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index e160dd8a36..2cc58b74a6 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -68,18 +68,20 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(FunctionObject); -Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, QV4::String *name, bool createProto) - : function(Q_NULLPTR) +void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, bool createProto) { + Object::init(); + function = nullptr; this->scope = scope->d(); Scope s(scope->engine()); ScopedFunctionObject f(s, this); f->init(name, createProto); } -Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, Function *function, bool createProto) - : function(Q_NULLPTR) +void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function, bool createProto) { + Object::init(); + function = nullptr; this->scope = scope->d(); Scope s(scope->engine()); ScopedString name(s, function->name()); @@ -87,9 +89,10 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, Function *fun f->init(name, createProto); } -Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const QString &name, bool createProto) - : function(Q_NULLPTR) +void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const QString &name, bool createProto) { + Object::init(); + function = nullptr; this->scope = scope->d(); Scope s(scope->engine()); ScopedFunctionObject f(s, this); @@ -97,9 +100,10 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const QString f->init(n, createProto); } -Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto) - : function(Q_NULLPTR) +void Heap::FunctionObject::init(ExecutionContext *scope, const QString &name, bool createProto) { + Object::init(); + function = nullptr; this->scope = scope; Scope s(scope->engine); ScopedFunctionObject f(s, this); @@ -107,9 +111,10 @@ Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const QString &nam f->init(n, createProto); } -Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const ReturnedValue name) - : function(Q_NULLPTR) +void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const ReturnedValue name) { + Object::init(); + function = nullptr; this->scope = scope->d(); Scope s(scope); ScopedFunctionObject f(s, this); @@ -117,9 +122,10 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const Returne f->init(n, false); } -Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValue name) - : function(Q_NULLPTR) +void Heap::FunctionObject::init(ExecutionContext *scope, const ReturnedValue name) { + Object::init(); + function = nullptr; this->scope = scope; Scope s(scope->engine); ScopedFunctionObject f(s, this); @@ -127,19 +133,21 @@ Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValu f->init(n, false); } -Heap::FunctionObject::FunctionObject() - : function(Q_NULLPTR) +void Heap::FunctionObject::init() { + Object::init(); + function = nullptr; this->scope = internalClass->engine->rootContext()->d(); Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype); *propertyData(Index_Prototype) = Encode::undefined(); } -Heap::FunctionObject::~FunctionObject() +void Heap::FunctionObject::destroy() { if (function) function->compilationUnit->release(); + Object::destroy(); } void FunctionObject::init(String *n, bool createProto) @@ -227,7 +235,7 @@ QQmlSourceLocation FunctionObject::sourceLocation() const { if (isBinding()) { Q_ASSERT(as<const QV4::QQmlBindingFunction>()); - return static_cast<QV4::Heap::QQmlBindingFunction *>(d())->bindingLocation; + return *static_cast<QV4::Heap::QQmlBindingFunction *>(d())->bindingLocation; } QV4::Function *function = d()->function; Q_ASSERT(function); @@ -237,9 +245,9 @@ QQmlSourceLocation FunctionObject::sourceLocation() const DEFINE_OBJECT_VTABLE(FunctionCtor); -Heap::FunctionCtor::FunctionCtor(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, QStringLiteral("Function")) +void Heap::FunctionCtor::init(QV4::ExecutionContext *scope) { + Heap::FunctionObject::init(scope, QStringLiteral("Function")); } // 15.3.2 @@ -305,8 +313,9 @@ void FunctionCtor::call(const Managed *that, Scope &scope, CallData *callData) DEFINE_OBJECT_VTABLE(FunctionPrototype); -Heap::FunctionPrototype::FunctionPrototype() +void Heap::FunctionPrototype::init() { + Heap::FunctionObject::init(); } void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor) @@ -417,9 +426,9 @@ ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) DEFINE_OBJECT_VTABLE(ScriptFunction); -Heap::ScriptFunction::ScriptFunction(QV4::ExecutionContext *scope, Function *function) - : Heap::SimpleScriptFunction(scope, function, true) +void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function) { + Heap::SimpleScriptFunction::init(scope, function, true); } void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData) @@ -478,8 +487,9 @@ void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData) DEFINE_OBJECT_VTABLE(SimpleScriptFunction); -Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, Function *function, bool createProto) +void Heap::SimpleScriptFunction::init(QV4::ExecutionContext *scope, Function *function, bool createProto) { + FunctionObject::init(); this->scope = scope->d(); this->function = function; @@ -599,10 +609,10 @@ Heap::Object *SimpleScriptFunction::protoForConstructor() DEFINE_OBJECT_VTABLE(BuiltinFunction); -Heap::BuiltinFunction::BuiltinFunction(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *)) - : Heap::FunctionObject(scope, name) - , code(code) +void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *)) { + Heap::FunctionObject::init(scope, name); + this->code = code; } void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *) @@ -656,10 +666,10 @@ DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction); DEFINE_OBJECT_VTABLE(BoundFunction); -Heap::BoundFunction::BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionObject *target, - const Value &boundThis, QV4::MemberData *boundArgs) - : Heap::FunctionObject(scope, QStringLiteral("__bound function__")) +void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, + const Value &boundThis, QV4::MemberData *boundArgs) { + Heap::FunctionObject::init(scope, QStringLiteral("__bound function__")); this->target = target->d(); this->boundArgs = boundArgs ? boundArgs->d() : 0; this->boundThis = boundThis; diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 182b762606..e58b83e2c3 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -69,14 +69,14 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { Index_ProtoConstructor = 0 }; - FunctionObject(QV4::ExecutionContext *scope, QV4::String *name, bool createProto = false); - FunctionObject(QV4::ExecutionContext *scope, QV4::Function *function, bool createProto = false); - FunctionObject(QV4::ExecutionContext *scope, const QString &name = QString(), bool createProto = false); - FunctionObject(ExecutionContext *scope, const QString &name = QString(), bool createProto = false); - FunctionObject(QV4::ExecutionContext *scope, const ReturnedValue name); - FunctionObject(ExecutionContext *scope, const ReturnedValue name); - FunctionObject(); - ~FunctionObject(); + void init(QV4::ExecutionContext *scope, QV4::String *name, bool createProto = false); + void init(QV4::ExecutionContext *scope, QV4::Function *function, bool createProto = false); + void init(QV4::ExecutionContext *scope, const QString &name = QString(), bool createProto = false); + void init(ExecutionContext *scope, const QString &name = QString(), bool createProto = false); + void init(QV4::ExecutionContext *scope, const ReturnedValue name); + void init(ExecutionContext *scope, const ReturnedValue name); + void init(); + void destroy(); unsigned int formalParameterCount() { return function ? function->nFormals : 0; } unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } @@ -87,20 +87,20 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { }; struct FunctionCtor : FunctionObject { - FunctionCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; struct FunctionPrototype : FunctionObject { - FunctionPrototype(); + void init(); }; struct Q_QML_EXPORT BuiltinFunction : FunctionObject { - BuiltinFunction(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *)); + void init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *)); ReturnedValue (*code)(QV4::CallContext *); }; struct IndexedBuiltinFunction : FunctionObject { - inline IndexedBuiltinFunction(QV4::ExecutionContext *scope, uint index, ReturnedValue (*code)(QV4::CallContext *ctx, uint index)); + inline void init(QV4::ExecutionContext *scope, uint index, ReturnedValue (*code)(QV4::CallContext *ctx, uint index)); ReturnedValue (*code)(QV4::CallContext *, uint index); uint index; }; @@ -110,15 +110,15 @@ struct SimpleScriptFunction : FunctionObject { Index_Name = FunctionObject::Index_Prototype + 1, Index_Length }; - SimpleScriptFunction(QV4::ExecutionContext *scope, Function *function, bool createProto); + void init(QV4::ExecutionContext *scope, Function *function, bool createProto); }; struct ScriptFunction : SimpleScriptFunction { - ScriptFunction(QV4::ExecutionContext *scope, Function *function); + void init(QV4::ExecutionContext *scope, Function *function); }; struct BoundFunction : FunctionObject { - BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs); + void init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs); Pointer<FunctionObject> target; Value boundThis; Pointer<MemberData> boundArgs; @@ -216,12 +216,12 @@ struct IndexedBuiltinFunction: FunctionObject static void call(const Managed *that, Scope &scope, CallData *callData); }; -Heap::IndexedBuiltinFunction::IndexedBuiltinFunction(QV4::ExecutionContext *scope, uint index, - ReturnedValue (*code)(QV4::CallContext *ctx, uint index)) - : Heap::FunctionObject(scope), - code(code) - , index(index) +void Heap::IndexedBuiltinFunction::init(QV4::ExecutionContext *scope, uint index, + ReturnedValue (*code)(QV4::CallContext *ctx, uint index)) { + Heap::FunctionObject::init(scope); + this->index = index; + this->code = code; } diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index b88e271a26..feb0d90d26 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -330,9 +330,9 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok) DEFINE_OBJECT_VTABLE(EvalFunction); -Heap::EvalFunction::EvalFunction(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, scope->d()->engine->id_eval()) +void Heap::EvalFunction::init(QV4::ExecutionContext *scope) { + Heap::FunctionObject::init(scope, scope->d()->engine->id_eval()); Scope s(scope); ScopedFunctionObject f(s, this); f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(1)); diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h index 403639f8c1..e8b3a92d34 100644 --- a/src/qml/jsruntime/qv4globalobject_p.h +++ b/src/qml/jsruntime/qv4globalobject_p.h @@ -60,7 +60,7 @@ namespace QV4 { namespace Heap { struct EvalFunction : FunctionObject { - EvalFunction(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; } diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index c33d2cad11..be8057e9f5 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -41,7 +41,7 @@ #include "qv4scopedvalue_p.h" #include <QtQml/qjsengine.h> -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) #include <QtNetwork/qnetworkrequest.h> #include <QtNetwork/qnetworkreply.h> #endif @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &callback) : v4(engine), m_url(url) -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) , m_redirectCount(0), m_network(0) , m_reply(0) #endif { @@ -71,7 +71,7 @@ QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, m_resultObject.set(v4, resultValue(v4)); -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) m_network = engine->v8Engine->networkAccessManager(); QNetworkRequest request; @@ -86,7 +86,7 @@ QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4Include::~QV4Include() { -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) delete m_reply; m_reply = 0; #endif @@ -135,7 +135,7 @@ QV4::ReturnedValue QV4Include::result() #define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15 void QV4Include::finished() { -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) m_redirectCount++; if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) { @@ -184,7 +184,7 @@ void QV4Include::finished() QV4::ScopedObject resultObj(scope, m_resultObject.value()); QV4::ScopedString status(scope, v4->newString(QStringLiteral("status"))); resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(NetworkError))); -#endif //QT_NO_NETWORK +#endif // qml_network QV4::ScopedValue cb(scope, m_callbackFunction.value()); callback(cb, resultObj); @@ -211,7 +211,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) if (ctx->argc() >= 2 && ctx->args()[1].as<QV4::FunctionObject>()) callbackFunction = ctx->args()[1]; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) QUrl url(scope.engine->resolvedUrl(ctx->args()[0].toQStringNoThrow())); if (scope.engine->qmlEngine() && scope.engine->qmlEngine()->urlInterceptor()) url = scope.engine->qmlEngine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::JavaScriptFile); diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h index 1750e6a7e1..4c601a5e7b 100644 --- a/src/qml/jsruntime/qv4include_p.h +++ b/src/qml/jsruntime/qv4include_p.h @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE class QQmlEngine; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) class QNetworkAccessManager; #endif class QNetworkReply; @@ -94,7 +94,7 @@ private: QV4::ExecutionEngine *v4; QUrl m_url; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) int m_redirectCount; QNetworkAccessManager *m_network; QPointer<QNetworkReply> m_reply; diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index bac45e18c8..d17da9af0c 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -132,16 +132,20 @@ static void insertHoleIntoPropertyData(Object *object, int idx) int icSize = object->internalClass()->size; int from = qMax(idx, inlineSize); int to = from + 1; - if (from < icSize) - memmove(object->propertyData(to), object->propertyData(from), icSize - from - 1); + if (from < icSize) { + memmove(object->propertyData(to), object->propertyData(from), + (icSize - from - 1) * sizeof(Value)); + } if (from == idx) return; if (inlineSize < icSize) *object->propertyData(inlineSize) = *object->propertyData(inlineSize - 1); from = idx; to = from + 1; - if (from < inlineSize - 1) - memmove(object->propertyData(to), object->propertyData(from), inlineSize - from - 1); + if (from < inlineSize - 1) { + memmove(object->propertyData(to), object->propertyData(from), + (inlineSize - from - 1) * sizeof(Value)); + } } static void removeFromPropertyData(Object *object, int idx, bool accessor = false) diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 5b665d8836..94a6e4daa1 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -44,6 +44,7 @@ #include <qv4objectiterator_p.h> #include <qv4scopedvalue_p.h> #include <qv4runtime_p.h> +#include <qv4variantobject_p.h> #include "qv4string_p.h" #include <qstack.h> @@ -734,6 +735,10 @@ QString Stringify::Str(const QString &key, const Value &v) return std::isfinite(d) ? scope.result.toQString() : QStringLiteral("null"); } + if (const QV4::VariantObject *v = scope.result.as<QV4::VariantObject>()) { + return v->d()->data().toString(); + } + o = scope.result.asReturnedValue(); if (o) { if (!o->as<FunctionObject>()) { @@ -867,8 +872,9 @@ QString Stringify::JA(ArrayObject *a) } -Heap::JsonObject::JsonObject() +void Heap::JsonObject::init() { + Object::init(); Scope scope(internalClass->engine); ScopedObject o(scope, this); diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h index c3a3b191c0..43248a214d 100644 --- a/src/qml/jsruntime/qv4jsonobject_p.h +++ b/src/qml/jsruntime/qv4jsonobject_p.h @@ -64,7 +64,7 @@ namespace QV4 { namespace Heap { struct JsonObject : Object { - JsonObject(); + void init(); }; } diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 764a8e7f3f..1fff5a45da 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -74,7 +74,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} #define V4_MANAGED_SIZE_TEST #endif -#define V4_NEEDS_DESTROY static void destroy(QV4::Heap::Base *b) { static_cast<Data *>(b)->~Data(); } +#define V4_NEEDS_DESTROY static void destroy(QV4::Heap::Base *b) { static_cast<Data *>(b)->destroy(); } #define V4_MANAGED_ITSELF(DataClass, superClass) \ @@ -88,9 +88,10 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} QV4::Heap::DataClass *d_unchecked() const { return static_cast<QV4::Heap::DataClass *>(m()); } \ QV4::Heap::DataClass *d() const { \ QV4::Heap::DataClass *dptr = d_unchecked(); \ - if (std::is_trivial<QV4::Heap::DataClass>::value) dptr->_checkIsInitialized(); \ + dptr->_checkIsInitialized(); \ return dptr; \ - } + } \ + V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass) #define V4_MANAGED(DataClass, superClass) \ private: \ @@ -105,6 +106,18 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} #define Q_VTABLE_FUNCTION(classname, func) \ (classname::func == QV4::Managed::func ? 0 : classname::func) +// Q_VTABLE_FUNCTION triggers a bogus tautological-compare warning in GCC6+ +#if defined(Q_CC_GNU) && Q_CC_GNU >= 600 +#define QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON \ + QT_WARNING_PUSH; \ + QT_WARNING_DISABLE_GCC("-Wtautological-compare") + +#define QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF \ + ;QT_WARNING_POP +#else +#define QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON +#define QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF +#endif #define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \ { \ @@ -124,7 +137,9 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} } #define DEFINE_MANAGED_VTABLE(classname) \ -const QV4::VTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname, 0) +QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON \ +const QV4::VTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname, 0) \ +QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF struct Q_QML_PRIVATE_EXPORT Managed : Value { diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp index 9fe8224736..e03b2762cc 100644 --- a/src/qml/jsruntime/qv4mathobject.cpp +++ b/src/qml/jsruntime/qv4mathobject.cpp @@ -51,8 +51,9 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(MathObject); -Heap::MathObject::MathObject() +void Heap::MathObject::init() { + Object::init(); Scope scope(internalClass->engine); ScopedObject m(scope, this); diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h index 01e778d9ec..f6b1a4395f 100644 --- a/src/qml/jsruntime/qv4mathobject_p.h +++ b/src/qml/jsruntime/qv4mathobject_p.h @@ -59,7 +59,7 @@ namespace QV4 { namespace Heap { struct MathObject : Object { - MathObject(); + void init(); }; } diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 41da730428..969eee3619 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -66,7 +66,7 @@ struct MemberData : Base { }; Value data[1]; }; -Q_STATIC_ASSERT(std::is_trivial<MemberData>::value); +V4_ASSERT_IS_TRIVIAL(MemberData) } diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 444a4cd6f0..9b1f72bc17 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -73,9 +73,9 @@ const NumberLocale *NumberLocale::instance() return numberLocaleHolder(); } -Heap::NumberCtor::NumberCtor(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, QStringLiteral("Number")) +void Heap::NumberCtor::init(QV4::ExecutionContext *scope) { + Heap::FunctionObject::init(scope, QStringLiteral("Number")); } void NumberCtor::construct(const Managed *, Scope &scope, CallData *callData) diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h index 2416165c78..6022b3a029 100644 --- a/src/qml/jsruntime/qv4numberobject_p.h +++ b/src/qml/jsruntime/qv4numberobject_p.h @@ -61,7 +61,7 @@ namespace QV4 { namespace Heap { struct NumberCtor : FunctionObject { - NumberCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; } diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index aeb185049f..00e6d230da 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -1160,10 +1160,10 @@ void Object::initSparseArray() DEFINE_OBJECT_VTABLE(ArrayObject); -Heap::ArrayObject::ArrayObject(const QStringList &list) - : Heap::Object() +void Heap::ArrayObject::init(const QStringList &list) { - init(); + Object::init(); + commonInit(); Scope scope(internalClass->engine); ScopedObject a(scope, this); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 54ce2ea60d..d5195adaf0 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -68,7 +68,8 @@ namespace QV4 { namespace Heap { struct Object : Base { - inline Object() { Base::init(); } + void init() { Base::init(); } + void destroy() { Base::destroy(); } const Value *propertyData(uint index) const { if (index < inlineMemberSize) return reinterpret_cast<const Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; } Value *propertyData(uint index) { if (index < inlineMemberSize) return reinterpret_cast<Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; } @@ -93,9 +94,10 @@ struct Object : Base { Data *d_unchecked() const { return static_cast<Data *>(m()); } \ Data *d() const { \ Data *dptr = d_unchecked(); \ - if (std::is_trivial<Data>::value) dptr->_checkIsInitialized(); \ + dptr->_checkIsInitialized(); \ return dptr; \ - } + } \ + V4_ASSERT_IS_TRIVIAL(Data); #define V4_OBJECT2(DataClass, superClass) \ private: \ @@ -111,9 +113,10 @@ struct Object : Base { QV4::Heap::DataClass *d_unchecked() const { return static_cast<QV4::Heap::DataClass *>(m()); } \ QV4::Heap::DataClass *d() const { \ QV4::Heap::DataClass *dptr = d_unchecked(); \ - if (std::is_trivial<QV4::Heap::DataClass>::value) dptr->_checkIsInitialized(); \ + dptr->_checkIsInitialized(); \ return dptr; \ - } + } \ + V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); #define V4_INTERNALCLASS(c) \ static QV4::InternalClass *defaultInternalClass(QV4::ExecutionEngine *e) \ @@ -141,7 +144,7 @@ struct ObjectVTable void (*advanceIterator)(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); }; -#define DEFINE_OBJECT_VTABLE(classname) \ +#define DEFINE_OBJECT_VTABLE_BASE(classname) \ const QV4::ObjectVTable classname::static_vtbl = \ { \ DEFINE_MANAGED_VTABLE_INT(classname, (QT_PREPEND_NAMESPACE(QtPrivate)::is_same<classname::SuperClass, Object>::value) ? Q_NULLPTR : &classname::SuperClass::static_vtbl.vTable), \ @@ -161,7 +164,15 @@ const QV4::ObjectVTable classname::static_vtbl = \ advanceIterator \ } +#define DEFINE_OBJECT_VTABLE(classname) \ +QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON \ +DEFINE_OBJECT_VTABLE_BASE(classname) \ +QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF +#define DEFINE_OBJECT_TEMPLATE_VTABLE(classname) \ +QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON \ +template<> DEFINE_OBJECT_VTABLE_BASE(classname) \ +QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF struct Q_QML_EXPORT Object: Managed { V4_OBJECT2(Object, Object) @@ -375,18 +386,22 @@ private: namespace Heap { struct BooleanObject : Object { - BooleanObject() {} - BooleanObject(bool b) - : b(b) - {} + void init() { Object::init(); } + void init(bool b) { + Object::init(); + this->b = b; + } + bool b; }; struct NumberObject : Object { - NumberObject() {} - NumberObject(double val) - : value(val) - {} + void init() { Object::init(); } + void init(double val) { + Object::init(); + value = val; + } + double value; }; @@ -395,10 +410,15 @@ struct ArrayObject : Object { LengthPropertyIndex = 0 }; - ArrayObject() - { init(); } - ArrayObject(const QStringList &list); - void init() + void init() { + Object::init(); + commonInit(); + } + + void init(const QStringList &list); + +private: + void commonInit() { *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); } }; diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index 4354e09248..7943a13ac0 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -45,30 +45,6 @@ using namespace QV4; -ObjectIterator::ObjectIterator(ExecutionEngine *e, Value *scratch1, Value *scratch2, Object *o, uint flags) - : engine(e) - , object(scratch1) - , current(scratch2) - , arrayNode(0) - , arrayIndex(0) - , memberIndex(0) - , flags(flags) -{ - init(o); -} - -ObjectIterator::ObjectIterator(Scope &scope, const Object *o, uint flags) - : engine(scope.engine) - , object(scope.alloc(1)) - , current(scope.alloc(1)) - , arrayNode(0) - , arrayIndex(0) - , memberIndex(0) - , flags(flags) -{ - init(o); -} - void ObjectIterator::init(const Object *o) { object->setM(o ? o->m() : 0); diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index 6bef703a4d..98e94a95ea 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE namespace QV4 { -struct Q_QML_EXPORT ObjectIterator +struct Q_QML_EXPORT ObjectIteratorData { enum Flags { NoFlags = 0, @@ -72,21 +72,52 @@ struct Q_QML_EXPORT ObjectIterator uint arrayIndex; uint memberIndex; uint flags; +}; +V4_ASSERT_IS_TRIVIAL(ObjectIteratorData) + +struct Q_QML_EXPORT ObjectIterator: ObjectIteratorData +{ + ObjectIterator(ExecutionEngine *e, Value *scratch1, Value *scratch2, Object *o, uint flags) + { + engine = e; + object = scratch1; + current = scratch2; + arrayNode = nullptr; + arrayIndex = 0; + memberIndex = 0; + this->flags = flags; + init(o); + } + + ObjectIterator(Scope &scope, const Object *o, uint flags) + { + engine = scope.engine; + object = scope.alloc(1); + current = scope.alloc(1); + arrayNode = nullptr; + arrayIndex = 0; + memberIndex = 0; + this->flags = flags; + init(o); + } - ObjectIterator(ExecutionEngine *e, Value *scratch1, Value *scratch2, Object *o, uint flags); - ObjectIterator(Scope &scope, const Object *o, uint flags); - void init(const Object *o); void next(Value *name, uint *index, Property *pd, PropertyAttributes *attributes = 0); ReturnedValue nextPropertyName(Value *value); ReturnedValue nextPropertyNameAsString(Value *value); ReturnedValue nextPropertyNameAsString(); + +private: + void init(const Object *o); }; namespace Heap { struct ForEachIteratorObject : Object { - ForEachIteratorObject(QV4::Object *o); - ObjectIterator it; + void init(QV4::Object *o); + ObjectIterator &it() { return *reinterpret_cast<ObjectIterator*>(&itData); } Value workArea[2]; + +private: + ObjectIteratorData itData; }; } @@ -95,16 +126,18 @@ struct ForEachIteratorObject: Object { V4_OBJECT2(ForEachIteratorObject, Object) Q_MANAGED_TYPE(ForeachIteratorObject) - ReturnedValue nextPropertyName() { return d()->it.nextPropertyNameAsString(); } + ReturnedValue nextPropertyName() { return d()->it().nextPropertyNameAsString(); } protected: static void markObjects(Heap::Base *that, ExecutionEngine *e); }; inline -Heap::ForEachIteratorObject::ForEachIteratorObject(QV4::Object *o) - : it(internalClass->engine, workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) +void Heap::ForEachIteratorObject::init(QV4::Object *o) { + Object::init(); + it() = ObjectIterator(internalClass->engine, workArea, workArea + 1, o, + ObjectIterator::EnumerableOnly | ObjectIterator::WithProtoChain); } diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index cfd76166f2..6020c48250 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -54,9 +54,9 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(ObjectCtor); -Heap::ObjectCtor::ObjectCtor(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, QStringLiteral("Object")) +void Heap::ObjectCtor::init(QV4::ExecutionContext *scope) { + Heap::FunctionObject::init(scope, QStringLiteral("Object")); } void ObjectCtor::construct(const Managed *that, Scope &scope, CallData *callData) diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h index 47a37b196f..e3d85782d5 100644 --- a/src/qml/jsruntime/qv4objectproto_p.h +++ b/src/qml/jsruntime/qv4objectproto_p.h @@ -61,7 +61,7 @@ namespace QV4 { namespace Heap { struct ObjectCtor : FunctionObject { - ObjectCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; } diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 7ca0692804..a892194df3 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -139,7 +139,7 @@ PersistentValueStorage::Iterator &PersistentValueStorage::Iterator::operator++() while (p) { while (index < kEntriesPerPage - 1) { ++index; - if (static_cast<Page *>(p)->values[index].tag() != QV4::Value::Empty_Type) + if (!static_cast<Page *>(p)->values[index].isEmpty()) return *this; } index = -1; diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index b901d9be85..295b3413da 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -195,8 +195,9 @@ static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object } } -Heap::QObjectWrapper::QObjectWrapper(QObject *object) +void Heap::QObjectWrapper::init(QObject *object) { + Object::init(); qObj.init(object); } @@ -613,8 +614,14 @@ bool QObjectWrapper::isEqualTo(Managed *a, Managed *b) ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object) { - if (engine->jsEngine()) - QQmlData::ensurePropertyCache(engine->jsEngine(), object); + if (QJSEngine *jsEngine = engine->jsEngine()) { + if (QQmlPropertyCache *cache = QQmlData::ensurePropertyCache(jsEngine, object)) { + ReturnedValue result = QV4::Encode::null(); + void *args[] = { &result, &engine }; + if (cache->callJSFactoryMethod(object, args)) + return result; + } + } return (engine->memoryManager->allocObject<QV4::QObjectWrapper>(object))->asReturnedValue(); } @@ -978,6 +985,10 @@ void QObjectWrapper::destroyObject(bool lastCall) delete h->object(); else h->object()->deleteLater(); + } else { + // If the object is C++-owned, we still have to release the weak reference we have + // to it. + ddata->jsWrapper.clear(); } } } @@ -1678,7 +1689,7 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, in method->d()->setObject(object); if (QQmlData *ddata = QQmlData::get(object)) - method->d()->propertyCache = ddata->propertyCache; + method->d()->setPropertyCache(ddata->propertyCache); method->d()->index = index; return method.asReturnedValue(); @@ -1688,21 +1699,21 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueType { Scope valueScope(scope); Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocObject<QObjectMethod>(scope)); - method->d()->propertyCache = valueType->d()->propertyCache; + method->d()->setPropertyCache(valueType->d()->propertyCache()); method->d()->index = index; method->d()->valueTypeWrapper = valueType->d(); return method.asReturnedValue(); } -Heap::QObjectMethod::QObjectMethod(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope) +void Heap::QObjectMethod::init(QV4::ExecutionContext *scope) { + Heap::FunctionObject::init(scope); } const QMetaObject *Heap::QObjectMethod::metaObject() { - if (propertyCache) - return propertyCache->createMetaObject(); + if (propertyCache()) + return propertyCache()->createMetaObject(); return object()->metaObject(); } @@ -1774,13 +1785,13 @@ void QObjectMethod::callInternal(CallData *callData, Scope &scope) const return; } - object = QQmlObjectOrGadget(d()->propertyCache.data(), d()->valueTypeWrapper->gadgetPtr); + object = QQmlObjectOrGadget(d()->propertyCache(), d()->valueTypeWrapper->gadgetPtr); } QQmlPropertyData method; - if (d()->propertyCache) { - QQmlPropertyData *data = d()->propertyCache->method(d()->index); + if (d()->propertyCache()) { + QQmlPropertyData *data = d()->propertyCache()->method(d()->index); if (!data) { scope.result = QV4::Encode::undefined(); return; @@ -1823,7 +1834,7 @@ void QObjectMethod::callInternal(CallData *callData, Scope &scope) const if (!method.isOverload()) { scope.result = CallPrecise(object, method, v4, callData); } else { - scope.result = CallOverloaded(object, method, v4, callData, d()->propertyCache); + scope.result = CallOverloaded(object, method, v4, callData, d()->propertyCache()); } } @@ -1839,13 +1850,15 @@ void QObjectMethod::markObjects(Heap::Base *that, ExecutionEngine *e) DEFINE_OBJECT_VTABLE(QObjectMethod); -Heap::QMetaObjectWrapper::QMetaObjectWrapper(const QMetaObject *metaObject) - : metaObject(metaObject) - , constructors(nullptr) - , constructorCount(0) -{} +void Heap::QMetaObjectWrapper::init(const QMetaObject *metaObject) +{ + FunctionObject::init(); + this->metaObject = metaObject; + constructors = nullptr; + constructorCount = 0; +} -Heap::QMetaObjectWrapper::~QMetaObjectWrapper() +void Heap::QMetaObjectWrapper::destroy() { delete[] constructors; } @@ -2011,9 +2024,10 @@ DEFINE_OBJECT_VTABLE(QMetaObjectWrapper); -Heap::QmlSignalHandler::QmlSignalHandler(QObject *object, int signalIndex) - : signalIndex(signalIndex) +void Heap::QmlSignalHandler::init(QObject *object, int signalIndex) { + Object::init(); + this->signalIndex = signalIndex; setObject(object); } @@ -2021,7 +2035,7 @@ DEFINE_OBJECT_VTABLE(QmlSignalHandler); void QmlSignalHandler::initProto(ExecutionEngine *engine) { - if (engine->signalHandlerPrototype()->d()) + if (engine->signalHandlerPrototype()->d_unchecked()) return; Scope scope(engine); diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 076f304fea..8b2fd506e8 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -77,9 +77,12 @@ namespace Heap { struct QQmlValueTypeWrapper; -struct QObjectWrapper : Object { - QObjectWrapper(QObject *object); - ~QObjectWrapper() { qObj.destroy(); } +struct Q_QML_EXPORT QObjectWrapper : Object { + void init(QObject *object); + void destroy() { + qObj.destroy(); + Object::destroy(); + } QObject *object() const { return qObj.data(); } @@ -88,10 +91,22 @@ private: }; struct QObjectMethod : FunctionObject { - QObjectMethod(QV4::ExecutionContext *scope); - ~QObjectMethod() { qObj.destroy(); } - QQmlRefPointer<QQmlPropertyCache> propertyCache; - int index; + void init(QV4::ExecutionContext *scope); + void destroy() + { + setPropertyCache(nullptr); + qObj.destroy(); + FunctionObject::destroy(); + } + + QQmlPropertyCache *propertyCache() const { return _propertyCache; } + void setPropertyCache(QQmlPropertyCache *c) { + if (c) + c->addref(); + if (_propertyCache) + _propertyCache->release(); + _propertyCache = c; + } Pointer<QQmlValueTypeWrapper> valueTypeWrapper; @@ -101,6 +116,10 @@ struct QObjectMethod : FunctionObject { private: QQmlQPointer<QObject> qObj; + QQmlPropertyCache *_propertyCache; + +public: + int index; }; struct QMetaObjectWrapper : FunctionObject { @@ -108,14 +127,17 @@ struct QMetaObjectWrapper : FunctionObject { QQmlPropertyData *constructors; int constructorCount; - QMetaObjectWrapper(const QMetaObject* metaObject); - ~QMetaObjectWrapper(); + void init(const QMetaObject* metaObject); + void destroy(); void ensureConstructorsCache(); }; struct QmlSignalHandler : Object { - QmlSignalHandler(QObject *object, int signalIndex); - ~QmlSignalHandler() { qObj.destroy(); } + void init(QObject *object, int signalIndex); + void destroy() { + qObj.destroy(); + Object::destroy(); + } int signalIndex; QObject *object() const { return qObj.data(); } @@ -130,6 +152,7 @@ private: struct Q_QML_EXPORT QObjectWrapper : public Object { V4_OBJECT2(QObjectWrapper, Object) + V4_NEEDS_DESTROY enum RevisionMode { IgnoreRevision, CheckRevision }; diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index 6d6d446ca2..9e94c58432 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -62,11 +62,11 @@ uint RegExp::match(const QString &string, int start, uint *matchOffsets) WTF::String s(string); #if ENABLE(YARR_JIT) - if (!jitCode().isFallBack() && jitCode().has16BitCode()) - return uint(jitCode().execute(s.characters16(), start, s.length(), (int*)matchOffsets).start); + if (!jitCode()->isFallBack() && jitCode()->has16BitCode()) + return uint(jitCode()->execute(s.characters16(), start, s.length(), (int*)matchOffsets).start); #endif - return JSC::Yarr::interpret(byteCode().get(), s.characters16(), string.length(), start, matchOffsets); + return JSC::Yarr::interpret(byteCode(), s.characters16(), string.length(), start, matchOffsets); } Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline) @@ -90,33 +90,41 @@ Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bo return result->d(); } -Heap::RegExp::RegExp(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline) - : pattern(pattern) - , ignoreCase(ignoreCase) - , multiLine(multiline) +void Heap::RegExp::init(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline) { Base::init(); + this->pattern = new QString(pattern); + this->ignoreCase = ignoreCase; + this->multiLine = multiline; const char* error = 0; JSC::Yarr::YarrPattern yarrPattern(WTF::String(pattern), ignoreCase, multiline, &error); if (error) return; subPatternCount = yarrPattern.m_numSubpatterns; - byteCode = JSC::Yarr::byteCompile(yarrPattern, engine->bumperPointerAllocator); + OwnPtr<JSC::Yarr::BytecodePattern> p = JSC::Yarr::byteCompile(yarrPattern, engine->bumperPointerAllocator); + byteCode = p.take(); #if ENABLE(YARR_JIT) + jitCode = new JSC::Yarr::YarrCodeBlock; if (!yarrPattern.m_containsBackreferences && engine->iselFactory->jitCompileRegexps()) { JSC::JSGlobalData dummy(engine->regExpAllocator); - JSC::Yarr::jitCompile(yarrPattern, JSC::Yarr::Char16, &dummy, jitCode); + JSC::Yarr::jitCompile(yarrPattern, JSC::Yarr::Char16, &dummy, *jitCode); } #endif } -Heap::RegExp::~RegExp() +void Heap::RegExp::destroy() { if (cache) { RegExpCacheKey key(this); cache->remove(key); } +#if ENABLE(YARR_JIT) + delete jitCode; +#endif + delete byteCode; + delete pattern; + Base::destroy(); } void RegExp::markObjects(Heap::Base *that, ExecutionEngine *e) diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h index b99d717847..d3e63375a5 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -76,12 +76,13 @@ struct RegExpCacheKey; namespace Heap { struct RegExp : Base { - RegExp(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline); - ~RegExp(); - QString pattern; - OwnPtr<JSC::Yarr::BytecodePattern> byteCode; + void init(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline); + void destroy(); + + QString *pattern; + JSC::Yarr::BytecodePattern *byteCode; #if ENABLE(YARR_JIT) - JSC::Yarr::YarrCodeBlock jitCode; + JSC::Yarr::YarrCodeBlock *jitCode; #endif RegExpCache *cache; int subPatternCount; @@ -90,6 +91,7 @@ struct RegExp : Base { int captureCount() const { return subPatternCount + 1; } }; +V4_ASSERT_IS_TRIVIAL(RegExp) } @@ -99,10 +101,10 @@ struct RegExp : public Managed Q_MANAGED_TYPE(RegExp) V4_NEEDS_DESTROY - QString pattern() const { return d()->pattern; } - OwnPtr<JSC::Yarr::BytecodePattern> &byteCode() { return d()->byteCode; } + QString pattern() const { return *d()->pattern; } + JSC::Yarr::BytecodePattern *byteCode() { return d()->byteCode; } #if ENABLE(YARR_JIT) - JSC::Yarr::YarrCodeBlock jitCode() const { return d()->jitCode; } + JSC::Yarr::YarrCodeBlock *jitCode() const { return d()->jitCode; } #endif RegExpCache *cache() const { return d()->cache; } int subPatternCount() const { return d()->subPatternCount; } @@ -111,7 +113,7 @@ struct RegExp : public Managed static Heap::RegExp *create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false); - bool isValid() const { return d()->byteCode.get(); } + bool isValid() const { return d()->byteCode; } uint match(const QString& string, int start, uint *matchOffsets); @@ -142,7 +144,7 @@ struct RegExpCacheKey }; inline RegExpCacheKey::RegExpCacheKey(const RegExp::Data *re) - : pattern(re->pattern) + : pattern(*re->pattern) , ignoreCase(re->ignoreCase) , multiLine(re->multiLine) {} diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 203def0bcf..4022d98c3f 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -69,8 +69,9 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(RegExpObject); -Heap::RegExpObject::RegExpObject() +void Heap::RegExpObject::init() { + Object::init(); Scope scope(internalClass->engine); Scoped<QV4::RegExpObject> o(scope, this); o->d()->value = QV4::RegExp::create(scope.engine, QString(), false, false); @@ -78,9 +79,10 @@ Heap::RegExpObject::RegExpObject() o->initProperties(); } -Heap::RegExpObject::RegExpObject(QV4::RegExp *value, bool global) - : global(global) +void Heap::RegExpObject::init(QV4::RegExp *value, bool global) { + Object::init(); + this->global = global; this->value = value->d(); Scope scope(internalClass->engine); Scoped<QV4::RegExpObject> o(scope, this); @@ -90,8 +92,9 @@ Heap::RegExpObject::RegExpObject(QV4::RegExp *value, bool global) // Converts a QRegExp to a JS RegExp. // The conversion is not 100% exact since ECMA regexp and QRegExp // have different semantics/flags, but we try to do our best. -Heap::RegExpObject::RegExpObject(const QRegExp &re) +void Heap::RegExpObject::init(const QRegExp &re) { + Object::init(); global = false; // Convert the pattern to a ECMAScript pattern. @@ -145,7 +148,7 @@ void RegExpObject::initProperties() Q_ASSERT(value()); - QString p = value()->pattern; + QString p = *value()->pattern; if (p.isEmpty()) { p = QStringLiteral("(?:)"); } else { @@ -180,7 +183,7 @@ Value *RegExpObject::lastIndexProperty() QRegExp RegExpObject::toQRegExp() const { Qt::CaseSensitivity caseSensitivity = value()->ignoreCase ? Qt::CaseInsensitive : Qt::CaseSensitive; - return QRegExp(value()->pattern, caseSensitivity, QRegExp::RegExp2); + return QRegExp(*value()->pattern, caseSensitivity, QRegExp::RegExp2); } QString RegExpObject::toString() const @@ -217,9 +220,9 @@ uint RegExpObject::flags() const DEFINE_OBJECT_VTABLE(RegExpCtor); -Heap::RegExpCtor::RegExpCtor(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, QStringLiteral("RegExp")) +void Heap::RegExpCtor::init(QV4::ExecutionContext *scope) { + Heap::FunctionObject::init(scope, QStringLiteral("RegExp")); clearLastMatch(); } diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index 655e120c16..2c82cfdfd1 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -74,16 +74,16 @@ namespace QV4 { namespace Heap { struct RegExpObject : Object { - RegExpObject(); - RegExpObject(QV4::RegExp *value, bool global); - RegExpObject(const QRegExp &re); + void init(); + void init(QV4::RegExp *value, bool global); + void init(const QRegExp &re); Pointer<RegExp> value; bool global; }; struct RegExpCtor : FunctionObject { - RegExpCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); Value lastMatch; Pointer<String> lastInput; int lastMatchStart; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 5460304e7b..fffa6b8009 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -555,7 +555,7 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu if (!pright->stringValue()->d()->length()) return pleft->asReturnedValue(); MemoryManager *mm = engine->memoryManager; - return (mm->alloc<String>(mm, pleft->stringValue()->d(), pright->stringValue()->d(), true))->asReturnedValue(); + return (mm->alloc<String>(mm, pleft->stringValue()->d(), pright->stringValue()->d()))->asReturnedValue(); } double x = RuntimeHelpers::toNumber(pleft); double y = RuntimeHelpers::toNumber(pright); @@ -572,7 +572,7 @@ QV4::ReturnedValue Runtime::method_addString(ExecutionEngine *engine, const Valu if (!right.stringValue()->d()->length()) return left.asReturnedValue(); MemoryManager *mm = engine->memoryManager; - return (mm->alloc<String>(mm, left.stringValue()->d(), right.stringValue()->d(), true))->asReturnedValue(); + return (mm->alloc<String>(mm, left.stringValue()->d(), right.stringValue()->d()))->asReturnedValue(); } Scope scope(engine); @@ -590,7 +590,7 @@ QV4::ReturnedValue Runtime::method_addString(ExecutionEngine *engine, const Valu if (!pright->stringValue()->d()->length()) return pleft->asReturnedValue(); MemoryManager *mm = engine->memoryManager; - return (mm->alloc<String>(mm, pleft->stringValue()->d(), pright->stringValue()->d(), true))->asReturnedValue(); + return (mm->alloc<String>(mm, pleft->stringValue()->d(), pright->stringValue()->d()))->asReturnedValue(); } void Runtime::method_setProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value) @@ -1462,7 +1462,7 @@ ReturnedValue Runtime::method_getQmlScopeObjectProperty(ExecutionEngine *engine, ReturnedValue Runtime::method_getQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired) { const QmlContext &c = static_cast<const QmlContext &>(context); - return QV4::QObjectWrapper::getProperty(engine, c.d()->qml->context->contextObject, propertyIndex, captureRequired); + return QV4::QObjectWrapper::getProperty(engine, (*c.d()->qml->context)->contextObject, propertyIndex, captureRequired); } ReturnedValue Runtime::method_getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired) @@ -1480,7 +1480,7 @@ ReturnedValue Runtime::method_getQmlIdObject(ExecutionEngine *engine, const Valu { Scope scope(engine); const QmlContext &qmlContext = static_cast<const QmlContext &>(c); - QQmlContextData *context = qmlContext.d()->qml->context; + QQmlContextData *context = *qmlContext.d()->qml->context; if (!context || index >= (uint)context->idValueCount) return Encode::undefined(); @@ -1500,7 +1500,7 @@ void Runtime::method_setQmlScopeObjectProperty(ExecutionEngine *engine, const Va void Runtime::method_setQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value) { const QmlContext &c = static_cast<const QmlContext &>(context); - return QV4::QObjectWrapper::setProperty(engine, c.d()->qml->context->contextObject, propertyIndex, value); + return QV4::QObjectWrapper::setProperty(engine, (*c.d()->qml->context)->contextObject, propertyIndex, value); } void Runtime::method_setQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value) diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 44d171e087..5022d7c3bc 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -324,7 +324,7 @@ struct ScopedCallData { { int size = qMax(argc, (int)QV4::Global::ReservedArgumentCount) + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value); ptr = reinterpret_cast<CallData *>(scope.alloc(size)); - ptr->tag = QV4::Value::Integer_Type; + ptr->tag = QV4::Value::Integer_Type_Internal; ptr->argc = argc; } diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index b40307d2f0..552171256f 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -65,7 +65,7 @@ namespace QV4 { namespace Heap { struct QmlBindingWrapper : FunctionObject { - QmlBindingWrapper(QV4::QmlContext *scope, Function *f); + void init(QV4::QmlContext *scope, Function *f); }; } @@ -84,9 +84,10 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlBindingWrapper); -Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::QmlContext *scope, Function *f) - : Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false) +void Heap::QmlBindingWrapper::init(QV4::QmlContext *scope, Function *f) { + Heap::FunctionObject::init(scope, scope->d()->engine->id_eval(), /*createProto = */ false); + Q_ASSERT(scope->inUse()); function = f; diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 59086c245c..3eb7772db7 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -216,11 +216,15 @@ namespace Heap { template <typename Container> struct QQmlSequence : Object { - QQmlSequence(const Container &container); - QQmlSequence(QObject *object, int propertyIndex); - ~QQmlSequence() { object.destroy(); } + void init(const Container &container); + void init(QObject *object, int propertyIndex); + void destroy() { + delete container; + object.destroy(); + Object::destroy(); + } - mutable Container container; + mutable Container *container; QQmlQPointer<QObject> object; int propertyIndex; bool isReference; @@ -260,10 +264,10 @@ public: loadReference(); } qint32 signedIdx = static_cast<qint32>(index); - if (signedIdx < d()->container.count()) { + if (signedIdx < d()->container->count()) { if (hasProperty) *hasProperty = true; - return convertElementToValue(engine(), d()->container.at(signedIdx)); + return convertElementToValue(engine(), d()->container->at(signedIdx)); } if (hasProperty) *hasProperty = false; @@ -289,22 +293,22 @@ public: qint32 signedIdx = static_cast<qint32>(index); - int count = d()->container.count(); + int count = d()->container->count(); typename Container::value_type element = convertValueToElement<typename Container::value_type>(value); if (signedIdx == count) { - d()->container.append(element); + d()->container->append(element); } else if (signedIdx < count) { - d()->container[signedIdx] = element; + (*d()->container)[signedIdx] = element; } else { /* according to ECMA262r3 we need to insert */ /* the value at the given index, increasing length to index+1. */ - d()->container.reserve(signedIdx + 1); + d()->container->reserve(signedIdx + 1); while (signedIdx > count++) { - d()->container.append(typename Container::value_type()); + d()->container->append(typename Container::value_type()); } - d()->container.append(element); + d()->container->append(element); } if (d()->isReference) @@ -324,7 +328,7 @@ public: loadReference(); } qint32 signedIdx = static_cast<qint32>(index); - return (signedIdx < d()->container.count()) ? QV4::Attr_Data : QV4::Attr_Invalid; + return (signedIdx < d()->container->count()) ? QV4::Attr_Data : QV4::Attr_Invalid; } void containerAdvanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) @@ -340,11 +344,11 @@ public: loadReference(); } - if (it->arrayIndex < static_cast<uint>(d()->container.count())) { + if (it->arrayIndex < static_cast<uint>(d()->container->count())) { *index = it->arrayIndex; ++it->arrayIndex; *attrs = QV4::Attr_Data; - p->value = convertElementToValue(engine(), d()->container.at(*index)); + p->value = convertElementToValue(engine(), d()->container->at(*index)); return; } QV4::Object::advanceIterator(this, it, name, index, p, attrs); @@ -362,12 +366,12 @@ public: } qint32 signedIdx = static_cast<qint32>(index); - if (signedIdx >= d()->container.count()) + if (signedIdx >= d()->container->count()) return false; /* according to ECMA262r3 it should be Undefined, */ /* but we cannot, so we insert a default-value instead. */ - d()->container.replace(signedIdx, typename Container::value_type()); + d()->container->replace(signedIdx, typename Container::value_type()); if (d()->isReference) storeReference(); @@ -432,10 +436,10 @@ public: QV4::Scope scope(ctx); if (ctx->argc() == 1 && ctx->args()[0].as<FunctionObject>()) { CompareFunctor cf(ctx, ctx->args()[0]); - std::sort(d()->container.begin(), d()->container.end(), cf); + std::sort(d()->container->begin(), d()->container->end(), cf); } else { DefaultCompareFunctor cf; - std::sort(d()->container.begin(), d()->container.end(), cf); + std::sort(d()->container->begin(), d()->container->end(), cf); } if (d()->isReference) @@ -454,7 +458,7 @@ public: return QV4::Encode(0); This->loadReference(); } - return QV4::Encode(This->d()->container.count()); + return QV4::Encode(This->d()->container->count()); } static QV4::ReturnedValue method_set_length(QV4::CallContext* ctx) @@ -478,23 +482,23 @@ public: } /* Determine whether we need to modify the sequence */ qint32 newCount = static_cast<qint32>(newLength); - qint32 count = This->d()->container.count(); + qint32 count = This->d()->container->count(); if (newCount == count) { return QV4::Encode::undefined(); } else if (newCount > count) { /* according to ECMA262r3 we need to insert */ /* undefined values increasing length to newLength. */ /* We cannot, so we insert default-values instead. */ - This->d()->container.reserve(newCount); + This->d()->container->reserve(newCount); while (newCount > count++) { - This->d()->container.append(typename Container::value_type()); + This->d()->container->append(typename Container::value_type()); } } else { /* according to ECMA262r3 we need to remove */ /* elements until the sequence is the required length. */ while (newCount < count) { count--; - This->d()->container.removeAt(count); + This->d()->container->removeAt(count); } } /* write back if required. */ @@ -506,7 +510,7 @@ public: } QVariant toVariant() const - { return QVariant::fromValue<Container>(d()->container); } + { return QVariant::fromValue<Container>(*d()->container); } static QVariant toVariant(QV4::ArrayObject *array) { @@ -523,7 +527,7 @@ public: { Q_ASSERT(d()->object); Q_ASSERT(d()->isReference); - void *a[] = { &d()->container, 0 }; + void *a[] = { d()->container, 0 }; QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->propertyIndex, a); } @@ -533,7 +537,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, 0, &status, &flags }; QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a); } @@ -554,11 +558,12 @@ public: template <typename Container> -Heap::QQmlSequence<Container>::QQmlSequence(const Container &container) - : container(container) - , propertyIndex(-1) - , isReference(false) +void Heap::QQmlSequence<Container>::init(const Container &container) { + Object::init(); + this->container = new Container(container); + propertyIndex = -1; + isReference = false; object.init(); QV4::Scope scope(internalClass->engine); @@ -568,10 +573,12 @@ Heap::QQmlSequence<Container>::QQmlSequence(const Container &container) } template <typename Container> -Heap::QQmlSequence<Container>::QQmlSequence(QObject *object, int propertyIndex) - : propertyIndex(propertyIndex) - , isReference(true) +void Heap::QQmlSequence<Container>::init(QObject *object, int propertyIndex) { + Object::init(); + this->container = new Container; + this->propertyIndex = propertyIndex; + isReference = true; this->object.init(object); QV4::Scope scope(internalClass->engine); QV4::Scoped<QV4::QQmlSequence<Container> > o(scope, this); @@ -594,29 +601,21 @@ typedef QQmlSequence<QVector<bool> > QQmlBoolVectorList; template<> DEFINE_OBJECT_VTABLE(QQmlBoolVectorList); typedef QQmlSequence<QStringList> QQmlQStringList; -template<> -DEFINE_OBJECT_VTABLE(QQmlQStringList); +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQStringList); typedef QQmlSequence<QList<QString> > QQmlStringList; -template<> -DEFINE_OBJECT_VTABLE(QQmlStringList); +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringList); typedef QQmlSequence<QList<int> > QQmlIntList; -template<> -DEFINE_OBJECT_VTABLE(QQmlIntList); +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlIntList); typedef QQmlSequence<QList<QUrl> > QQmlUrlList; -template<> -DEFINE_OBJECT_VTABLE(QQmlUrlList); +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlList); typedef QQmlSequence<QModelIndexList> QQmlQModelIndexList; -template<> -DEFINE_OBJECT_VTABLE(QQmlQModelIndexList); +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexList); typedef QQmlSequence<QItemSelection> QQmlQItemSelectionRangeList; -template<> -DEFINE_OBJECT_VTABLE(QQmlQItemSelectionRangeList); +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQItemSelectionRangeList); typedef QQmlSequence<QList<bool> > QQmlBoolList; -template<> -DEFINE_OBJECT_VTABLE(QQmlBoolList); +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolList); typedef QQmlSequence<QList<qreal> > QQmlRealList; -template<> -DEFINE_OBJECT_VTABLE(QQmlRealList); +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlRealList); } diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 8bc867e2cd..3365ffe637 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -74,10 +74,10 @@ bool String::isEqualTo(Managed *t, Managed *o) } -Heap::String::String(MemoryManager *mm, const QString &t) - : mm(mm) +void Heap::String::init(MemoryManager *mm, const QString &t) { Base::init(); + this->mm = mm; subtype = String::StringType_Unknown; @@ -89,10 +89,10 @@ Heap::String::String(MemoryManager *mm, const QString &t) len = text->size; } -Heap::String::String(MemoryManager *mm, String *l, String *r, bool) // TODO: remove the dummy bool when String is trivial - : mm(mm) +void Heap::String::init(MemoryManager *mm, String *l, String *r) { Base::init(); + this->mm = mm; subtype = String::StringType_Unknown; diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index f347ea8897..23ec3349b9 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -71,11 +71,12 @@ struct Q_QML_PRIVATE_EXPORT String : Base { }; #ifndef V4_BOOTSTRAP - String(MemoryManager *mm, const QString &text); - String(MemoryManager *mm, String *l, String *n, bool dummy); - ~String() { + void init(MemoryManager *mm, const QString &text); + void init(MemoryManager *mm, String *l, String *n); + void destroy() { if (!largestSubLength && !text->ref.deref()) QStringData::deallocate(text); + Base::destroy(); } void simplifyString() const; int length() const { @@ -133,6 +134,7 @@ private: static void append(const String *data, QChar *ch); #endif }; +V4_ASSERT_IS_TRIVIAL(String) } diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 1989f747e9..829ada0c1a 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -73,15 +73,17 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(StringObject); -Heap::StringObject::StringObject() +void Heap::StringObject::init() { + Object::init(); Q_ASSERT(vtable() == QV4::StringObject::staticVTable()); string = internalClass->engine->id_empty()->d(); *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); } -Heap::StringObject::StringObject(const QV4::String *str) +void Heap::StringObject::init(const QV4::String *str) { + Object::init(); string = str->d(); *propertyData(LengthPropertyIndex) = Primitive::fromInt32(length()); } @@ -152,9 +154,9 @@ void StringObject::markObjects(Heap::Base *that, ExecutionEngine *e) DEFINE_OBJECT_VTABLE(StringCtor); -Heap::StringCtor::StringCtor(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, QStringLiteral("String")) +void Heap::StringCtor::init(QV4::ExecutionContext *scope) { + Heap::FunctionObject::init(scope, QStringLiteral("String")); } void StringCtor::construct(const Managed *m, Scope &scope, CallData *callData) @@ -715,7 +717,7 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx) Scoped<RegExpObject> re(scope, separatorValue); if (re) { - if (re->value()->pattern.isEmpty()) { + if (re->value()->pattern->isEmpty()) { re = (RegExpObject *)0; separatorValue = ctx->d()->engine->newString(); } diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index 54425b0909..b9f9d44fe8 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -65,8 +65,8 @@ struct StringObject : Object { LengthPropertyIndex = 0 }; - StringObject(); - StringObject(const QV4::String *string); + void init(); + void init(const QV4::String *string); String *string; Heap::String *getIndex(uint index) const; @@ -74,7 +74,7 @@ struct StringObject : Object { }; struct StringCtor : FunctionObject { - StringCtor(QV4::ExecutionContext *scope); + void init(QV4::ExecutionContext *scope); }; } diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index ae5ebcad1b..009c573bf8 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -202,10 +202,10 @@ const TypedArrayOperations operations[Heap::TypedArray::NTypes] = { }; -Heap::TypedArrayCtor::TypedArrayCtor(QV4::ExecutionContext *scope, TypedArray::Type t) - : Heap::FunctionObject(scope, QLatin1String(operations[t].name)) - , type(t) +void Heap::TypedArrayCtor::init(QV4::ExecutionContext *scope, TypedArray::Type t) { + Heap::FunctionObject::init(scope, QLatin1String(operations[t].name)); + type = t; } void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callData) @@ -363,10 +363,11 @@ void TypedArrayCtor::call(const Managed *that, Scope &scope, CallData *callData) construct(that, scope, callData); } -Heap::TypedArray::TypedArray(Type t) - : type(operations + t), - arrayType(t) +void Heap::TypedArray::init(Type t) { + Object::init(); + type = operations + t; + arrayType = t; } Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type t) diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index d96027b96a..0112d2e4a1 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -86,7 +86,7 @@ struct TypedArray : Object { NTypes }; - TypedArray(Type t); + void init(Type t); const TypedArrayOperations *type; Pointer<ArrayBuffer> buffer; @@ -96,13 +96,13 @@ struct TypedArray : Object { }; struct TypedArrayCtor : FunctionObject { - TypedArrayCtor(QV4::ExecutionContext *scope, TypedArray::Type t); + void init(QV4::ExecutionContext *scope, TypedArray::Type t); TypedArray::Type type; }; struct TypedArrayPrototype : Object { - inline TypedArrayPrototype(TypedArray::Type t); + inline void init(TypedArray::Type t); TypedArray::Type type; }; @@ -160,10 +160,11 @@ struct TypedArrayPrototype : Object static ReturnedValue method_subarray(CallContext *ctx); }; -inline -Heap::TypedArrayPrototype::TypedArrayPrototype(TypedArray::Type t) - : type(t) +inline void +Heap::TypedArrayPrototype::init(TypedArray::Type t) { + Object::init(); + type = t; } } // namespace QV4 diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 78cd4de9fb..4428c48d80 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -76,23 +76,85 @@ private: /* We use two different ways of encoding JS values. One for 32bit and one for 64bit systems. - In both cases, we use 8 bytes for a value and a different variant of NaN boxing. A Double NaN (actually -qNaN) - is indicated by a number that has the top 13 bits set. The other values are usually set to 0 by the - processor, and are thus free for us to store other data. We keep pointers in there for managed objects, - and encode the other types using the free space given to use by the unused bits for NaN values. This also - works for pointers on 64 bit systems, as they all currently only have 48 bits of addressable memory. - - On 32bit, we store doubles as doubles. All other values, have the high 32bits set to a value that - will make the number a NaN. The Masks below are used for encoding the other types. - - On 64 bit, we xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will get encoded - with the 13 highest bits all 0. We are now using special values for bits 14-17 to encode our values. These - can be used, as the highest valid pointer on a 64 bit system is 2^48-1. - - If they are all 0, we have a pointer to a Managed object. If bit 14 is set we have an integer. - This makes testing for pointers and numbers very fast (we have a number if any of the highest 14 bits is set). - - Bit 15-17 is then used to encode other immediates. + In both cases, we use 8 bytes for a value and a different variant of NaN boxing. A Double + NaN (actually -qNaN) is indicated by a number that has the top 13 bits set, and for a + signalling NaN it is the top 14 bits. The other values are usually set to 0 by the + processor, and are thus free for us to store other data. We keep pointers in there for + managed objects, and encode the other types using the free space given to use by the unused + bits for NaN values. This also works for pointers on 64 bit systems, as they all currently + only have 48 bits of addressable memory. (Note: we do leave the lower 49 bits available for + pointers.) + + On 32bit, we store doubles as doubles. All other values, have the high 32bits set to a value + that will make the number a NaN. The Masks below are used for encoding the other types. + + On 64 bit, we xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will + get encoded with bits 63-49 all set to 0. We then use bit 48 to distinguish between + managed/undefined (0), or Null/Int/Bool/Empty (1). So, storing a 49 bit pointer will leave + the top 15 bits 0, which is exactly the 'natural' representation of pointers. If bit 49 is + set, bit 48 indicates Empty (0) or integer-convertible (1). Then the 3 bit below that are + used to encode Null/Int/Bool. + + On both 32bit and 64bit, Undefined is encoded as a managed pointer with value 0. This is + the same as a nullptr. + + Specific bit-sequences: + 0 = always 0 + 1 = always 1 + x = stored value + a,b,c,d = specific bit values, see notes + + 64bit: + + 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 | + 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 | JS Value + ------------------------------------------------------------------------+-------------- + 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | Undefined + 00000000 0000000x xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Managed (heap pointer) + a0000000 0000bc00 00000000 00000000 00000000 00000000 00000000 00000000 | NaN/Inf + dddddddd ddddddxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double + 00000000 00000010 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole) + 00000000 00000011 10000000 00000000 00000000 00000000 00000000 00000000 | Null + 00000000 00000011 01000000 00000000 00000000 00000000 00000000 0000000x | Bool + 00000000 00000011 00100000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int + + Notes: + - a: xor-ed signbit, always 1 for NaN + - bc, xor-ed values: 11 = inf, 10 = sNaN, 01 = qNaN, 00 = boxed value + - d: xor-ed bits, where at least one bit is set, so: (val >> (64-14)) > 0 + - Undefined maps to C++ nullptr, so the "default" initialization is the same for both C++ + and JS + - Managed has the left 15 bits set to 0, so: (val >> (64-15)) == 0 + - empty, Null, Bool, and Int have the left 14 bits set to 0, and bit 49 set to 1, + so: (val >> (64-15)) == 1 + - Null, Bool, and Int have bit 48 set, indicating integer-convertible + - xoring _val with NaNEncodeMask will convert to a double in "natural" representation, where + any non double results in a NaN + + 32bit: + + 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 | + 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 | JS Value + ------------------------------------------------------------------------+-------------- + 01111111 11111100 00000000 00000000 00000000 00000000 00000000 00000000 | Undefined + 01111111 11111100 00000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Managed (heap pointer) + a1111111 1111bc00 00000000 00000000 00000000 00000000 00000000 00000000 | NaN/Inf + xddddddd ddddddxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double + 01111111 11111110 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole) + 01111111 11111111 10000000 00000000 00000000 00000000 00000000 00000000 | Null + 01111111 11111111 01000000 00000000 00000000 00000000 00000000 0000000x | Bool + 01111111 11111111 00100000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int + + Notes: + - the upper 32 bits are the tag, the lower 32 bits the value + - Undefined has a nullptr in the value, Managed has a non-nullptr stored in the value + - a: sign bit, always 0 for NaN + - b,c: 00=inf, 01 = sNaN, 10 = qNaN, 11 = boxed value + - d: stored double value, as long as not *all* of them are 1, because that's a boxed value + (see above) + - empty, Null, Bool, and Int have bit 63 set to 0, bits 62-50 set to 1 (same as undefined + and managed), and bit 49 set to 1 (where undefined and managed have it set to 0) + - Null, Bool, and Int have bit 48 set, indicating integer-convertible */ quint64 _val; @@ -140,7 +202,7 @@ public: { quint32 v; memcpy(&v, &b, 4); - setTagValue(Managed_Type, v); + setTagValue(Managed_Type_Internal, v); } #endif @@ -156,12 +218,43 @@ public: Q_ALWAYS_INLINE void setEmpty() { - setTagValue(Empty_Type, value()); + setTagValue(Empty_Type_Internal, value()); } Q_ALWAYS_INLINE void setEmpty(int i) { - setTagValue(Empty_Type, quint32(i)); + setTagValue(Empty_Type_Internal, quint32(i)); + } + + Q_ALWAYS_INLINE void setEmpty(quint32 i) + { + setTagValue(Empty_Type_Internal, i); + } + + Q_ALWAYS_INLINE quint32 emptyValue() + { + Q_ASSERT(isEmpty()); + return quint32(value()); + } + + enum Type { + Undefined_Type, + Managed_Type, + Empty_Type, + Integer_Type, + Boolean_Type, + Null_Type, + Double_Type + }; + + inline Type type() const { + if (isUndefined()) return Undefined_Type; + if (isManaged()) return Managed_Type; + if (isEmpty()) return Empty_Type; + if (isInteger()) return Integer_Type; + if (isBoolean()) return Boolean_Type; + if (isNull()) return Null_Type; + Q_ASSERT(isDouble()); return Double_Type; } #ifndef QV4_USE_64_BIT_VALUE_ENCODING @@ -169,101 +262,64 @@ public: SilentNaNBit = 0x00040000, NaN_Mask = 0x7ff80000, NotDouble_Mask = 0x7ffa0000, - Type_Mask = 0xffffc000, - Immediate_Mask = NotDouble_Mask | 0x00004000 | SilentNaNBit, - IsNullOrUndefined_Mask = Immediate_Mask | 0x08000, + Immediate_Mask = NotDouble_Mask | 0x00020000u | SilentNaNBit, Tag_Shift = 32 }; - enum ValueType { - Undefined_Type = Immediate_Mask | 0x00000, - Null_Type = Immediate_Mask | 0x10000, - Boolean_Type = Immediate_Mask | 0x08000, - Integer_Type = Immediate_Mask | 0x18000, - Managed_Type = NotDouble_Mask | 0x00000 | SilentNaNBit, - Empty_Type = NotDouble_Mask | 0x18000 | SilentNaNBit - }; - - enum ImmediateFlags { - ConvertibleToInt = Immediate_Mask | 0x1 - }; - - enum ValueTypeInternal { - Null_Type_Internal = Null_Type | ConvertibleToInt, - Boolean_Type_Internal = Boolean_Type | ConvertibleToInt, - Integer_Type_Internal = Integer_Type | ConvertibleToInt, + enum { + Managed_Type_Internal = NotDouble_Mask }; #else - static const quint64 NaNEncodeMask = 0xffff800000000000ll; - static const quint64 IsInt32Mask = 0x0002000000000000ll; - static const quint64 IsDoubleMask = 0xfffc000000000000ll; - static const quint64 IsNumberMask = IsInt32Mask|IsDoubleMask; - static const quint64 IsNullOrUndefinedMask = 0x0000800000000000ll; - static const quint64 IsNullOrBooleanMask = 0x0001000000000000ll; - static const quint64 IsConvertibleToIntMask = IsInt32Mask|IsNullOrBooleanMask; + static const quint64 NaNEncodeMask = 0xfffc000000000000ll; + static const quint64 Immediate_Mask = 0x00020000u; // bit 49 enum Masks { NaN_Mask = 0x7ff80000, - Type_Mask = 0xffff8000, - IsDouble_Mask = 0xfffc0000, - Immediate_Mask = 0x00018000, - IsNullOrUndefined_Mask = 0x00008000, - IsNullOrBoolean_Mask = 0x00010000, - Tag_Shift = 32 - }; - enum ValueType { - Undefined_Type = IsNullOrUndefined_Mask, - Null_Type = IsNullOrUndefined_Mask|IsNullOrBoolean_Mask, - Boolean_Type = IsNullOrBoolean_Mask, - Integer_Type = 0x20000|IsNullOrBoolean_Mask, - Managed_Type = 0, - Empty_Type = Undefined_Type | 0x4000 }; enum { IsDouble_Shift = 64-14, - IsNumber_Shift = 64-15, - IsConvertibleToInt_Shift = 64-16, - IsManaged_Shift = 64-17 + IsManagedOrUndefined_Shift = 64-15, + IsIntegerConvertible_Shift = 64-16, + Tag_Shift = 32, + IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift, + Managed_Type_Internal = 0 }; - - +#endif enum ValueTypeInternal { - Null_Type_Internal = Null_Type, - Boolean_Type_Internal = Boolean_Type, - Integer_Type_Internal = Integer_Type + Empty_Type_Internal = Immediate_Mask | 0, + ConvertibleToInt = Immediate_Mask | 0x10000u, // bit 48 + Null_Type_Internal = ConvertibleToInt | 0x08000u, + Boolean_Type_Internal = ConvertibleToInt | 0x04000u, + Integer_Type_Internal = ConvertibleToInt | 0x02000u }; -#endif - - inline unsigned type() const { - return tag() & Type_Mask; - } // used internally in property - inline bool isEmpty() const { return tag() == Empty_Type; } - - inline bool isUndefined() const { return tag() == Undefined_Type; } + inline bool isEmpty() const { return tag() == Empty_Type_Internal; } inline bool isNull() const { return tag() == Null_Type_Internal; } - inline bool isBoolean() const { return tag ()== Boolean_Type_Internal; } + inline bool isBoolean() const { return tag() == Boolean_Type_Internal; } + inline bool isInteger() const { return tag() == Integer_Type_Internal; } + inline bool isNullOrUndefined() const { return isNull() || isUndefined(); } + inline bool isNumber() const { return isDouble() || isInteger(); } + #ifdef QV4_USE_64_BIT_VALUE_ENCODING - inline bool isInteger() const { return (_val >> IsNumber_Shift) == 1; } + inline bool isUndefined() const { return _val == 0; } inline bool isDouble() const { return (_val >> IsDouble_Shift); } - inline bool isNumber() const { return (_val >> IsNumber_Shift); } - inline bool isManaged() const { return !(_val >> IsManaged_Shift); } - inline bool isNullOrUndefined() const { return ((_val >> IsManaged_Shift) & ~2) == 1; } - inline bool integerCompatible() const { return ((_val >> IsConvertibleToInt_Shift) & ~2) == 1; } + inline bool isManaged() const { return !isUndefined() && ((_val >> IsManagedOrUndefined_Shift) == 0); } + + inline bool integerCompatible() const { + return (_val >> IsIntegerConvertible_Shift) == 3; + } static inline bool integerCompatible(Value a, Value b) { return a.integerCompatible() && b.integerCompatible(); } static inline bool bothDouble(Value a, Value b) { return a.isDouble() && b.isDouble(); } - inline bool isNaN() const { return (tag() & 0x7fff8000) == 0x00078000; } + inline bool isNaN() const { return (tag() & 0x7ffc0000 ) == 0x00040000; } #else - inline bool isInteger() const { return tag() == Integer_Type_Internal; } + inline bool isUndefined() const { return tag() == Managed_Type_Internal && value() == 0; } inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; } - inline bool isNumber() const { return tag() == Integer_Type_Internal || (tag() & NotDouble_Mask) != NotDouble_Mask; } - inline bool isManaged() const { return tag() == Managed_Type; } - inline bool isNullOrUndefined() const { return (tag() & IsNullOrUndefined_Mask) == Undefined_Type; } + inline bool isManaged() const { return tag() == Managed_Type_Internal && !isUndefined(); } inline bool integerCompatible() const { return (tag() & ConvertibleToInt) == ConvertibleToInt; } static inline bool integerCompatible(Value a, Value b) { return ((a.tag() & b.tag()) & ConvertibleToInt) == ConvertibleToInt; @@ -428,7 +484,7 @@ public: template<typename T> Value &operator=(const Scoped<T> &t); }; -Q_STATIC_ASSERT(std::is_trivial<Value>::value); +V4_ASSERT_IS_TRIVIAL(Value) inline bool Value::isString() const { @@ -491,6 +547,7 @@ ReturnedValue Heap::Base::asReturnedValue() const struct Q_QML_PRIVATE_EXPORT Primitive : public Value { inline static Primitive emptyValue(); + inline static Primitive emptyValue(uint v); static inline Primitive fromBoolean(bool b); static inline Primitive fromInt32(int i); inline static Primitive undefinedValue(); @@ -509,14 +566,21 @@ struct Q_QML_PRIVATE_EXPORT Primitive : public Value inline Primitive Primitive::undefinedValue() { Primitive v; - v.setTagValue(Undefined_Type, 0); + v.setM(Q_NULLPTR); return v; } inline Primitive Primitive::emptyValue() { Primitive v; - v.setTagValue(Value::Empty_Type, 0); + v.setEmpty(0); + return v; +} + +inline Primitive Primitive::emptyValue(uint e) +{ + Primitive v; + v.setEmpty(e); return v; } @@ -544,7 +608,6 @@ inline Primitive Primitive::fromDouble(double d) inline Primitive Primitive::fromInt32(int i) { Primitive v; - v.setTagValue(Integer_Type_Internal, 0); v.setInt_32(i); return v; } @@ -562,31 +625,23 @@ inline Primitive Primitive::fromUInt32(uint i) struct Encode { static ReturnedValue undefined() { - return quint64(Value::Undefined_Type) << Value::Tag_Shift; + return Primitive::undefinedValue().rawValue(); } static ReturnedValue null() { - return quint64(Value::Null_Type_Internal) << Value::Tag_Shift; + return Primitive::nullValue().rawValue(); } Encode(bool b) { - val = (quint64(Value::Boolean_Type_Internal) << Value::Tag_Shift) | (uint)b; + val = Primitive::fromBoolean(b).rawValue(); } Encode(double d) { - Value v; - v.setDouble(d); - val = v.rawValue(); + val = Primitive::fromDouble(d).rawValue(); } Encode(int i) { - val = (quint64(Value::Integer_Type_Internal) << Value::Tag_Shift) | (uint)i; + val = Primitive::fromInt32(i).rawValue(); } Encode(uint i) { - if (i <= INT_MAX) { - val = (quint64(Value::Integer_Type_Internal) << Value::Tag_Shift) | i; - } else { - Value v; - v.setDouble(i); - val = v.rawValue(); - } + val = Primitive::fromUInt32(i).rawValue(); } Encode(ReturnedValue v) { val = v; diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index 39b41dd0d8..455a7ccb65 100644 --- a/src/qml/jsruntime/qv4variantobject.cpp +++ b/src/qml/jsruntime/qv4variantobject.cpp @@ -50,20 +50,23 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(VariantObject); -Heap::VariantObject::VariantObject() +void Heap::VariantObject::init() { + Object::init(); + scarceData = new ExecutionEngine::ScarceResourceData; } -Heap::VariantObject::VariantObject(const QVariant &value) +void Heap::VariantObject::init(const QVariant &value) { - data = value; + Object::init(); + scarceData = new ExecutionEngine::ScarceResourceData(value); if (isScarce()) - internalClass->engine->scarceResources.insert(this); + removeVmePropertyReference(); } bool VariantObject::Data::isScarce() const { - QVariant::Type t = data.type(); + QVariant::Type t = data().type(); return t == QVariant::Pixmap || t == QVariant::Image; } @@ -73,10 +76,10 @@ bool VariantObject::isEqualTo(Managed *m, Managed *other) QV4::VariantObject *lv = static_cast<QV4::VariantObject *>(m); if (QV4::VariantObject *rv = other->as<QV4::VariantObject>()) - return lv->d()->data == rv->d()->data; + return lv->d()->data() == rv->d()->data(); if (QV4::QQmlValueTypeWrapper *v = other->as<QQmlValueTypeWrapper>()) - return v->isEqual(lv->d()->data); + return v->isEqual(lv->d()->data()); return false; } @@ -87,7 +90,7 @@ void VariantObject::addVmePropertyReference() // remove from the ep->scarceResources list // since it is now no longer eligible to be // released automatically by the engine. - d()->node.remove(); + d()->addVmePropertyReference(); } } @@ -97,7 +100,7 @@ void VariantObject::removeVmePropertyReference() // and add to the ep->scarceResources list // since it is now eligible to be released // automatically by the engine. - internalClass()->engine->scarceResources.insert(d()); + d()->removeVmePropertyReference(); } } @@ -115,7 +118,7 @@ QV4::ReturnedValue VariantPrototype::method_preserve(CallContext *ctx) Scope scope(ctx); Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>()); if (o && o->d()->isScarce()) - o->d()->node.remove(); + o->d()->addVmePropertyReference(); return Encode::undefined(); } @@ -125,8 +128,8 @@ QV4::ReturnedValue VariantPrototype::method_destroy(CallContext *ctx) Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>()); if (o) { if (o->d()->isScarce()) - o->d()->node.remove(); - o->d()->data = QVariant(); + o->d()->addVmePropertyReference(); + o->d()->data() = QVariant(); } return Encode::undefined(); } @@ -137,10 +140,10 @@ QV4::ReturnedValue VariantPrototype::method_toString(CallContext *ctx) Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>()); if (!o) return Encode::undefined(); - QString result = o->d()->data.toString(); - if (result.isEmpty() && !o->d()->data.canConvert(QVariant::String)) { + QString result = o->d()->data().toString(); + if (result.isEmpty() && !o->d()->data().canConvert(QVariant::String)) { result = QLatin1String("QVariant(") - + QLatin1String(o->d()->data.typeName()) + + QLatin1String(o->d()->data().typeName()) + QLatin1Char(')'); } return Encode(ctx->d()->engine->newString(result)); @@ -151,7 +154,7 @@ QV4::ReturnedValue VariantPrototype::method_valueOf(CallContext *ctx) Scope scope(ctx); Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>()); if (o) { - QVariant v = o->d()->data; + QVariant v = o->d()->data(); switch (v.type()) { case QVariant::Invalid: return Encode::undefined(); diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h index e50706ef94..9a04069c12 100644 --- a/src/qml/jsruntime/qv4variantobject_p.h +++ b/src/qml/jsruntime/qv4variantobject_p.h @@ -64,16 +64,28 @@ namespace QV4 { namespace Heap { -struct VariantObject : Object, public ExecutionEngine::ScarceResourceData +struct VariantObject : Object { - VariantObject(); - VariantObject(const QVariant &value); - ~VariantObject() { + void init(); + void init(const QVariant &value); + void destroy() { + Q_ASSERT(scarceData); if (isScarce()) - node.remove(); + addVmePropertyReference(); + delete scarceData; + Object::destroy(); } bool isScarce() const; int vmePropertyReferenceCount; + + const QVariant &data() const { return scarceData->data; } + QVariant &data() { return scarceData->data; } + + void addVmePropertyReference() { scarceData->node.remove(); } + void removeVmePropertyReference() { internalClass->engine->scarceResources.insert(scarceData); } + +private: + ExecutionEngine::ScarceResourceData *scarceData; }; } diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 9d18713253..0f7f6b1f75 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -571,7 +571,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code #endif // DO_TRACE_INSTR Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type; + callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, engine->runtime.callValue(engine, VALUE(instr.dest), callData)); @@ -581,7 +581,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type; + callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, engine->runtime.callProperty(engine, instr.name, callData)); @@ -590,7 +590,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallPropertyLookup) Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type; + callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, engine->runtime.callPropertyLookup(engine, instr.lookupIndex, callData)); @@ -600,7 +600,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type; + callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, engine->runtime.callQmlScopeObjectProperty(engine, instr.index, callData)); @@ -610,7 +610,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type; + callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, engine->runtime.callQmlContextObjectProperty(engine, instr.index, callData)); @@ -619,7 +619,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallElement) Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type; + callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, engine->runtime.callElement(engine, VALUE(instr.index), callData)); @@ -628,7 +628,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallActivationProperty) Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type; + callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, engine->runtime.callActivationProperty(engine, instr.name, callData)); @@ -637,7 +637,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallGlobalLookup) Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type; + callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, Runtime::method_callGlobalLookup(engine, instr.index, callData)); @@ -743,7 +743,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CreateValue) Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type; + callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, engine->runtime.constructValue(engine, VALUE(instr.func), callData)); @@ -752,7 +752,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CreateProperty) Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type; + callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, engine->runtime.constructProperty(engine, instr.name, callData)); @@ -761,7 +761,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(ConstructPropertyLookup) Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type; + callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, engine->runtime.constructPropertyLookup(engine, instr.index, callData)); @@ -770,7 +770,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CreateActivationProperty) Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type; + callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, engine->runtime.constructActivationProperty(engine, instr.name, callData)); @@ -779,7 +779,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(ConstructGlobalLookup) Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type; + callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, engine->runtime.constructGlobalLookup(engine, instr.index, callData)); diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h index cd8d335f1c..f8893509d9 100644 --- a/src/qml/jsruntime/qv4vme_moth_p.h +++ b/src/qml/jsruntime/qv4vme_moth_p.h @@ -51,9 +51,12 @@ // We mean it. // +#include <private/qv4global_p.h> #include <private/qv4runtime_p.h> #include <private/qv4instr_moth_p.h> +QT_REQUIRE_CONFIG(qml_interpreter); + QT_BEGIN_NAMESPACE namespace QV4 { diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index d15d14e463..5a3797f397 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -58,6 +58,12 @@ // parent's init all up the inheritance chain), define QML_CHECK_INIT_DESTROY_CALLS below. #undef QML_CHECK_INIT_DESTROY_CALLS +#if defined(_MSC_VER) && (_MSC_VER < 1900) // broken compilers: +# define V4_ASSERT_IS_TRIVIAL(x) +#else // working compilers: +# define V4_ASSERT_IS_TRIVIAL(x) Q_STATIC_ASSERT(std::is_trivial< x >::value); +#endif + QT_BEGIN_NAMESPACE namespace QV4 { @@ -82,6 +88,8 @@ struct VTable namespace Heap { struct Q_QML_EXPORT Base { + void *operator new(size_t) = delete; + quintptr mm_data; // vtable and markbit inline ReturnedValue asReturnedValue() const; @@ -125,16 +133,44 @@ struct Q_QML_EXPORT Base { void *operator new(size_t, Heap::Base *m) { return m; } void operator delete(void *, Heap::Base *) {} - void init() { setInitialized(); } + void init() { _setInitialized(); } + void destroy() { _setDestroyed(); } #ifdef QML_CHECK_INIT_DESTROY_CALLS - bool _isInitialized; - void _checkIsInitialized() { Q_ASSERT(_isInitialized); } - void setInitialized() { Q_ASSERT(!_isInitialized); _isInitialized = true; } + enum { Uninitialized = 0, Initialized, Destroyed } _livenessStatus; + void _checkIsInitialized() { + if (_livenessStatus == Uninitialized) + fprintf(stderr, "ERROR: use of object '%s' before call to init() !!\n", + vtable()->className); + else if (_livenessStatus == Destroyed) + fprintf(stderr, "ERROR: use of object '%s' after call to destroy() !!\n", + vtable()->className); + Q_ASSERT(_livenessStatus = Initialized); + } + void _checkIsDestroyed() { + if (_livenessStatus == Initialized) + fprintf(stderr, "ERROR: object '%s' was never destroyed completely !!\n", + vtable()->className); + Q_ASSERT(_livenessStatus == Destroyed); + } + void _setInitialized() { Q_ASSERT(_livenessStatus == Uninitialized); _livenessStatus = Initialized; } + void _setDestroyed() { + if (_livenessStatus == Uninitialized) + fprintf(stderr, "ERROR: attempting to destroy an uninitialized object '%s' !!\n", + vtable()->className); + else if (_livenessStatus == Destroyed) + fprintf(stderr, "ERROR: attempting to destroy repeatedly object '%s' !!\n", + vtable()->className); + Q_ASSERT(_livenessStatus == Initialized); + _livenessStatus = Destroyed; + } #else Q_ALWAYS_INLINE void _checkIsInitialized() {} - Q_ALWAYS_INLINE void setInitialized() {} + Q_ALWAYS_INLINE void _checkIsDestroyed() {} + Q_ALWAYS_INLINE void _setInitialized() {} + Q_ALWAYS_INLINE void _setDestroyed() {} #endif }; +V4_ASSERT_IS_TRIVIAL(Base) template <typename T> struct Pointer { @@ -148,7 +184,7 @@ struct Pointer { T *ptr; }; -Q_STATIC_ASSERT(std::is_trivial<Pointer<void>>::value); +V4_ASSERT_IS_TRIVIAL(Pointer<void>) } @@ -204,7 +240,7 @@ private: QtSharedPointer::ExternalRefCountData *d; QObject *qObject; }; -Q_STATIC_ASSERT(std::is_trivial<QQmlQPointer<QObject>>::value); +V4_ASSERT_IS_TRIVIAL(QQmlQPointer<QObject>) #endif } diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 3d25bd1639..6ef2380561 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -46,7 +46,7 @@ #include "PageAllocation.h" #include "StdLibExtras.h" -#include <QTime> +#include <QElapsedTimer> #include <QMap> #include <QScopedValueRollback> @@ -229,10 +229,12 @@ bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, Exec *unmanagedHeapSize -= heapBytes; } - if (m->vtable()->destroy) + if (m->vtable()->destroy) { m->vtable()->destroy(m); + m->_checkIsDestroyed(); + } - memset(m, 0, header->itemSize); + memset(m, 0, sizeof(Heap::Base)); #ifdef V4_USE_VALGRIND VALGRIND_DISABLE_ERROR_REPORTING; VALGRIND_MEMPOOL_FREE(engine->memoryManager, m); @@ -482,7 +484,7 @@ void MemoryManager::sweep(bool lastSweep) remainingWeakQObjectWrappers.reserve(pendingCount); for (int i = 0; i < pendingCount; ++i) { Value *v = m_pendingFreedObjectWrapperValue.at(i); - if (v->tag() == Value::Undefined_Type) + if (v->isUndefined() || v->isEmpty()) PersistentValueStorage::free(v); else remainingWeakQObjectWrappers.append(v); @@ -594,18 +596,17 @@ void MemoryManager::runGC() } else { const size_t totalMem = getAllocatedMem(); - QTime t; + QElapsedTimer t; t.start(); mark(); - int markTime = t.elapsed(); - t.restart(); + qint64 markTime = t.restart(); const size_t usedBefore = getUsedMem(); const size_t largeItemsBefore = getLargeItemsMem(); size_t chunksBefore = m_d->heapChunks.size(); sweep(); const size_t usedAfter = getUsedMem(); const size_t largeItemsAfter = getLargeItemsMem(); - int sweepTime = t.elapsed(); + qint64 sweepTime = t.elapsed(); qDebug() << "========== GC =========="; qDebug() << "Marked object in" << markTime << "ms."; diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 6db5b54760..dfa0d85dff 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -108,8 +108,10 @@ public: template<typename ManagedType> inline typename ManagedType::Data *allocManaged(std::size_t size, std::size_t unmanagedSize = 0) { + V4_ASSERT_IS_TRIVIAL(typename ManagedType::Data) size = align(size); Heap::Base *o = allocData(size, unmanagedSize); + memset(o, 0, size); o->setVtable(ManagedType::staticVTable()); return static_cast<typename ManagedType::Data *>(o); } @@ -144,7 +146,7 @@ public: { Scope scope(engine); Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data), unmanagedSize)); - (void)new (t->d()) typename ManagedType::Data(this, arg1); + t->d_unchecked()->init(this, arg1); return t->d(); } @@ -153,7 +155,7 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - (void)new (t->d()) typename ObjectType::Data(); + t->d_unchecked()->init(); return t->d(); } @@ -162,8 +164,8 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d()->prototype = prototype->d(); - (void)new (t->d()) typename ObjectType::Data(); + t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->init(); return t->d(); } @@ -172,8 +174,8 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d()->prototype = prototype->d(); - (void)new (t->d()) typename ObjectType::Data(arg1); + t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->init(arg1); return t->d(); } @@ -182,8 +184,8 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d()->prototype = prototype->d(); - (void)new (t->d()) typename ObjectType::Data(arg1, arg2); + t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->init(arg1, arg2); return t->d(); } @@ -192,8 +194,8 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d()->prototype = prototype->d(); - (void)new (t->d()) typename ObjectType::Data(arg1, arg2, arg3); + t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->init(arg1, arg2, arg3); return t->d(); } @@ -202,8 +204,8 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d()->prototype = prototype->d(); - (void)new (t->d()) typename ObjectType::Data(arg1, arg2, arg3, arg4); + t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->init(arg1, arg2, arg3, arg4); return t->d(); } @@ -212,7 +214,7 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>()); - (void)new (t->d()) typename ObjectType::Data(); + t->d_unchecked()->init(); return t->d(); } @@ -221,7 +223,7 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>()); - (void)new (t->d()) typename ObjectType::Data(arg1); + t->d_unchecked()->init(arg1); return t->d(); } @@ -230,7 +232,7 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>()); - (void)new (t->d()) typename ObjectType::Data(arg1, arg2); + t->d_unchecked()->init(arg1, arg2); return t->d(); } @@ -239,7 +241,7 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>()); - (void)new (t->d()) typename ObjectType::Data(arg1, arg2, arg3); + t->d_unchecked()->init(arg1, arg2, arg3); return t->d(); } @@ -248,7 +250,7 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>()); - (void)new (t->d()) typename ObjectType::Data(arg1, arg2, arg3, arg4); + t->d_unchecked()->init(arg1, arg2, arg3, arg4); return t->d(); } @@ -258,7 +260,7 @@ public: { Scope scope(engine); Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data))); - (void)new (t->d()) typename ManagedType::Data(); + t->d_unchecked()->init(); return t->d(); } @@ -267,7 +269,7 @@ public: { Scope scope(engine); Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data))); - (void)new (t->d()) typename ManagedType::Data(arg1); + t->d_unchecked()->init(arg1); return t->d(); } @@ -294,7 +296,7 @@ public: { Scope scope(engine); Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data))); - (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4); + t->d_unchecked()->init(arg1, arg2, arg3, arg4); return t->d(); } @@ -303,7 +305,7 @@ public: { Scope scope(engine); Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data))); - (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4, arg5); + t->d_unchecked()->init(arg1, arg2, arg3, arg4, arg5); return t->d(); } diff --git a/src/qml/qml.pro b/src/qml/qml.pro index 13e00d8812..826a074701 100644 --- a/src/qml/qml.pro +++ b/src/qml/qml.pro @@ -1,11 +1,8 @@ TARGET = QtQml QT = core-private -no_network { - DEFINES += QT_NO_NETWORK -} else { +qtConfig(qml-network): \ QT += network -} DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES @@ -22,11 +19,6 @@ exists("qqml_enable_gcov") { LIBS_PRIVATE += -lgcov } -gcc:!intel_icc:greaterThan(QT_GCC_MAJOR_VERSION, 5) { - # Our code is bad. Temporary workaround. - QMAKE_CXXFLAGS += -fno-delete-null-pointer-checks -fno-lifetime-dse -} - # QTBUG-55238, disable new optimizer for MSVC 2015/Update 3. release:win32-msvc*:equals(QT_CL_MAJOR_VERSION, 19):equals(QT_CL_MINOR_VERSION, 00): \ greaterThan(QT_CL_PATCH_VERSION, 24212):QMAKE_CXXFLAGS += -d2SSAOptimizer- diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index e12472760f..4fe76ddf29 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -600,7 +600,7 @@ protected: resultMo = resultObject->metaObject(); } } else if (auto variant = result.as<QV4::VariantObject>()) { - QVariant value = variant->d()->data; + QVariant value = variant->d()->data(); QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()); resultMo = QQmlPropertyPrivate::rawMetaObjectForType(ep, value.userType()); if (resultMo.isNull()) diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index b78028dcf9..6ebcd142fb 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1058,9 +1058,9 @@ namespace QV4 { namespace Heap { struct QmlIncubatorObject : Object { - QmlIncubatorObject(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous); - ~QmlIncubatorObject() { parent.destroy(); } - QScopedPointer<QQmlComponentIncubator> incubator; + void init(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous); + inline void destroy(); + QQmlComponentIncubator *incubator; QQmlQPointer<QObject> parent; QV4::Value valuemap; QV4::Value statusChanged; @@ -1389,7 +1389,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) r->d()->qmlContext = v4->qmlContext(); r->d()->parent = parent; - QQmlIncubator *incubator = r->d()->incubator.data(); + QQmlIncubator *incubator = r->d()->incubator; create(*incubator, creationContext()); if (incubator->status() == QQmlIncubator::Null) { @@ -1484,13 +1484,20 @@ QQmlComponentExtension::~QQmlComponentExtension() { } -QV4::Heap::QmlIncubatorObject::QmlIncubatorObject(QQmlIncubator::IncubationMode m) - : valuemap(QV4::Primitive::undefinedValue()) - , statusChanged(QV4::Primitive::undefinedValue()) +void QV4::Heap::QmlIncubatorObject::init(QQmlIncubator::IncubationMode m) { + Object::init(); + valuemap = QV4::Primitive::undefinedValue(); + statusChanged = QV4::Primitive::undefinedValue(); parent.init(); qmlContext = nullptr; - incubator.reset(new QQmlComponentIncubator(this, m)); + incubator = new QQmlComponentIncubator(this, m); +} + +void QV4::Heap::QmlIncubatorObject::destroy() { + delete incubator; + parent.destroy(); + Object::destroy(); } void QV4::QmlIncubatorObject::setInitialState(QObject *o) diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index 13d708bc17..2418003519 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -61,20 +61,23 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlContextWrapper); -Heap::QmlContextWrapper::QmlContextWrapper(QQmlContextData *context, QObject *scopeObject, bool ownsContext) - : readOnly(true) - , ownsContext(ownsContext) - , isNullWrapper(false) - , context(context) +void Heap::QmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject, bool ownsContext) { + Object::init(); + readOnly = true; + this->ownsContext = ownsContext; + isNullWrapper = false; + this->context = new QQmlGuardedContextData(context); this->scopeObject.init(scopeObject); } -Heap::QmlContextWrapper::~QmlContextWrapper() +void Heap::QmlContextWrapper::destroy() { - if (context && ownsContext) - context->destroy(); + if (*context && ownsContext) + (*context)->destroy(); + delete context; scopeObject.destroy(); + Object::destroy(); } ReturnedValue QmlContextWrapper::qmlScope(ExecutionEngine *v4, QQmlContextData *ctxt, QObject *scope) @@ -120,7 +123,7 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr if (resource->d()->isNullWrapper) return Object::get(m, name, hasProperty); - if (v4->callingQmlContext() != resource->d()->context) + if (v4->callingQmlContext() != *resource->d()->context) return Object::get(m, name, hasProperty); result = Object::get(m, name, &hasProp); diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h index 2b8c16f274..126ffecf0d 100644 --- a/src/qml/qml/qqmlcontextwrapper_p.h +++ b/src/qml/qml/qqmlcontextwrapper_p.h @@ -64,13 +64,13 @@ namespace QV4 { namespace Heap { struct QmlContextWrapper : Object { - QmlContextWrapper(QQmlContextData *context, QObject *scopeObject, bool ownsContext = false); - ~QmlContextWrapper(); + void init(QQmlContextData *context, QObject *scopeObject, bool ownsContext = false); + void destroy(); bool readOnly; bool ownsContext; bool isNullWrapper; - QQmlGuardedContextData context; + QQmlGuardedContextData *context; QQmlQPointer<QObject> scopeObject; }; @@ -89,7 +89,7 @@ struct Q_QML_EXPORT QmlContextWrapper : Object } inline QObject *getScopeObject() const { return d()->scopeObject; } - inline QQmlContextData *getContext() const { return d()->context; } + inline QQmlContextData *getContext() const { return *d()->context; } void setReadOnly(bool b) { d()->readOnly = b; } diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index daa12fae26..c273330a0a 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -70,7 +70,7 @@ #include <QtCore/qthread.h> #include <private/qthread_p.h> -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) #include "qqmlnetworkaccessmanagerfactory.h" #include <QNetworkAccessManager> #include <QtNetwork/qnetworkconfigmanager.h> @@ -660,7 +660,7 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) cleanup(0), erroredBindings(0), inProgressCreations(0), workerScriptEngine(0), activeObjectCreator(0), -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) networkAccessManager(0), networkAccessManagerFactory(0), #endif urlInterceptor(0), scarceResourcesRefCount(0), importDatabase(e), typeLoader(e), @@ -1143,7 +1143,7 @@ void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index) } } -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) /*! Sets the \a factory to use for creating QNetworkAccessManager(s). @@ -1210,7 +1210,7 @@ QNetworkAccessManager *QQmlEngine::networkAccessManager() const Q_D(const QQmlEngine); return d->getNetworkAccessManager(); } -#endif // QT_NO_NETWORK +#endif // qml_network /*! diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index 3111d1013e..3102a20fac 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -87,7 +87,7 @@ class QQmlExpression; class QQmlContext; class QQmlType; class QUrl; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) class QNetworkAccessManager; class QQmlNetworkAccessManagerFactory; #endif @@ -117,7 +117,7 @@ public: bool importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors); -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) void setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *); QQmlNetworkAccessManagerFactory *networkAccessManagerFactory() const; diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 713b03dbf3..916566b6c7 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -162,7 +162,7 @@ public: void registerFinalizeCallback(QObject *obj, int index); QQmlObjectCreator *activeObjectCreator; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const; QNetworkAccessManager *getNetworkAccessManager() const; mutable QNetworkAccessManager *networkAccessManager; diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp index 4769402855..4e4db086b0 100644 --- a/src/qml/qml/qqmlfile.cpp +++ b/src/qml/qml/qqmlfile.cpp @@ -68,7 +68,7 @@ static char assets_string[] = "assets"; class QQmlFilePrivate; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) class QQmlFileNetworkReply : public QObject { Q_OBJECT @@ -117,12 +117,12 @@ public: Error error; QString errorString; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) QQmlFileNetworkReply *reply; #endif }; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) int QQmlFileNetworkReply::finishedIndex = -1; int QQmlFileNetworkReply::downloadProgressIndex = -1; int QQmlFileNetworkReply::networkFinishedIndex = -1; @@ -205,11 +205,11 @@ void QQmlFileNetworkReply::networkDownloadProgress(qint64 a, qint64 b) { emit downloadProgress(a, b); } -#endif // QT_NO_NETWORK +#endif // qml_network QQmlFilePrivate::QQmlFilePrivate() : error(None) -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) , reply(0) #endif { @@ -233,7 +233,7 @@ QQmlFile::QQmlFile(QQmlEngine *e, const QString &url) QQmlFile::~QQmlFile() { -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) delete d->reply; #endif delete d; @@ -273,7 +273,7 @@ QQmlFile::Status QQmlFile::status() const { if (d->url.isEmpty() && d->urlString.isEmpty()) return Null; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) else if (d->reply) return Loading; #endif @@ -333,7 +333,7 @@ void QQmlFile::load(QQmlEngine *engine, const QUrl &url) d->error = QQmlFilePrivate::NotFound; } } else { -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) d->reply = new QQmlFileNetworkReply(engine, d, url); #else d->error = QQmlFilePrivate::NotFound; @@ -364,7 +364,7 @@ void QQmlFile::load(QQmlEngine *engine, const QString &url) d->error = QQmlFilePrivate::NotFound; } } else { -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) QUrl qurl(url); d->url = qurl; d->urlString = QString(); @@ -388,7 +388,7 @@ void QQmlFile::clear(QObject *) clear(); } -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) bool QQmlFile::connectFinished(QObject *object, const char *method) { if (!d || !d->reply) { diff --git a/src/qml/qml/qqmlfile.h b/src/qml/qml/qqmlfile.h index 3dd683a2cd..aec0981a95 100644 --- a/src/qml/qml/qqmlfile.h +++ b/src/qml/qml/qqmlfile.h @@ -80,7 +80,7 @@ public: void clear(); void clear(QObject *); -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) bool connectFinished(QObject *, const char *); bool connectFinished(QObject *, int); bool connectDownloadProgress(QObject *, const char *); diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index 425a720867..8aa107dc17 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -52,17 +52,19 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlListWrapper); -Heap::QmlListWrapper::QmlListWrapper() +void Heap::QmlListWrapper::init() { + Object::init(); object.init(); QV4::Scope scope(internalClass->engine); QV4::ScopedObject o(scope, this); o->setArrayType(Heap::ArrayData::Custom); } -Heap::QmlListWrapper::~QmlListWrapper() +void Heap::QmlListWrapper::destroy() { object.destroy(); + Object::destroy(); } ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, QObject *object, int propId, int propType) @@ -75,7 +77,7 @@ ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, QObject *object, i Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocObject<QmlListWrapper>()); r->d()->object = object; r->d()->propertyType = propType; - void *args[] = { &r->d()->property, 0 }; + void *args[] = { &r->d()->property(), 0 }; QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args); return r.asReturnedValue(); } @@ -86,7 +88,7 @@ ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, const QQmlListProp Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocObject<QmlListWrapper>()); r->d()->object = prop.object; - r->d()->property = prop; + r->d()->property() = prop; r->d()->propertyType = propType; return r.asReturnedValue(); } @@ -96,7 +98,7 @@ QVariant QmlListWrapper::toVariant() const if (!d()->object) return QVariant(); - return QVariant::fromValue(QQmlListReferencePrivate::init(d()->property, d()->propertyType, engine()->qmlEngine())); + return QVariant::fromValue(QQmlListReferencePrivate::init(d()->property(), d()->propertyType, engine()->qmlEngine())); } @@ -107,7 +109,7 @@ ReturnedValue QmlListWrapper::get(const Managed *m, String *name, bool *hasPrope QV4::ExecutionEngine *v4 = w->engine(); if (name->equals(v4->id_length()) && !w->d()->object.isNull()) { - quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; + quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0; return Primitive::fromUInt32(count).asReturnedValue(); } @@ -126,11 +128,11 @@ ReturnedValue QmlListWrapper::getIndexed(const Managed *m, uint index, bool *has const QmlListWrapper *w = static_cast<const QmlListWrapper *>(m); QV4::ExecutionEngine *v4 = w->engine(); - quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; - if (index < count && w->d()->property.at) { + quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0; + if (index < count && w->d()->property().at) { if (hasProperty) *hasProperty = true; - return QV4::QObjectWrapper::wrap(v4, w->d()->property.at(&w->d()->property, index)); + return QV4::QObjectWrapper::wrap(v4, w->d()->property().at(&w->d()->property(), index)); } if (hasProperty) @@ -152,12 +154,12 @@ void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name *index = UINT_MAX; Q_ASSERT(m->as<QmlListWrapper>()); QmlListWrapper *w = static_cast<QmlListWrapper *>(m); - quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; + quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0; if (it->arrayIndex < count) { *index = it->arrayIndex; ++it->arrayIndex; *attrs = QV4::Attr_Data; - p->value = QV4::QObjectWrapper::wrap(w->engine(), w->d()->property.at(&w->d()->property, *index)); + p->value = QV4::QObjectWrapper::wrap(w->engine(), w->d()->property().at(&w->d()->property(), *index)); return; } return QV4::Object::advanceIterator(m, it, name, index, p, attrs); diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h index 1107b957c9..d01b332159 100644 --- a/src/qml/qml/qqmllistwrapper_p.h +++ b/src/qml/qml/qqmllistwrapper_p.h @@ -66,11 +66,18 @@ namespace QV4 { namespace Heap { struct QmlListWrapper : Object { - QmlListWrapper(); - ~QmlListWrapper(); + void init(); + void destroy(); QQmlQPointer<QObject> object; - QQmlListProperty<QObject> property; + + QQmlListProperty<QObject> &property() { + return *reinterpret_cast<QQmlListProperty<QObject>*>(propertyData); + } + int propertyType; + +private: + void *propertyData[sizeof(QQmlListProperty<QObject>)/sizeof(void*)]; }; } diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index 76752f509c..6f66475aa5 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -109,16 +109,16 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ct if (ctx->argc() == 2) { if (ctx->args()[1].isString()) { QString format = ctx->args()[1].stringValue()->toQString(); - formattedDt = r->d()->locale.toString(dt, format); + formattedDt = r->d()->locale->toString(dt, format); } else if (ctx->args()[1].isNumber()) { quint32 intFormat = ctx->args()[1].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - formattedDt = r->d()->locale.toString(dt, format); + formattedDt = r->d()->locale->toString(dt, format); } else { V4THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format"); } } else { - formattedDt = r->d()->locale.toString(dt, enumFormat); + formattedDt = r->d()->locale->toString(dt, enumFormat); } return ctx->d()->engine->newString(formattedDt)->asReturnedValue(); @@ -154,16 +154,16 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::CallContext if (ctx->argc() == 2) { if (ctx->args()[1].isString()) { QString format = ctx->args()[1].stringValue()->toQString(); - formattedTime = r->d()->locale.toString(time, format); + formattedTime = r->d()->locale->toString(time, format); } else if (ctx->args()[1].isNumber()) { quint32 intFormat = ctx->args()[1].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - formattedTime = r->d()->locale.toString(time, format); + formattedTime = r->d()->locale->toString(time, format); } else { V4THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format"); } } else { - formattedTime = r->d()->locale.toString(time, enumFormat); + formattedTime = r->d()->locale->toString(time, enumFormat); } return ctx->d()->engine->newString(formattedTime)->asReturnedValue(); @@ -199,16 +199,16 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::CallContext if (ctx->argc() == 2) { if (ctx->args()[1].isString()) { QString format = ctx->args()[1].stringValue()->toQString(); - formattedDate = r->d()->locale.toString(date, format); + formattedDate = r->d()->locale->toString(date, format); } else if (ctx->args()[1].isNumber()) { quint32 intFormat = ctx->args()[1].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - formattedDate = r->d()->locale.toString(date, format); + formattedDate = r->d()->locale->toString(date, format); } else { V4THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format"); } } else { - formattedDate = r->d()->locale.toString(date, enumFormat); + formattedDate = r->d()->locale->toString(date, enumFormat); } return ctx->d()->engine->newString(formattedDate)->asReturnedValue(); @@ -237,16 +237,16 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::CallContext * if (ctx->argc() == 3) { if (ctx->args()[2].isString()) { QString format = ctx->args()[2].stringValue()->toQString(); - dt = r->d()->locale.toDateTime(dateString, format); + dt = r->d()->locale->toDateTime(dateString, format); } else if (ctx->args()[2].isNumber()) { quint32 intFormat = ctx->args()[2].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - dt = r->d()->locale.toDateTime(dateString, format); + dt = r->d()->locale->toDateTime(dateString, format); } else { V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format"); } } else { - dt = r->d()->locale.toDateTime(dateString, enumFormat); + dt = r->d()->locale->toDateTime(dateString, enumFormat); } return QV4::Encode(engine->newDateObject(dt)); @@ -278,16 +278,16 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallConte if (ctx->argc() == 3) { if (ctx->args()[2].isString()) { QString format = ctx->args()[2].stringValue()->toQString(); - tm = r->d()->locale.toTime(dateString, format); + tm = r->d()->locale->toTime(dateString, format); } else if (ctx->args()[2].isNumber()) { quint32 intFormat = ctx->args()[2].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - tm = r->d()->locale.toTime(dateString, format); + tm = r->d()->locale->toTime(dateString, format); } else { V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format"); } } else { - tm = r->d()->locale.toTime(dateString, enumFormat); + tm = r->d()->locale->toTime(dateString, enumFormat); } QDateTime dt; @@ -323,16 +323,16 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::CallConte if (ctx->argc() == 3) { if (ctx->args()[2].isString()) { QString format = ctx->args()[2].stringValue()->toQString(); - dt = r->d()->locale.toDate(dateString, format); + dt = r->d()->locale->toDate(dateString, format); } else if (ctx->args()[2].isNumber()) { quint32 intFormat = ctx->args()[2].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - dt = r->d()->locale.toDate(dateString, format); + dt = r->d()->locale->toDate(dateString, format); } else { V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format"); } } else { - dt = r->d()->locale.toDate(dateString, enumFormat); + dt = r->d()->locale->toDate(dateString, enumFormat); } return QV4::Encode(engine->newDateObject(QDateTime(dt))); @@ -393,7 +393,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::CallContext * prec = ctx->args()[2].toInt32(); } - return ctx->d()->engine->newString(r->d()->locale.toString(number, (char)format, prec))->asReturnedValue(); + return ctx->d()->engine->newString(r->d()->locale->toString(number, (char)format, prec))->asReturnedValue(); } QV4::ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(QV4::CallContext *ctx) @@ -423,7 +423,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(QV4::CallC symbol = ctx->args()[1].toQStringNoThrow(); } - return ctx->d()->engine->newString(r->d()->locale.toCurrencyString(number, symbol))->asReturnedValue(); + return ctx->d()->engine->newString(r->d()->locale->toCurrencyString(number, symbol))->asReturnedValue(); } QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::CallContext *ctx) @@ -441,7 +441,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::CallContext V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments"); GET_LOCALE_DATA_RESOURCE(ctx->args()[0]); - locale = r->d()->locale; + locale = *r->d()->locale; numberIdx = 1; } @@ -813,7 +813,7 @@ QV4::ReturnedValue QQmlLocale::wrap(ExecutionEngine *v4, const QLocale &locale) QV4::Scope scope(v4); QV4LocaleDataDeletable *d = localeV4Data(scope.engine); QV4::Scoped<QQmlLocaleData> wrapper(scope, v4->memoryManager->allocObject<QQmlLocaleData>()); - wrapper->d()->locale = locale; + *wrapper->d()->locale = locale; QV4::ScopedObject p(scope, d->prototype.value()); wrapper->setPrototype(p); return wrapper.asReturnedValue(); diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h index 652a3ca0d4..275f58db7d 100644 --- a/src/qml/qml/qqmllocale_p.h +++ b/src/qml/qml/qqmllocale_p.h @@ -143,8 +143,12 @@ namespace QV4 { namespace Heap { struct QQmlLocaleData : Object { - inline QQmlLocaleData() {} - QLocale locale; + inline void init() { locale = new QLocale; } + void destroy() { + delete locale; + Object::destroy(); + } + QLocale *locale; }; } @@ -161,7 +165,7 @@ struct QQmlLocaleData : public QV4::Object ctx->engine()->throwTypeError(); return 0; } - return &thisObject->d()->locale; + return thisObject->d()->locale; } static QV4::ReturnedValue method_currencySymbol(QV4::CallContext *ctx); diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/qml/qqmlloggingcategory.cpp index 88cf14cba0..fd8fb477c7 100644 --- a/src/qml/qml/qqmlloggingcategory.cpp +++ b/src/qml/qml/qqmlloggingcategory.cpp @@ -81,7 +81,7 @@ \note This property needs to be set when declaring the LoggingCategory and cannot be changed later. - \sa QLoggingCategory::name() + \sa QLoggingCategory::categoryName() */ QQmlLoggingCategory::QQmlLoggingCategory(QObject *parent) diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp index c94db8e168..1680253d73 100644 --- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp +++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp @@ -41,7 +41,7 @@ QT_BEGIN_NAMESPACE -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) /*! \class QQmlNetworkAccessManagerFactory @@ -103,6 +103,6 @@ QQmlNetworkAccessManagerFactory::~QQmlNetworkAccessManagerFactory() implementation of this method is reentrant. */ -#endif //QT_NO_NETWORK +#endif // qml_network QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h index ba3561b9f4..57dec1da29 100644 --- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h +++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h @@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) class QNetworkAccessManager; class Q_QML_EXPORT QQmlNetworkAccessManagerFactory @@ -56,7 +56,7 @@ public: }; -#endif //QT_NO_NETWORK +#endif // qml_network QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 2543fd069c..672b36ea75 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -246,7 +246,7 @@ Creates a new empty QQmlPropertyCache. QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e) : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), - _metaObject(0), argumentsCache(0) + _metaObject(0), argumentsCache(0), _jsFactoryMethodIndex(-1) { Q_ASSERT(engine); } @@ -507,6 +507,11 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, const char *name = mci.name(); if (0 == qstrcmp(name, "DefaultProperty")) { _defaultPropertyName = QString::fromUtf8(mci.value()); + } else if (0 == qstrcmp(name, "qt_QmlJSWrapperFactoryMethod")) { + const char * const factoryMethod = mci.value(); + _jsFactoryMethodIndex = metaObject->indexOfSlot(factoryMethod); + if (_jsFactoryMethodIndex != -1) + _jsFactoryMethodIndex -= metaObject->methodOffset(); } } } diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index f90945bf57..b820777973 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -431,6 +431,8 @@ public: void toMetaObjectBuilder(QMetaObjectBuilder &); + inline bool callJSFactoryMethod(QObject *object, void **args) const; + static bool determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount); static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo); @@ -505,6 +507,7 @@ private: QByteArray _dynamicStringData; QString _defaultPropertyName; QQmlPropertyCacheMethodArguments *argumentsCache; + int _jsFactoryMethodIndex; QByteArray _checksum; }; @@ -806,6 +809,17 @@ int QQmlPropertyCache::signalOffset() const return signalHandlerIndexCacheStart; } +bool QQmlPropertyCache::callJSFactoryMethod(QObject *object, void **args) const +{ + if (_jsFactoryMethodIndex != -1) { + _metaObject->d.static_metacall(object, QMetaObject::InvokeMetaMethod, _jsFactoryMethodIndex, args); + return true; + } + if (_parent) + return _parent->callJSFactoryMethod(object, args); + return false; +} + QQmlMetaObject::QQmlMetaObject() { } diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index b576366abf..3e599aed6c 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -123,7 +123,7 @@ namespace { }; } -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) // This is a lame object that we need to ensure that slots connected to // QNetworkReply get called in the correct thread (the loader thread). // As QQmlTypeLoader lives in the main thread, and we can't use @@ -143,7 +143,7 @@ public slots: private: QQmlTypeLoader *l; }; -#endif // QT_NO_NETWORK +#endif // qml_network class QQmlTypeLoaderThread : public QQmlThread { @@ -151,10 +151,10 @@ class QQmlTypeLoaderThread : public QQmlThread public: QQmlTypeLoaderThread(QQmlTypeLoader *loader); -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) QNetworkAccessManager *networkAccessManager() const; QQmlTypeLoaderNetworkReplyProxy *networkReplyProxy() const; -#endif // QT_NO_NETWORK +#endif // qml_network void load(QQmlDataBlob *b); void loadAsync(QQmlDataBlob *b); void loadWithStaticData(QQmlDataBlob *b, const QByteArray &); @@ -177,13 +177,13 @@ private: void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri); QQmlTypeLoader *m_loader; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) mutable QNetworkAccessManager *m_networkAccessManager; mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy; -#endif // QT_NO_NETWORK +#endif // qml_network }; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) QQmlTypeLoaderNetworkReplyProxy::QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l) : l(l) { @@ -212,7 +212,7 @@ void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply) l->networkReplyProgress(reply, replySize, replySize); l->networkReplyFinished(reply); } -#endif // QT_NO_NETWORK +#endif // qml_network /*! \class QQmlDataBlob @@ -529,7 +529,7 @@ void QQmlDataBlob::done() { } -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) /*! Invoked if there is a network error while fetching this blob. @@ -582,7 +582,7 @@ void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError) setError(error); } -#endif // QT_NO_NETWORK +#endif // qml_network /*! Called if \a blob, which was previously waited for, has an error. @@ -782,15 +782,15 @@ void QQmlDataBlob::ThreadData::setProgress(quint8 v) QQmlTypeLoaderThread::QQmlTypeLoaderThread(QQmlTypeLoader *loader) : m_loader(loader) -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) , m_networkAccessManager(0), m_networkReplyProxy(0) -#endif // QT_NO_NETWORK +#endif // qml_network { // Do that after initializing all the members. startup(); } -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) QNetworkAccessManager *QQmlTypeLoaderThread::networkAccessManager() const { Q_ASSERT(isThisThread()); @@ -808,7 +808,7 @@ QQmlTypeLoaderNetworkReplyProxy *QQmlTypeLoaderThread::networkReplyProxy() const Q_ASSERT(m_networkReplyProxy); // Must call networkAccessManager() first return m_networkReplyProxy; } -#endif // QT_NO_NETWORK +#endif // qml_network void QQmlTypeLoaderThread::load(QQmlDataBlob *b) { @@ -866,12 +866,12 @@ void QQmlTypeLoaderThread::initializeEngine(QQmlExtensionInterface *iface, void QQmlTypeLoaderThread::shutdownThread() { -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) delete m_networkAccessManager; m_networkAccessManager = 0; delete m_networkReplyProxy; m_networkReplyProxy = 0; -#endif // QT_NO_NETWORK +#endif // qml_network } void QQmlTypeLoaderThread::loadThread(QQmlDataBlob *b) @@ -957,14 +957,14 @@ void QQmlTypeLoader::invalidate() m_thread = 0; } -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) // Need to delete the network replies after // the loader thread is shutdown as it could be // getting new replies while we clear them for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter) (*iter)->release(); m_networkReplies.clear(); -#endif // QT_NO_NETWORK +#endif // qml_network } void QQmlTypeLoader::lock() @@ -1138,7 +1138,7 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) setData(blob, fileName); } else { -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(blob->m_url)); QQmlTypeLoaderNetworkReplyProxy *nrp = m_thread->networkReplyProxy(); blob->addref(); @@ -1156,14 +1156,14 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) #ifdef DATABLOB_DEBUG qWarning("QQmlDataBlob: requested %s", qPrintable(blob->url().toString())); #endif // DATABLOB_DEBUG -#endif // QT_NO_NETWORK +#endif // qml_network } } #define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16 #define TYPELOADER_MINIMUM_TRIM_THRESHOLD 64 -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply) { Q_ASSERT(m_thread->isThisThread()); @@ -1219,7 +1219,7 @@ void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply, m_thread->callDownloadProgressChanged(blob, blob->m_data.progress()); } } -#endif // QT_NO_NETWORK +#endif // qml_network /*! Return the QQmlEngine associated with this loader @@ -1968,12 +1968,11 @@ void QQmlTypeLoader::trimCache() for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end; ++iter) { QQmlTypeData *typeData = iter.value(); - const bool hasError = !typeData->m_compiledData && !typeData->m_errors.isEmpty(); - const bool isNotReferenced = typeData->isComplete() && typeData->m_compiledData - && typeData->m_compiledData->count() == 1; - // typeData->m_compiledData may be set early on in the proccess of loading a file, so it's important - // to check the general loading status of the typeData before making any other decisions. - if (typeData->count() == 1 && (hasError || isNotReferenced)) { + // typeData->m_compiledData may be set early on in the proccess of loading a file, so + // it's important to check the general loading status of the typeData before making any + // other decisions. + if (typeData->count() == 1 && (typeData->isError() || typeData->isComplete()) + && (!typeData->m_compiledData || typeData->m_compiledData->count() == 1)) { // There are no live objects of this type unneededTypes.append(iter); } @@ -3106,8 +3105,14 @@ QByteArray QQmlDataBlob::Data::readAll(QString *error, qint64 *sourceTimeStamp) *error = f.errorString(); return QByteArray(); } - if (sourceTimeStamp) - *sourceTimeStamp = QFileInfo(f).lastModified().toMSecsSinceEpoch(); + if (sourceTimeStamp) { + QDateTime timeStamp = QFileInfo(f).lastModified(); + // Files from the resource system do not have any time stamps, so fall back to the application + // executable. + if (!timeStamp.isValid()) + timeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified(); + *sourceTimeStamp = timeStamp.toMSecsSinceEpoch(); + } QByteArray data(f.size(), Qt::Uninitialized); if (f.read(data.data(), data.length()) != data.length()) { *error = f.errorString(); diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 12c55e9179..ad5ab3124e 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -51,9 +51,10 @@ // We mean it. // +#include <QtQml/qtqmlglobal.h> #include <QtCore/qobject.h> #include <QtCore/qatomic.h> -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) #include <QtNetwork/qnetworkreply.h> #endif #include <QtQml/qqmlerror.h> @@ -154,7 +155,7 @@ protected: virtual void dataReceived(const Data &) = 0; virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*) = 0; virtual void done(); -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) virtual void networkError(QNetworkReply::NetworkError); #endif virtual void dependencyError(QQmlDataBlob *); @@ -320,16 +321,16 @@ public: private: friend class QQmlDataBlob; friend class QQmlTypeLoaderThread; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) friend class QQmlTypeLoaderNetworkReplyProxy; -#endif // QT_NO_NETWORK +#endif // qml_network void shutdownThread(); void loadThread(QQmlDataBlob *); void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &); void loadWithCachedUnitThread(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit); -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) void networkReplyFinished(QNetworkReply *); void networkReplyProgress(QNetworkReply *, qint64, qint64); @@ -366,7 +367,7 @@ private: QQmlEngine *m_engine; QQmlTypeLoaderThread *m_thread; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) NetworkReplies m_networkReplies; #endif TypeCache m_typeCache; diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 28c2588117..5c3ad6b2a6 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -55,17 +55,19 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlTypeWrapper); -Heap::QmlTypeWrapper::QmlTypeWrapper() - : mode(IncludeEnums) +void Heap::QmlTypeWrapper::init() { + Object::init(); + mode = IncludeEnums; object.init(); } -Heap::QmlTypeWrapper::~QmlTypeWrapper() +void Heap::QmlTypeWrapper::destroy() { if (typeNamespace) typeNamespace->release(); object.destroy(); + Object::destroy(); } bool QmlTypeWrapper::isSingleton() const diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index 7c5105b184..3b0ae04cc1 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -71,8 +71,8 @@ struct QmlTypeWrapper : Object { ExcludeEnums }; - QmlTypeWrapper(); - ~QmlTypeWrapper(); + void init(); + void destroy(); TypeNameMode mode; QQmlQPointer<QObject> object; diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index 2625f5af11..43b9e4bd3b 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -63,8 +63,14 @@ namespace Heap { struct QQmlValueTypeReference : QQmlValueTypeWrapper { - QQmlValueTypeReference() { object.init(); } - ~QQmlValueTypeReference() { object.destroy(); } + void init() { + QQmlValueTypeWrapper::init(); + object.init(); + } + void destroy() { + object.destroy(); + QQmlValueTypeWrapper::destroy(); + } QQmlQPointer<QObject> object; int property; }; @@ -74,8 +80,7 @@ struct QQmlValueTypeReference : QQmlValueTypeWrapper struct QQmlValueTypeReference : public QQmlValueTypeWrapper { V4_OBJECT2(QQmlValueTypeReference, QQmlValueTypeWrapper) - - static void destroy(Heap::Base *that); + V4_NEEDS_DESTROY bool readReferenceValue() const; }; @@ -86,12 +91,13 @@ DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeReference); using namespace QV4; -Heap::QQmlValueTypeWrapper::~QQmlValueTypeWrapper() +void Heap::QQmlValueTypeWrapper::destroy() { if (gadgetPtr) { valueType->metaType.destruct(gadgetPtr); ::operator delete(gadgetPtr); } + Object::destroy(); } void Heap::QQmlValueTypeWrapper::setValue(const QVariant &value) const @@ -140,7 +146,7 @@ bool QQmlValueTypeReference::readReferenceValue() const ::operator delete(d()->gadgetPtr); } d()->gadgetPtr =0; - d()->propertyCache = cache; + d()->setPropertyCache(cache); d()->valueType = QQmlValueTypeFactory::valueType(variantReferenceType); if (!cache) return false; @@ -163,7 +169,7 @@ bool QQmlValueTypeReference::readReferenceValue() const void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4) { - if (v4->valueTypeWrapperPrototype()->d()) + if (v4->valueTypeWrapperPrototype()->d_unchecked()) return; Scope scope(v4); @@ -180,7 +186,7 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *obj Scoped<QQmlValueTypeReference> r(scope, engine->memoryManager->allocObject<QQmlValueTypeReference>()); r->d()->object = object; r->d()->property = property; - r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); + r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject)); r->d()->valueType = QQmlValueTypeFactory::valueType(typeId); r->d()->gadgetPtr = 0; return r->asReturnedValue(); @@ -192,7 +198,7 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVaria initProto(engine); Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocObject<QQmlValueTypeWrapper>()); - r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); + r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject)); r->d()->valueType = QQmlValueTypeFactory::valueType(typeId); r->d()->gadgetPtr = 0; r->d()->setValue(value); @@ -218,19 +224,13 @@ bool QQmlValueTypeWrapper::toGadget(void *data) const return true; } -void QQmlValueTypeWrapper::destroy(Heap::Base *that) -{ - Heap::QQmlValueTypeWrapper *w = static_cast<Heap::QQmlValueTypeWrapper *>(that); - w->Heap::QQmlValueTypeWrapper::~QQmlValueTypeWrapper(); -} - bool QQmlValueTypeWrapper::isEqualTo(Managed *m, Managed *other) { Q_ASSERT(m && m->as<QQmlValueTypeWrapper>() && other); QV4::QQmlValueTypeWrapper *lv = static_cast<QQmlValueTypeWrapper *>(m); if (QV4::VariantObject *rv = other->as<VariantObject>()) - return lv->isEqual(rv->d()->data); + return lv->isEqual(rv->d()->data()); if (QV4::QQmlValueTypeWrapper *v = other->as<QQmlValueTypeWrapper>()) return lv->isEqual(v->toVariant()); @@ -243,7 +243,7 @@ PropertyAttributes QQmlValueTypeWrapper::query(const Managed *m, String *name) Q_ASSERT(m->as<const QQmlValueTypeWrapper>()); const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m); - QQmlPropertyData *result = r->d()->propertyCache->property(name, 0, 0); + QQmlPropertyData *result = r->d()->propertyCache()->property(name, 0, 0); return result ? Attr_Data : Attr_Invalid; } @@ -259,8 +259,8 @@ void QQmlValueTypeWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value return; } - if (that->d()->propertyCache) { - const QMetaObject *mo = that->d()->propertyCache->createMetaObject(); + if (that->d()->propertyCache()) { + const QMetaObject *mo = that->d()->propertyCache()->createMetaObject(); const int propertyCount = mo->propertyCount(); if (it->arrayIndex < static_cast<uint>(propertyCount)) { Scope scope(that->engine()); @@ -335,7 +335,7 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx) } else { result += QString::fromUtf8(QMetaType::typeName(w->d()->valueType->typeId)) + QLatin1Char('('); - const QMetaObject *mo = w->d()->propertyCache->metaObject(); + const QMetaObject *mo = w->d()->propertyCache()->metaObject(); const int propCount = mo->propertyCount(); for (int i = 0; i < propCount; ++i) { if (mo->property(i).isDesignable()) { @@ -362,7 +362,7 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha return Primitive::undefinedValue().asReturnedValue(); } - QQmlPropertyData *result = r->d()->propertyCache->property(name, 0, 0); + QQmlPropertyData *result = r->d()->propertyCache()->property(name, 0, 0); if (!result) return Object::get(m, name, hasProperty); @@ -381,7 +381,7 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha return QV4::Encode(constructor(v)); \ } - const QMetaObject *metaObject = r->d()->propertyCache->metaObject(); + const QMetaObject *metaObject = r->d()->propertyCache()->metaObject(); int index = result->coreIndex(); QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index); @@ -429,8 +429,8 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) writeBackPropertyType = writebackProperty.userType(); } - const QMetaObject *metaObject = r->d()->propertyCache->metaObject(); - const QQmlPropertyData *pd = r->d()->propertyCache->property(name, 0, 0); + const QMetaObject *metaObject = r->d()->propertyCache()->metaObject(); + const QQmlPropertyData *pd = r->d()->propertyCache()->property(name, 0, 0); if (!pd) return; @@ -494,9 +494,4 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) } } -void QQmlValueTypeReference::destroy(Heap::Base *that) -{ - static_cast<Heap::QQmlValueTypeReference*>(that)->Heap::QQmlValueTypeReference::~QQmlValueTypeReference(); -} - QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index 5ef480061d..fec54df770 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -66,14 +66,24 @@ namespace QV4 { namespace Heap { struct QQmlValueTypeWrapper : Object { - QQmlValueTypeWrapper() {} - ~QQmlValueTypeWrapper(); - QQmlRefPointer<QQmlPropertyCache> propertyCache; + void init() { Object::init(); } + void destroy(); + QQmlPropertyCache *propertyCache() const { return _propertyCache; } + void setPropertyCache(QQmlPropertyCache *c) { + if (c) + c->addref(); + if (_propertyCache) + _propertyCache->release(); + _propertyCache = c; + } mutable void *gadgetPtr; QQmlValueType *valueType; void setValue(const QVariant &value) const; QVariant toVariant() const; + +private: + QQmlPropertyCache *_propertyCache; }; } @@ -82,7 +92,7 @@ struct Q_QML_EXPORT QQmlValueTypeWrapper : Object { V4_OBJECT2(QQmlValueTypeWrapper, Object) V4_PROTOTYPE(valueTypeWrapperPrototype) - static void destroy(Heap::Base *b); + V4_NEEDS_DESTROY public: diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 6f56931e73..791870b831 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -503,9 +503,9 @@ QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id) const QV4::Scope scope(cache->engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); - if (!v || v->d()->data.type() != QVariant::Url) + if (!v || v->d()->data().type() != QVariant::Url) return QUrl(); - return v->d()->data.value<QUrl>(); + return v->d()->data().value<QUrl>(); } QDate QQmlVMEMetaObject::readPropertyAsDate(int id) const @@ -517,9 +517,9 @@ QDate QQmlVMEMetaObject::readPropertyAsDate(int id) const QV4::Scope scope(cache->engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); - if (!v || v->d()->data.type() != QVariant::Date) + if (!v || v->d()->data().type() != QVariant::Date) return QDate(); - return v->d()->data.value<QDate>(); + return v->d()->data().value<QDate>(); } QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id) @@ -531,9 +531,9 @@ QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id) QV4::Scope scope(cache->engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); - if (!v || v->d()->data.type() != QVariant::DateTime) + if (!v || v->d()->data().type() != QVariant::DateTime) return QDateTime(); - return v->d()->data.value<QDateTime>(); + return v->d()->data().value<QDateTime>(); } QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) const @@ -545,9 +545,9 @@ QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) const QV4::Scope scope(cache->engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); - if (!v || v->d()->data.type() != QVariant::SizeF) + if (!v || v->d()->data().type() != QVariant::SizeF) return QSizeF(); - return v->d()->data.value<QSizeF>(); + return v->d()->data().value<QSizeF>(); } QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id) const @@ -559,9 +559,9 @@ QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id) const QV4::Scope scope(cache->engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); - if (!v || v->d()->data.type() != QVariant::PointF) + if (!v || v->d()->data().type() != QVariant::PointF) return QPointF(); - return v->d()->data.value<QPointF>(); + return v->d()->data().value<QPointF>(); } QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) const @@ -586,12 +586,12 @@ QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) const QV4::Scope scope(cache->engine); QV4::Scoped<QV4::VariantObject> v(scope, *(md->data() + id)); - if (!v || (int)v->d()->data.userType() != qMetaTypeId<QList<QObject *> >()) { + if (!v || (int)v->d()->data().userType() != qMetaTypeId<QList<QObject *> >()) { QVariant variant(qVariantFromValue(QList<QObject*>())); v = cache->engine->newVariantObject(variant); *(md->data() + id) = v; } - return static_cast<QList<QObject *> *>(v->d()->data.data()); + return static_cast<QList<QObject *> *>(v->d()->data().data()); } QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) const @@ -603,9 +603,9 @@ QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) const QV4::Scope scope(cache->engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); - if (!v || v->d()->data.type() != QVariant::RectF) + if (!v || v->d()->data().type() != QVariant::RectF) return QRectF(); - return v->d()->data.value<QRectF>(); + return v->d()->data().value<QRectF>(); } #if defined(Q_OS_WINRT) && defined(_M_ARM) @@ -740,7 +740,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { QVariant propertyAsVariant; if (QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>()) - propertyAsVariant = v->d()->data; + propertyAsVariant = v->d()->data(); QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType); } break; @@ -816,10 +816,10 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * if (!v) { *(md->data() + id) = cache->engine->newVariantObject(QVariant()); v = (md->data() + id)->as<QV4::VariantObject>(); - QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data); + QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data()); } - needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data); - QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data); + needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data()); + QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data()); } break; case QV4::CompiledData::Property::Var: @@ -1009,7 +1009,7 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) const return QVariant::fromValue(wrapper->object()); const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); if (v) - return v->d()->data; + return v->d()->data(); return cache->engine->toVariant(*(md->data() + id), -1); } return QVariant(); @@ -1092,8 +1092,8 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) if (md) { QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); needActivate = (!v || - v->d()->data.userType() != value.userType() || - v->d()->data != value); + v->d()->data().userType() != value.userType() || + v->d()->data() != value); if (v) v->removeVmePropertyReference(); *(md->data() + id) = cache->engine->newVariantObject(value); diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index dd517374a5..b4be709b37 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -70,7 +70,7 @@ using namespace QV4; -#if !defined(QT_NO_XMLSTREAMREADER) && !defined(QT_NO_NETWORK) +#if !defined(QT_NO_XMLSTREAMREADER) && QT_CONFIG(qml_network) #define V4THROW_REFERENCE(string) { \ ScopedObject error(scope, ctx->engine()->newReferenceErrorObject(QStringLiteral(string))); \ @@ -174,33 +174,43 @@ public: namespace Heap { struct NamedNodeMap : Object { - NamedNodeMap(NodeImpl *data, const QList<NodeImpl *> &list); - ~NamedNodeMap() { + void init(NodeImpl *data, const QList<NodeImpl *> &list); + void destroy() { + delete listPtr; if (d) d->release(); + Object::destroy(); } - QList<NodeImpl *> list; // Only used in NamedNodeMap + QList<NodeImpl *> &list() { + if (listPtr == nullptr) + listPtr = new QList<NodeImpl *>; + return *listPtr; + } + + QList<NodeImpl *> *listPtr; // Only used in NamedNodeMap NodeImpl *d; }; struct NodeList : Object { - NodeList(NodeImpl *data); - ~NodeList() { + void init(NodeImpl *data); + void destroy() { if (d) d->release(); + Object::destroy(); } NodeImpl *d; }; struct NodePrototype : Object { - NodePrototype(); + void init(); }; struct Node : Object { - Node(NodeImpl *data); - ~Node() { + void init(NodeImpl *data); + void destroy() { if (d) d->release(); + Object::destroy(); } NodeImpl *d; }; @@ -221,10 +231,11 @@ public: static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); }; -Heap::NamedNodeMap::NamedNodeMap(NodeImpl *data, const QList<NodeImpl *> &list) - : list(list) - , d(data) +void Heap::NamedNodeMap::init(NodeImpl *data, const QList<NodeImpl *> &list) { + Object::init(); + d = data; + this->list() = list; if (d) d->addref(); } @@ -246,9 +257,10 @@ public: }; -Heap::NodeList::NodeList(NodeImpl *data) - : d(data) +void Heap::NodeList::init(NodeImpl *data) { + Object::init(); + d = data; if (d) d->addref(); } @@ -287,8 +299,9 @@ public: }; -Heap::NodePrototype::NodePrototype() +void Heap::NodePrototype::init() { + Object::init(); Scope scope(internalClass->engine); ScopedObject o(scope, this); @@ -320,9 +333,10 @@ struct Node : public Object bool isNull() const; }; -Heap::Node::Node(NodeImpl *data) - : d(data) +void Heap::Node::init(NodeImpl *data) { + Object::init(); + d = data; if (d) d->addref(); } @@ -878,10 +892,10 @@ ReturnedValue NamedNodeMap::getIndexed(const Managed *m, uint index, bool *hasPr const NamedNodeMap *r = static_cast<const NamedNodeMap *>(m); QV4::ExecutionEngine *v4 = r->engine(); - if ((int)index < r->d()->list.count()) { + if ((int)index < r->d()->list().count()) { if (hasProperty) *hasProperty = true; - return Node::create(v4, r->d()->list.at(index)); + return Node::create(v4, r->d()->list().at(index)); } if (hasProperty) *hasProperty = false; @@ -896,14 +910,14 @@ ReturnedValue NamedNodeMap::get(const Managed *m, String *name, bool *hasPropert name->makeIdentifier(v4); if (name->equals(v4->id_length())) - return Primitive::fromInt32(r->d()->list.count()).asReturnedValue(); + return Primitive::fromInt32(r->d()->list().count()).asReturnedValue(); QString str = name->toQString(); - for (int ii = 0; ii < r->d()->list.count(); ++ii) { - if (r->d()->list.at(ii)->name == str) { + for (int ii = 0; ii < r->d()->list().count(); ++ii) { + if (r->d()->list().at(ii)->name == str) { if (hasProperty) *hasProperty = true; - return Node::create(v4, r->d()->list.at(ii)); + return Node::create(v4, r->d()->list().at(ii)); } } @@ -1588,15 +1602,20 @@ namespace QV4 { namespace Heap { struct QQmlXMLHttpRequestWrapper : Object { - QQmlXMLHttpRequestWrapper(QQmlXMLHttpRequest *request); - ~QQmlXMLHttpRequestWrapper() { + void init(QQmlXMLHttpRequest *request) { + Object::init(); + this->request = request; + } + + void destroy() { delete request; + Object::destroy(); } QQmlXMLHttpRequest *request; }; struct QQmlXMLHttpRequestCtor : FunctionObject { - QQmlXMLHttpRequestCtor(ExecutionEngine *engine); + void init(ExecutionEngine *engine); Pointer<Object> proto; }; @@ -1609,11 +1628,6 @@ struct QQmlXMLHttpRequestWrapper : public Object V4_NEEDS_DESTROY }; -Heap::QQmlXMLHttpRequestWrapper::QQmlXMLHttpRequestWrapper(QQmlXMLHttpRequest *request) - : request(request) -{ -} - struct QQmlXMLHttpRequestCtor : public FunctionObject { V4_OBJECT2(QQmlXMLHttpRequestCtor, FunctionObject) @@ -1665,9 +1679,9 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject DEFINE_OBJECT_VTABLE(QQmlXMLHttpRequestWrapper); -Heap::QQmlXMLHttpRequestCtor::QQmlXMLHttpRequestCtor(ExecutionEngine *engine) - : Heap::FunctionObject(engine->rootContext(), QStringLiteral("XMLHttpRequest")) +void Heap::QQmlXMLHttpRequestCtor::init(ExecutionEngine *engine) { + Heap::FunctionObject::init(engine->rootContext(), QStringLiteral("XMLHttpRequest")); Scope scope(engine); Scoped<QV4::QQmlXMLHttpRequestCtor> ctor(scope, this); @@ -2043,6 +2057,6 @@ void *qt_add_qmlxmlhttprequest(ExecutionEngine *v4) QT_END_NAMESPACE -#endif // QT_NO_XMLSTREAMREADER && QT_NO_NETWORK +#endif // QT_NO_XMLSTREAMREADER && qml_network #include <qqmlxmlhttprequest.moc> diff --git a/src/qml/qml/qqmlxmlhttprequest_p.h b/src/qml/qml/qqmlxmlhttprequest_p.h index df30873915..fdb6194537 100644 --- a/src/qml/qml/qqmlxmlhttprequest_p.h +++ b/src/qml/qml/qqmlxmlhttprequest_p.h @@ -55,7 +55,7 @@ #include <QtCore/qglobal.h> #include <private/qqmlglobal_p.h> -#if !defined(QT_NO_XMLSTREAMREADER) && !defined(QT_NO_NETWORK) +#if !defined(QT_NO_XMLSTREAMREADER) && QT_CONFIG(qml_network) QT_BEGIN_NAMESPACE @@ -64,7 +64,7 @@ void qt_rem_qmlxmlhttprequest(QV4::ExecutionEngine *engine, void *); QT_END_NAMESPACE -#endif // QT_NO_XMLSTREAMREADER && QT_NO_NETWORK +#endif // QT_NO_XMLSTREAMREADER && qml_network #endif // QQMLXMLHTTPREQUEST_P_H diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 222b61ae49..cf0fd57773 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -91,10 +91,11 @@ struct StaticQtMetaObject : public QObject { return &staticQtMetaObject; } }; -Heap::QtObject::QtObject(QQmlEngine *qmlEngine) - : enumeratorIterator(0) - , keyIterator(0) +void Heap::QtObject::init(QQmlEngine *qmlEngine) { + Heap::Object::init(); + enumeratorIterator = 0; + keyIterator = 0; Scope scope(internalClass->engine); ScopedObject o(scope, this); @@ -1302,17 +1303,18 @@ ReturnedValue QtObject::method_locale(CallContext *ctx) return QQmlLocale::locale(ctx->engine(), code); } -Heap::QQmlBindingFunction::QQmlBindingFunction(const QV4::FunctionObject *originalFunction) - : QV4::Heap::FunctionObject(originalFunction->scope(), originalFunction->name()) +void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *originalFunction) { + QV4::Heap::FunctionObject::init(originalFunction->scope(), originalFunction->name()); + bindingLocation = new QQmlSourceLocation; this->originalFunction = originalFunction->d(); } void QQmlBindingFunction::initBindingLocation() { QV4::StackFrame frame = engine()->currentStackFrame(); - d()->bindingLocation.sourceFile = frame.source; - d()->bindingLocation.line = frame.line; + d()->bindingLocation->sourceFile = frame.source; + d()->bindingLocation->line = frame.line; } void QQmlBindingFunction::call(const Managed *that, Scope &scope, CallData *callData) @@ -1436,8 +1438,9 @@ ReturnedValue QtObject::method_get_styleHints(CallContext *ctx) } -QV4::Heap::ConsoleObject::ConsoleObject() +void QV4::Heap::ConsoleObject::init() { + Object::init(); QV4::Scope scope(internalClass->engine); QV4::ScopedObject o(scope, this); @@ -1559,6 +1562,8 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *c return QV4::Encode::undefined(); } +DEFINE_OBJECT_VTABLE(ConsoleObject); + QV4::ReturnedValue ConsoleObject::method_error(CallContext *ctx) { return writeToConsole(Error, ctx); diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index 8c0759679a..7602a92582 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -64,7 +64,7 @@ namespace QV4 { namespace Heap { struct QtObject : Object { - QtObject(QQmlEngine *qmlEngine); + void init(QQmlEngine *qmlEngine); QObject *platform; QObject *application; @@ -77,14 +77,18 @@ struct QtObject : Object { }; struct ConsoleObject : Object { - ConsoleObject(); + void init(); }; struct QQmlBindingFunction : FunctionObject { - QQmlBindingFunction(const QV4::FunctionObject *originalFunction); + void init(const QV4::FunctionObject *originalFunction); + void destroy() { + delete bindingLocation; + Object::destroy(); + } Pointer<FunctionObject> originalFunction; // Set when the binding is created later - QQmlSourceLocation bindingLocation; + QQmlSourceLocation *bindingLocation; }; } @@ -145,9 +149,7 @@ private: struct ConsoleObject : Object { - typedef Heap::ConsoleObject Data; - const Data *d() const { return static_cast<const Data *>(Object::d()); } - Data *d() { return static_cast<Data *>(Object::d()); } + V4_OBJECT2(ConsoleObject, Object) static ReturnedValue method_error(CallContext *ctx); static ReturnedValue method_log(CallContext *ctx); diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index f15020f6c9..b0599dd0a2 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -160,8 +160,10 @@ QV8Engine::~QV8Engine() qDeleteAll(m_extensionData); m_extensionData.clear(); +#if !defined(QT_NO_XMLSTREAMREADER) && QT_CONFIG(qml_network) qt_rem_qmlxmlhttprequest(m_v4Engine, m_xmlHttpRequestData); m_xmlHttpRequestData = 0; +#endif delete m_listModelData; m_listModelData = 0; @@ -169,7 +171,7 @@ QV8Engine::~QV8Engine() delete m_v4Engine; } -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) QNetworkAccessManager *QV8Engine::networkAccessManager() { return QQmlEnginePrivate::get(m_engine)->getNetworkAccessManager(); @@ -193,7 +195,7 @@ void QV8Engine::initializeGlobal() QQmlDateExtension::registerExtension(m_v4Engine); QQmlNumberExtension::registerExtension(m_v4Engine); -#if !defined(QT_NO_XMLSTREAMREADER) && !defined(QT_NO_NETWORK) +#if !defined(QT_NO_XMLSTREAMREADER) && QT_CONFIG(qml_network) qt_add_domexceptions(m_v4Engine); m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(m_v4Engine); #endif diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index 390831609b..0cbe34fd30 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -188,7 +188,7 @@ public: void freezeObject(const QV4::Value &value); -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) // Return the network access manager for this engine. By default this returns the network // access manager of the QQmlEngine. It is overridden in the case of a threaded v8 // instance (like in WorkerScript). diff --git a/src/qml/qtqmlglobal.h b/src/qml/qtqmlglobal.h index 34191d06b2..89228b7777 100644 --- a/src/qml/qtqmlglobal.h +++ b/src/qml/qtqmlglobal.h @@ -41,6 +41,10 @@ #define QTQMLGLOBAL_H #include <QtCore/qglobal.h> +#include <QtQml/qtqml-config.h> +#if QT_CONFIG(qml_network) +#include <QtNetwork/qtnetworkglobal.h> +#endif QT_BEGIN_NAMESPACE diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h index 1b0872298d..63585fd62e 100644 --- a/src/qml/qtqmlglobal_p.h +++ b/src/qml/qtqmlglobal_p.h @@ -51,7 +51,9 @@ // We mean it. // -#include "qtqmlglobal.h" +#include <QtCore/private/qglobal_p.h> +#include <QtQml/private/qtqml-config_p.h> +#include <QtQml/qtqmlglobal.h> #if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) # define Q_QML_PRIVATE_EXPORT diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index be4258cdfd..c4fabbedcc 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -62,21 +62,26 @@ namespace QV4 { namespace Heap { struct DelegateModelGroupFunction : FunctionObject { - DelegateModelGroupFunction(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg)); + void init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg)); - uint flag; QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg); + uint flag; }; struct QQmlDelegateModelGroupChange : Object { - QQmlDelegateModelGroupChange() {} + void init() { Object::init(); } - QQmlChangeSet::Change change; + QQmlChangeSet::ChangeData change; }; struct QQmlDelegateModelGroupChangeArray : Object { - QQmlDelegateModelGroupChangeArray(const QVector<QQmlChangeSet::Change> &changes); - QVector<QQmlChangeSet::Change> changes; + void init(const QVector<QQmlChangeSet::Change> &changes); + void destroy() { + delete changes; + Object::destroy(); + } + + QVector<QQmlChangeSet::Change> *changes; }; @@ -105,11 +110,11 @@ struct DelegateModelGroupFunction : QV4::FunctionObject } }; -Heap::DelegateModelGroupFunction::DelegateModelGroupFunction(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg)) - : QV4::Heap::FunctionObject(scope, QStringLiteral("DelegateModelGroupFunction")) - , flag(flag) - , code(code) +void Heap::DelegateModelGroupFunction::init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg)) { + QV4::Heap::FunctionObject::init(scope, QStringLiteral("DelegateModelGroupFunction")); + this->flag = flag; + this->code = code; } } @@ -1865,9 +1870,10 @@ QV4::ReturnedValue QQmlDelegateModelItem::get_index(QQmlDelegateModelItem *thisI DEFINE_OBJECT_VTABLE(QQmlDelegateModelItemObject); -QV4::Heap::QQmlDelegateModelItemObject::~QQmlDelegateModelItemObject() +void QV4::Heap::QQmlDelegateModelItemObject::destroy() { item->Dispose(); + Object::destroy(); } @@ -3256,8 +3262,8 @@ public: return engine->memoryManager->allocObject<QQmlDelegateModelGroupChangeArray>(changes); } - quint32 count() const { return d()->changes.count(); } - const QQmlChangeSet::Change &at(int index) const { return d()->changes.at(index); } + quint32 count() const { return d()->changes->count(); } + const QQmlChangeSet::Change &at(int index) const { return d()->changes->at(index); } static QV4::ReturnedValue getIndexed(const QV4::Managed *m, uint index, bool *hasProperty) { @@ -3299,9 +3305,10 @@ public: } }; -QV4::Heap::QQmlDelegateModelGroupChangeArray::QQmlDelegateModelGroupChangeArray(const QVector<QQmlChangeSet::Change> &changes) - : changes(changes) +void QV4::Heap::QQmlDelegateModelGroupChangeArray::init(const QVector<QQmlChangeSet::Change> &changes) { + Object::init(); + this->changes = new QVector<QQmlChangeSet::Change>(changes); QV4::Scope scope(internalClass->engine); QV4::ScopedObject o(scope, this); o->setArrayType(QV4::Heap::ArrayData::Custom); diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h index 7031cf779c..f4ffdf38aa 100644 --- a/src/qml/types/qqmldelegatemodel_p_p.h +++ b/src/qml/types/qqmldelegatemodel_p_p.h @@ -160,8 +160,8 @@ protected: namespace QV4 { namespace Heap { struct QQmlDelegateModelItemObject : Object { - inline QQmlDelegateModelItemObject(QQmlDelegateModelItem *item); - ~QQmlDelegateModelItemObject(); + inline void init(QQmlDelegateModelItem *item); + void destroy(); QQmlDelegateModelItem *item; }; @@ -174,9 +174,10 @@ struct QQmlDelegateModelItemObject : QV4::Object V4_NEEDS_DESTROY }; -QV4::Heap::QQmlDelegateModelItemObject::QQmlDelegateModelItemObject(QQmlDelegateModelItem *item) - : item(item) +void QV4::Heap::QQmlDelegateModelItemObject::init(QQmlDelegateModelItem *item) { + Object::init(); + this->item = item; } diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h index 887f5a1edc..ddf77e52c0 100644 --- a/src/qml/types/qqmllistmodel_p_p.h +++ b/src/qml/types/qqmllistmodel_p_p.h @@ -162,11 +162,13 @@ namespace QV4 { namespace Heap { struct ModelObject : public QObjectWrapper { - ModelObject(QObject *object, QQmlListModel *model, int elementIndex) - : QObjectWrapper(object) - , m_model(model) - , m_elementIndex(elementIndex) - {} + void init(QObject *object, QQmlListModel *model, int elementIndex) + { + QObjectWrapper::init(object); + m_model = model; + m_elementIndex = elementIndex; + } + void destroy() { QObjectWrapper::destroy(); } QQmlListModel *m_model; int m_elementIndex; }; @@ -180,6 +182,7 @@ struct ModelObject : public QObjectWrapper static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); V4_OBJECT2(ModelObject, QObjectWrapper) + V4_NEEDS_DESTROY }; } // namespace QV4 diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp index b77675df0e..cdcc894da9 100644 --- a/src/qml/types/qquickworkerscript.cpp +++ b/src/qml/types/qquickworkerscript.cpp @@ -54,7 +54,7 @@ #include <QtCore/qdatetime.h> #include <QtQml/qqmlinfo.h> #include <QtQml/qqmlfile.h> -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) #include <QtNetwork/qnetworkaccessmanager.h> #include "qqmlnetworkaccessmanagerfactory.h" #endif @@ -144,7 +144,7 @@ public: void init(); -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) QNetworkAccessManager *networkAccessManager() override; #endif @@ -155,7 +155,7 @@ public: QV4::PersistentValue onmessage; private: QV4::PersistentValue createsend; -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) QNetworkAccessManager *accessManager; #endif }; @@ -202,7 +202,7 @@ private: QQuickWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QQuickWorkerScriptEnginePrivate *parent) : QV8Engine(0), p(parent) -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) , accessManager(0) #endif { @@ -211,7 +211,7 @@ QQuickWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QQuickWorkerScriptEn QQuickWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine() { -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) delete accessManager; #endif } @@ -274,7 +274,7 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::WorkerEngine::sendFunction(i return scope.result.asReturnedValue(); } -#ifndef QT_NO_NETWORK +#if QT_CONFIG(qml_network) QNetworkAccessManager *QQuickWorkerScriptEnginePrivate::WorkerEngine::networkAccessManager() { if (!accessManager) { diff --git a/src/qml/util/qqmlchangeset_p.h b/src/qml/util/qqmlchangeset_p.h index b7a637fb2e..8e1fa3f9f2 100644 --- a/src/qml/util/qqmlchangeset_p.h +++ b/src/qml/util/qqmlchangeset_p.h @@ -68,16 +68,31 @@ public: int offset; }; - struct Change + // The storrage for Change (below). This struct is trivial, which it has to be in order to store + // it in a QV4::Heap::Base object. The Change struct doesn't add any storage fields, so it is + // safe to cast ChangeData to/from Change. + struct ChangeData { - Change() : index(0), count(0), moveId(-1) {} - Change(int index, int count, int moveId = -1, int offset = 0) - : index(index), count(count), moveId(moveId), offset(offset) {} - int index; int count; int moveId; int offset; + }; + + struct Change: ChangeData + { + Change() { + index = 0; + count = 0; + moveId = -1; + offset = 0; + } + Change(int index, int count, int moveId = -1, int offset = 0) { + this->index = index; + this->count = count; + this->moveId = moveId; + this->offset = offset; + } bool isMove() const { return moveId >= 0; } |