Date: prev next · Thread: first prev next last
2013 Archives by date, by thread · List index


On 10/08/2013 03:23 PM, Michael Meeks wrote:
** Part one - splitting factories

        Clearly we need a new naming scheme for these; this should be
based on a mangled version of the implementation name; so:

   <implementation name="com.sun.star.comp.Draw.GraphicExporter">

        ->

        com_sun_star_comp_Draw_GraphicExporter_getFactory();

        Despite everyone's loathing of the css. namespace this makes
part three much easier.

        There are various ways to annotate that a .component file
eg. svx/util/svx.component refers to a shlib with a split factory. I
suggest we reduce the problem space by asserting that each shlib with
this property has it's components entirely split up - yielding a
single attribute change.

        For these we alter the prefix="svx" to prefix="<name>" or
some equivalent magic, and tweak:

stoc/source/loader/dllcomponentloader.cxx:

Reference<XInterface> SAL_CALL DllComponentLoader::activate(
     const OUString & rImplName, const OUString &, const OUString & rLibName,
     const Reference< XRegistryKey > & xKey )

        To special case this prefix, and build a symbol name (in
aPrefix) and use a new variant of:

cppuhelper/source/shlib.cxx:Reference< XInterface > SAL_CALL loadSharedLibComponentFactory(

        To load and hook out the correctly named symbol there.

DllComponentLoader is mostly dead by now, only comes into play during live-deployment of (non-bundled) extensions. And since, as per <http://cgit.freedesktop.org/libreoffice/core/commit/?id=3bafe5f5f529f6539363c5a291dd13ef1e2cbbde> "Extension shared library components must not use the 'prefix' feature," see <http://cgit.freedesktop.org/libreoffice/core/commit/?id=22edbdf53cc22c6cd5bb1cff99508fe4f588f462> "No need to support 'prefix' in DllComponentLoader."

Handling of the prefix feature is done entirely in cppuhelper/source/servicemanger.cxx and cppu::loadSharedLibComponentFactory.

Having reached this point, we basically have two options:

Either, keep with the current design of <prefix>_component_getFactory functions (responsible for returning factories for potentially many object implementations, dispatched by name). To split into smaller, unconnected parts would mean to split existing <component> XML entities into smaller ones, each with its own prefix attribute (but potentially multiple ones with the same uri attribute), and to split exisiting <prefix>_component_getFactory function definitions into smaller ones accordingly (but keeping their structure). That way, a <prefix>_component_getFactory could still be responsible for either multiple or just a single object implementation (though in the latter case would incur somewhat more overhead than a more straightforward design), and we would need no modifications to the infrastructure.

Or, as you detail below, go further and add more efficient support for the "single-object-implementation" factory case. (Do you have any idea whether this is worth it, given we have to continue supporting the other case for extension-compatibility anyway?)

Anyway, given that the current "prefix" feature should only be used by internal code we have under full control (see recent discussion elsewhere on this mailing list), should we go down that road, I'd prefer to replace the existing "prefix" feature with something new (e.g., an extension of the components XML schema that associates an individual <implementation> rather than a <component> with a prefix attribute), rather than keeping both. (Though we could support both for a transition period while we incrementally update the existing code.)

        We also define these factory functions to always be passed a
valid pServiceManager, and only ever to be asked to construct the
exact service name mangled into the symbol, hence:


SAL_DLLPUBLIC_EXPORT void * SAL_CALL com_sun_star_drawing_SvxUnoColorTable_getFactory ( void * 
pServiceManager )
{
     // Ideally this reference, and the branch below would be subsumed
     // by a helper, such that this method call was a single line, and
     // ideally could be macro-ized elegantly.

     uno::Reference< lang::XSingleServiceFactory > xFactory;

     xFactory = cppu::createSingleFactory(
                  reinterpret_cast< lang::XMultiServiceFactory * >( pServiceManager ),
                  SvxUnoColorTable::getImplementationName_Static(),
                  SvxUnoColorTable_createInstance,
                  SvxUnoColorTable::getSupportedServiceNames_Static() );
      if( xFactory.is())
      {
         xFactory->acquire();
         return xFactory.get();
      }
      return NULL;
}

Not sure what that specific step buys you in comparison to keeping with the existing

  extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL
  <prefix>_component_getFactory(
      char const * name, void * serviceManager, void * registryKey)

interface (which is already "always [...] passed a valid pServiceManager," and always ignores the long-time legacy registryKey argument) and just ignoring the name argument in the "single-object-implementation" case.

What would likely be more entertaining is to get rid of the cppu::createSingleFactory layer of indirection. (As you come to in part three. But note that there are service implementations that rather act like singletons and always hand out the same object instance; that needs to be taken care of.)

** Part two - list generation cleanup


      For this, we define during configure time a list of services
which we want to be internal, and unconditionally resolved into our
binaries. This would be in the form of a flat list of implementations:

com.sun.star.comp.Svx.GraphicExportHelper
com.sun.star.comp.Svx.GraphicImportHelper
com.sun.star.comp.graphic.PrimitiveFactory2D
...

      Instead of having great lists of shlibs and their locations (a
thing that would get significantly worse with longer / fragmented
lists) eg.

     static lib_to_component_mapping map[] = {
         { "libsvxlo.a", svx_component_getFactory },
        ...

        would turn one line into 10 - we instead auto-generate both
these lines, and also the 'extern' statements required to import the
symbols required inside ios/experimental/LibreOffice/LibreOffice/lo.mm
android/experimental/desktop/native-code.cxx etc.

        It is unclear that we still require the 'lib' piece in this
picture - though that could be inferred from the aggregated .component
files. It would almost certainly be preferable to fix the:

include/osl/detail/component-mapping.h (lib_to_component_mapping)
cppuhelper/source/shlib.cxx

        To instead map implementation directly to symbol, something we
can't do programatically since we need the internally bound function
pointer listed thus:

     static uno_component_mapping map[] = {
        { "com.sun.star.comp.Svx.GraphicExportHelper",
          com_sun_star_comp_Svx_GraphicExportHelper" },
        ...

        etc.

[I have trouble parsing the above, starting at "It would almost certainly..."]

An alternative is to extend the components XML schema to support lookup of the factory function directly in the executable (say) rather than a given dynamic library (e.g., by having a local="true" attribute rather than a uri="..." one). Since the uri attributes are already inserted into the .component XML files at build-time, it shouldn't be too hard to combine that with a configurable list of components that end up directly linked into the executable.

Somewhat orthogonal to that is the question how the components XML data is represented in installation sets. In addition to having them stored as XML files that are parsed at start-up in cppuhelper::ServiceManager::init, one could optionally have them pre-compiled into some data structure that is accessible from cppuhelper/source/servicemanager.cxx. In which case the data structures for such local="true" components could directly contain function pointers to the corresponding factories.

* Part three - faster component instantiation

        The wonderful work Noel has been doing around more beautiful
ways to instantiate components should dove-tail with this nicely. When
we have the list from part-two of which components are available
inside our Merged Library Domain, we should be able to directly
instantiate them ourselves, without using the UNO factory / activation
process; that should reduce code-size and improve performance, hence:


codemaker/source/cppumaker/cpputype.cxx

void ServiceType::dumpHxxFile(
     FileStream & o, codemaker::cppumaker::Includes & includes)
...

                   << codemaker::cpp::translateUnoToCppIdentifier(
                       "create", "method", codemaker::cpp::ITM_NONGLOBAL,
                       &cppName)
                   << ("(::com::sun::star::uno::Reference<"
                       " ::com::sun::star::uno::XComponentContext > const &"
                       " the_context) {\n");

        (this method should be split)

        should load and parse our list if internal implementations,
and produce a much simpler method eg. existing:

workdir/unxlngi6.pro/UnoApiHeadersTarget/offapi/comprehensive/com/sun/star/frame/FrameLoaderFactory.hpp:

        would turn into:

         try {
             the_instance = css::uno::Reference< css::frame::XLoaderFactory >(
                com_sun_star_frame_FrameLoaderFactory_create(the_context->getServiceManager()),
                ::com::sun::star::uno::UNO_QUERY);
        } ... existing disasterous size-wise exception code ... {
            // or better we could pass the fn' pointer and all the details
            // we need into a
        }

        Which should be much smaller and neater.

Question is how much that "much" would actually be. (And one would have to generate two variants of service/singleton C++ headers, an optimized one for internal use and a traditional one for external use.)

Stephan

Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.