Example #1
0
bool QmcUnit::loadUnitData(QDataStream &stream)
{
    char *qmlUnitPtr = new char[header->sizeQmlUnit];
    char *dataPtr = new char[header->sizeUnit];
    qmlUnit = reinterpret_cast<QV4::CompiledData::QmlUnit*>(qmlUnitPtr);
    unit = reinterpret_cast<QV4::CompiledData::Unit*>(dataPtr);
    compilationUnit->data = unit;
    if (!qmlUnit || !unit)
        return false;

    if (!readData(qmlUnitPtr, header->sizeQmlUnit, stream))
        return false;

    if (!readData(dataPtr, header->sizeUnit, stream))
        return false;

    // load imports
    for (int i = 0; i < (int)header->imports; i++) {
        QV4::CompiledData::Import import;
        if (!readData((char *)&import, sizeof(QV4::CompiledData::Import), stream))
            return false;
        if (import.uriIndex >= header->strings || import.qualifierIndex >= header->strings)
            return false;
        imports.append(import);
    }

    for (int i = 0; i < (int)header->strings; i++) {
        QString string;
        if (!readString(string, stream))
            return false;
        strings.append(string);
    }

    for (int i = 0; i < (int)header->namespaces; i++) {
        QString ns;
        if (!readString(ns, stream))
            return false;
        namespaces.append(ns);
    }

    for (int i = 0; i < (int)header->typeReferences; i++) {
        QmcUnitTypeReference typeRef;
        if (!readData((char *)&typeRef, sizeof (QmcUnitTypeReference), stream))
            return false;
        typeReferences.append(typeRef);
    }

    // coderefs
    codeRefSizes.resize(header->codeRefs);
    for (int i = 0; i < (int)header->codeRefs; i++) {

#if CPU(ARM_THUMB2)
        linkRecords.clear();
        quint32 linkRecordsCount = 0;
        if (!readData((char *)&linkRecordsCount, sizeof(quint32), stream))
            return false;
        if (linkRecordsCount > QMC_UNIT_MAX_LINK_RECORDS)
            return false;

        for (uint j = 0; j < linkRecordsCount; j++) {
            QmcUnitLinkRecord record;
            if (!readData((char *)&record, sizeof (QmcUnitLinkRecord), stream))
                return false;
            linkRecords.append(record);
        }
#endif

        quint32 codeRefLen = 0;
        if (!readData((char *)&codeRefLen, sizeof(quint32), stream))
            return false;
        if (codeRefLen > QMC_UNIT_MAX_CODE_REF_SIZE)
            return false;
        //qDebug() << "Codereflen" << QString("%1").arg(codeRefLen, 0, 16);
        if (codeRefLen == 0) {
            JSC::MacroAssemblerCodeRef codeRef;
            compilationUnit->codeRefs.append(codeRef);
            QVector<QmcUnitCodeRefLinkCall> linkData;
            linkCalls.append(linkData);
            QVector<QV4::Primitive> constData;
            constantVectors.append(constData);
            continue;
        }

        // read code to temporary variable, there will be executable code if it
        QVector<char> code;
        code.resize(codeRefLen);
        if (!readData(code.data(), codeRefLen, stream)) {
            return false;
        }
        codeRefData.append(code);

        quint32 linkCallsCount = 0;
        if (!readData((char *)&linkCallsCount, sizeof(quint32), stream))
            return false;
        if (linkCallsCount > QMC_UNIT_MAX_CODE_REF_LINK_CALLS)
            return false;
        QVector<QmcUnitCodeRefLinkCall> linkData;
        if (linkCallsCount > 0) {
            linkData.resize(linkCallsCount);
            if (!readData((char *)linkData.data(), sizeof (QmcUnitCodeRefLinkCall) * linkCallsCount, stream))
                return false;
        }
        linkCalls.append(linkData);

        quint32 constantVectorLen = 0;
        if (!readData((char *)&constantVectorLen, sizeof(quint32), stream))
            return false;
        if (constantVectorLen > QMC_UNIT_MAX_CONSTANT_VECTOR_SIZE)
            return false;
        QVector<QV4::Primitive > constantVector;
        if (constantVectorLen > 0) {
            constantVector.resize(constantVectorLen);
            if (constantVectorLen == 0)
                continue;
            if (!readData((char *)constantVector.data(), constantVectorLen, stream))
                return false;
        }
        constantVectors.append(constantVector);

#if 0
        QV4::ExecutableAllocator::Allocation *executableMemory =
                QQmlEnginePrivate::get(engine)->v4engine()->executableAllocator->allocate(codeRefLen);
        if (!executableMemory)
            return false;
        allocations.append(executableMemory);
        char *codeExec = (char *) executableMemory->start();
        //ASSERT(code);
        JSC::ExecutableAllocator::makeWritable(codeExec, codeRefLen);
        memcpy(codeExec, code.data(), codeRefLen);

        JSC::MacroAssemblerCodePtr codePtr = JSC::MacroAssemblerCodePtr::createFromExecutableAddress(codeExec);
        JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(codePtr);
        compilationUnit->constantValues.append(constantVectors);
#else
        QV4::ExecutableAllocator* executableAllocator = QQmlEnginePrivate::get(engine)->v4engine()->executableAllocator;
        QmcBackedInstructionSelection *isel = new QmcBackedInstructionSelection(compilationUnit);
        QV4::IR::Function nullFunction(0, 0);
        QV4::JIT::Assembler* as = new QV4::JIT::Assembler(isel, &nullFunction, executableAllocator, 6); // 6 == max argc for calls to built-ins with an argument array

#if CPU(ARM_THUMB2)
        foreach (const QmcUnitLinkRecord &record, linkRecords) {
            as->addJump(JSC::AssemblerLabel(record.from), JSC::AssemblerLabel(record.to),
                    record.type, record.condition);
        }
#endif

        QList<QV4::JIT::Assembler::CallToLink>& callsToLink = as->callsToLink();
        foreach (const QmcUnitCodeRefLinkCall &call, linkData) {
            // resolve function pointer
            if (call.index > sizeof (QMC_LINK_TABLE) / sizeof (QmcLinkEntry))
                return false;
            void *functionPtr = QMC_LINK_TABLE[call.index].addr;
            QV4::JIT::Assembler::CallToLink c;
            JSC::AssemblerLabel label(call.offset);
            c.call = QV4::JIT::Assembler::Call(label, QV4::JIT::Assembler::Call::Linkable);
            c.externalFunction = JSC::FunctionPtr((quint64(*)(void))functionPtr);
#if QT_VERSION > QT_VERSION_CHECK(5,3,0)
            c.label.m_label = label;
#endif
            callsToLink.append(c);
        }

        QV4::JIT::Assembler::ConstantTable& constTable = as->constantTable();
        int iii = 0;
        foreach (const QV4::Primitive &p, constantVector) {
            int idx = constTable.add(p);
            Q_ASSERT(idx == iii++);
        }
Example #2
0
bool QmcUnit::loadUnitData(QDataStream &stream)
{
    char *qmlUnitPtr = new char[header->sizeQmlUnit];
    char *dataPtr = new char[header->sizeUnit];
    qmlUnit = reinterpret_cast<QV4::CompiledData::QmlUnit*>(qmlUnitPtr);
    unit = reinterpret_cast<QV4::CompiledData::Unit*>(dataPtr);
    compilationUnit->data = unit;
    if (!qmlUnit || !unit)
        return false;

    if (!readData(qmlUnitPtr, header->sizeQmlUnit, stream))
        return false;

    if (!readData(dataPtr, header->sizeUnit, stream))
        return false;

    // load imports
    for (int i = 0; i < (int)header->imports; i++) {
        QV4::CompiledData::Import import;
        if (!readData((char *)&import, sizeof(QV4::CompiledData::Import), stream))
            return false;
        if (import.uriIndex >= header->strings || import.qualifierIndex >= header->strings)
            return false;
        imports.append(import);
    }

    for (int i = 0; i < (int)header->strings; i++) {
        QString string;
        if (!readString(string, stream))
            return false;
        strings.append(string);
    }

    for (int i = 0; i < (int)header->namespaces; i++) {
        QString ns;
        if (!readString(ns, stream))
            return false;
        namespaces.append(ns);
    }

    for (int i = 0; i < (int)header->typeReferences; i++) {
        QmcUnitTypeReference typeRef;
        if (!readData((char *)&typeRef, sizeof (QmcUnitTypeReference), stream))
            return false;
        typeReferences.append(typeRef);
    }

    // coderefs
    codeRefSizes.resize(header->codeRefs);
    for (int i = 0; i < (int)header->codeRefs; i++) {
        quint32 codeRefLen = 0;
        if (!readData((char *)&codeRefLen, sizeof(quint32), stream))
            return false;
        if (codeRefLen > QMC_UNIT_MAX_CODE_REF_SIZE)
            return false;
        //qDebug() << "Codereflen" << QString("%1").arg(codeRefLen, 0, 16);
        if (codeRefLen == 0) {
            JSC::MacroAssemblerCodeRef codeRef;
            compilationUnit->codeRefs.append(codeRef);
            QVector<QmcUnitCodeRefLinkCall> linkData;
            linkCalls.append(linkData);
            QVector<QV4::Primitive> constData;
            constantVectors.append(constData);
            continue;
        }

        // read code to temporary variable, there will be executable code if it
        QVector<char> code;
        code.resize(codeRefLen);
        if (!readData(code.data(), codeRefLen, stream)) {
            return false;
        }
        codeRefData.append(code);

        quint32 linkCallsCount = 0;
        if (!readData((char *)&linkCallsCount, sizeof(quint32), stream))
            return false;
        if (linkCallsCount > QMC_UNIT_MAX_CODE_REF_LINK_CALLS)
            return false;
        QVector<QmcUnitCodeRefLinkCall> linkData;
        if (linkCallsCount > 0) {
            linkData.resize(linkCallsCount);
            if (!readData((char *)linkData.data(), sizeof (QmcUnitCodeRefLinkCall) * linkCallsCount, stream))
                return false;
        }
        linkCalls.append(linkData);

        quint32 constantVectorLen = 0;
        if (!readData((char *)&constantVectorLen, sizeof(quint32), stream))
            return false;
        if (constantVectorLen > QMC_UNIT_MAX_CONSTANT_VECTOR_SIZE)
            return false;
        QVector<QV4::Primitive > constantVector;
        if (constantVectorLen > 0) {
            constantVector.resize(constantVectorLen);
            if (constantVectorLen == 0)
                continue;
            if (!readData((char *)constantVector.data(), constantVectorLen, stream))
                return false;
        }
        constantVectors.append(constantVector);

#if 0
        QV4::ExecutableAllocator::Allocation *executableMemory =
                QQmlEnginePrivate::get(engine)->v4engine()->executableAllocator->allocate(codeRefLen);
        if (!executableMemory)
            return false;
        allocations.append(executableMemory);
        char *codeExec = (char *) executableMemory->start();
        //ASSERT(code);
        JSC::ExecutableAllocator::makeWritable(codeExec, codeRefLen);
        memcpy(codeExec, code.data(), codeRefLen);

        JSC::MacroAssemblerCodePtr codePtr = JSC::MacroAssemblerCodePtr::createFromExecutableAddress(codeExec);
        JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(codePtr);
        compilationUnit->constantValues.append(constantVectors);
#else
        QV4::ExecutableAllocator* executableAllocator = QQmlEnginePrivate::get(engine)->v4engine()->executableAllocator;
        QmcBackedInstructionSelection *isel = new QmcBackedInstructionSelection(compilationUnit);
        QV4::IR::Function nullFunction(0, 0);
        QV4::JIT::Assembler* as = new QV4::JIT::Assembler(isel, &nullFunction, executableAllocator, 6); // 6 == max argc for calls to built-ins with an argument array

        QList<QV4::JIT::Assembler::CallToLink>& callsToLink = as->callsToLink();
        foreach (const QmcUnitCodeRefLinkCall &call, linkData) {
            // resolve function pointer
            if (call.index > sizeof (QMC_LINK_TABLE) / sizeof (QmcLinkEntry))
                return false;
            void *functionPtr = QMC_LINK_TABLE[call.index].addr;
            QV4::JIT::Assembler::CallToLink c;
            JSC::AssemblerLabel label(call.offset);
            c.call = QV4::JIT::Assembler::Call(label, QV4::JIT::Assembler::Call::Linkable);
            c.externalFunction = JSC::FunctionPtr((quint64(*)(void))functionPtr);
            c.label.m_label = label;
            callsToLink.append(c);
        }

        QV4::JIT::Assembler::ConstantTable& constTable = as->constantTable();
        int iii = 0;
        foreach (const QV4::Primitive &p, constantVector) {
            int idx = constTable.add(p);
            Q_ASSERT(idx == iii++);
        }
        as->appendData(code.data(), codeRefLen);

        // TBD: need to restore the state of the assembler
        // need done:
        //  _executableAllocator
        //  _as->_callsToLink
        //  _as->_constTable
        //  _as->_constTable->_values
        //  _as->m_assembler = _as (qv4isel_masm.cpp:143)
        // need maybe done:
        //  _as->_isel
        //  _as->_isel->addConstantTable (values from _as->_constTable->_values will be appended here)
        //  _as->_isel->compilationUnit (need to be final compilation unit, QV4::JIT::CompilationUnit)
        //  _as->m_formatter (X86Assembler.h:2066~2563)
        //  _as->m_formatter->m_buffer (X86Assembler.h:2562 + AssemblerBuffer.h:63)
        //  _as->m_formatter->m_buffer->m_index (AssemblerBuffer.h:174)
        //  _as->m_formatter->m_buffer->m_buffer (AssemblerBuffer.h:172)
        //  _as->m_formatter->m_buffer->m_index (size of code)
        //  _as->m_formatter->m_buffer->m_buffer (code pointer)
        // need:
        //  function->maxNumberOfArguments
        //  function->tempCount
        // need ?:
        //  _constTable->_toPatch
        //  _patches -> need to be preparsed
        //  _dataLabelPatches
        //  exceptionPropagationJumps
        //  _labelPatches
        int dummySize;
        JSC::MacroAssemblerCodeRef codeRef = as->link(&dummySize);
        Q_ASSERT(dummySize == (int)codeRefLen);
        delete as;
        this->codeRefData.append(codeRefData);
#endif

        compilationUnit->codeRefs.append(codeRef);
        codeRefSizes[i] = codeRefLen;
    }