diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/fdegen/fdegen.pro | 8 | ||||
-rw-r--r-- | tools/fdegen/main.cpp | 375 | ||||
-rw-r--r-- | tools/qmlbundle/qmlbundle.pro | 2 | ||||
-rw-r--r-- | tools/qmlplugindump/main.cpp | 196 | ||||
-rw-r--r-- | tools/qmlprofiler/qmlprofiler.pro | 2 | ||||
-rw-r--r-- | tools/qmlprofiler/qmlprofilerdata.cpp | 6 | ||||
-rw-r--r-- | tools/tools.pro | 3 | ||||
-rw-r--r-- | tools/v4/main.cpp | 227 | ||||
-rw-r--r-- | tools/v4/v4.pro | 9 |
9 files changed, 768 insertions, 60 deletions
diff --git a/tools/fdegen/fdegen.pro b/tools/fdegen/fdegen.pro new file mode 100644 index 0000000000..a52533280e --- /dev/null +++ b/tools/fdegen/fdegen.pro @@ -0,0 +1,8 @@ +TEMPLATE = app +TARGET = fdegen +INCLUDEPATH += . + +# Input +SOURCES += main.cpp + +LIBS += -ldwarf -lelf diff --git a/tools/fdegen/main.cpp b/tools/fdegen/main.cpp new file mode 100644 index 0000000000..8c24fb88af --- /dev/null +++ b/tools/fdegen/main.cpp @@ -0,0 +1,375 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the V4VM module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <libdwarf.h> +#include <dwarf.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#define DEBUG + +#ifdef DEBUG +#include <libelf.h> +#endif + +#include <qglobal.h> + +enum DwarfRegs { +#if defined(Q_PROCESSOR_X86_64) + // X86-64 + RAX = 0, + RDX = 1, + RCX = 2, + RBX = 3, + RSI = 4, + RDI = 5, + RBP = 6, + RSP = 7, + R8 = 8, + R9 = 9, + R10 = 10, + R11 = 11, + R12 = 12, + R13 = 13, + R14 = 14, + R15 = 15, + RIP = 16, + + InstructionPointerRegister = RIP, + StackPointerRegister = RSP, + StackFrameRegister = RBP +#elif defined(Q_PROCESSOR_X86) + // x86 + EAX = 0, + EDX = 1, + ECX = 2, + EBX = 3, + ESP = 4, + EBP = 5, + ESI = 6, + EDI = 7, + EIP = 8, + + InstructionPointerRegister = EIP, + StackPointerRegister = ESP, + StackFrameRegister = EBP +#else +#error Not ported yet +#endif +}; + +static const DwarfRegs calleeSavedRegisters[] = { +#if defined(Q_PROCESSOR_X86_64) + R12, + R14 +#elif defined(Q_PROCESSOR_X86) + ESI, + EDI +#endif +}; +static const int calleeSavedRegisterCount = sizeof(calleeSavedRegisters) / sizeof(calleeSavedRegisters[0]); + +#if QT_POINTER_SIZE == 8 +#define Elf_Ehdr Elf64_Ehdr +#define elf_newehdr elf64_newehdr +#define Elf_Shdr Elf64_Shdr +#define elf_getshdr elf64_getshdr +#else +#define Elf_Ehdr Elf32_Ehdr +#define elf_newehdr elf32_newehdr +#define Elf_Shdr Elf32_Shdr +#define elf_getshdr elf32_getshdr +#endif + +static void die(const char *msg) +{ + fprintf(stderr, "error: %s\n", msg); + exit(1); +} + +static int createSectionCallback( + char *name, + int size, + Dwarf_Unsigned /*type*/, + Dwarf_Unsigned /*flags*/, + Dwarf_Unsigned /*link*/, + Dwarf_Unsigned /*info*/, + Dwarf_Unsigned* /*sect_name_index*/, + void * /*user_data*/, + int* /*error*/) +{ + if (strcmp(name, ".debug_frame")) + return 0; + fprintf(stderr, "createsection called with %s and size %d\n", name, size); + return 1; +} + +static unsigned char cie_init_instructions[] = { + DW_CFA_def_cfa, StackPointerRegister, /*offset in bytes */QT_POINTER_SIZE, + DW_CFA_offset | InstructionPointerRegister, 1, +}; + +int main() +{ + Dwarf_Error error = 0; + Dwarf_P_Debug dw = dwarf_producer_init_c(DW_DLC_WRITE | DW_DLC_SIZE_64, + createSectionCallback, + /* error handler */0, + /* error arg */0, + /* user data */0, + &error); + if (error != 0) + die("dwarf_producer_init_c failed"); + + Dwarf_Unsigned cie = dwarf_add_frame_cie(dw, + "", + /* code alignment factor */QT_POINTER_SIZE, + /* data alignment factor */-QT_POINTER_SIZE, + /* return address reg*/InstructionPointerRegister, + cie_init_instructions, + sizeof(cie_init_instructions), + &error); + if (error != 0) + die("dwarf_add_frame_cie failed"); + + Dwarf_P_Fde fde = dwarf_new_fde(dw, &error); + if (error != 0) + die("dwarf_new_fde failed"); + + /* New entry in state machine for code offset 1 after push rbp instruction */ + dwarf_add_fde_inst(fde, + DW_CFA_advance_loc, + /*offset in code alignment units*/ 1, + /* unused*/ 0, + &error); + + /* After "push rbp" the offset to the CFA is now 2 instead of 1 */ + dwarf_add_fde_inst(fde, + DW_CFA_def_cfa_offset_sf, + /*offset in code alignment units*/ -2, + /* unused*/ 0, + &error); + + /* After "push rbp" the value of rbp is now stored at offset 1 from CFA */ + dwarf_add_fde_inst(fde, + DW_CFA_offset, + StackFrameRegister, + 2, + &error); + + /* New entry in state machine for code offset 3 for mov rbp, rsp instruction */ + dwarf_add_fde_inst(fde, + DW_CFA_advance_loc, + /*offset in code alignment units*/ 3, + /* unused */ 0, + &error); + + /* After "mov rbp, rsp" the cfa is reachable via rbp */ + dwarf_add_fde_inst(fde, + DW_CFA_def_cfa_register, + StackFrameRegister, + /* unused */0, + &error); + + /* Callee saved registers */ + for (int i = 0; i < calleeSavedRegisterCount; ++i) { + dwarf_add_fde_inst(fde, + DW_CFA_offset, + calleeSavedRegisters[i], + i + 3, + &error); + } + + dwarf_add_frame_fde(dw, fde, + /* die */0, + cie, + /*virt addr */0, + /* length of code */0, + /* symbol index */0, + &error); + if (error != 0) + die("dwarf_add_frame_fde failed"); + + dwarf_transform_to_disk_form(dw, &error); + if (error != 0) + die("dwarf_transform_to_disk_form failed"); + + Dwarf_Unsigned len = 0; + Dwarf_Signed elfIdx = 0; + unsigned char *bytes = (unsigned char *)dwarf_get_section_bytes(dw, /* section */1, + &elfIdx, &len, &error); + if (error != 0) + die("dwarf_get_section_bytes failed"); + + // libdwarf doesn't add a terminating FDE with zero length, so let's add one + // ourselves. + unsigned char *newBytes = (unsigned char *)alloca(len + 4); + memcpy(newBytes, bytes, len); + newBytes[len] = 0; + newBytes[len + 1] = 0; + newBytes[len + 2] = 0; + newBytes[len + 3] = 0; + newBytes[len + 4] = 0; + bytes = newBytes; + len += 4; + + // Reset CIE-ID back to 0 as expected for .eh_frames + bytes[4] = 0; + bytes[5] = 0; + bytes[6] = 0; + bytes[7] = 0; + + unsigned fde_offset = bytes[0] + 4; + + bytes[fde_offset + 4] = fde_offset + 4; + + printf("static const unsigned char cie_fde_data[] = {\n"); + int i = 0; + while (i < len) { + printf(" "); + for (int j = 0; i < len && j < 8; ++j, ++i) + printf("0x%x, ", bytes[i]); + printf("\n"); + } + printf("};\n"); + + printf("static const int fde_offset = %d;\n", fde_offset); + printf("static const int initial_location_offset = %d;\n", fde_offset + 8); + printf("static const int address_range_offset = %d;\n", fde_offset + 8 + QT_POINTER_SIZE); + +#ifdef DEBUG + { + if (elf_version(EV_CURRENT) == EV_NONE) + die("wrong elf version"); + int fd = open("debug.o", O_WRONLY | O_CREAT, 0777); + if (fd < 0) + die("cannot create debug.o"); + + Elf *e = elf_begin(fd, ELF_C_WRITE, 0); + if (!e) + die("elf_begin failed"); + + Elf_Ehdr *ehdr = elf_newehdr(e); + if (!ehdr) + die(elf_errmsg(-1)); + + ehdr->e_ident[EI_DATA] = ELFDATA2LSB; +#if defined(Q_PROCESSOR_X86_64) + ehdr->e_machine = EM_X86_64; +#elif defined(Q_PROCESSOR_X86) + ehdr->e_machine = EM_386; +#else +#error port me :) +#endif + ehdr->e_type = ET_EXEC; + ehdr->e_version = EV_CURRENT; + + Elf_Scn *section = elf_newscn(e); + if (!section) + die("elf_newscn failed"); + + Elf_Data *data = elf_newdata(section); + if (!data) + die(elf_errmsg(-1)); + data->d_align = 4; + data->d_off = 0; + data->d_buf = bytes; + data->d_size = len; + data->d_type = ELF_T_BYTE; + data->d_version = EV_CURRENT; + + Elf_Shdr *shdr = elf_getshdr(section); + if (!shdr) + die(elf_errmsg(-1)); + + shdr->sh_name = 1; + shdr->sh_type = SHT_PROGBITS; + shdr->sh_entsize = 0; + + char stringTable[] = { + 0, + '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', 0, + '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0 + }; + + section = elf_newscn(e); + if (!section) + die("elf_newscn failed"); + + data = elf_newdata(section); + if (!data) + die(elf_errmsg(-1)); + data->d_align = 1; + data->d_off = 0; + data->d_buf = stringTable; + data->d_size = sizeof(stringTable); + data->d_type = ELF_T_BYTE; + data->d_version = EV_CURRENT; + + shdr = elf_getshdr(section); + if (!shdr) + die(elf_errmsg(-1)); + + shdr->sh_name = 11; + shdr->sh_type = SHT_STRTAB; + shdr->sh_flags = SHF_STRINGS | SHF_ALLOC; + shdr->sh_entsize = 0; + + ehdr->e_shstrndx = elf_ndxscn(section); + + if (elf_update(e, ELF_C_WRITE) < 0) + die(elf_errmsg(-1)); + + elf_end(e); + close(fd); + } +#endif + + dwarf_producer_finish(dw, &error); + if (error != 0) + die("dwarf_producer_finish failed"); + return 0; +} diff --git a/tools/qmlbundle/qmlbundle.pro b/tools/qmlbundle/qmlbundle.pro index 440b152149..89b7477f63 100644 --- a/tools/qmlbundle/qmlbundle.pro +++ b/tools/qmlbundle/qmlbundle.pro @@ -1,4 +1,4 @@ -QT = core qml-private v8-private core-private +QT = core qml-private core-private SOURCES += main.cpp diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index 4337db1689..f312604e17 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -58,6 +58,7 @@ #include <QtCore/private/qmetaobject_p.h> #include <iostream> +#include <algorithm> #include "qmlstreamwriter.h" @@ -139,6 +140,9 @@ public: */ static QHash<QByteArray, QSet<const QQmlType *> > qmlTypesByCppName; +// No different versioning possible for a composite type. +static QMap<QString, const QQmlType * > qmlTypesByCompositeName; + static QHash<QByteArray, QByteArray> cppToId; /* Takes a C++ type name, such as Qt::LayoutDirection or QString and @@ -190,8 +194,9 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine, const if (ty->isExtendedType()) extensions[ty->typeName()].insert(ty->metaObject()->className()); collectReachableMetaObjects(ty, &metas); + } else { + qmlTypesByCompositeName[ty->elementName()] = ty; } - // TODO actually handle composite types } // Adjust exports of the base object if there are extensions. @@ -287,6 +292,135 @@ public: relocatableModuleUri = uri; } + const QString getExportString(QString qmlTyName, int majorVersion, int minorVersion) + { + if (qmlTyName.startsWith(relocatableModuleUri + QLatin1Char('/'))) { + qmlTyName.remove(0, relocatableModuleUri.size() + 1); + } + if (qmlTyName.startsWith("./")) { + qmlTyName.remove(0, 2); + } + if (qmlTyName.startsWith("/")) { + qmlTyName.remove(0, 1); + } + const QString exportString = enquote( + QString("%1 %2.%3").arg( + qmlTyName, + QString::number(majorVersion), + QString::number(minorVersion))); + return exportString; + } + + void writeMetaContent(const QMetaObject *meta) + { + QSet<QString> implicitSignals; + for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index) { + const QMetaProperty &property = meta->property(index); + dump(property); + implicitSignals.insert(QString("%1Changed").arg(QString::fromUtf8(property.name()))); + } + + if (meta == &QObject::staticMetaObject) { + // for QObject, hide deleteLater() and onDestroyed + for (int index = meta->methodOffset(); index < meta->methodCount(); ++index) { + QMetaMethod method = meta->method(index); + QByteArray signature = method.methodSignature(); + if (signature == QByteArrayLiteral("destroyed(QObject*)") + || signature == QByteArrayLiteral("destroyed()") + || signature == QByteArrayLiteral("deleteLater()")) + continue; + dump(method, implicitSignals); + } + + // and add toString(), destroy() and destroy(int) + qml->writeStartObject(QLatin1String("Method")); + qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("toString"))); + qml->writeEndObject(); + qml->writeStartObject(QLatin1String("Method")); + qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy"))); + qml->writeEndObject(); + qml->writeStartObject(QLatin1String("Method")); + qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy"))); + qml->writeStartObject(QLatin1String("Parameter")); + qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("delay"))); + qml->writeScriptBinding(QLatin1String("type"), enquote(QLatin1String("int"))); + qml->writeEndObject(); + qml->writeEndObject(); + } else { + for (int index = meta->methodOffset(); index < meta->methodCount(); ++index) + dump(meta->method(index), implicitSignals); + } + } + + QString getPrototypeNameForCompositeType(const QMetaObject *metaObject) + { + QString prototypeName; + const QMetaObject *superMetaObject = metaObject->superClass(); + if (!superMetaObject) + return "QObject"; + QString className = convertToId(superMetaObject->className()); + if (className.startsWith("QQuick")) + prototypeName = className; + else + prototypeName = getPrototypeNameForCompositeType(superMetaObject); + return prototypeName; + } + + void dumpComposite(QQmlEngine *engine, const QQmlType *compositeType, QSet<QByteArray> &defaultReachableNames) + { + + QQmlComponent e(engine, compositeType->sourceUrl()); + QObject *object = e.create(); + + if (!object) + return; + + qml->writeStartObject("Component"); + + const QMetaObject *mainMeta = object->metaObject(); + + // Get C++ base class name for the composite type + QString prototypeName = getPrototypeNameForCompositeType(mainMeta); + qml->writeScriptBinding(QLatin1String("prototype"), enquote(prototypeName)); + + QString qmlTyName = compositeType->qmlTypeName(); + // name should be unique + qml->writeScriptBinding(QLatin1String("name"), enquote(qmlTyName)); + const QString exportString = getExportString(qmlTyName, compositeType->majorVersion(), compositeType->minorVersion()); + qml->writeArrayBinding(QLatin1String("exports"), QStringList() << exportString); + qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), QStringList() << QString::number(compositeType->minorVersion())); + + for (int index = mainMeta->classInfoCount() - 1 ; index >= 0 ; --index) { + QMetaClassInfo classInfo = mainMeta->classInfo(index); + if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) { + qml->writeScriptBinding(QLatin1String("defaultProperty"), enquote(QLatin1String(classInfo.value()))); + break; + } + } + + QSet<const QMetaObject *> metas; + QSet<const QMetaObject *> candidatesComposite; + collectReachableMetaObjects(mainMeta, &candidatesComposite); + + // Also eliminate meta objects with the same classname. + // This is required because extended objects seem not to share + // a single meta object instance. + foreach (const QMetaObject *mo, candidatesComposite) { + if (!defaultReachableNames.contains(mo->className())) + metas.insert(mo); + } + + // put the metaobjects into a map so they are always dumped in the same order + QMap<QString, const QMetaObject *> nameToMeta; + foreach (const QMetaObject *meta, metas) + nameToMeta.insert(convertToId(meta), meta); + + foreach (const QMetaObject *meta, nameToMeta) + writeMetaContent(meta); + + qml->writeEndObject(); + } + void dump(const QMetaObject *meta) { qml->writeStartObject("Component"); @@ -310,27 +444,13 @@ public: QHash<QString, const QQmlType *> exports; foreach (const QQmlType *qmlTy, qmlTypes) { - QString qmlTyName = qmlTy->qmlTypeName(); - if (qmlTyName.startsWith(relocatableModuleUri + QLatin1Char('/'))) { - qmlTyName.remove(0, relocatableModuleUri.size() + 1); - } - if (qmlTyName.startsWith("./")) { - qmlTyName.remove(0, 2); - } - if (qmlTyName.startsWith("/")) { - qmlTyName.remove(0, 1); - } - const QString exportString = enquote( - QString("%1 %2.%3").arg( - qmlTyName, - QString::number(qmlTy->majorVersion()), - QString::number(qmlTy->minorVersion()))); + const QString exportString = getExportString(qmlTy->qmlTypeName(), qmlTy->majorVersion(), qmlTy->minorVersion()); exports.insert(exportString, qmlTy); } // ensure exports are sorted and don't change order when the plugin is dumped again QStringList exportStrings = exports.keys(); - qSort(exportStrings); + std::sort(exportStrings.begin(), exportStrings.end()); qml->writeArrayBinding(QLatin1String("exports"), exportStrings); // write meta object revisions @@ -354,43 +474,7 @@ public: for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index) dump(meta->enumerator(index)); - QSet<QString> implicitSignals; - for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index) { - const QMetaProperty &property = meta->property(index); - dump(property); - implicitSignals.insert(QString("%1Changed").arg(QString::fromUtf8(property.name()))); - } - - if (meta == &QObject::staticMetaObject) { - // for QObject, hide deleteLater() and onDestroyed - for (int index = meta->methodOffset(); index < meta->methodCount(); ++index) { - QMetaMethod method = meta->method(index); - QByteArray signature = method.methodSignature(); - if (signature == QByteArrayLiteral("destroyed(QObject*)") - || signature == QByteArrayLiteral("destroyed()") - || signature == QByteArrayLiteral("deleteLater()")) - continue; - dump(method, implicitSignals); - } - - // and add toString(), destroy() and destroy(int) - qml->writeStartObject(QLatin1String("Method")); - qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("toString"))); - qml->writeEndObject(); - qml->writeStartObject(QLatin1String("Method")); - qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy"))); - qml->writeEndObject(); - qml->writeStartObject(QLatin1String("Method")); - qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy"))); - qml->writeStartObject(QLatin1String("Parameter")); - qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("delay"))); - qml->writeScriptBinding(QLatin1String("type"), enquote(QLatin1String("int"))); - qml->writeEndObject(); - qml->writeEndObject(); - } else { - for (int index = meta->methodOffset(); index < meta->methodCount(); ++index) - dump(meta->method(index), implicitSignals); - } + writeMetaContent(meta); qml->writeEndObject(); } @@ -672,6 +756,7 @@ int main(int argc, char *argv[]) // add some otherwise unreachable QMetaObjects defaultReachable.insert(&QQuickMouseEvent::staticMetaObject); // QQuickKeyEvent, QQuickPinchEvent, QQuickDropEvent are not exported + QSet<QByteArray> defaultReachableNames; // this will hold the meta objects we want to dump information of QSet<const QMetaObject *> metas; @@ -723,7 +808,6 @@ int main(int argc, char *argv[]) // Also eliminate meta objects with the same classname. // This is required because extended objects seem not to share // a single meta object instance. - QSet<QByteArray> defaultReachableNames; foreach (const QMetaObject *mo, defaultReachable) defaultReachableNames.insert(QByteArray(mo->className())); foreach (const QMetaObject *mo, candidates) { @@ -761,6 +845,8 @@ int main(int argc, char *argv[]) foreach (const QMetaObject *meta, nameToMeta) { dumper.dump(meta); } + foreach (const QQmlType *compositeType, qmlTypesByCompositeName) + dumper.dumpComposite(&engine, compositeType, defaultReachableNames); // define QEasingCurve as an extension of QQmlEasingValueType, this way // properties using the QEasingCurve type get useful type information. diff --git a/tools/qmlprofiler/qmlprofiler.pro b/tools/qmlprofiler/qmlprofiler.pro index b3833a83ab..a939612c67 100644 --- a/tools/qmlprofiler/qmlprofiler.pro +++ b/tools/qmlprofiler/qmlprofiler.pro @@ -1,4 +1,4 @@ -QT = qml qml-private v8-private network core-private +QT = qml qml-private network core-private SOURCES += main.cpp \ qmlprofilerapplication.cpp \ diff --git a/tools/qmlprofiler/qmlprofilerdata.cpp b/tools/qmlprofiler/qmlprofilerdata.cpp index 5d387d6234..038d2177f9 100644 --- a/tools/qmlprofiler/qmlprofilerdata.cpp +++ b/tools/qmlprofiler/qmlprofilerdata.cpp @@ -47,6 +47,8 @@ #include <QFile> #include <QXmlStreamReader> +#include <algorithm> + namespace Constants { const char TYPE_PAINTING_STR[] = "Painting"; const char TYPE_COMPILING_STR[] = "Compiling"; @@ -437,9 +439,9 @@ void QmlProfilerData::sortStartTimes() itFrom--; if (itTo->startTime <= itFrom->startTime) - qSort(itFrom, itTo + 1, compareStartTimes); + std::sort(itFrom, itTo + 1, compareStartTimes); else - qSort(itFrom + 1, itTo + 1, compareStartTimes); + std::sort(itFrom + 1, itTo + 1, compareStartTimes); // move to next block itTo = itFrom; diff --git a/tools/tools.pro b/tools/tools.pro index eda9e85c8c..43b6c14022 100644 --- a/tools/tools.pro +++ b/tools/tools.pro @@ -4,7 +4,8 @@ qtHaveModule(qmltest): SUBDIRS += qmltestrunner SUBDIRS += \ qmlmin \ qmlprofiler \ - qmlbundle + qmlbundle \ + v4 qtHaveModule(quick):qtHaveModule(widgets): SUBDIRS += qmleasing # qmlmin & qmlbundle are build tools. diff --git a/tools/v4/main.cpp b/tools/v4/main.cpp new file mode 100644 index 0000000000..c6fa1c986f --- /dev/null +++ b/tools/v4/main.cpp @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the V4VM module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qv4object_p.h" +#include "private/qv4runtime_p.h" +#include "private/qv4functionobject_p.h" +#include "private/qv4errorobject_p.h" +#include "private/qv4globalobject_p.h" +#include "private/qv4codegen_p.h" +#include "private/qv4isel_moth_p.h" +#include "private/qv4vme_moth_p.h" +#include "private/qv4objectproto_p.h" +#include "private/qv4isel_p.h" +#include "private/qv4mm_p.h" +#include "private/qv4context_p.h" +#include "private/qv4script_p.h" +#include "private/qv4exception_p.h" + +#ifdef V4_ENABLE_JIT +# include "private/qv4isel_masm_p.h" +#endif // V4_ENABLE_JIT + +#include <QtCore> +#include <private/qqmljsengine_p.h> +#include <private/qqmljslexer_p.h> +#include <private/qqmljsparser_p.h> +#include <private/qqmljsast_p.h> + +#include <iostream> + +namespace builtins { + +using namespace QV4; + +struct Print: FunctionObject +{ + Print(ExecutionContext *scope): FunctionObject(scope) { + vtbl = &static_vtbl; + name = scope->engine->newString("print"); + } + + static Value call(Managed *, CallData *callData) + { + for (int i = 0; i < callData->argc; ++i) { + QString s = callData->args[i].toQStringNoThrow(); + if (i) + std::cout << ' '; + std::cout << qPrintable(s); + } + std::cout << std::endl; + return Value::undefinedValue(); + } + + static const ManagedVTable static_vtbl; +}; + +DEFINE_MANAGED_VTABLE(Print); + +struct GC: public FunctionObject +{ + GC(ExecutionContext* scope) + : FunctionObject(scope) + { + vtbl = &static_vtbl; + name = scope->engine->newString("gc"); + } + static Value call(Managed *m, CallData *) + { + m->engine()->memoryManager->runGC(); + return Value::undefinedValue(); + } + + static const ManagedVTable static_vtbl; +}; + +DEFINE_MANAGED_VTABLE(GC); + +} // builtins + +static void showException(QV4::ExecutionContext *ctx, const QV4::Exception &exception) +{ + QV4::ErrorObject *e = exception.value().asErrorObject(); + if (!e) { + std::cerr << "Uncaught exception: " << qPrintable(exception.value().toString(ctx)->toQString()) << std::endl; + } else { + std::cerr << "Uncaught exception: " << qPrintable(e->get(ctx->engine->newString(QStringLiteral("message")), 0).toString(ctx)->toQString()) << std::endl; + } + + foreach (const QV4::ExecutionEngine::StackFrame &frame, exception.stackTrace()) { + std::cerr << " at " << qPrintable(frame.function) << " (" << qPrintable(frame.source); + if (frame.line >= 0) + std::cerr << ":" << frame.line; + std::cerr << ")" << std::endl; + } +} + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + QStringList args = app.arguments(); + args.removeFirst(); + + enum { + use_masm, + use_moth + } mode; +#ifdef V4_ENABLE_JIT + mode = use_masm; +#else + mode = use_moth; +#endif + + bool runAsQml = false; + + if (!args.isEmpty()) { + if (args.first() == QLatin1String("--jit")) { + mode = use_masm; + args.removeFirst(); + } + + if (args.first() == QLatin1String("--interpret")) { + mode = use_moth; + args.removeFirst(); + } + + if (args.first() == QLatin1String("--qml")) { + runAsQml = true; + args.removeFirst(); + } + + if (args.first() == QLatin1String("--help")) { + std::cerr << "Usage: v4 [|--debug|-d] [|--jit|--interpret|--compile|--aot|--llvm-jit] file..." << std::endl; + return EXIT_SUCCESS; + } + } + + switch (mode) { + case use_masm: + case use_moth: { + QQmlJS::EvalISelFactory* iSelFactory = 0; + if (mode == use_moth) { + iSelFactory = new QQmlJS::Moth::ISelFactory; +#ifdef V4_ENABLE_JIT + } else { + iSelFactory = new QQmlJS::MASM::ISelFactory; +#endif // V4_ENABLE_JIT + } + + QV4::ExecutionEngine vm(iSelFactory); + + QV4::ExecutionContext *ctx = vm.rootContext; + + QV4::Object *globalObject = vm.globalObject; + QV4::Object *print = new (ctx->engine->memoryManager) builtins::Print(ctx); + globalObject->put(vm.newIdentifier(QStringLiteral("print")), QV4::Value::fromObject(print)); + QV4::Object *gc = new (ctx->engine->memoryManager) builtins::GC(ctx); + globalObject->put(vm.newIdentifier(QStringLiteral("gc")), QV4::Value::fromObject(gc)); + + foreach (const QString &fn, args) { + QFile file(fn); + if (file.open(QFile::ReadOnly)) { + const QString code = QString::fromUtf8(file.readAll()); + file.close(); + + try { + QV4::Script script(ctx, code, fn); + script.parseAsBinding = runAsQml; + script.parse(); + QV4::Value result = script.run(); + if (!result.isUndefined()) { + if (! qgetenv("SHOW_EXIT_VALUE").isEmpty()) + std::cout << "exit value: " << qPrintable(result.toString(ctx)->toQString()) << std::endl; + } + } catch (QV4::Exception& ex) { + ex.accept(ctx); + showException(ctx, ex); + return EXIT_FAILURE; + } + + } else { + std::cerr << "Error: cannot open file " << fn.toUtf8().constData() << std::endl; + return EXIT_FAILURE; + } + } + + vm.memoryManager->dumpStats(); + } return EXIT_SUCCESS; + } // switch (mode) +} diff --git a/tools/v4/v4.pro b/tools/v4/v4.pro new file mode 100644 index 0000000000..c67bb9caaf --- /dev/null +++ b/tools/v4/v4.pro @@ -0,0 +1,9 @@ +TEMPLATE = app +QT = qml-private core-private +SOURCES = main.cpp + +include($$PWD/../../src/3rdparty/masm/masm-defs.pri) + +CONFIG += exceptions + +load(qt_tool) |