Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/static/source/wasmbridgegen/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 36 kB image not shown  

Quelle  wasmbridgegen.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */


#include <sal/config.h>

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <fstream>
#include <ios>
#include <iostream>
#include <set>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include <codemaker/global.hxx>
#include <codemaker/typemanager.hxx>
#include <codemaker/unotype.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/temporary.hxx>
#include <o3tl/unreachable.hxx>
#include <osl/file.hxx>
#include <osl/process.h>
#include <osl/thread.h>
#include <rtl/character.hxx>
#include <rtl/process.h>
#include <rtl/ref.hxx>
#include <rtl/strbuf.hxx>
#include <rtl/string.hxx>
#include <rtl/textcvt.h>
#include <rtl/textenc.h>
#include <rtl/ustrbuf.hxx>
#include <rtl/ustring.hxx>
#include <sal/main.h>
#include <sal/types.h>
#include <unoidl/unoidl.hxx>

namespace
{
[[noreturn]] void badUsage()
{
    std::cerr
        << "Usage:\n\n"
           " wasmbridgegen \n\n"
           "where each is '+' (primary) or ':' (secondary), followed by: either a\n"
           "new- or legacy-format .rdb file, a single .idl file, or a root directory of an\n"
           ".idl file tree. For all primary registries, Wasm UNO bridge code is written to\n"
           "/, and to-be-exported exception RTTI symbols are written\n"
           "to .\n";
    std::exit(EXIT_FAILURE);
}

std::string getPathnameArgument(sal_uInt32 argument)
{
    OUString arg;
    rtl_getAppCommandArg(argument, &arg.pData);
    OString path;
    auto const enc = osl_getThreadTextEncoding();
    if (!arg.convertToString(&path, enc,
                             RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
                                 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
    {
        std::cerr << "Cannot convert \"" << arg << "\" to system encoding " << enc << "\n";
        std::exit(EXIT_FAILURE);
    }
    return std::string(path);
}

std::pair<OUString, bool> parseRegistryArgument(sal_uInt32 argument)
{
    OUString arg;
    rtl_getAppCommandArg(argument, &arg.pData);
    bool primary;
    if (arg.startsWith(u"+", &arg))
    {
        primary = true;
    }
    else if (arg.startsWith(u":", &arg))
    {
        primary = false;
    }
    else
    {
        std::cerr << "Bad registry argument \"" << arg << "\"\n";
        std::exit(EXIT_FAILURE);
    }
    OUString url;
    auto const e1 = osl::FileBase::getFileURLFromSystemPath(arg, url);
    if (e1 != osl::FileBase::E_None)
    {
        std::cerr << "Cannot convert \"" << arg << "\" to file URL, error code " << +e1 << "\n";
        std::exit(EXIT_FAILURE);
    }
    OUString cwd;
    auto const e2 = osl_getProcessWorkingDir(&cwd.pData);
    if (e2 != osl_Process_E_None)
    {
        std::cerr << "Cannot obtain working directory, error code " << +e2 << "\n";
        std::exit(EXIT_FAILURE);
    }
    OUString abs;
    auto const e3 = osl::FileBase::getAbsoluteFileURL(cwd, url, abs);
    if (e3 != osl::FileBase::E_None)
    {
        std::cerr << "Cannot make \"" << url << "\" into an absolute file URL, error code " << +e3
                  << "\n";
        std::exit(EXIT_FAILURE);
    }
    return { abs, primary };
}

OUString resolveAllTypedefs(rtl::Reference<TypeManager> const& manager, std::u16string_view name)
{
    sal_Int32 k1;
    OUString n(b2u(codemaker::UnoType::decompose(u2b(name), &k1)));
    for (;;)
    {
        rtl::Reference<unoidl::Entity> ent;
        if (manager->getSort(n, &ent) != codemaker::UnoType::Sort::Typedef)
        {
            break;
        }
        sal_Int32 k2;
        n = b2u(codemaker::UnoType::decompose(
            u2b(static_cast<unoidl::TypedefEntity*>(ent.get())->getType()), &k2));
        k1 += k2; //TODO: overflow
    }
    OUStringBuffer b;
    for (sal_Int32 i = 0; i != k1; ++i)
    {
        b.append("[]");
    }
    b.append(n);
    return b.makeStringAndClear();
}

enum class StructKind
{
    Empty,
    I32,
    I64,
    F32,
    F64,
    General
};

StructKind getKind(rtl::Reference<TypeManager> const& manager, std::u16string_view type)
{
    std::vector<OUString> args;
    rtl::Reference<unoidl::Entity> ent;
    OUString singleMemberType;
    switch (manager->decompose(type, true, nullptr, nullptr, &args, &ent))
    {
        case codemaker::UnoType::Sort::PlainStruct:
        {
            auto const strct = static_cast<unoidl::PlainStructTypeEntity const*>(ent.get());
            if (strct->getDirectMembers().size() > 1)
            {
                return StructKind::General;
            }
            auto k = StructKind::Empty;
            if (!strct->getDirectBase().isEmpty())
            {
                k = getKind(manager, strct->getDirectBase());
            }
            if (strct->getDirectMembers().empty())
            {
                return k;
            }
            if (k != StructKind::Empty)
            {
                return StructKind::General;
            }
            singleMemberType = strct->getDirectMembers()[0].type;
            break;
        }
        case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
        {
            auto const strct
                = static_cast<unoidl::PolymorphicStructTypeTemplateEntity const*>(ent.get());
            switch (strct->getMembers().size())
            {
                case 0:
                    return StructKind::Empty;
                case 1:
                    if (strct->getMembers()[0].parameterized)
                    {
                        auto const i = std::find(strct->getTypeParameters().begin(),
                                                 strct->getTypeParameters().end(),
                                                 strct->getMembers()[0].type);
                        if (i == strct->getTypeParameters().end())
                        {
                            throw CannotDumpException("bad type parameter \""
                                                      + strct->getMembers()[0].type
                                                      + "\" in call to getKind");
                        }
                        auto const n = i - strct->getTypeParameters().begin();
                        if (o3tl::make_unsigned(n) > args.size())
                        {
                            throw CannotDumpException("bad type parameter \""
                                                      + strct->getMembers()[0].type
                                                      + "\" in call to getKind");
                        }
                        singleMemberType = args[n];
                    }
                    else
                    {
                        singleMemberType = strct->getMembers()[0].type;
                    }
                    break;
                default:
                    return StructKind::General;
            }
            break;
        }
        default:
            throw CannotDumpException(OUString::Concat("unexpected entity \"") + type
                                      + "\" in call to getKind");
    }
    switch (manager->getSort(resolveAllTypedefs(manager, singleMemberType)))
    {
        case codemaker::UnoType::Sort::Boolean:
        case codemaker::UnoType::Sort::Byte:
        case codemaker::UnoType::Sort::Short:
        case codemaker::UnoType::Sort::UnsignedShort:
        case codemaker::UnoType::Sort::Long:
        case codemaker::UnoType::Sort::UnsignedLong:
        case codemaker::UnoType::Sort::Char:
        case codemaker::UnoType::Sort::Enum:
            return StructKind::I32;
        case codemaker::UnoType::Sort::Hyper:
        case codemaker::UnoType::Sort::UnsignedHyper:
            return StructKind::I64;
        case codemaker::UnoType::Sort::Float:
            return StructKind::F32;
        case codemaker::UnoType::Sort::Double:
            return StructKind::F64;
        default:
            return StructKind::General;
    }
}

void appendCallSignatureReturnType(OStringBuffer& buffer,
                                   rtl::Reference<TypeManager> const& manager, OUString const& type)
{
    switch (manager->getSort(resolveAllTypedefs(manager, type)))
    {
        case codemaker::UnoType::Sort::Void:
            buffer.append('v');
            break;
        case codemaker::UnoType::Sort::Boolean:
        case codemaker::UnoType::Sort::Byte:
        case codemaker::UnoType::Sort::Short:
        case codemaker::UnoType::Sort::UnsignedShort:
        case codemaker::UnoType::Sort::Long:
        case codemaker::UnoType::Sort::UnsignedLong:
        case codemaker::UnoType::Sort::Char:
        case codemaker::UnoType::Sort::Enum:
            buffer.append('i');
            break;
        case codemaker::UnoType::Sort::Hyper:
        case codemaker::UnoType::Sort::UnsignedHyper:
            buffer.append('j');
            break;
        case codemaker::UnoType::Sort::Float:
            buffer.append('f');
            break;
        case codemaker::UnoType::Sort::Double:
            buffer.append('d');
            break;
        case codemaker::UnoType::Sort::String:
        case codemaker::UnoType::Sort::Type:
        case codemaker::UnoType::Sort::Any:
        case codemaker::UnoType::Sort::Sequence:
        case codemaker::UnoType::Sort::Interface:
            buffer.append("vi");
            break;
        case codemaker::UnoType::Sort::PlainStruct:
        case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
        {
            switch (getKind(manager, type))
            {
                case StructKind::Empty:
                    break;
                case StructKind::I32:
                    buffer.append('i');
                    break;
                case StructKind::I64:
                    buffer.append('j');
                    break;
                case StructKind::F32:
                    buffer.append('f');
                    break;
                case StructKind::F64:
                    buffer.append('d');
                    break;
                case StructKind::General:
                    buffer.append("vi");
                    break;
            }
            break;
        }
        default:
            throw CannotDumpException("unexpected entity \"" + type
                                      + "\" in call to appendCallSignatureReturnType");
    }
}

void appendCallSignatureParameter(
    OStringBuffer& buffer, rtl::Reference<TypeManager> const& manager,
    unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction, OUString const&&nbsp;type)
{
    if (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN)
    {
        switch (manager->getSort(resolveAllTypedefs(manager, type)))
        {
            case codemaker::UnoType::Sort::Boolean:
            case codemaker::UnoType::Sort::Byte:
            case codemaker::UnoType::Sort::Short:
            case codemaker::UnoType::Sort::UnsignedShort:
            case codemaker::UnoType::Sort::Long:
            case codemaker::UnoType::Sort::UnsignedLong:
            case codemaker::UnoType::Sort::Char:
            case codemaker::UnoType::Sort::Enum:
            case codemaker::UnoType::Sort::String:
            case codemaker::UnoType::Sort::Type:
            case codemaker::UnoType::Sort::Any:
            case codemaker::UnoType::Sort::Sequence:
            case codemaker::UnoType::Sort::PlainStruct:
            case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
            case codemaker::UnoType::Sort::Interface:
                buffer.append('i');
                break;
            case codemaker::UnoType::Sort::Hyper:
            case codemaker::UnoType::Sort::UnsignedHyper:
                buffer.append('j');
                break;
            case codemaker::UnoType::Sort::Float:
                buffer.append('f');
                break;
            case codemaker::UnoType::Sort::Double:
                buffer.append('d');
                break;
            default:
                throw CannotDumpException("unexpected entity \"" + type
                                          + "\" in call to appendCallSignatureParameter");
        }
    }
    else
    {
        buffer.append('i');
    }
}

OString computeGetterCallSignature(rtl::Reference<TypeManager> const& manager,
                                   unoidl::InterfaceTypeEntity::Attribute const& attribute)
{
    OStringBuffer buf;
    appendCallSignatureReturnType(buf, manager, attribute.type);
    buf.append('i');
    return buf.makeStringAndClear();
}

OString computeSetterCallSignature(rtl::Reference<TypeManager> const& manager,
                                   unoidl::InterfaceTypeEntity::Attribute const& attribute)
{
    OStringBuffer buf("vi");
    appendCallSignatureParameter(
        buf, manager, unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN, attribute.type);
    return buf.makeStringAndClear();
}

OString computeMethodCallSignature(rtl::Reference<TypeManager> const& manager,
                                   unoidl::InterfaceTypeEntity::Method const& method)
{
    OStringBuffer buf;
    appendCallSignatureReturnType(buf, manager, method.returnType);
    buf.append('i');
    for (auto const& param : method.parameters)
    {
        appendCallSignatureParameter(buf, manager, param.direction, param.type);
    }
    return buf.makeStringAndClear();
}

void appendSlotSignatureOffsets(OStringBuffer& buffer, sal_Int32 functionOffset,
                                sal_Int32 vtableOffset)
{
    buffer.append(OString::number(functionOffset) + "_" + OString::number(vtableOffset));
}

void appendSlotSignatureReturnType(OStringBuffer& buffer,
                                   rtl::Reference<TypeManager> const& manager, OUString const& type)
{
    switch (manager->getSort(resolveAllTypedefs(manager, type)))
    {
        case codemaker::UnoType::Sort::Void:
            buffer.append('v');
            break;
        case codemaker::UnoType::Sort::Boolean:
        case codemaker::UnoType::Sort::Byte:
        case codemaker::UnoType::Sort::Short:
        case codemaker::UnoType::Sort::UnsignedShort:
        case codemaker::UnoType::Sort::Long:
        case codemaker::UnoType::Sort::UnsignedLong:
        case codemaker::UnoType::Sort::Char:
        case codemaker::UnoType::Sort::Enum:
            buffer.append('i');
            break;
        case codemaker::UnoType::Sort::Hyper:
        case codemaker::UnoType::Sort::UnsignedHyper:
            buffer.append('j');
            break;
        case codemaker::UnoType::Sort::Float:
            buffer.append('f');
            break;
        case codemaker::UnoType::Sort::Double:
            buffer.append('d');
            break;
        case codemaker::UnoType::Sort::String:
        case codemaker::UnoType::Sort::Type:
        case codemaker::UnoType::Sort::Any:
        case codemaker::UnoType::Sort::Sequence:
        case codemaker::UnoType::Sort::Interface:
            buffer.append('I');
            break;
        case codemaker::UnoType::Sort::PlainStruct:
        case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
        {
            switch (getKind(manager, type))
            {
                case StructKind::Empty:
                    break;
                case StructKind::I32:
                    buffer.append('i');
                    break;
                case StructKind::I64:
                    buffer.append('j');
                    break;
                case StructKind::F32:
                    buffer.append('f');
                    break;
                case StructKind::F64:
                    buffer.append('d');
                    break;
                case StructKind::General:
                    buffer.append('I');
                    break;
            }
            break;
        }
        default:
            throw CannotDumpException("unexpected entity \"" + type
                                      + "\" in call to appendSlotSignatureReturnType");
    }
}

void appendSlotSignatureParameter(
    OStringBuffer& buffer, rtl::Reference<TypeManager> const& manager,
    unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction, OUString const&&nbsp;type)
{
    if (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN)
    {
        switch (manager->getSort(resolveAllTypedefs(manager, type)))
        {
            case codemaker::UnoType::Sort::Boolean:
            case codemaker::UnoType::Sort::Byte:
            case codemaker::UnoType::Sort::Short:
            case codemaker::UnoType::Sort::UnsignedShort:
            case codemaker::UnoType::Sort::Long:
            case codemaker::UnoType::Sort::UnsignedLong:
            case codemaker::UnoType::Sort::Char:
            case codemaker::UnoType::Sort::Enum:
            case codemaker::UnoType::Sort::String:
            case codemaker::UnoType::Sort::Type:
            case codemaker::UnoType::Sort::Any:
            case codemaker::UnoType::Sort::Sequence:
            case codemaker::UnoType::Sort::PlainStruct:
            case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
            case codemaker::UnoType::Sort::Interface:
                buffer.append('i');
                break;
            case codemaker::UnoType::Sort::Hyper:
            case codemaker::UnoType::Sort::UnsignedHyper:
                buffer.append('j');
                break;
            case codemaker::UnoType::Sort::Float:
                buffer.append('f');
                break;
            case codemaker::UnoType::Sort::Double:
                buffer.append('d');
                break;
            default:
                throw CannotDumpException("unexpected entity \"" + type
                                          + "\" in call to appendSlotSignatureParameter");
        }
    }
    else
    {
        buffer.append('i');
    }
}

OString computeGetterSlotSignature(rtl::Reference<TypeManager> const& manager,
                                   unoidl::InterfaceTypeEntity::Attribute const& attribute,
                                   sal_Int32 functionOffset, sal_Int32 vtableOffset)
{
    OStringBuffer buf;
    appendSlotSignatureOffsets(buf, functionOffset, vtableOffset);
    appendSlotSignatureReturnType(buf, manager, attribute.type);
    return buf.makeStringAndClear();
}

OString computeSetterSlotSignature(rtl::Reference<TypeManager> const& manager,
                                   unoidl::InterfaceTypeEntity::Attribute const& attribute,
                                   sal_Int32 functionOffset, sal_Int32 vtableOffset)
{
    OStringBuffer buf;
    appendSlotSignatureOffsets(buf, functionOffset, vtableOffset);
    buf.append('v');
    appendSlotSignatureParameter(
        buf, manager, unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN, attribute.type);
    return buf.makeStringAndClear();
}

OString computeMethodSlotSignature(rtl::Reference<TypeManager> const& manager,
                                   unoidl::InterfaceTypeEntity::Method const& method,
                                   sal_Int32 functionOffset, sal_Int32 vtableOffset)
{
    OStringBuffer buf;
    appendSlotSignatureOffsets(buf, functionOffset, vtableOffset);
    appendSlotSignatureReturnType(buf, manager, method.returnType);
    for (auto const& param : method.parameters)
    {
        appendSlotSignatureParameter(buf, manager, param.direction, param.type);
    }
    return buf.makeStringAndClear();
}

void computeSlotSignatures(rtl::Reference<TypeManager> const& manager,
                           unoidl::InterfaceTypeEntity const& interface, sal_Int32& functionOffset,
                           sal_Int32& vtableOffset, std::set<OString>& slotSignatures)
{
    auto const orgVtableOffset = vtableOffset;
    auto firstBase = true;
    for (auto const& base : interface.getDirectMandatoryBases())
    {
        auto const ent = manager->getManager()->findEntity(base.name);
        if (!ent.is() || ent->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
        {
            throw CannotDumpException("unexpected base type \"" + base.name
                                      + "\" in call to computeSlotSignatures");
        }
        sal_Int32 freshFunctionOffset = 0;
        computeSlotSignatures(manager, *static_cast<unoidl::InterfaceTypeEntity const*>(ent.get()),
                              firstBase ? functionOffset : freshFunctionOffset, vtableOffset,
                              slotSignatures);
        vtableOffset += 4;
        firstBase = false;
    }
    for (auto const& attr : interface.getDirectAttributes())
    {
        slotSignatures.insert(
            computeGetterSlotSignature(manager, attr, functionOffset, orgVtableOffset));
        ++functionOffset;
        if (!attr.readOnly)
        {
            slotSignatures.insert(
                computeSetterSlotSignature(manager, attr, functionOffset, orgVtableOffset));
            ++functionOffset;
        }
    }
    for (auto const& meth : interface.getDirectMethods())
    {
        slotSignatures.insert(
            computeMethodSlotSignature(manager, meth, functionOffset, orgVtableOffset));
        ++functionOffset;
    }
}

void appendRttiSymbolSegment(OStringBuffer& buffer, OUString const& id)
{
    OString s(OUStringToOString(id, RTL_TEXTENCODING_ASCII_US));
    buffer.append(OString::number(s.getLength()) + s);
}

OString computeRttiSymbol(std::vector<OUString> const& path, OUString const& id)
{
    OStringBuffer buf("__ZTI");
    if (!path.empty())
    {
        buf.append('N');
        for (auto const& i : path)
        {
            appendRttiSymbolSegment(buf, i);
        }
    }
    appendRttiSymbolSegment(buf, id);
    if (!path.empty())
    {
        buf.append('E');
    }
    return buf.makeStringAndClear();
}

void scan(rtl::Reference<TypeManager> const& manager,
          rtl::Reference<unoidl::MapCursor> const& cursor, std::vector<OUString>& path,
          std::set<OString>& callSignatures, std::set<OString>& slotSignatures,
          std::set<OString>& rttis)
{
    assert(cursor.is());
    for (;;)
    {
        OUString id;
        auto const ent = cursor->getNext(&id);
        if (!ent.is())
        {
            break;
        }
        switch (ent->getSort())
        {
            case unoidl::Entity::SORT_MODULE:
                path.push_back(id);
                scan(manager, static_cast<unoidl::ModuleEntity*>(ent.get())->createCursor(), path,
                     callSignatures, slotSignatures, rttis);
                path.pop_back();
                break;
            case unoidl::Entity::SORT_EXCEPTION_TYPE:
                rttis.insert(computeRttiSymbol(path, id));
                break;
            case unoidl::Entity::SORT_INTERFACE_TYPE:
            {
                auto const ite = static_cast<unoidl::InterfaceTypeEntity const*>(ent.get());
                for (auto const& attr : ite->getDirectAttributes())
                {
                    callSignatures.insert(computeGetterCallSignature(manager, attr));
                    if (!attr.readOnly)
                    {
                        callSignatures.insert(computeSetterCallSignature(manager, attr));
                    }
                }
                for (auto const& meth : ite->getDirectMethods())
                {
                    callSignatures.insert(computeMethodCallSignature(manager, meth));
                }
                computeSlotSignatures(manager, *ite, o3tl::temporary<sal_Int32>(0),
                                      o3tl::temporary<sal_Int32>(0), slotSignatures);
                break;
            }
            default:
                break;
        }
    }
}
}

SAL_IMPLEMENT_MAIN()
{
    try
    {
        auto const args = rtl_getAppCommandArgCount();
        if (args < 3)
        {
            badUsage();
        }
        auto const cppPathname = getPathnameArgument(0);
        auto const asmPathname = getPathnameArgument(1);
        auto const expPathname = getPathnameArgument(2);
        rtl::Reference<TypeManager> mgr(new TypeManager);
        for (sal_uInt32 i = 3; i != args; ++i)
        {
            auto const & [ uri, primary ] = parseRegistryArgument(i);
            try
            {
                mgr->loadProvider(uri, primary);
            }
            catch (unoidl::NoSuchFileException&)
            {
                std::cerr << "Input <" << uri << "> does not exist\n";
                std::exit(EXIT_FAILURE);
            }
        }
        std::vector<OUString> path;
        std::set<OString> callSignatures;
        std::set<OString> slotSignatures;
        std::set<OString> rttis;
        for (auto const& prov : mgr->getPrimaryProviders())
        {
            scan(mgr, prov->createRootCursor(), path, callSignatures, slotSignatures, rttis);
        }
        std::ofstream cppOut(cppPathname, std::ios_base::out | std::ios_base::trunc);
        if (!cppOut)
        {
            std::cerr << "Cannot open \"" << cppPathname << "\" for writing\n";
            std::exit(EXIT_FAILURE);
        }
        cppOut << "#include \n"
                  "#include \n"
                  "#include \n"
                  "#include \n"
                  "#include \n"
                  "#include \n"
                  "#include \n";
        for (auto const& sig : callSignatures)
        {
            cppOut << "extern \"C\" void callVirtualFunction_" << sig
                   << "(sal_uInt32 target, sal_uInt64 const * arguments, void * returnValue);\n";
        }
        cppOut << "void callVirtualFunction(std::string_view signature, sal_uInt32 target, "
                  "sal_uInt64 const * arguments, void * returnValue) {\n";
        for (auto const& sig : callSignatures)
        {
            cppOut << " if (signature == \"" << sig << "\") {\n"
                   << " callVirtualFunction_" << sig << "(target, arguments, returnValue);\n"
                   << " return;\n"
                   << " }\n";
        }
        cppOut << " throw css::uno::RuntimeException(\"Wasm bridge cannot call virtual functio"
                  "with signature \" + OUString::fromUtf8(signature));\n"
                  "}\n";
        if (!slotSignatures.empty())
        {
            cppOut << "namespace {\n";
        }
        for (auto const& sig : slotSignatures)
        {
            auto const i1 = sig.indexOf('_');
            assert(i1 != -1);
            sal_Int32 i2 = i1 + 1;
            for (;; ++i2)
            {
                assert(i2 < sig.getLength());
                if (!rtl::isAsciiDigit(static_cast<unsigned char>(sig[i2])))
                {
                    break;
                }
            }
            assert(i2 != i1);
            cppOut << "extern \"C\" ";
            switch (sig[i2])
            {
                case 'd':
                    cppOut << "double";
                    break;
                case 'f':
                    cppOut << "float";
                    break;
                case 'i':
                    cppOut << "unsigned";
                    break;
                case 'j':
                    cppOut << "unsigned long long";
                    break;
                default:
                    cppOut << "void";
                    break;
            }
            cppOut << " vtableSlotFunction_" << sig << "(";
            if (sig[i2] == 'I')
            {
                cppOut << "unsigned indirectRet, ";
            }
            cppOut << "unsigned thisPtr";
            for (sal_Int32 i = i2 + 1; i != sig.getLength(); ++i)
            {
                cppOut << ", ";
                switch (sig[i])
                {
                    case 'd':
                        cppOut << "double";
                        break;
                    case 'f':
                        cppOut << "float";
                        break;
                    case 'i':
                        cppOut << "unsigned";
                        break;
                    case 'j':
                        cppOut << "unsigned long long";
                        break;
                    default:
                        O3TL_UNREACHABLE;
                }
                cppOut << " arg" << (i - i2);
            }
            cppOut << ") { ";
            switch (sig[i2])
            {
                case 'd':
                    cppOut << "return std::bit_cast(static_cast(";
                    break;
                case 'f':
                    cppOut << "return std::bit_cast(static_cast(";
                    break;
                case 'i':
                    cppOut << "return static_cast(";
                    break;
                case 'j':
                    cppOut << "return static_cast(";
                    break;
            }
            cppOut << "vtableCall(" << sig.subView(0, i1) << ", "
                   << sig.subView(i1 + 1, i2 - (i1 + 1)) << ", thisPtr, {";
            for (sal_Int32 i = i2 + 1; i != sig.getLength(); ++i)
            {
                if (i != i2 + 1)
                {
                    cppOut << ", ";
                }
                cppOut << "sal_uInt64(";
                switch (sig[i])
                {
                    case 'd':
                        cppOut << "std::bit_cast(";
                        break;
                    case 'f':
                        cppOut << "std::bit_cast(";
                        break;
                }
                cppOut << "arg" << (i - i2) << ")";
                switch (sig[i])
                {
                    case 'd':
                    case 'f':
                        cppOut << ")";
                        break;
                }
            }
            cppOut << "}, "
                   << (sig[i2] == 'I' ? "indirectRet" : "reinterpret_cast(nullptr)")
                   << ")";
            switch (sig[i2])
            {
                case 'd':
                case 'f':
                    cppOut << "))";
                    break;
                case 'i':
                case 'j':
                    cppOut << ")";
                    break;
            }
            cppOut << "; }\n";
        }
        if (!slotSignatures.empty())
        {
            cppOut << "}\n";
        }
        cppOut << "void const * getVtableSlotFunction(std::string_view signature) {\n";
        for (auto const& sig : slotSignatures)
        {
            cppOut << " if (signature == \"" << sig << "\") {\n"
                   << " return reinterpret_cast(vtableSlotFunction_" << sig
                   << ");\n"
                   << " }\n";
        }
        cppOut << " throw css::uno::RuntimeException(\"Wasm bridge cannot fill virtual functio"
                  "slot with signature \" + OUString::fromUtf8(signature));\n"
                  "}\n";
        cppOut.close();
        if (!cppOut)
        {
            std::cerr << "Failed to write \"" << cppPathname << "\"\n";
            std::exit(EXIT_FAILURE);
        }
        std::ofstream asmOut(asmPathname, std::ios_base::out | std::ios_base::trunc);
        if (!asmOut)
        {
            std::cerr << "Cannot open \"" << asmPathname << "\" for writing\n";
            std::exit(EXIT_FAILURE);
        }
        asmOut << "\t.text\n"
                  "\t.tabletype __indirect_function_table, funcref\n";
        for (auto const& sig : callSignatures)
        {
            asmOut << "\t.functype callVirtualFunction_" << sig << " (i32, i32, i32) -> ()\n";
        }
        for (auto const& sig : callSignatures)
        {
            asmOut << "\t.section .text.callVirtualFunction_" << sig
                   << ",\"\",@\n"
                      "\t.globl callVirtualFunction_"
                   << sig
                   << "\n"
                      "\t.type callVirtualFunction_"
                   << sig
                   << ",@function\n"
                      "callVirtualFunction_"
                   << sig
                   << ":\n"
                      "\t.functype callVirtualFunction_"
                   << sig << " (i32, i32, i32) -> ()\n";
            if (sig[0] != 'v')
            {
                asmOut << "\tlocal.get 2\n";
            }
            unsigned off = 0;
            for (auto c : sig.subView(1))
            {
                asmOut << "\tlocal.get 1\n"
                          "\t";
                switch (c)
                {
                    case 'd':
                        asmOut << "f64";
                        break;
                    case 'f':
                        asmOut << "f32";
                        break;
                    case 'i':
                        asmOut << "i32";
                        break;
                    case 'j':
                        asmOut << "i64";
                        break;
                    default:
                        assert(false);
                }
                asmOut << ".load " << off << "\n";
                off += 8; //TODO: overflow
            }
            asmOut << "\tlocal.get 0\n"
                      "\tcall_indirect (";
            auto first = true;
            for (auto c : sig.subView(1))
            {
                if (first)
                {
                    first = false;
                }
                else
                {
                    asmOut << ", ";
                }
                switch (c)
                {
                    case 'd':
                        asmOut << "f64";
                        break;
                    case 'f':
                        asmOut << "f32";
                        break;
                    case 'i':
                        asmOut << "i32";
                        break;
                    case 'j':
                        asmOut << "i64";
                        break;
                    default:
                        assert(false);
                }
            }
            asmOut << ") -> (";
            switch (sig[0])
            {
                case 'd':
                    asmOut << "f64";
                    break;
                case 'f':
                    asmOut << "f32";
                    break;
                case 'i':
                    asmOut << "i32";
                    break;
                case 'j':
                    asmOut << "i64";
                    break;
                case 'v':
                    break;
                default:
                    assert(false);
            }
            asmOut << ")\n";
            if (sig[0] != 'v')
            {
                asmOut << "\t";
                switch (sig[0])
                {
                    case 'd':
                        asmOut << "f64";
                        break;
                    case 'f':
                        asmOut << "f32";
                        break;
                    case 'i':
                        asmOut << "i32";
                        break;
                    case 'j':
                        asmOut << "i64";
                        break;
                    default:
                        assert(false);
                }
                asmOut << ".store 0\n";
            }
            asmOut << "\tend_function\n";
        }
        asmOut.close();
        if (!asmOut)
        {
            std::cerr << "Failed to write \"" << asmPathname << "\"\n";
            std::exit(EXIT_FAILURE);
        }
        std::ofstream expOut(expPathname, std::ios_base::out | std::ios_base::trunc);
        if (!expOut)
        {
            std::cerr << "Cannot open \"" << expPathname << "\" for writing\n";
            std::exit(EXIT_FAILURE);
        }
        for (auto const& rtti : rttis)
        {
            expOut << rtti.getStr() << "\n";
        }
        expOut.close();
        if (!expOut)
        {
            std::cerr << "Failed to write \"" << expPathname << "\"\n";
            std::exit(EXIT_FAILURE);
        }
        return EXIT_SUCCESS;
    }
    catch (unoidl::FileFormatException const& e)
    {
        std::cerr << "Bad input <" << e.getUri() << ">: " << e.getDetail() << "\n";
        std::exit(EXIT_FAILURE);
    }
    catch (CannotDumpException const& e)
    {
        std::cerr << "Failure: " << e.getMessage() << "\n";
        std::exit(EXIT_FAILURE);
    }
    catch (std::exception const& e)
    {
        std::cerr << "Failure: " << e.what() << "\n";
        std::exit(EXIT_FAILURE);
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

Messung V0.5
C=100 H=92 G=95

¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.