Mozilla 2/XPCOM and Binary Embedding
NOTE: This document is a writeup of things that bsmedberg has been thinking. It is not (yet) a decision, only a proposal. Discussion of this document should be directed to the mozilla.dev.platform mailing list.
XPCOM is currently being used in native code by both embedders and extension authors. This is possible because XPCOM has methods to expose both stable (frozen) and unstable APIs using a stable ABI in ways that are safe to link against and, if proper precautions are taken, can be used in multiple versions of mozilla-based products.
NOTE: The scripted reflection of the XPCOM object model will remain almost exactly as it is today. Components.classes, Components.interfaces, registering various objects using categories and contracts, etc will not change. This document is only discussing XPCOM used from binary code.
In Mozilla 2, the nature of XPCOM is changing significantly. It will no longer expose a stable ABI. For example:
- XPCOM Interfaces will no longer be reference-counted. Instead, XPCOM objects will be garbage-collected. nsISupports is being changed to inherit from MMgc::GCFinalizable, which is not stable by design.
- In future versions, the requirements placed upon XPCOM objects may change. For instance, for Mozilla 2 XPCOM objects will be conservatively scanned by default. In future versions, objects may be required to implement a custom-mark routine or provide a bitmap of GC pointers to mark.
- The XPCOM string classes will be changing: see Mozilla 2/Strings
Therefore, I do not believe it is a good idea to encourage embedders or extension authors to continue to use binary XPCOM, and we should encourage or require alternate solutions.
In order to actively move away from "binary XPCOM", we will need to solve the following use cases:
Extensions and XR applications
Extension authors can write most of their application in JS. However, they may still need the ability to interact with native code. This is important so that they can use
- precompiled external libraries (imagemagick)
- perform operations in native code which would be too slow in JS
Embedders need to bootstrap gecko inside some binary application. This application may be a browser (Epiphany) or a specialty application which needs some browsing/internet capabilities (a feed reader, perhaps).
The current solutions for embedding:
- gtkmozembed (Linux)
- Mozilla ActiveX control (Windows)
- CHBrowserView (Camino)
- custom bootstrap using XPCOM
While the current embedding APIs provide some limited functionality, almost all embedders currently must use XPCOM to achieve more complex goals, for example:
- customizing prompts displayed to the user (nsIPromptService)
- providing custom UI (download manager)
- providing correct security UI
Many of these techniques rely on unstable APIs and break between major releases of Mozilla, and some even between minor releases. This relegates embedders to a second-class position that is frustrating for everyone involved.
I believe that we should revamp our embedding APIs so that a full set of functionality is provided, i.e. everything needed by Epiphany and various mobile-device embedders using the Mozilla platform.
There are at least two possible paths here:
- Provide a single embedding API for all platforms, probably declared in C++
- Provide a different embedding API for each platform (fix gtkmozembed, activex control, chbrowserview)
In either case, we should not only implement these embedding APIs, but actively test them using the same unit-test infrastructure as the rest of our tree. This will go a long way to avoid accidental breakage or obsolescence.
In either case, I think that if embedders need access to individual DOM elements, that should be exposed through the scriptable NPAPI object interface. The advantages of this interface are:
- Already implemented
- provides simple access to a wide range of DOM objects and properties
Should XPCOM still be available to extensions or embedders that absolutely require it, with the knowledge that it is and will remain an unstable binary API?
There are significant costs of usably exposing C++ APIs through a shared library interface, even if we don't promise any binary compatibility. Every function in libxul that calls an exported function pays a price in terms of PIC code and startup time.
In addition, we may be able to make more dramatic changes to the Mozilla binary code if we don't have to expose any of it directly to the outside world. Many methods are currently virtual simply because that's the necessary structure of an XPCOM interface called across DLL boundaries. If xpconnect no longer operates on XPCOM interfaces (at least in the common case) many virtual methods can be made non-virtual. This means however that to access these C++ methods from outside the DSO you would either have to explicitly export the class.
If we decide to continue to expose XPCOM interfaces for the time being, I believe it should be seen as a compatibility crutch until other solutions such as js-ctypes and native embedding APIs are completely usable.