Convert xpcom/docs/*.rst to MyST-flavored Markdown. Update stringguide.xpidl :ref: targets to the explicit (stringguide-xpidl)= MyST anchor. Differential Revision: https://phabricator.services.mozilla.com/D304220
377 lines
22 KiB
Markdown
377 lines
22 KiB
Markdown
# XPIDL
|
|
|
|
**XPIDL** is an Interface Description Language used to specify XPCOM interface
|
|
classes.
|
|
|
|
Interface Description Languages (IDL) are used to describe interfaces in a
|
|
language- and machine-independent way. IDLs make it possible to define
|
|
interfaces which can then be processed by tools to autogenerate
|
|
language-dependent interface specifications.
|
|
|
|
An xpidl file is essentially just a series of declarations. At the top level,
|
|
we can define typedefs, native types, or interfaces. Interfaces may
|
|
furthermore contain typedefs, natives, methods, constants, or attributes.
|
|
Most declarations can have properties applied to them.
|
|
|
|
## Types
|
|
|
|
There are three ways to make types: a typedef, a native, or an interface. In
|
|
addition, there are a few built-in native types. The built-in native types
|
|
are those listed under the type_spec production above. The following is the
|
|
correspondence table:
|
|
|
|
| IDL Type | Javascript Type | C++ in parameter | C++ out parameter | Rust in parameter | Rust out parameter |
|
|
| ------------------------- | --------------- | ------------------------- | -------------------------- | ------------------- | ------------------ |
|
|
| `boolean` | boolean | `bool` | `bool*` | `bool` | `*mut bool` |
|
|
| `char` | string | `char` | `char*` | `c_char` | `*mut c_char` |
|
|
| `double` | number | `double` | `double*` | `f64` | `*mut f64` |
|
|
| `float` | number | `float` | `float*` | `f32` | `*mut f32` |
|
|
| `long` | number | `int32_t` | `int32_t*` | `i32` | `*mut i32` |
|
|
| `long long` | number | `int64_t` | `int64_t*` | `i64` | `*mut i64` |
|
|
| `octet` | number | `uint8_t` | `uint8_t*` | `u8` | `*mut u8` |
|
|
| `short` | number | `uint16_t` | `uint16_t*` | `u16` | `*mut u16` |
|
|
| `string` [^strptr] | string | `const char*` | `char**` | `*const c_char` | `*mut *mut c_char` |
|
|
| `unsigned long` | number | `uint32_t` | `uint32_t*` | `u32` | `*mut u32` |
|
|
| `unsigned long long` | number | `uint64_t` | `uint64_t*` | `u64` | `*mut u64` |
|
|
| `unsigned short` | number | `uint16_t` | `uint16_t*` | `u16` | `*mut u16` |
|
|
| `wchar` | string | `char16_t` | `char16_t*` | `i16` | `*mut i16` |
|
|
| `wstring` [^strptr] | string | `const char16_t*` | `char16_t**` | `*const i16` | `*mut *mut i16` |
|
|
| `MozExternalRefCountType` | number | `MozExternalRefCountType` | `MozExternalRefCountType*` | `u32` | `*mut u32` |
|
|
| `Array<T>` [^array] | array | `const nsTArray<T>&` | `nsTArray<T>&` | `*const ThinVec<T>` | `*mut ThinVec<T>` |
|
|
|
|
[^strptr]: Prefer using the string class types such as `AString`, `AUTF8String`
|
|
or `ACString` to this type. The behaviour of these types is documented
|
|
more in the {ref}`String Guide <stringguide-xpidl>`
|
|
|
|
[^array]: The C++ or Rust exposed type `T` will be an owned variant. (e.g.
|
|
`ns[C]String`, `RefPtr<T>`, or `uint32_t`)
|
|
|
|
`string`, `wstring`, `[ptr] native` and `[ref] native` are
|
|
unsupported as element types.
|
|
|
|
In addition to this list, nearly every IDL file includes `nsrootidl.idl` in
|
|
some fashion, which also defines the following types:
|
|
|
|
| IDL Type | Javascript Type | C++ in parameter | C++ out parameter | Rust in parameter | Rust out parameter |
|
|
| -------------------- | --------------- | ------------------- | -------------------- | ------------------- | ------------------ |
|
|
| `PRTime` | number | `uint64_t` | `uint64_t*` | `u64` | `*mut u64` |
|
|
| `nsresult` | number | `nsresult` | `nsresult*` | `u32` [^rsresult] | `*mut u32` |
|
|
| `size_t` | number | `uint32_t` | `uint32_t*` | `u32` | `*mut u32` |
|
|
| `voidPtr` | N/A | `void*` | `void**` | `*mut c_void` | `*mut *mut c_void` |
|
|
| `charPtr` | N/A | `char*` | `char**` | `*mut c_char` | `*mut *mut c_char` |
|
|
| `unicharPtr` | N/A | `char16_t*` | `char16_t**` | `*mut i16` | `*mut *mut i16` |
|
|
| `nsIDRef` | ID object | `const nsID&` | `nsID*` | `*const nsID` | `*mut nsID` |
|
|
| `nsIIDRef` | ID object | `const nsIID&` | `nsIID*` | `*const nsIID` | `*mut nsIID` |
|
|
| `nsCIDRef` | ID object | `const nsCID&` | `nsCID*` | `*const nsCID` | `*mut nsCID` |
|
|
| `nsIDPtr` | ID object | `const nsID*` | `nsID**` | `*const nsID` | `*mut *mut nsID` |
|
|
| `nsIIDPtr` | ID object | `const nsIID*` | `nsIID**` | `*const nsIID` | `*mut *mut nsIID` |
|
|
| `nsCIDPtr` | ID object | `const nsCID*` | `nsCID**` | `*const nsCID` | `*mut *mut nsCID` |
|
|
| `nsID` | N/A | `nsID` | `nsID*` | N/A | N/A |
|
|
| `nsIID` | N/A | `nsIID` | `nsIID*` | N/A | N/A |
|
|
| `nsCID` | N/A | `nsCID` | `nsCID*` | N/A | N/A |
|
|
| `nsQIResult` | object | `void*` | `void**` | `*mut c_void` | `*mut *mut c_void` |
|
|
| `AUTF8String` [^str] | string | `const nsACString&` | `nsACString&` | `*const nsACString` | `*mut nsACString` |
|
|
| `ACString` [^str] | string | `const nsACString&` | `nsACString&` | `*const nsACString` | `*mut nsACString` |
|
|
| `AString` [^str] | string | `const nsAString&` | `nsAString&` | `*const nsAString` | `*mut nsAString` |
|
|
| `jsval` | any | `HandleValue` | `MutableHandleValue` | N/A | N/A |
|
|
| `jsid` | N/A | `jsid` | `jsid*` | N/A | N/A |
|
|
| `Promise` | Promise object | `dom::Promise*` | `dom::Promise**` | N/A | N/A |
|
|
|
|
[^rsresult]: A bare `u32` is only for bare `nsresult` in/outparams in XPIDL. The
|
|
result should be wrapped as the `nserror::nsresult` type.
|
|
|
|
[^str]: The behaviour of these types is documented more in the {ref}`String Guide
|
|
<stringguide-xpidl>`
|
|
|
|
Typedefs in IDL are basically as they are in C or C++: you define first the
|
|
type that you want to refer to and then the name of the type. Types can of
|
|
course be one of the fundamental types, or any other type declared via a
|
|
typedef, interface, or a native type.
|
|
|
|
Native types are types which correspond to a given C++ type. Most native
|
|
types are not scriptable: if it is not present in the list above, then it is
|
|
certainly not scriptable (some of the above, particularly jsid, are not
|
|
scriptable).
|
|
|
|
The contents of the parentheses of a native type declaration (although native
|
|
declarations without parentheses are parsable, I do not trust that they are
|
|
properly handled by the xpidl handlers) is a string equivalent to the C++
|
|
type. XPIDL itself does not interpret this string, it just literally pastes
|
|
it anywhere the native type is used. The interpretation of the type can be
|
|
modified by using the `[ptr]` or `[ref]` attributes on the native
|
|
declaration. Other attributes are only intended for use in `nsrootidl.idl`.
|
|
|
|
### WebIDL Interfaces
|
|
|
|
WebIDL interfaces are also valid XPIDL types. To declare a WebIDL interface in
|
|
XPIDL, write:
|
|
|
|
```JavaScript
|
|
webidl InterfaceName;
|
|
```
|
|
|
|
WebIDL types will be passed as `mozilla::dom::InterfaceName*` when used as
|
|
in-parameters, as `mozilla::dom::InterfaceName**` when used as out or
|
|
inout-parameters, and as `RefPtr<mozilla::dom::InterfaceName>` when used as
|
|
an array element.
|
|
|
|
:::{note}
|
|
Other WebIDL types (e.g. dictionaries, enums, and unions) are not currently
|
|
supported.
|
|
:::
|
|
|
|
### Constants and CEnums
|
|
|
|
Constants must be attached to an interface. The only constants supported are
|
|
those which become integer types when compiled to source code; string constants
|
|
and floating point constants are currently not supported.
|
|
|
|
Often constants are used to describe a set of enum values. In cases like this
|
|
the `cenum` construct can be used to group constants together. Constants
|
|
grouped in a `cenum` will be reflected as-if they were declared directly on
|
|
the interface, in Rust and Javascript code.
|
|
|
|
```JavaScript
|
|
cenum MyCEnum : 8 {
|
|
eSomeValue, // starts at 0
|
|
eSomeOtherValue,
|
|
};
|
|
```
|
|
|
|
The number after the enum name, like `: 8` in the example above, defines the
|
|
width of enum values with the given type. The cenum's type may be referenced in
|
|
xpidl as `nsIInterfaceName_MyCEnum`.
|
|
|
|
## Interfaces
|
|
|
|
Interfaces are basically a collection of constants, methods, and attributes.
|
|
Interfaces can inherit from one-another, and every interface must eventually
|
|
inherit from `nsISupports`.
|
|
|
|
### Interface Attributes
|
|
|
|
Interfaces may have the following attributes:
|
|
|
|
#### `uuid`
|
|
|
|
The internal unique identifier for the interface. it must be unique, and the
|
|
uuid must be generated when creating the interface. After that, it doesn't need
|
|
to be changed any more.
|
|
|
|
`mach gen-uuid`, a cli tool like `uuidgen`, or an online tool like
|
|
<https://mozilla.pettay.fi/uuidgen.html> can help generate UUIDs for new
|
|
interfaces.
|
|
|
|
#### `builtinclass`
|
|
|
|
JavaScript classes are forbidden from implementing this interface. All child
|
|
interfaces must also be marked with this property.
|
|
|
|
#### `function`
|
|
|
|
The JavaScript implementation of this interface may be a function that is
|
|
invoked on property calls instead of an object with the given property
|
|
|
|
#### `scriptable`
|
|
|
|
This interface is usable by JavaScript classes. Must inherit from a
|
|
`scriptable` interface.
|
|
|
|
#### `rust_sync`
|
|
|
|
This interface is safe to use from multiple threads concurrently. All child
|
|
interfaces must also be marked with this property. Interfaces marked this way
|
|
must be either non-scriptable or `builtinclass`, and must use threadsafe
|
|
reference counting.
|
|
|
|
Interfaces marked as `rust_sync` will implement the `Sync` trait in Rust.
|
|
For more details on what that means, read the trait's documentation:
|
|
<https://doc.rust-lang.org/nightly/std/marker/trait.Sync.html>.
|
|
|
|
### Methods and Attributes
|
|
|
|
Interfaces declare a series of attributes and methods. Attributes in IDL are
|
|
akin to JavaScript properties, in that they are a getter and (optionally) a
|
|
setter pair. In JavaScript contexts, attributes are exposed as a regular
|
|
property access, while native code sees attributes as a Get and possibly a Set
|
|
method.
|
|
|
|
Attributes can be declared readonly, in which case setting causes an error to
|
|
be thrown in script contexts and native contexts lack the Set method, by using
|
|
the `readonly` keyword.
|
|
|
|
To native code, on attribute declared `attribute type foo;` is syntactic
|
|
sugar for the declaration of two methods `type getFoo();` and `void
|
|
setFoo(in type foo);`. If `foo` were declared readonly, the latter method
|
|
would not be present. Attributes support all of the properties of methods with
|
|
the exception of `optional_argc`, as this does not make sense for attributes.
|
|
|
|
There are some special rules for attribute naming. As a result of vtable
|
|
munging by the MSVC++ compiler, an attribute with the name `IID` is
|
|
forbidden. Also like methods, if the first character of an attribute is
|
|
lowercase in IDL, it is made uppercase in native code only.
|
|
|
|
Methods define a return type and a series of in and out parameters. When called
|
|
from a JavaScript context, they invocation looks as it is declared for the most
|
|
part; some parameter properties can adjust what the code looks like. The calls
|
|
are more mangled in native contexts.
|
|
|
|
An important attribute for methods and attributes is scriptability. A method or
|
|
attribute is scriptable if it is declared in a `scriptable` interface and it
|
|
lacks a `noscript` or `notxpcom` property. Any method that is not
|
|
scriptable can only be accessed by native code. However, `scriptable` methods
|
|
must contain parameters and a return type that can be translated to script: any
|
|
native type, save a few declared in `nsrootidl.idl` (see above), may not be
|
|
used in a scriptable method or attribute. An exception to the above rule is if
|
|
a `nsQIResult` parameter has the `iid_is` property (a special case for some
|
|
QueryInterface-like operations).
|
|
|
|
Methods and attributes are mangled on conversion to native code. If a method is
|
|
declared `notxpcom`, the mangling of the return type is prevented, so it is
|
|
called mostly as it looks. Otherwise, the return type of the native method is
|
|
`nsresult`, and the return type acts as a final outparameter if it is not
|
|
`void`. The name is translated so that the first character is
|
|
unconditionally uppercase; subsequent characters are unaffected. However, the
|
|
presence of the `binaryname` property allows the user to select another name
|
|
to use in native code (to avoid conflicts with other functions). For example,
|
|
the method `[binaryname(foo)] void bar();` becomes `nsresult Foo()` in
|
|
native code (note that capitalization is still applied). However, the
|
|
capitalization is not applied when using `binaryname` with attributes; i.e.,
|
|
`[binaryname(foo)] readonly attribute Quux bar;` becomes `Getfoo(Quux**)`
|
|
in native code.
|
|
|
|
The `implicit_jscontext` and `optional_argc` parameters are properties
|
|
which help native code implementations determine how the call was made from
|
|
script. If `implicit_jscontext` is present on a method, then an additional
|
|
`JSContext* cx` parameter is added just after the regular list which receives
|
|
the context of the caller. If `optional_argc` is present, then an additional
|
|
`uint8_t _argc` parameter is added at the end which receives the number of
|
|
optional arguments that were actually used (obviously, you need to have an
|
|
optional argument in the first place). Note that if both properties are set,
|
|
the `JSContext* cx` is added first, followed by the `uint8_t _argc`, and
|
|
then ending with return value parameter. Finally, as an exception to everything
|
|
already mentioned, for attribute getters and setters the `JSContext *cx`
|
|
comes before any other arguments.
|
|
|
|
Another native-only property is `nostdcall`. Normally, declarations are made
|
|
in the stdcall ABI on Windows to be ABI-compatible with COM interfaces. Any
|
|
non-scriptable method or attribute with `nostdcall` instead uses the
|
|
`thiscall` ABI convention. Methods without this property generally use
|
|
`NS_IMETHOD` in their declarations and `NS_IMETHODIMP` in their definitions
|
|
to automatically add in the stdcall declaration specifier on requisite
|
|
compilers; those that use this method may use a plain `nsresult` instead.
|
|
|
|
Another property, `infallible`, is attribute-only. When present, it causes an
|
|
infallible C++ getter function definition to be generated for the attribute
|
|
alongside the normal fallible C++ getter declaration. It should only be used if
|
|
the fallible getter will be infallible in practice (i.e. always return
|
|
`NS_OK`) for all possible implementations. This infallible getter contains
|
|
code that calls the fallible getter, asserts success, and returns the gotten
|
|
value directly. The point of using this property is to make C++ code nicer -- a
|
|
call to the infallible getter is more concise and readable than a call to the
|
|
fallible getter. This property can only be used for attributes having built-in
|
|
or interface types, and within classes that are marked with `builtinclass`.
|
|
The latter restriction is because C++ implementations of fallible getters can
|
|
be audited for infallibility, but JS implementations can always throw (e.g. due
|
|
to OOM).
|
|
|
|
The `must_use` property is useful if the result of a method call or an
|
|
attribute get/set should always (or usually) be checked, which is frequently
|
|
the case. (e.g. a method that opens a file should almost certainly have its
|
|
result checked.) This property will cause `[[nodiscard]]` to be added to the
|
|
generated function declarations, which means certain compilers (e.g. clang and
|
|
GCC) will reports errors if these results are not used.
|
|
|
|
### Method Parameters
|
|
|
|
Each method parameter can be specified in one of three modes: `in`, `out`,
|
|
or `inout`. An `out` parameter is essentially an auxiliary return value,
|
|
although these are moderately cumbersome to use from script contexts and should
|
|
therefore be avoided if reasonable. An `inout` parameter is an in parameter
|
|
whose value may be changed as a result of the method; these parameters are
|
|
rather annoying to use and should generally be avoided if at all possible.
|
|
|
|
`out` and `inout` parameters are reflected as objects having the `.value`
|
|
property which contains the real value of the parameter; the `value`
|
|
attribute is missing in the case of `out` parameters and is initialized to
|
|
the passed-in-value for `inout` parameters. The script code needs to set this
|
|
property to assign a value to the parameter. Regular `in` parameters are
|
|
reflected more or less normally, with numeric types all representing numbers,
|
|
booleans as `true` or `false`, the various strings (including `AString`
|
|
etc.) as a JavaScript string, and `nsID` types as a `Components.ID`
|
|
instance. In addition, the `jsval` type is translated as the appropriate
|
|
JavaScript value (since a `jsval` is the internal representation of all
|
|
JavaScript values), and parameters with the `nsIVeriant` interface have their
|
|
types automatically boxed and unboxed as appropriate.
|
|
|
|
The equivalent representations of all IDL types in native code is given in the
|
|
earlier tables; parameters of type `inout` follow their `out` form. Native
|
|
code should pay particular attention to not passing in null values for out
|
|
parameters (although some parts of the codebase are known to violate this, it
|
|
is strictly enforced at the JS\<->native barrier).
|
|
|
|
Representations of types additionally depend on some of the many types of
|
|
properties they may have. The `array` property turns the parameter into an array;
|
|
the parameter must also have a corresponding `size_is` property whose argument is
|
|
the parameter that has the size of the array. In native code, the type gains
|
|
another pointer indirection, and JavaScript arrays are used in script code.
|
|
Script code callers can ignore the value of array parameter, but implementers
|
|
must still set the values appropriately.
|
|
|
|
:::{note}
|
|
Prefer using the `Array<T>` builtin over the `[array]` attribute for
|
|
new code. It is more ergonomic to use from both JS and C++. In the future,
|
|
`[array]` may be deprecated and removed.
|
|
:::
|
|
|
|
The `const` and `shared` properties are special to native code. As its name
|
|
implies, the `const` property makes its corresponding argument `const`. The
|
|
`shared` property is only meaningful for `out` or `inout` parameters and
|
|
it means that the pointer value should not be freed by the caller. Only simple
|
|
native pointer types like `string`, `wstring`, and `octetPtr` may be
|
|
declared shared. The shared property also makes its corresponding argument
|
|
const.
|
|
|
|
The `retval` property indicates that the parameter is actually acting as the
|
|
return value, and it is only the need to assign properties to the parameter
|
|
that is causing it to be specified as a parameter. It has no effect on native
|
|
code, but script code uses it like a regular return value. Naturally, a method
|
|
which contains a `retval` parameter must be declared `void`, and the
|
|
parameter itself must be an `out` parameter and the last parameter.
|
|
|
|
Other properties are the `optional` and `iid_is` property. The `optional`
|
|
property indicates that script code may omit the property without problems; all
|
|
subsequent parameters must either by optional themselves or the retval
|
|
parameter. Note that optional out parameters still pass in a variable for the
|
|
parameter, but its value will be ignored. The `iid_is` parameter indicates
|
|
that the real IID of an `nsQIResult` parameter may be found in the
|
|
corresponding parameter, to allow script code to automatically unbox the type.
|
|
|
|
Not all type combinations are possible. Native types with the various string
|
|
properties are all forbidden from being used as an `inout` parameter or as an
|
|
`array` parameter. In addition, native types with the `nsid` property but
|
|
lacking either a `ptr` or `ref` property are forbidden unless the method is
|
|
`notxpcom` and it is used as an `in` parameter.
|
|
|
|
#### Ownership Rules
|
|
|
|
For types that reference heap-allocated data (strings, arrays, interface
|
|
pointers, etc), you must follow the XPIDL data ownership conventions in order
|
|
to avoid memory corruption and security vulnerabilities:
|
|
|
|
- For `in` parameters, the caller allocates and deallocates all data. If the
|
|
callee needs to use the data after the call completes, it must make a private
|
|
copy of the data, or, in the case of interface pointers, `AddRef` it.
|
|
- For `out` parameters, the callee creates the data, and transfers ownership
|
|
to the caller. For buffers, the callee allocates the buffer with `malloc`,
|
|
and the caller frees the buffer with `free`. For interface pointers, the
|
|
callee does the `AddRef` on behalf of the caller, and the caller must call
|
|
`Release`. This manual reference/memory management should be performed
|
|
using the `getter_AddRefs` and `getter_Transfers` helpers in new code.
|
|
- For `inout` parameters, the callee must clean up the old data if it chooses
|
|
to replace it. Buffers must be deallocated with `free`, and interface
|
|
pointers must be `Release`'d. Afterwards, the above rules for `out`
|
|
apply.
|
|
- `shared` out-parameters should not be freed, as they are intended to refer
|
|
to constant string literals.
|