mozilla/gecko-dev
Patterns and conventions
Gecko's coding patterns are partly modern, partly legacy. The codebase has accumulated decades of conventions, and you will see all of them depending on which directory you're in.
C++ conventions
Namespaces
- Old code uses no namespace; types start with
ns(nsCOMPtr,nsString). - Newer code uses
mozilla::and submodules (mozilla::dom::,mozilla::layout::,mozilla::ipc::). - Pure-platform code lives directly in
mozilla::. - New types should generally go in
mozilla::<subsystem>::rather than the globalns*namespace.
Strings
nsAString/nsACStringare the abstract base classes for UTF-16 / UTF-8 strings.nsString(UTF-16, owned),nsAutoString(stack buffer + heap fallback),nsLiteralString(compile-time).nsCString(8-bit),nsAutoCString,nsLiteralCString.- Avoid
std::stringandstd::wstringin platform code. - Headers under
xpcom/string/andmfbt/.
Smart pointers
RefPtr<T>for refcounted classes (whereThasAddRef/Release).nsCOMPtr<T>for XPCOM interface pointers (nsIFoo).mozilla::UniquePtr<T>(≈std::unique_ptr).mozilla::WeakPtr<T>.- Raw
T*is fine for non-owning, non-escaping references.
Refcounting
NS_INLINE_DECL_REFCOUNTING(Class)for cheap, single-threaded ref counting.NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Class)for cross-thread.NS_DECL_ISUPPORTS+NS_IMPL_ISUPPORTS(...)for full XPCOM types.- Cycle-collected classes use
NS_DECL_CYCLE_COLLECTING_ISUPPORTSandNS_IMPL_CYCLE_COLLECTING_ADDREF/RELEASE.
Annotations
MOZ_CAN_RUN_SCRIPT— function may invoke JS. Static analysis enforces transitive correctness.MOZ_CAN_RUN_SCRIPT_BOUNDARY— JS boundary stop.MOZ_KNOWN_LIVE— argument is guaranteed live for the duration.MOZ_NEVER_INLINE,MOZ_ALWAYS_INLINE.MOZ_ASSERT(...)— debug-only assert.MOZ_RELEASE_ASSERT(...)— release-mode assert.MOZ_DIAGNOSTIC_ASSERT(...)— release on Nightly/dev, off in release builds.
Error handling
- Most XPCOM APIs return
nsresult.NS_OKis success;NS_FAILED(rv)/NS_SUCCEEDED(rv)to check. - Use
NS_ENSURE_SUCCESS(rv, ret)andNS_ENSURE_TRUE(...)for early returns. - New code prefers
mozilla::Result<T, E>andMOZ_TRY(...)(analogous to?in Rust).
JavaScript conventions
File naming
.sys.mjs— JS modules loaded into the system principal (ChromeUtils.importESModule(...)). Replaced the older.jsmextension..mjs— content-side ES modules..jsm— legacy module format; in active migration to.sys.mjs.
Module patterns
// Modern (.sys.mjs)
export class Foo {
/* ... */
}
// Legacy (.jsm)
this.EXPORTED_SYMBOLS = ['Foo'];Importing
// In chrome / browser code
import { Foo } from 'resource://gre/modules/Foo.sys.mjs';
// Or from a chrome script
const { Foo } = ChromeUtils.importESModule(
'resource://gre/modules/Foo.sys.mjs'
);Lazy modules
For startup performance, define lazy getters:
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
Foo: 'resource://gre/modules/Foo.sys.mjs',
});Linting
eslint.config.mjsis the entry point. Sub-config files apply per-directory rules.- The Mozilla-specific ESLint plugin lives at
tools/lint/eslint/eslint-plugin-mozilla/. - Run
./mach eslint <path> --fixto auto-fix.
Build files
Every directory that contains source files has a moz.build. Common patterns:
# Sources
SOURCES += ["MyFile.cpp"]
UNIFIED_SOURCES += ["A.cpp", "B.cpp"] # combined for faster compile
EXPORTS.mozilla.foo += ["MyFile.h"]
# JS modules
EXTRA_JS_MODULES += ["MyModule.sys.mjs"]
# IDL
XPIDL_SOURCES += ["nsIFoo.idl"]
WEBIDL_FILES += ["Foo.webidl"]
IPDL_SOURCES += ["PFoo.ipdl"]
# Subdirs
DIRS += ["sub1", "sub2"]
TEST_DIRS += ["test"]
# Bug component
with Files("**"):
BUG_COMPONENT = ("Component", "Sub-component")UNIFIED_SOURCES concatenates files into one translation unit for faster builds; this means symbols you static-define can collide with the next file in the unification.
IDL conventions
- WebIDL goes in
*/dom/.../*.webidl. Bindings auto-generated bydom/bindings/. - XPIDL
.idlfiles declare XPCOM interfaces; the resulting C++ headers and JS bindings flow through the typelib system. - IPDL
.ipdlfiles declare per-protocol IPC actors. EachPFoo.ipdlgeneratesPFooParentandPFooChildC++ classes.
Cycle collection
If a class can hold references that form cycles with other cycle-collected classes (very common in DOM), it must participate in the cycle collector. Use NS_DECL_CYCLE_COLLECTION_CLASS(...) and implement traversal/unlink macros. See xpcom/base/nsCycleCollector.cpp.
Threading
- The "main thread" is the only thread allowed to touch most XPCOM types.
NS_DispatchToMainThread(runnable)to post work.nsISerialEventTargetis the standard type for "thread or thread-pool slot".MOZ_ASSERT(NS_IsMainThread())is everywhere.- For C++ async/await-style code, see
mozilla::MozPromise(xpcom/threads/MozPromise.h).
Pref naming
branch.subsystem.feature.knob— dot-separated, lowercase, hyphens for words.- Defaults defined in
modules/libpref/init/all.jsand per-component*.jspref files. - Read with
Services.prefs.getBoolPref("path", default)orStaticPrefs::path()(generated frommodules/libpref/init/StaticPrefList.yaml).
Cross-process actors
- IPDL actors — heavy, full protocol with state machines. Use for performance-critical channels.
*.ipdlfiles. - JSActor — declarative, JS-only. Two pieces: a
JSWindowActorParentand aJSWindowActorChild. Registered throughMessageManagerJSON config. Seedom/ipc/JSActor.cpp. Most browser chrome uses these.
Linting tools
| Tool | Scope |
|---|---|
clang-format |
C/C++ formatting |
clang-tidy (selected checks) |
C++ static analysis |
eslint + Mozilla plugin |
JS |
prettier |
JS, CSS, JSON |
stylelint |
CSS |
ruff, black |
Python |
rustfmt, clippy |
Rust |
mozlint |
meta-linter that runs all of the above |
Run them all with ./mach lint.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.