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++); }
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; }