From f96b77bf46a29b1c09d6ebff2f18a475c7ca0b2f Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 9 Jan 2017 17:06:25 +0100 Subject: [PATCH 01/24] add QQmlEngine::offlineStorageDatabaseFilePath(db), use in LocalStorage This is C++ API to get the actual storage path for a particular database. [ChangeLog][QtQml] Added QQmlEngine::offlineStorageDatabaseFilePath(dbName) to allow getting the actual storage path for a particular database. Task-number: QTBUG-52013 Change-Id: I1cbd9454c537f08c97f4dafc06fd6b14e81c51af Reviewed-by: Simon Hausmann --- src/imports/localstorage/plugin.cpp | 37 +++++--------------- src/qml/qml/qqmlengine.cpp | 21 +++++++++++ src/qml/qml/qqmlengine.h | 1 + src/qml/qml/qqmlengine_p.h | 1 + tests/auto/qml/qqmlengine/tst_qqmlengine.cpp | 29 +++++++++++++++ 5 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index d3ea93c80a..433b7fe430 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -219,24 +219,6 @@ QQmlSqlDatabaseData::~QQmlSqlDatabaseData() { } -static QString qmlsqldatabase_databasesPath(QV4::ExecutionEngine *engine) -{ - return engine->qmlEngine()->offlineStoragePath() + - QDir::separator() + QLatin1String("Databases"); -} - -static void qmlsqldatabase_initDatabasesPath(QV4::ExecutionEngine *engine) -{ - QString databasesPath = qmlsqldatabase_databasesPath(engine); - if (!QDir().mkpath(databasesPath)) - qWarning() << "LocalStorage: can't create path - " << databasesPath; -} - -static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV4::ExecutionEngine *engine) -{ - return qmlsqldatabase_databasesPath(engine) + QDir::separator() + connectionName; -} - static ReturnedValue qmlsqldatabase_rows_index(const QQmlSqlDatabaseWrapper *r, ExecutionEngine *v4, quint32 index, bool *hasProperty = 0) { Scope scope(v4); @@ -450,7 +432,8 @@ static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx) if (ok) { *w->d()->version = to_version; #if QT_CONFIG(settings) - QSettings ini(qmlsqldatabase_databaseFile(db.connectionName(), scope.engine) + QLatin1String(".ini"), QSettings::IniFormat); + const QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(scope.engine->qmlEngine()); + QSettings ini(enginePrivate->offlineStorageDatabaseDirectory() + db.connectionName() + QLatin1String(".ini"), QSettings::IniFormat); ini.setValue(QLatin1String("Version"), to_version); #endif } @@ -723,24 +706,20 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args) if (scope.engine->qmlEngine()->offlineStoragePath().isEmpty()) V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled.")); - qmlsqldatabase_initDatabasesPath(scope.engine); - - QSqlDatabase database; - QV4::ScopedValue v(scope); QString dbname = (v = (*args)[0])->toQStringNoThrow(); QString dbversion = (v = (*args)[1])->toQStringNoThrow(); QString dbdescription = (v = (*args)[2])->toQStringNoThrow(); int dbestimatedsize = (v = (*args)[3])->toInt32(); FunctionObject *dbcreationCallback = (v = (*args)[4])->as(); - - QCryptographicHash md5(QCryptographicHash::Md5); - md5.addData(dbname.toUtf8()); - QString dbid(QLatin1String(md5.result().toHex())); - - QString basename = qmlsqldatabase_databaseFile(dbid, scope.engine); + QString basename = args->v4engine()->qmlEngine()->offlineStorageDatabaseFilePath(dbname); + QFileInfo dbFile(basename); + if (!QDir().mkpath(dbFile.dir().absolutePath())) + V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("LocalStorage: can't create path ") + dbFile.dir().absolutePath()); + QString dbid = dbFile.fileName(); bool created = false; QString version = dbversion; + QSqlDatabase database; { QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat); diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index e1fa97b52f..fe3f1dbaf1 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -2178,6 +2178,27 @@ QString QQmlEngine::offlineStoragePath() const return d->offlineStoragePath; } +/*! + Returns the file path where a \l{QtQuick.LocalStorage}{Local Storage} + database with the identifier \a databaseName is (or would be) located. + + \sa LocalStorage.openDatabaseSync() + \since 5.9 +*/ +QString QQmlEngine::offlineStorageDatabaseFilePath(const QString &databaseName) const +{ + Q_D(const QQmlEngine); + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(databaseName.toUtf8()); + return d->offlineStorageDatabaseDirectory() + QLatin1String(md5.result().toHex()); +} + +QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const +{ + Q_Q(const QQmlEngine); + return q->offlineStoragePath() + QDir::separator() + QLatin1String("Databases") + QDir::separator(); +} + QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion) { QList types; diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index 3102a20fac..8cada954fe 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -136,6 +136,7 @@ public: void setOfflineStoragePath(const QString& dir); QString offlineStoragePath() const; + QString offlineStorageDatabaseFilePath(const QString &databaseName) const; QUrl baseUrl() const; void setBaseUrl(const QUrl &); diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 916566b6c7..1bdeacd524 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -205,6 +205,7 @@ public: inline void deleteInEngineThread(T *); template inline static void deleteInEngineThread(QQmlEngine *, T *); + QString offlineStorageDatabaseDirectory() const; // These methods may be called from the loader thread inline QQmlPropertyCache *cache(QQmlType *, int); diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index 9c155eda5b..e170920486 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -56,6 +56,7 @@ private slots: void baseUrl(); void contextForObject(); void offlineStoragePath(); + void offlineDatabaseStoragePath(); void clearComponentCache(); void trimComponentCache(); void trimComponentCache_data(); @@ -252,6 +253,34 @@ void tst_qqmlengine::offlineStoragePath() QCOMPARE(engine.offlineStoragePath(), QDir::homePath()); } +void tst_qqmlengine::offlineDatabaseStoragePath() +{ + // Without these set, QDesktopServices::storageLocation returns + // strings with extra "//" at the end. We set them to ignore this problem. + qApp->setApplicationName("tst_qqmlengine"); + qApp->setOrganizationName("QtProject"); + qApp->setOrganizationDomain("www.qt-project.org"); + + QQmlEngine engine; + QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation); + const QString databaseName = QLatin1String("foo"); + QString databaseLocation = engine.offlineStorageDatabaseFilePath(databaseName); + QCOMPARE(dataLocation.isEmpty(), databaseLocation.isEmpty()); + + QDir dir(dataLocation); + dir.mkpath("QML"); + dir.cd("QML"); + dir.mkpath("OfflineStorage"); + dir.cd("OfflineStorage"); + dir.mkpath("Databases"); + dir.cd("Databases"); + QCOMPARE(QFileInfo(databaseLocation).dir().path(), dir.path()); + + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(databaseName.toUtf8()); + QCOMPARE(databaseLocation, QDir::toNativeSeparators(dir.filePath(QLatin1String(md5.result().toHex())))); +} + void tst_qqmlengine::clearComponentCache() { QQmlEngine engine; From b0ced704bcaeb6dc71622c9ce87b78f3b5bd827c Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Thu, 2 Feb 2017 14:22:08 +0100 Subject: [PATCH 02/24] Canvas Item: Prevent polish loop when calling requestAnimationFrame Currently if you call requestAnimationFrame within the callback given by requestAnimationFrame there is a polish loop. This is however the common way when using Canvas2D in the browser to get screen refresh rate animations. This patch makes sure that polish won't be called when processing polish items by calling polish indirectly. Task-number: QTBUG-55778 Change-Id: Ib96e39f7ca3cecc33609976e9049cc309768f9f7 Reviewed-by: Laszlo Agocs --- .../items/context2d/qquickcanvasitem.cpp | 20 ++++++++++++++++++- .../items/context2d/qquickcanvasitem_p.h | 2 ++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp index b772ed97d2..1167f408f5 100644 --- a/src/quick/items/context2d/qquickcanvasitem.cpp +++ b/src/quick/items/context2d/qquickcanvasitem.cpp @@ -640,6 +640,17 @@ void QQuickCanvasItem::releaseResources() } } +bool QQuickCanvasItem::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::PolishRequest: + polish(); + return true; + default: + return QQuickItem::event(event); + } +} + void QQuickCanvasItem::invalidateSceneGraph() { Q_D(QQuickCanvasItem); @@ -651,6 +662,12 @@ void QQuickCanvasItem::invalidateSceneGraph() d->textureProvider = 0; } +void QQuickCanvasItem::schedulePolish() +{ + auto polishRequestEvent = new QEvent(QEvent::PolishRequest); + QCoreApplication::postEvent(this, polishRequestEvent); +} + void QQuickCanvasItem::componentComplete() { QQuickItem::componentComplete(); @@ -892,8 +909,9 @@ void QQuickCanvasItem::requestAnimationFrame(QQmlV4Function *args) d->animationCallbacks.insert(++id, QV4::PersistentValue(scope.engine, f->asReturnedValue())); + // QTBUG-55778: Calling polish directly here can lead to a polish loop if (isVisible()) - polish(); + schedulePolish(); args->setReturnValue(QV4::Encode(id)); } diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h index 8af84d0e7c..217ae9bb69 100644 --- a/src/quick/items/context2d/qquickcanvasitem_p.h +++ b/src/quick/items/context2d/qquickcanvasitem_p.h @@ -182,6 +182,7 @@ private Q_SLOTS: void sceneGraphInitialized(); void checkAnimationCallbacks(); void invalidateSceneGraph(); + void schedulePolish(); protected: void componentComplete() Q_DECL_OVERRIDE; @@ -190,6 +191,7 @@ protected: QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; void releaseResources() Q_DECL_OVERRIDE; + bool event(QEvent *event) Q_DECL_OVERRIDE; private: Q_DECLARE_PRIVATE(QQuickCanvasItem) Q_INVOKABLE void delayedCreate(); From ecd4c83ef764f086f2e101b4201484f3d828c0e3 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 3 Feb 2017 10:10:52 +0100 Subject: [PATCH 03/24] Allow to pass all the relevant info to QQuickPixmap::isCached If we don't allow to pass the QQuickImageProviderOptions to the isCached we are missing one of the three components that identify if the pixmap is actually cached. Old code is ok for the QQuickAnimatedImagePrivate use case since it always creates QQuickPixmap with the default QQuickImageProviderOptions options, but if someone else wants to use QQuickPixmap::isCached they will need to be able to pass the options part of the cache key. Change-Id: I3153ad9ed30e7332b5cb4896dcebd408f2bd9afe Reviewed-by: Robin Burchell --- src/quick/items/qquickanimatedimage.cpp | 2 +- src/quick/util/qquickpixmapcache.cpp | 4 ++-- src/quick/util/qquickpixmapcache_p.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp index a1833081c8..22ea4774be 100644 --- a/src/quick/items/qquickanimatedimage.cpp +++ b/src/quick/items/qquickanimatedimage.cpp @@ -67,7 +67,7 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine .arg(current)); } if (!requestedUrl.isEmpty()) { - if (QQuickPixmap::isCached(requestedUrl, QSize())) + if (QQuickPixmap::isCached(requestedUrl, QSize(), QQuickImageProviderOptions())) pixmap = new QQuickPixmap(engine, requestedUrl); else pixmap = new QQuickPixmap(requestedUrl, _movie->currentImage()); diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index be6d4d18bd..be27cba989 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -1541,9 +1541,9 @@ void QQuickPixmap::clear(QObject *obj) } } -bool QQuickPixmap::isCached(const QUrl &url, const QSize &requestSize) +bool QQuickPixmap::isCached(const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &options) { - QQuickPixmapKey key = { &url, &requestSize, QQuickImageProviderOptions() }; + QQuickPixmapKey key = { &url, &requestSize, options }; QQuickPixmapStore *store = pixmapStore(); return store->m_cache.contains(key); diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h index a867771755..93d5a1cf56 100644 --- a/src/quick/util/qquickpixmapcache_p.h +++ b/src/quick/util/qquickpixmapcache_p.h @@ -175,7 +175,7 @@ public: bool connectDownloadProgress(QObject *, int); static void purgeCache(); - static bool isCached(const QUrl &url, const QSize &requestSize); + static bool isCached(const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &options); static const QLatin1String itemGrabberScheme; From 7834c673511e77ce4211d4ae38e6e3d4dffded19 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 3 Feb 2017 11:41:33 +0100 Subject: [PATCH 04/24] Add missing include to qmlengine.cpp Fix error: qml\qqmlengine.cpp: In member function 'QString QQmlEngine::offlineStorageDatabaseFilePath(const QString&) const': qml\qqmlengine.cpp:2191:51: error: variable 'QCryptographicHash md5' has initializer but incomplete type QCryptographicHash md5(QCryptographicHash::Md5); ^ qml\qqmlengine.cpp:2191:28: error: incomplete type 'QCryptographicHash' used in nested name specifier QCryptographicHash md5(QCryptographicHash::Md5); Change-Id: I1f116758fe061a6bad4718cc264cf608dd3cc0b5 Reviewed-by: Simon Hausmann Reviewed-by: J-P Nurmi --- src/qml/qml/qqmlengine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index fe3f1dbaf1..7fb94da9ce 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -65,6 +65,7 @@ #include #include #include +#include #include #include #include From 790cfb2bb26990c8345c860d6a23e4116df92f48 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Mon, 30 Jan 2017 13:29:09 +0100 Subject: [PATCH 05/24] Doc: added doc for parameter window Undocumented parameter 'window' in QSGRendererInterface::getResource() Change-Id: I13cd520ad0b06abe1ad76be7aec83eae5c3e4d7c Reviewed-by: Martin Smith --- src/quick/scenegraph/coreapi/qsgrendererinterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp index 3b0b2faf97..0f49e615e4 100644 --- a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp @@ -127,7 +127,7 @@ QSGRendererInterface::~QSGRendererInterface() */ /*! - Queries a graphics \a resource. Returns null when the resource in question is + Queries a graphics \a resource in \a window. Returns null when the resource in question is not supported or not available. When successful, the returned pointer is either a direct pointer to an From b7090f1334ac7b8ad2548f084c749eda4fa82451 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Fri, 3 Feb 2017 08:45:12 +0100 Subject: [PATCH 06/24] Fix a crash in setInternalClass Revealed by the ES6 testsuite, ./test/built-ins/Object/freeze/15.2.3.9-2-1.js and probably others. We cannot unconditionally dereference memberData, it may not always exist. ES6 tests test/built-ins/Object/freeze before: === Summary === - Ran 92 tests - Passed 66 tests (71.7%) - Failed 26 tests (28.3%) after: === Summary === - Ran 92 tests - Passed 90 tests (97.8%) - Failed 2 tests (2.2%) Change-Id: I22a6c9ca081394ba15edfde09f73769eb3ce47b3 Reviewed-by: Simon Hausmann Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4object.cpp | 3 ++- .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 2f664c6398..12157af728 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -61,7 +61,8 @@ DEFINE_OBJECT_VTABLE(Object); void Object::setInternalClass(InternalClass *ic) { d()->internalClass = ic; - if ((!d()->memberData && ic->size) || (d()->memberData->size < ic->size)) + bool hasMD = d()->memberData != nullptr; + if ((!hasMD && ic->size) || (hasMD && d()->memberData->size < ic->size)) d()->memberData = MemberData::allocate(ic->engine, ic->size, d()->memberData); } diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 89dac33671..83725dbf12 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -333,6 +333,7 @@ private slots: void stringify_qtbug_50592(); void instanceof_data(); void instanceof(); + void freeze_empty_object(); private: // static void propertyVarWeakRefCallback(v8::Persistent object, void* parameter); @@ -8183,6 +8184,19 @@ void tst_qqmlecmascript::instanceof() } } +void tst_qqmlecmascript::freeze_empty_object() +{ + // this shouldn't crash + QJSEngine engine; + QJSValue v = engine.evaluate(QString::fromLatin1( + "var obj = {};\n" + "Object.freeze(obj);\n" + )); + QVERIFY(!v.isError()); + QCOMPARE(v.toBool(), true); +} + + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" From f89e7596b76ea4d3444f187e425ce7fec9d3a635 Mon Sep 17 00:00:00 2001 From: Frederik Schwarzer Date: Mon, 6 Feb 2017 11:21:31 +0100 Subject: [PATCH 07/24] QDoc: sync description with described code layout The table with several code examples was rearranged once and the code description still refers to the old layout. Old: left-right New: upper-lower but with labels for C++ and QML code so it's safe to refer to the labels. Change-Id: I0edb9adc747b5081ec52445e132ce38784703e46 Reviewed-by: Frederik Gladhorn --- src/qml/doc/src/cppintegration/data.qdoc | 11 ++++++----- .../doc/src/cppintegration/exposecppattributes.qdoc | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc index ac6600f38c..4523ee39d8 100644 --- a/src/qml/doc/src/cppintegration/data.qdoc +++ b/src/qml/doc/src/cppintegration/data.qdoc @@ -167,9 +167,9 @@ additional features. See the \l {qtqml-javascript-hostenvironment.html} The QML engine provides automatic type conversion between QVariantList and JavaScript arrays, and between QVariantMap and JavaScript objects. -For example, the function defined in QML below left expects two arguments, an +For example, the function defined in QML below expects two arguments, an array and an object, and prints their contents using the standard JavaScript -syntax for array and object item access. The C++ code below right calls this +syntax for array and object item access. The C++ code below calls this function, passing a QVariantList and a QVariantMap, which are automatically converted to JavaScript array and object values, repectively: @@ -204,9 +204,9 @@ when it is passed to C++. The QML engine provides automatic type conversion between QDateTime values and JavaScript \c Date objects. -For example, the function defined in QML below left expects a JavaScript +For example, the function defined in QML below expects a JavaScript \c Date object, and also returns a new \c Date object with the current date and -time. The C++ code below right calls this function, passing a QDateTime value +time. The C++ code below calls this function, passing a QDateTime value that is automatically converted by the engine into a \c Date object when it is passed to the \c readDate() function. In turn, the readDate() function returns a \c Date object that is automatically converted into a QDateTime value when it @@ -215,7 +215,7 @@ is received in C++: \table \header \row - +\li QML \li \qml // MyItem.qml @@ -227,6 +227,7 @@ Item { } \endqml \row +\li C++ \li \code // C++ diff --git a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc index ed0d049564..3bffd2eb6f 100644 --- a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc +++ b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc @@ -390,8 +390,8 @@ that is a public slot: \endcode If an instance of \c MessageBoard was set as the context data for a file \c -MyItem.qml, as shown below left, then \c MyItem.qml could invoke the two -methods, as shown below right: +MyItem.qml, then \c MyItem.qml could invoke the two methods as shown in the +examples below: \table \row From 9e926ddbf985f8d41747ae8a89ee3752a11011e4 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 6 Feb 2017 10:57:36 +0100 Subject: [PATCH 08/24] Eliminate VALUE_FITS_IN_REGISTER #ifdef These macros do not apply anymore when cross-compiling. This patch replaces the macro use for locals JS stack initialization with register size dependent operations as well as when loading the this object into a stack slot. Change-Id: Ia986f6dbfa37c6d6ce2f1de6253e7008e4aa87dd Reviewed-by: Lars Knoll --- src/qml/jit/qv4assembler_p.h | 45 ++++++++++++++++++++++++++++++- src/qml/jit/qv4isel_masm.cpp | 34 ++--------------------- src/qml/jit/qv4targetplatform_p.h | 6 ----- 3 files changed, 46 insertions(+), 39 deletions(-) diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 6d8d773ff0..b2d7b13401 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -145,11 +145,13 @@ struct RegisterSizeDependentAssemblerbranch32(RelationalCondition::NotEqual, tagOrValueRegister, TrustedImm32(Value::NotDouble_Mask)); } + + static void initializeLocalVariables(JITAssembler *as, int localsCount) + { + as->move(TrustedImm32(0), TargetPlatform::ReturnValueRegister); + as->move(TrustedImm32(localsCount), TargetPlatform::ScratchRegister); + Label loop = as->label(); + as->store32(TargetPlatform::ReturnValueRegister, Address(TargetPlatform::LocalsRegister)); + as->add32(TrustedImm32(4), TargetPlatform::LocalsRegister); + as->store32(TargetPlatform::ReturnValueRegister, Address(TargetPlatform::LocalsRegister)); + as->add32(TrustedImm32(4), TargetPlatform::LocalsRegister); + Jump jump = as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister); + jump.linkTo(loop, as); + } }; template @@ -364,8 +379,10 @@ struct RegisterSizeDependentAssemblerloadArgumentInRegister(source, TargetPlatform::ReturnValueRegister, 0); + loadArgumentInRegister(as, source, TargetPlatform::ReturnValueRegister, 0); as->storeReturnValue(destination); } @@ -477,6 +494,12 @@ struct RegisterSizeDependentAssemblermove64ToDouble(TargetPlatform::ReturnValueRegister, target); } + static void loadArgumentInRegister(JITAssembler *as, Address addressOfValue, RegisterID dest, int argumentNumber) + { + Q_UNUSED(argumentNumber); + as->load64(addressOfValue, dest); + } + static void loadArgumentInRegister(JITAssembler *as, IR::Temp* temp, RegisterID dest, int argumentNumber) { Q_UNUSED(argumentNumber); @@ -625,6 +648,17 @@ struct RegisterSizeDependentAssemblerbranch32(RelationalCondition::NotEqual, tagOrValueRegister, TrustedImm32(0)); } + + static void initializeLocalVariables(JITAssembler *as, int localsCount) + { + as->move(TrustedImm64(0), TargetPlatform::ReturnValueRegister); + as->move(TrustedImm32(localsCount), TargetPlatform::ScratchRegister); + Label loop = as->label(); + as->store64(TargetPlatform::ReturnValueRegister, Address(TargetPlatform::LocalsRegister)); + as->add64(TrustedImm32(8), TargetPlatform::LocalsRegister); + Jump jump = as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister); + jump.linkTo(loop, as); + } }; template @@ -1585,6 +1619,15 @@ public: void setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave); const StackLayout &stackLayout() const { return *_stackLayout.data(); } + void initializeLocalVariables() + { + const int locals = _stackLayout->calculateJSStackFrameSize(); + if (locals <= 0) + return; + loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)), JITTargetPlatform::LocalsRegister); + RegisterSizeDependentOps::initializeLocalVariables(this, locals); + storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop))); + } Label exceptionReturnLabel; IR::BasicBlock * catchBlock; diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index b1134d2bec..11e1c6c726 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -120,31 +120,7 @@ void InstructionSelection::run(int functionIndex) _as->loadPtr(addressForArgument(0), JITTargetPlatform::EngineRegister); #endif - const int locals = _as->stackLayout().calculateJSStackFrameSize(); - if (locals > 0) { - _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)), JITTargetPlatform::LocalsRegister); -#ifdef VALUE_FITS_IN_REGISTER - _as->move(TrustedImm64(0), JITTargetPlatform::ReturnValueRegister); - _as->move(TrustedImm32(locals), JITTargetPlatform::ScratchRegister); - Label loop = _as->label(); - _as->store64(JITTargetPlatform::ReturnValueRegister, Address(JITTargetPlatform::LocalsRegister)); - _as->add64(TrustedImm32(8), JITTargetPlatform::LocalsRegister); - Jump jump = _as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), JITTargetPlatform::ScratchRegister); - jump.linkTo(loop, _as); -#else - _as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister); - _as->move(TrustedImm32(locals), JITTargetPlatform::ScratchRegister); - Label loop = _as->label(); - _as->store32(JITTargetPlatform::ReturnValueRegister, Address(JITTargetPlatform::LocalsRegister)); - _as->add32(TrustedImm32(4), JITTargetPlatform::LocalsRegister); - _as->store32(JITTargetPlatform::ReturnValueRegister, Address(JITTargetPlatform::LocalsRegister)); - _as->add32(TrustedImm32(4), JITTargetPlatform::LocalsRegister); - Jump jump = _as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), JITTargetPlatform::ScratchRegister); - jump.linkTo(loop, _as); -#endif - _as->storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop))); - } - + _as->initializeLocalVariables(); int lastLine = 0; for (int i = 0, ei = _function->basicBlockCount(); i != ei; ++i) { @@ -474,13 +450,7 @@ void InstructionSelection::loadThisObject(IR::Expr *temp) { _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister); _as->loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), JITTargetPlatform::ScratchRegister); -#if defined(VALUE_FITS_IN_REGISTER) - _as->load64(Pointer(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject)), - JITTargetPlatform::ReturnValueRegister); - _as->storeReturnValue(temp); -#else - _as->copyValue(temp, Pointer(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject))); -#endif + _as->copyValue(temp, Address(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject))); } template diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h index 1c29aa2a70..46a618d733 100644 --- a/src/qml/jit/qv4targetplatform_p.h +++ b/src/qml/jit/qv4targetplatform_p.h @@ -130,7 +130,6 @@ public: } # define HAVE_ALU_OPS_WITH_MEM_OPERAND 1 -# undef VALUE_FITS_IN_REGISTER static const int RegisterSize = 4; # undef ARGUMENTS_IN_REGISTERS @@ -216,7 +215,6 @@ public: } #define HAVE_ALU_OPS_WITH_MEM_OPERAND 1 -#define VALUE_FITS_IN_REGISTER static const int RegisterSize = 8; #define ARGUMENTS_IN_REGISTERS @@ -285,7 +283,6 @@ public: } #define HAVE_ALU_OPS_WITH_MEM_OPERAND 1 -#define VALUE_FITS_IN_REGISTER static const int RegisterSize = 8; #define ARGUMENTS_IN_REGISTERS @@ -389,7 +386,6 @@ public: } #undef HAVE_ALU_OPS_WITH_MEM_OPERAND -#undef VALUE_FITS_IN_REGISTER static const int RegisterSize = 4; #define ARGUMENTS_IN_REGISTERS @@ -510,7 +506,6 @@ public: } #undef HAVE_ALU_OPS_WITH_MEM_OPERAND -#define VALUE_FITS_IN_REGISTER static const int RegisterSize = 8; #define ARGUMENTS_IN_REGISTERS @@ -598,7 +593,6 @@ public: } #undef HAVE_ALU_OPS_WITH_MEM_OPERAND -#undef VALUE_FITS_IN_REGISTER static const int RegisterSize = 4; #define ARGUMENTS_IN_REGISTERS From ff46a4127bbe46d9887457d5740e52ffff4d43d4 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 1 Feb 2017 13:49:37 +0100 Subject: [PATCH 09/24] Fix assembler cross-compilation on 32-bit hosts The GOT register restoring logic needs to be done via TargetPLatform members instead of plain #ifdefs. Task-number: QTBUG-58569 Change-Id: If00d3f92558361ad5dcb20c3ff7eff78d31d75d3 Reviewed-by: Lars Knoll --- src/qml/jit/qv4assembler.cpp | 2 +- src/qml/jit/qv4assembler_p.h | 5 ++--- src/qml/jit/qv4binop.cpp | 2 +- src/qml/jit/qv4isel_masm.cpp | 6 ++---- src/qml/jit/qv4targetplatform_p.h | 27 ++++++++++++++++++++++----- src/qml/jit/qv4unop.cpp | 2 +- 6 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 646d9a8871..c6da60384e 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -709,7 +709,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) } template class QV4::JIT::Assembler; -#if defined(V4_BOOTSTRAP) && CPU(X86_64) +#if defined(V4_BOOTSTRAP) template class QV4::JIT::Assembler>; #endif diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index b2d7b13401..fd65c9b3d2 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -1372,9 +1372,8 @@ public: if (prepareCall(function)) loadArgumentOnStackOrRegister<0>(arg1); -#ifdef RESTORE_EBX_ON_CALL - load32(this->ebxAddressOnStack(), JSC::X86Registers::ebx); // restore the GOT ptr -#endif + if (JITTargetPlatform::gotRegister != -1) + load32(Address(JITTargetPlatform::FramePointerRegister, JITTargetPlatform::savedGOTRegisterSlotOnStack()), static_cast(JITTargetPlatform::gotRegister)); // restore the GOT ptr callAbsolute(functionName, function); diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp index 8468bf65a6..a09f3f8449 100644 --- a/src/qml/jit/qv4binop.cpp +++ b/src/qml/jit/qv4binop.cpp @@ -577,7 +577,7 @@ typename JITAssembler::Jump Binop::genInlineBinop(IR::Expr *leftSo } template struct QV4::JIT::Binop>; -#if defined(V4_BOOTSTRAP) && CPU(X86_64) +#if defined(V4_BOOTSTRAP) template struct QV4::JIT::Binop>>; #endif diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 11e1c6c726..343062c1be 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -1344,12 +1344,10 @@ void InstructionSelection::calculateRegistersToSave(const Register fpRegistersToSave.clear(); for (const RegisterInfo &ri : JITTargetPlatform::getRegisterInfo()) { -#if defined(RESTORE_EBX_ON_CALL) - if (ri.isRegularRegister() && ri.reg() == JSC::X86Registers::ebx) { + if (JITTargetPlatform::gotRegister != -1 && ri.isRegularRegister() && ri.reg() == JITTargetPlatform::gotRegister) { regularRegistersToSave.append(ri); continue; } -#endif // RESTORE_EBX_ON_CALL if (ri.isCallerSaved()) continue; if (ri.isRegularRegister()) { @@ -1636,7 +1634,7 @@ QT_BEGIN_NAMESPACE namespace QV4 { namespace JIT { template class Q_QML_EXPORT InstructionSelection<>; template class Q_QML_EXPORT ISelFactory<>; -#if defined(V4_BOOTSTRAP) && CPU(X86_64) +#if defined(V4_BOOTSTRAP) Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &architecture) { diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h index 46a618d733..4fc9d83059 100644 --- a/src/qml/jit/qv4targetplatform_p.h +++ b/src/qml/jit/qv4targetplatform_p.h @@ -145,10 +145,8 @@ public: #if OS(WINDOWS) || OS(QNX) || \ ((OS(LINUX) || OS(FREEBSD)) && (defined(__PIC__) || defined(__PIE__))) -#define RESTORE_EBX_ON_CALL - using Address = PlatformAssembler::Address; - static Address ebxAddressOnStack() - { + static const int gotRegister = JSC::X86Registers::ebx; + static int savedGOTRegisterSlotOnStack() { static int ebxIdx = -1; if (ebxIdx == -1) { int calleeSaves = 0; @@ -164,8 +162,11 @@ public: Q_ASSERT(ebxIdx >= 0); ebxIdx += 1; } - return Address(FramePointerRegister, ebxIdx * -int(sizeof(void*))); + return ebxIdx * -int(sizeof(void*)); } +#else + static const int gotRegister = -1; + static int savedGOTRegisterSlotOnStack() { return -1; } #endif }; #endif // x86 @@ -238,6 +239,9 @@ public: static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU. static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); } static void platformLeaveStandardStackFrame(PlatformAssembler *as) { as->pop(FramePointerRegister); } + + static const int gotRegister = -1; + static int savedGOTRegisterSlotOnStack() { return -1; } }; #endif // Linux/MacOS on x86_64 @@ -304,6 +308,9 @@ public: static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU. static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); } static void platformLeaveStandardStackFrame(PlatformAssembler *as) { as->pop(FramePointerRegister); } + + static const int gotRegister = -1; + static int savedGOTRegisterSlotOnStack() { return -1; } }; #endif // Windows on x86_64 @@ -418,6 +425,9 @@ public: as->pop(FramePointerRegister); as->pop(JSC::ARMRegisters::lr); } + + static const int gotRegister = -1; + static int savedGOTRegisterSlotOnStack() { return -1; } }; #endif // ARM (32 bit) @@ -540,6 +550,9 @@ public: { as->popPair(FramePointerRegister, JSC::ARM64Registers::lr); } + + static const int gotRegister = -1; + static int savedGOTRegisterSlotOnStack() { return -1; } }; #endif // ARM64 @@ -625,6 +638,10 @@ public: as->pop(FramePointerRegister); as->pop(JSC::MIPSRegisters::ra); } + + + static const int gotRegister = -1; + static int savedGOTRegisterSlotOnStack() { return -1; } }; #endif // Linux on MIPS (32 bit) diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp index 31355e5dce..6c19d20592 100644 --- a/src/qml/jit/qv4unop.cpp +++ b/src/qml/jit/qv4unop.cpp @@ -145,7 +145,7 @@ void Unop::generateCompl(IR::Expr *source, IR::Expr *target) } template struct QV4::JIT::Unop>; -#if defined(V4_BOOTSTRAP) && CPU(X86_64) +#if defined(V4_BOOTSTRAP) template struct QV4::JIT::Unop>>; #endif From eea43b5cc5aa6fab0d7523f92a83a5f75849782d Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 7 Feb 2017 13:37:44 +0100 Subject: [PATCH 10/24] Fix a crash in canvas2d when calling some methods This fixes a regression introduced in change 4d23faf34192cef372f846dcf02fd8cc398b14c0, where some return values from functions weren't properly encoded as QV4::Value. Task-number: QTBUG-58683 Change-Id: I9dc5f1eb8f5779c58f8b062b9ae3d02284ab2678 Reviewed-by: Simon Hausmann Reviewed-by: J-P Nurmi --- src/quick/items/context2d/qquickcontext2d.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index b0c1d50907..e25cc5ccbe 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -1879,7 +1879,7 @@ void QQuickJSContext2D::method_get_lineWidth(const QV4::BuiltinFunction *, QV4:: QV4::Scoped r(scope, callData->thisObject); CHECK_CONTEXT(r) - RETURN_RESULT(r->d()->context->state.lineWidth); + RETURN_RESULT(QV4::Encode(r->d()->context->state.lineWidth)); } void QQuickJSContext2D::method_set_lineWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) @@ -1906,7 +1906,7 @@ void QQuickJSContext2D::method_get_miterLimit(const QV4::BuiltinFunction *, QV4: QV4::Scoped r(scope, callData->thisObject); CHECK_CONTEXT(r) - RETURN_RESULT(r->d()->context->state.miterLimit); + RETURN_RESULT(QV4::Encode(r->d()->context->state.miterLimit)); } void QQuickJSContext2D::method_set_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) @@ -1933,7 +1933,7 @@ void QQuickJSContext2D::method_get_shadowBlur(const QV4::BuiltinFunction *, QV4: QV4::Scoped r(scope, callData->thisObject); CHECK_CONTEXT(r) - RETURN_RESULT(r->d()->context->state.shadowBlur); + RETURN_RESULT(QV4::Encode(r->d()->context->state.shadowBlur)); } void QQuickJSContext2D::method_set_shadowBlur(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) @@ -1990,7 +1990,7 @@ void QQuickJSContext2D::method_get_shadowOffsetX(const QV4::BuiltinFunction *, Q QV4::Scoped r(scope, callData->thisObject); CHECK_CONTEXT(r) - RETURN_RESULT(r->d()->context->state.shadowOffsetX); + RETURN_RESULT(QV4::Encode(r->d()->context->state.shadowOffsetX)); } void QQuickJSContext2D::method_set_shadowOffsetX(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) @@ -2016,7 +2016,7 @@ void QQuickJSContext2D::method_get_shadowOffsetY(const QV4::BuiltinFunction *, Q QV4::Scoped r(scope, callData->thisObject); CHECK_CONTEXT(r) - RETURN_RESULT(r->d()->context->state.shadowOffsetY); + RETURN_RESULT(QV4::Encode(r->d()->context->state.shadowOffsetY)); } void QQuickJSContext2D::method_set_shadowOffsetY(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) @@ -3043,7 +3043,7 @@ void QQuickJSContext2DPixelData::proto_get_length(const QV4::BuiltinFunction *, if (!r || r->d()->image->isNull()) RETURN_UNDEFINED(); - RETURN_RESULT(r->d()->image->width() * r->d()->image->height() * 4); + RETURN_RESULT(QV4::Encode(r->d()->image->width() * r->d()->image->height() * 4)); } QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m, uint index, bool *hasProperty) From da35e3233335545125da51714298db6134cecb67 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 1 Feb 2017 15:00:44 +0100 Subject: [PATCH 11/24] Fix register argument passing in cross-compiled code when host == x86 Replace the use of host-dependent pre-processor macro with variable usage from the target platform template specializations. Task-number: QTBUG-58577 Change-Id: I7e5ca4b79c2238954d6be7ec6b110eadd78a104d Reviewed-by: Lars Knoll --- src/qml/jit/qv4isel_masm.cpp | 9 ++++----- src/qml/jit/qv4isel_masm_p.h | 2 -- src/qml/jit/qv4targetplatform_p.h | 6 ------ 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 343062c1be..6769b22b77 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -114,11 +114,10 @@ void InstructionSelection::run(int functionIndex) fpRegistersToSave.size()); _as->enterStandardStackFrame(regularRegistersToSave, fpRegistersToSave); -#ifdef ARGUMENTS_IN_REGISTERS - _as->move(_as->registerForArgument(0), JITTargetPlatform::EngineRegister); -#else - _as->loadPtr(addressForArgument(0), JITTargetPlatform::EngineRegister); -#endif + if (JITTargetPlatform::RegisterArgumentCount > 0) + _as->move(_as->registerForArgument(0), JITTargetPlatform::EngineRegister); + else + _as->loadPtr(addressForArgument(0), JITTargetPlatform::EngineRegister); _as->initializeLocalVariables(); diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index 6ae50c3260..5c046cb397 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/src/qml/jit/qv4isel_masm_p.h @@ -155,7 +155,6 @@ protected: using JITTargetPlatform = typename JITAssembler::JITTargetPlatform; -#if !defined(ARGUMENTS_IN_REGISTERS) Address addressForArgument(int index) const { // FramePointerRegister points to its old value on the stack, and above @@ -163,7 +162,6 @@ protected: // values before reaching the first argument. return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * sizeof(void*)); } -#endif Pointer baseAddressForCallArguments() { diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h index 4fc9d83059..fa01d911ef 100644 --- a/src/qml/jit/qv4targetplatform_p.h +++ b/src/qml/jit/qv4targetplatform_p.h @@ -132,7 +132,6 @@ public: # define HAVE_ALU_OPS_WITH_MEM_OPERAND 1 static const int RegisterSize = 4; -# undef ARGUMENTS_IN_REGISTERS static const int RegisterArgumentCount = 0; static RegisterID registerForArgument(int) { Q_UNREACHABLE(); } @@ -218,7 +217,6 @@ public: #define HAVE_ALU_OPS_WITH_MEM_OPERAND 1 static const int RegisterSize = 8; -#define ARGUMENTS_IN_REGISTERS static const int RegisterArgumentCount = 6; static RegisterID registerForArgument(int index) { @@ -289,7 +287,6 @@ public: #define HAVE_ALU_OPS_WITH_MEM_OPERAND 1 static const int RegisterSize = 8; -#define ARGUMENTS_IN_REGISTERS static const int RegisterArgumentCount = 4; static RegisterID registerForArgument(int index) { @@ -395,7 +392,6 @@ public: #undef HAVE_ALU_OPS_WITH_MEM_OPERAND static const int RegisterSize = 4; -#define ARGUMENTS_IN_REGISTERS static const int RegisterArgumentCount = 4; static RegisterID registerForArgument(int index) { @@ -518,7 +514,6 @@ public: #undef HAVE_ALU_OPS_WITH_MEM_OPERAND static const int RegisterSize = 8; -#define ARGUMENTS_IN_REGISTERS static const int RegisterArgumentCount = 8; static RegisterID registerForArgument(int index) { @@ -608,7 +603,6 @@ public: #undef HAVE_ALU_OPS_WITH_MEM_OPERAND static const int RegisterSize = 4; -#define ARGUMENTS_IN_REGISTERS static const int RegisterArgumentCount = 4; static RegisterID registerForArgument(int index) { From d7161f3af6104faaedb68e1a8a4277dabeb1f8af Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 8 Feb 2017 11:22:50 +0100 Subject: [PATCH 12/24] Fix compilation of qmldevtools on Windows when cross-compiling The use of wildcards in SOURCES is an unspecified "feature" and it turns out that it doesn't work when doing option(host_build) and cross-compiling. We could use $$files(), but there is no truly good reason for using it for only some directories and not others, so this is now a manual expansion. Task-number: QTBUG-58705 Change-Id: Ib3bd7bbba01fe4130703d5635fa344b62caea5bb Reviewed-by: Lars Knoll --- src/3rdparty/masm/masm.pri | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/3rdparty/masm/masm.pri b/src/3rdparty/masm/masm.pri index c63cd5da66..248be6e18c 100644 --- a/src/3rdparty/masm/masm.pri +++ b/src/3rdparty/masm/masm.pri @@ -31,7 +31,17 @@ HEADERS += $$PWD/stubs/WTFStubs.h SOURCES += $$PWD/stubs/Options.cpp -HEADERS += $$PWD/stubs/wtf/*.h +HEADERS += $$PWD/stubs/wtf/FastAllocBase.h \ + $$PWD/stubs/wtf/FastMalloc.h \ + $$PWD/stubs/wtf/Noncopyable.h \ + $$PWD/stubs/wtf/OwnPtr.h \ + $$PWD/stubs/wtf/PassOwnPtr.h \ + $$PWD/stubs/wtf/PassRefPtr.h \ + $$PWD/stubs/wtf/RefCounted.h \ + $$PWD/stubs/wtf/RefPtr.h \ + $$PWD/stubs/wtf/TypeTraits.h \ + $$PWD/stubs/wtf/UnusedParam.h \ + $$PWD/stubs/wtf/Vector.h SOURCES += $$PWD/disassembler/Disassembler.cpp SOURCES += $$PWD/disassembler/UDis86Disassembler.cpp @@ -67,9 +77,19 @@ SOURCES += $$PWD/disassembler/ARM64Disassembler.cpp SOURCES += $$PWD/disassembler/ARM64/A64DOpcode.cpp HEADERS += $$PWD/disassembler/ARM64/A64DOpcode.h -SOURCES += $$PWD/yarr/*.cpp -HEADERS += $$PWD/yarr/*.h +SOURCES += $$PWD/yarr/YarrCanonicalizeUCS2.cpp \ + $$PWD/yarr/YarrInterpreter.cpp \ + $$PWD/yarr/YarrJIT.cpp \ + $$PWD/yarr/YarrPattern.cpp \ + $$PWD/yarr/YarrSyntaxChecker.cpp +HEADERS += $$PWD/yarr/Yarr.h \ + $$PWD/yarr/YarrCanonicalizeUCS2.h \ + $$PWD/yarr/YarrInterpreter.h \ + $$PWD/yarr/YarrJIT.h \ + $$PWD/yarr/YarrParser.h \ + $$PWD/yarr/YarrPattern.h \ + $$PWD/yarr/YarrSyntaxChecker.h # # Generate RegExpJitTables.h # From aa76e89b4d66e80c66999680e6a3db00c8a00b33 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 6 Feb 2017 15:47:33 +0100 Subject: [PATCH 13/24] Local storage: Improve error message Use %-placeholder formatting instead of concatenating strings which may not work in some languages and pass path through QDir::toNativeSeparators(). Amends change f96b77bf46a29b1c09d6ebff2f18a475c7ca0b2f. Change-Id: Iee6782a41513529bb6e4c0cde62b477a68bbcd02 Reviewed-by: Shawn Rutledge --- src/imports/localstorage/plugin.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 433b7fe430..60b8dad5fb 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -714,8 +714,11 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args) FunctionObject *dbcreationCallback = (v = (*args)[4])->as(); QString basename = args->v4engine()->qmlEngine()->offlineStorageDatabaseFilePath(dbname); QFileInfo dbFile(basename); - if (!QDir().mkpath(dbFile.dir().absolutePath())) - V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("LocalStorage: can't create path ") + dbFile.dir().absolutePath()); + if (!QDir().mkpath(dbFile.dir().absolutePath())) { + const QString message = QQmlEngine::tr("LocalStorage: can't create path %1"). + arg(QDir::toNativeSeparators(dbFile.dir().absolutePath())); + V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, message); + } QString dbid = dbFile.fileName(); bool created = false; QString version = dbversion; From be92f31b7eb2a689c8a12fc0e193878a84c4532e Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 7 Feb 2017 13:22:32 +0100 Subject: [PATCH 14/24] Enable cross-compiling binops from 32-bit host 64-bit target Move the #if CPU(X86) specific bits into a template specialization, so that we won't try to call 32-bit specific methods on the assembler when targeting a 64-bit architecture. Change-Id: I3b7e6c2c77d8a34ef50913cbfd34dad2c3199923 Reviewed-by: Qt CI Bot Reviewed-by: Lars Knoll --- src/qml/jit/qv4binop.cpp | 193 +++++++++++++++++++++++++++------------ 1 file changed, 135 insertions(+), 58 deletions(-) diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp index a09f3f8449..988425d73f 100644 --- a/src/qml/jit/qv4binop.cpp +++ b/src/qml/jit/qv4binop.cpp @@ -41,8 +41,128 @@ #if ENABLE(ASSEMBLER) -using namespace QV4; -using namespace JIT; +QT_BEGIN_NAMESPACE + +namespace QV4 { +namespace JIT { + +template +struct ArchitectureSpecificBinaryOperation +{ + using FPRegisterID = typename JITAssembler::FPRegisterID; + + static bool doubleAdd(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg) + { + Q_UNUSED(as); + Q_UNUSED(lhs); + Q_UNUSED(rhs); + Q_UNUSED(targetReg); + return false; + } + static bool doubleMul(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg) + { + Q_UNUSED(as); + Q_UNUSED(lhs); + Q_UNUSED(rhs); + Q_UNUSED(targetReg); + return false; + } + static bool doubleSub(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg) + { + Q_UNUSED(as); + Q_UNUSED(lhs); + Q_UNUSED(rhs); + Q_UNUSED(targetReg); + return false; + } + static bool doubleDiv(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg) + { + Q_UNUSED(as); + Q_UNUSED(lhs); + Q_UNUSED(rhs); + Q_UNUSED(targetReg); + return false; + } +}; + +#if CPU(X86) +template <> +struct ArchitectureSpecificBinaryOperation>> +{ + using JITAssembler = Assembler>; + using FPRegisterID = JITAssembler::FPRegisterID; + using Address = JITAssembler::Address; + + static bool doubleAdd(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg) + { + if (IR::Const *c = rhs->asConst()) { // Y = X + constant -> Y = X; Y += [constant-address] + as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); + Address addr = as->loadConstant(c, JITAssembler::ScratchRegister); + as->addDouble(addr, targetReg); + return true; + } + if (IR::Temp *t = rhs->asTemp()) { // Y = X + [temp-memory-address] -> Y = X; Y += [temp-memory-address] + if (t->kind != IR::Temp::PhysicalRegister) { + as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); + as->addDouble(as->loadTempAddress(t), targetReg); + return true; + } + } + return false; + } + static bool doubleMul(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg) + { + if (IR::Const *c = rhs->asConst()) { // Y = X * constant -> Y = X; Y *= [constant-address] + as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); + Address addr = as->loadConstant(c, JITAssembler::ScratchRegister); + as->mulDouble(addr, targetReg); + return true; + } + if (IR::Temp *t = rhs->asTemp()) { // Y = X * [temp-memory-address] -> Y = X; Y *= [temp-memory-address] + if (t->kind != IR::Temp::PhysicalRegister) { + as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); + as->mulDouble(as->loadTempAddress(t), targetReg); + return true; + } + } + return false; + } + static bool doubleSub(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg) + { + if (IR::Const *c = rhs->asConst()) { // Y = X - constant -> Y = X; Y -= [constant-address] + as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); + Address addr = as->loadConstant(c, JITAssembler::ScratchRegister); + as->subDouble(addr, targetReg); + return true; + } + if (IR::Temp *t = rhs->asTemp()) { // Y = X - [temp-memory-address] -> Y = X; Y -= [temp-memory-address] + if (t->kind != IR::Temp::PhysicalRegister) { + as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); + as->subDouble(as->loadTempAddress(t), targetReg); + return true; + } + } + return false; + } + static bool doubleDiv(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg) + { + if (IR::Const *c = rhs->asConst()) { // Y = X / constant -> Y = X; Y /= [constant-address] + as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); + Address addr = as->loadConstant(c, JITAssembler::ScratchRegister); + as->divDouble(addr, targetReg); + return true; + } + if (IR::Temp *t = rhs->asTemp()) { // Y = X / [temp-memory-address] -> Y = X; Y /= [temp-memory-address] + if (t->kind != IR::Temp::PhysicalRegister) { + as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); + as->divDouble(as->loadTempAddress(t), targetReg); + return true; + } + } + return false; + } +}; +#endif #define OP(op) \ { "Runtime::" isel_stringIfy(op), offsetof(QV4::Runtime, op), INT_MIN, 0, 0, QV4::Runtime::Method_##op##_NeedsExceptionCheck } @@ -162,21 +282,9 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *ta if (lhs->asConst()) std::swap(lhs, rhs); // Y = constant + X -> Y = X + constant -#if CPU(X86) - if (IR::Const *c = rhs->asConst()) { // Y = X + constant -> Y = X; Y += [constant-address] - as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - Address addr = as->loadConstant(c, JITAssembler::ScratchRegister); - as->addDouble(addr, targetReg); + if (ArchitectureSpecificBinaryOperation::doubleAdd(as, lhs, rhs, targetReg)) break; - } - if (IR::Temp *t = rhs->asTemp()) { // Y = X + [temp-memory-address] -> Y = X; Y += [temp-memory-address] - if (t->kind != IR::Temp::PhysicalRegister) { - as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - as->addDouble(as->loadTempAddress(t), targetReg); - break; - } - } -#endif + as->addDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg); break; @@ -184,40 +292,16 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *ta if (lhs->asConst()) std::swap(lhs, rhs); // Y = constant * X -> Y = X * constant -#if CPU(X86) - if (IR::Const *c = rhs->asConst()) { // Y = X * constant -> Y = X; Y *= [constant-address] - as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - Address addr = as->loadConstant(c, JITAssembler::ScratchRegister); - as->mulDouble(addr, targetReg); + if (ArchitectureSpecificBinaryOperation::doubleMul(as, lhs, rhs, targetReg)) break; - } - if (IR::Temp *t = rhs->asTemp()) { // Y = X * [temp-memory-address] -> Y = X; Y *= [temp-memory-address] - if (t->kind != IR::Temp::PhysicalRegister) { - as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - as->mulDouble(as->loadTempAddress(t), targetReg); - break; - } - } -#endif + as->mulDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg); break; case IR::OpSub: -#if CPU(X86) - if (IR::Const *c = rhs->asConst()) { // Y = X - constant -> Y = X; Y -= [constant-address] - as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - Address addr = as->loadConstant(c, JITAssembler::ScratchRegister); - as->subDouble(addr, targetReg); + if (ArchitectureSpecificBinaryOperation::doubleSub(as, lhs, rhs, targetReg)) break; - } - if (IR::Temp *t = rhs->asTemp()) { // Y = X - [temp-memory-address] -> Y = X; Y -= [temp-memory-address] - if (t->kind != IR::Temp::PhysicalRegister) { - as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - as->subDouble(as->loadTempAddress(t), targetReg); - break; - } - } -#endif + if (rhs->asTemp() && rhs->asTemp()->kind == IR::Temp::PhysicalRegister && targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister @@ -231,21 +315,8 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *ta break; case IR::OpDiv: -#if CPU(X86) - if (IR::Const *c = rhs->asConst()) { // Y = X / constant -> Y = X; Y /= [constant-address] - as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - Address addr = as->loadConstant(c, JITAssembler::ScratchRegister); - as->divDouble(addr, targetReg); + if (ArchitectureSpecificBinaryOperation::doubleDiv(as, lhs, rhs, targetReg)) break; - } - if (IR::Temp *t = rhs->asTemp()) { // Y = X / [temp-memory-address] -> Y = X; Y /= [temp-memory-address] - if (t->kind != IR::Temp::PhysicalRegister) { - as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - as->divDouble(as->loadTempAddress(t), targetReg); - break; - } - } -#endif if (rhs->asTemp() && rhs->asTemp()->kind == IR::Temp::PhysicalRegister && targetTemp @@ -581,4 +652,10 @@ template struct QV4::JIT::Binop>>; #endif +} // end of namespace JIT +} // end of namespace QV4 + +QT_END_NAMESPACE + + #endif From 32e24c58664f8e864e591fa03ea86418f0cf0674 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 6 Feb 2017 11:24:40 +0100 Subject: [PATCH 15/24] Fix ARM64 build Add the ARM64 assembler to cross-compilation. Task-number: QTBUG-58568 Change-Id: I91461ebf79fb83e31e8ae2962ab0e155d308281a Reviewed-by: Qt CI Bot Reviewed-by: Lars Knoll --- src/3rdparty/masm/assembler/ARM64Assembler.h | 139 ++++++++++++++---- src/3rdparty/masm/assembler/ARMv7Assembler.h | 3 + .../masm/assembler/AbstractMacroAssembler.h | 6 +- src/3rdparty/masm/assembler/LinkBuffer.h | 2 +- src/3rdparty/masm/assembler/MacroAssembler.h | 2 +- .../masm/assembler/MacroAssemblerARM64.h | 43 +++++- src/qml/jit/qv4assembler.cpp | 1 + src/qml/jit/qv4binop.cpp | 1 + src/qml/jit/qv4isel_masm.cpp | 5 +- src/qml/jit/qv4targetplatform_p.h | 2 +- src/qml/jit/qv4unop.cpp | 1 + 11 files changed, 163 insertions(+), 42 deletions(-) diff --git a/src/3rdparty/masm/assembler/ARM64Assembler.h b/src/3rdparty/masm/assembler/ARM64Assembler.h index ad5acdbb85..7390997af1 100644 --- a/src/3rdparty/masm/assembler/ARM64Assembler.h +++ b/src/3rdparty/masm/assembler/ARM64Assembler.h @@ -26,9 +26,10 @@ #ifndef ARM64Assembler_h #define ARM64Assembler_h -#if ENABLE(ASSEMBLER) && CPU(ARM64) +#if ENABLE(ASSEMBLER) && (CPU(ARM64) || defined(V4_BOOTSTRAP)) #include "AssemblerBuffer.h" +#include "AbstractMacroAssembler.h" #include #include #include @@ -520,8 +521,8 @@ typedef enum { #undef DECLARE_REGISTER } FPRegisterID; -static constexpr bool isSp(RegisterID reg) { return reg == sp; } -static constexpr bool isZr(RegisterID reg) { return reg == zr; } +static Q_DECL_CONSTEXPR bool isSp(RegisterID reg) { return reg == sp; } +static Q_DECL_CONSTEXPR bool isZr(RegisterID reg) { return reg == zr; } } // namespace ARM64Registers @@ -530,15 +531,15 @@ public: typedef ARM64Registers::RegisterID RegisterID; typedef ARM64Registers::FPRegisterID FPRegisterID; - static constexpr RegisterID firstRegister() { return ARM64Registers::x0; } - static constexpr RegisterID lastRegister() { return ARM64Registers::sp; } + static Q_DECL_CONSTEXPR RegisterID firstRegister() { return ARM64Registers::x0; } + static Q_DECL_CONSTEXPR RegisterID lastRegister() { return ARM64Registers::sp; } - static constexpr FPRegisterID firstFPRegister() { return ARM64Registers::q0; } - static constexpr FPRegisterID lastFPRegister() { return ARM64Registers::q31; } + static Q_DECL_CONSTEXPR FPRegisterID firstFPRegister() { return ARM64Registers::q0; } + static Q_DECL_CONSTEXPR FPRegisterID lastFPRegister() { return ARM64Registers::q31; } private: - static constexpr bool isSp(RegisterID reg) { return ARM64Registers::isSp(reg); } - static constexpr bool isZr(RegisterID reg) { return ARM64Registers::isZr(reg); } + static Q_DECL_CONSTEXPR bool isSp(RegisterID reg) { return ARM64Registers::isSp(reg); } + static Q_DECL_CONSTEXPR bool isZr(RegisterID reg) { return ARM64Registers::isZr(reg); } public: ARM64Assembler() @@ -546,7 +547,7 @@ public: , m_indexOfTailOfLastWatchpoint(INT_MIN) { } - + AssemblerBuffer& buffer() { return m_buffer; } // (HS, LO, HI, LS) -> (AE, B, A, BE) @@ -653,9 +654,7 @@ public: } void operator=(const LinkRecord& other) { - data.copyTypes.content[0] = other.data.copyTypes.content[0]; - data.copyTypes.content[1] = other.data.copyTypes.content[1]; - data.copyTypes.content[2] = other.data.copyTypes.content[2]; + data.realTypes = other.data.realTypes; } intptr_t from() const { return data.realTypes.m_from; } void setFrom(intptr_t from) { data.realTypes.m_from = from; } @@ -671,8 +670,8 @@ public: private: union { struct RealTypes { - intptr_t m_from : 48; - intptr_t m_to : 48; + int64_t m_from : 48; + int64_t m_to : 48; JumpType m_type : 8; JumpLinkType m_linkType : 8; Condition m_condition : 4; @@ -680,10 +679,6 @@ public: RegisterID m_compareRegister : 6; bool m_is64Bit : 1; } realTypes; - struct CopyTypes { - uint64_t content[3]; - } copyTypes; - COMPILE_ASSERT(sizeof(RealTypes) == sizeof(CopyTypes), LinkRecordCopyStructSizeEqualsRealStruct); } data; }; @@ -743,6 +738,89 @@ public: return isValidSignedImm9(offset); } + + // Jump: + // + // A jump object is a reference to a jump instruction that has been planted + // into the code buffer - it is typically used to link the jump, setting the + // relative offset such that when executed it will jump to the desired + // destination. + template + class Jump { + template + friend class AbstractMacroAssembler; + friend class Call; + template class> friend class LinkBufferBase; + public: + Jump() + { + } + + Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type = ARM64Assembler::JumpNoCondition, ARM64Assembler::Condition condition = ARM64Assembler::ConditionInvalid) + : m_label(jmp) + , m_type(type) + , m_condition(condition) + { + } + + Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type, ARM64Assembler::Condition condition, bool is64Bit, ARM64Assembler::RegisterID compareRegister) + : m_label(jmp) + , m_type(type) + , m_condition(condition) + , m_is64Bit(is64Bit) + , m_compareRegister(compareRegister) + { + ASSERT((type == ARM64Assembler::JumpCompareAndBranch) || (type == ARM64Assembler::JumpCompareAndBranchFixedSize)); + } + + Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type, ARM64Assembler::Condition condition, unsigned bitNumber, ARM64Assembler::RegisterID compareRegister) + : m_label(jmp) + , m_type(type) + , m_condition(condition) + , m_bitNumber(bitNumber) + , m_compareRegister(compareRegister) + { + ASSERT((type == ARM64Assembler::JumpTestBit) || (type == ARM64Assembler::JumpTestBitFixedSize)); + } + + LabelType label() const + { + LabelType result; + result.m_label = m_label; + return result; + } + + void link(AbstractMacroAssembler* masm) const + { + if ((m_type == ARM64Assembler::JumpCompareAndBranch) || (m_type == ARM64Assembler::JumpCompareAndBranchFixedSize)) + masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition, m_is64Bit, m_compareRegister); + else if ((m_type == ARM64Assembler::JumpTestBit) || (m_type == ARM64Assembler::JumpTestBitFixedSize)) + masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition, m_bitNumber, m_compareRegister); + else + masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition); + } + + void linkTo(LabelType label, AbstractMacroAssembler* masm) const + { + if ((m_type == ARM64Assembler::JumpCompareAndBranch) || (m_type == ARM64Assembler::JumpCompareAndBranchFixedSize)) + masm->m_assembler.linkJump(m_label, label.label(), m_type, m_condition, m_is64Bit, m_compareRegister); + else if ((m_type == ARM64Assembler::JumpTestBit) || (m_type == ARM64Assembler::JumpTestBitFixedSize)) + masm->m_assembler.linkJump(m_label, label.label(), m_type, m_condition, m_bitNumber, m_compareRegister); + else + masm->m_assembler.linkJump(m_label, label.label(), m_type, m_condition); + } + + bool isSet() const { return m_label.isSet(); } + + private: + AssemblerLabel m_label; + ARM64Assembler::JumpType m_type; + ARM64Assembler::Condition m_condition; + bool m_is64Bit; + unsigned m_bitNumber; + ARM64Assembler::RegisterID m_compareRegister; + }; + private: int encodeFPImm(double d) { @@ -2857,11 +2935,11 @@ public: expected = disassembleMoveWideImediate(address + 1, sf, opc, hw, imm16, rd); ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 1 && rd == rdFirst); - result |= static_cast(imm16) << 16; + result |= static_cast(imm16) << 16; expected = disassembleMoveWideImediate(address + 2, sf, opc, hw, imm16, rd); ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 2 && rd == rdFirst); - result |= static_cast(imm16) << 32; + result |= static_cast(imm16) << 32; return reinterpret_cast(result); } @@ -2932,7 +3010,10 @@ public: static void cacheFlush(void* code, size_t size) { -#if OS(IOS) +#if defined(V4_BOOTSTRAP) + UNUSED_PARAM(code) + UNUSED_PARAM(size) +#elif OS(IOS) sys_cache_control(kCacheFunctionPrepareForExecution, code, size); #elif OS(LINUX) size_t page = pageSize(); @@ -2989,7 +3070,7 @@ public: case JumpCondition: { ASSERT(!(reinterpret_cast(from) & 0x3)); ASSERT(!(reinterpret_cast(to) & 0x3)); - intptr_t relative = reinterpret_cast(to) - (reinterpret_cast(from)); + int64_t relative = reinterpret_cast(to) - (reinterpret_cast(from)); if (((relative << 43) >> 43) == relative) return LinkJumpConditionDirect; @@ -2999,7 +3080,7 @@ public: case JumpCompareAndBranch: { ASSERT(!(reinterpret_cast(from) & 0x3)); ASSERT(!(reinterpret_cast(to) & 0x3)); - intptr_t relative = reinterpret_cast(to) - (reinterpret_cast(from)); + int64_t relative = reinterpret_cast(to) - (reinterpret_cast(from)); if (((relative << 43) >> 43) == relative) return LinkJumpCompareAndBranchDirect; @@ -3009,7 +3090,7 @@ public: case JumpTestBit: { ASSERT(!(reinterpret_cast(from) & 0x3)); ASSERT(!(reinterpret_cast(to) & 0x3)); - intptr_t relative = reinterpret_cast(to) - (reinterpret_cast(from)); + int64_t relative = reinterpret_cast(to) - (reinterpret_cast(from)); if (((relative << 50) >> 50) == relative) return LinkJumpTestBitDirect; @@ -3121,7 +3202,7 @@ private: { ASSERT(!(reinterpret_cast(from) & 3)); ASSERT(!(reinterpret_cast(to) & 3)); - intptr_t offset = (reinterpret_cast(to) - reinterpret_cast(from)) >> 2; + int64_t offset = (reinterpret_cast(to) - reinterpret_cast(from)) >> 2; ASSERT(((offset << 38) >> 38) == offset); bool useDirect = ((offset << 45) >> 45) == offset; // Fits in 19 bits @@ -3142,7 +3223,7 @@ private: { ASSERT(!(reinterpret_cast(from) & 3)); ASSERT(!(reinterpret_cast(to) & 3)); - intptr_t offset = (reinterpret_cast(to) - reinterpret_cast(from)) >> 2; + int64_t offset = (reinterpret_cast(to) - reinterpret_cast(from)) >> 2; ASSERT(((offset << 38) >> 38) == offset); bool useDirect = ((offset << 45) >> 45) == offset; // Fits in 19 bits @@ -3163,7 +3244,7 @@ private: { ASSERT(!(reinterpret_cast(from) & 3)); ASSERT(!(reinterpret_cast(to) & 3)); - intptr_t offset = (reinterpret_cast(to) - reinterpret_cast(from)) >> 2; + int64_t offset = (reinterpret_cast(to) - reinterpret_cast(from)) >> 2; ASSERT(static_cast(offset) == offset); ASSERT(((offset << 38) >> 38) == offset); @@ -3766,6 +3847,8 @@ private: #undef DATASIZE #undef MEMOPSIZE #undef CHECK_FP_MEMOP_DATASIZE +#undef JUMP_ENUM_WITH_SIZE +#undef JUMP_ENUM_SIZE #endif // ENABLE(ASSEMBLER) && CPU(ARM64) diff --git a/src/3rdparty/masm/assembler/ARMv7Assembler.h b/src/3rdparty/masm/assembler/ARMv7Assembler.h index 6b32fbf487..615c72fc15 100644 --- a/src/3rdparty/masm/assembler/ARMv7Assembler.h +++ b/src/3rdparty/masm/assembler/ARMv7Assembler.h @@ -2867,6 +2867,9 @@ private: int m_indexOfTailOfLastWatchpoint; }; +#undef JUMP_ENUM_WITH_SIZE +#undef JUMP_ENUM_SIZE + } // namespace JSC #endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2) diff --git a/src/3rdparty/masm/assembler/AbstractMacroAssembler.h b/src/3rdparty/masm/assembler/AbstractMacroAssembler.h index 4f27e85c98..6fac27fdf1 100644 --- a/src/3rdparty/masm/assembler/AbstractMacroAssembler.h +++ b/src/3rdparty/masm/assembler/AbstractMacroAssembler.h @@ -66,7 +66,7 @@ public: typedef MacroAssemblerCodePtr CodePtr; typedef MacroAssemblerCodeRef CodeRef; -#if !CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP) +#if !CPU(ARM_THUMB2) && !CPU(ARM64) && !defined(V4_BOOTSTRAP) class Jump; #endif @@ -455,7 +455,7 @@ public: AssemblerLabel m_label; }; -#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP) +#if CPU(ARM_THUMB2) || CPU(ARM64) || defined(V4_BOOTSTRAP) using Jump = typename AssemblerType::template Jump