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.