# include "mozilla/HashTable.h" # include "mozilla/Maybe.h" # include "mozilla/RefPtr.h" # include "mozilla/Span.h" # include "mozilla/Variant.h" # include "mozilla/Vector.h" # include "wasm/WasmModule.h"
namespace js { namespace wasm {
// A helper macro allowing component names to be printed with `%.*s`. Component // names are always ASCII, so this is safe. # define ComponentName_Printf(n) \
(int)(n).utf8Bytes().Length(), (n).utf8Bytes().data()
// A "sort", or "kind", of item in the component model, used for all cases where // we must refer to a different item. // // This type is also used for the `externdesc` type, which describes what // components (not core modules) can import and export, and whose cases are a // subset of `sort`. Sorts that are valid for `externdesc` have the highest bit // set. Additionally, sorts that can be exported by core modules (core:sort) // have the second-highest bit set, and correspond to wasm::DefinitionKind. enumclass ComponentSort : uint8_t {
Invalid = 0,
// Checks if the given sort is valid for a component import or export (the // component `externdesc` type). inlinebool ComponentSortValidForExternDesc(ComponentSort sort) { return (uint8_t(sort) & 0x80) != 0;
}
// Checks if the given sort is for a core item that can be imported or exported, // i.e. a DefinitionKind imported into the component model. To extract the // underlying DefinitionKind, use CoreSortFromComponentSort. inlinebool ComponentSortIsCoreSort(ComponentSort sort) { return (uint8_t(sort) & 0x40) != 0;
}
// Extracts the underlying DefinitionKind from a ComponentSort (if there is // one). inline DefinitionKind CoreSortFromComponentSort(ComponentSort sort) {
MOZ_ASSERT(ComponentSortIsCoreSort(sort)); return DefinitionKind(uint8_t(sort) & ~0xc0);
}
// Every kind of type that can be defined in the component model. Not all types // are valid in all contexts. enumclass ComponentTypeKind : uint8_t {
Invalid = 0,
Record = 0x72,
Variant = 0x71,
List = 0x70,
Tuple = 0x6f,
Flags = 0x6e, Enum = 0x6d,
Option = 0x6b,
Result = 0x6a,
Own = 0x69,
Borrow = 0x68,
Func = 0x40, // async func types are not a separate kind
Component = 0x41,
Instance = 0x42,
Resource = 0x3f, // resource types with callbacks are not a separate kind
// Type bounds
Eq = 0x20,
SubResource = 0x21,
// Convenience for ComponentTypeKindIsPrimitive. "First" and "last" refer to // the actual byte value.
FirstPrimitive = String,
LastPrimitive = Bool,
};
// Checks if the given kind is for a primitive type (`primvaltype`), i.e. one // that doesn't need to be defined and referenced. inlinebool ComponentTypeKindIsPrimitive(ComponentTypeKind kind) { return ComponentTypeKind::FirstPrimitive <= kind &&
kind <= ComponentTypeKind::LastPrimitive;
}
// Checks if the given kind is for a value type (`valtype`), i.e. one that can // be used for function parameters. inlinebool ComponentTypeKindIsValueType(ComponentTypeKind kind) { return ComponentTypeKindIsPrimitive(kind) ||
(ComponentTypeKind::Borrow <= kind &&
kind <= ComponentTypeKind::Record && int(kind) != 0x6c // the one weird gap in the binary
);
}
// Forward declarations to satisfy the methods in ComponentType class ComponentTypeDef; class ComponentType; struct ComponentRecordField; struct ComponentVariantCase; struct ComponentResultType; struct ComponentFuncType; class ComponentResourceType; using ComponentTypeVector =
mozilla::Vector<ComponentType, 0, SystemAllocPolicy>; using ComponentRecordFieldVector =
mozilla::Vector<ComponentRecordField, 0, SystemAllocPolicy>; using ComponentVariantCaseVector =
mozilla::Vector<ComponentVariantCase, 0, SystemAllocPolicy>;
// The type of an item within a component. class ComponentType { // TODO(wasm-cm): See if we could do a fancy tagging scheme to store the kind // in the bits of the pointer. It's a bit funky because right now we use high // bits in the kind for various purposes and so we can't pack it down into 3 // or 4 bits like you'd want.
ComponentTypeKind kind_;
// Cheaply checks if two canonicalized component types are equal under the // rules of the component model. This is fully general and handles resource // types, but because it compares ComponentTypeDef pointers for equality, only // canonicalized types are supported. booloperator==(const ComponentType& other) const { return kind_ == other.kind_ && typeDef_ == other.typeDef_;
} staticbool maybeEquals(mozilla::Maybe<ComponentType> a,
mozilla::Maybe<ComponentType> b) { if (a.isNothing() && b.isNothing()) { returntrue;
} if (a.isSome() != b.isSome()) { returnfalse;
} return *a == *b;
}
// Checks if two (non-canonical) component types are structurally equal. This // is different from the usual `==` operator, which assumes types have been // canonicalized. Resource types will always come back as unequal. // // In almost all cases, the `==` operator is what you want. staticbool structurallyEqual(const ComponentType& a, const ComponentType& b);
};
// Canonicalizes `type` against the process-wide canonical type set, returning // the canonical representative through `*canonicalized`. Thread-safe.
[[nodiscard]] bool CanonicalizeComponentType(const ComponentType& type,
ComponentType* canonicalized);
// Empties the process-wide canonical type set. Intended for shutdown / testing. void PurgeComponentCanonicalTypes();
// Checks two typedefs for structural equality. Note that this is NOT the same // as comparing two types for equality, because a) not all types even have // ComponentTypeDefs, b) different type kinds may share the same kind of // backing storage (e.g. flags and enums), and c) because this method always // considers resource types to be unequal. staticbool structurallyEqual(const ComponentTypeDef& a, const ComponentTypeDef& b);
};
// A hash policy for StronglyUniqueNameSet that hashes items based on their // trimmed, lowercased versions, but matches based on the full strongly-unique // rules. // // The full strongly-unique rules are not hash-friendly; we have not yet figured // out any way to "normalize" the name to a unique key that satisfies the // strange carve-out rules for constructor and method names. But, we don't want // to quadratically check each new name against every other name, so we take a // disappointing halfway approach of hashing only the base part of the name, and // then running the full strongly-unique logic in `match`. This results in more // hash collisions and a less-inexpensive `match` method, but at least it keeps // things from growing quadratically. struct StronglyUniqueNameHasher { using Key = CacheableName; using Lookup = mozilla::Span<constchar>;
// A class which can be used to check if a set of component model names is // strongly-unique. The set owns its keys. class StronglyUniqueNameSet {
mozilla::HashSet<CacheableName, StronglyUniqueNameHasher, SystemAllocPolicy>
data_;
// This returns the raw type index. To get the ComponentFuncType, call // Component::typeForFunc instead.
uint32_t typeIndex() const { return typeIndex_; } const ComponentCanonOptVector& canonOpts() const { return canonOpts_; }
};
// A generalized reference to an item in the component model. A ComponentItem // may reference an import, an export, an item defined in the component itself, // or an alias to an item defined elsewhere. This is the main type used for each // index space in the component model, as imports, exports, aliases, and defined // items can be interleaved in any order. // // The data is stored into two fields, one of which identifies the index space // for the item (possibly in another component), and the other of which is the // index in that index space. // // This first field, whatAndWhere_, stores all the information necessary to find // the index space for the item. It is a packed field laid out like so: // // 00 00 00000000 00000000000000000000 // │ │ │ └ instance index (ItemKind::Alias only) // │ │ └ alias sort (type ComponentSort, ItemKind::Alias only) // │ └ alias kind (type ComponentAliasKind, ItemKind::Alias only) // └ kind (type ItemKind) // // For all ItemKinds except ItemKind::Alias, this is basically a big 32-bit enum // where only the top two bits are used. But for ItemKind::Alias we additionally // store the ComponentAliasKind (core export alias, component export alias, or // outer alias) and the ComponentSort (e.g. Func or Type). Finally there is the // instance index, which is the index of the core instance, component instance, // or outer component to fetch an item from. // // The second field, itemIndex_, is simply a uint32_t item index like you'd find // anywhere else. Together, this means the common case for defined items, // imports, and exports is just: // // if (whatAndWhere_ == (ItemKind::Defined << ItemKindShift)) { // return items[itemIndex_]; // } // class ComponentItem {
uint32_t whatAndWhere_;
uint32_t itemIndex_;
// TODO(wasm-cm): Add static asserts for MaxComponents and // MaxComponentNestingDepth or whatever, eventually
static_assert(MaxComponentCoreInstances <= ComponentItem::AliasInstanceMask);
using CoreInstanceInstantiateArgVector =
mozilla::Vector<CoreInstanceInstantiateArg, 0, SystemAllocPolicy>;
// Instructions for instantiating a core instance from a core module, // corresponding to this text production: // // (core instance (instantiate <modidx>) (with ...)*)` // struct CoreInstanceDescFromModule { // The core module to instantiate.
uint32_t moduleIndex;
// The instance's "with" declarations. In the binary format there is no inline // export form, only a form that uses the exports of another core instance.
CoreInstanceInstantiateArgVector args;
};
// Instructions for instantiating a core instance by re-exporting core items // already present in the component's index spaces. Corresponds to this text: // // (core instance (export ...)*) // // This form of core instantiation semantically creates a new anonymous module // which imports the given definitions and re-exports them. Alternatively, you // can consider it a mere renaming of the items exported by other modules, but // creating an anonymous module simplifies our implementation. Note that the // module does not live in the component's core module index space. // // TODO(wasm-cm): Fill this out and figure out how to satisfy the module's // imports. struct CoreInstanceDescFromInlineExports {
SharedModule mod;
};
// Instructions for instantiating a core instance. using CoreInstanceDesc = mozilla::Variant<CoreInstanceDescFromModule,
CoreInstanceDescFromInlineExports>;
// Describes an import or export from a wasm component. class ComponentExternDesc {
ComponentSort sort_;
ComponentType type_;
// TODO(wasm-cm): This is a total hack, but since we currently don't have a // notion of core module types, we actually just store the index of the // relevant core module within the component. This obviously will not work as // soon as we do anything with multiple components.
uint32_t coreModuleIndex_;
// TODO(wasm-cm): This type is enormous, but a lot of the storage is due to // containers like HashMap and Vector that aren't actually required once the // component is built and validated. It would probably be smart to split this // into ComponentBuilder and Component classes so that the final version can be // smaller. (After all, we will have a lot of components in practice!) class Component : public JS::WasmComponent { public: using CoreModuleVector = mozilla::Vector<SharedModule, 0, SystemAllocPolicy>; using CoreInstanceVector =
mozilla::Vector<CoreInstanceDesc, 0, SystemAllocPolicy>; using TypeVector = mozilla::Vector<ComponentType, 0, SystemAllocPolicy>; using FuncVector = mozilla::Vector<ComponentFuncDesc, 0, SystemAllocPolicy>; using ImportVector = mozilla::Vector<ComponentImport, 0, SystemAllocPolicy>; using ExportVector = mozilla::Vector<ComponentExport, 0, SystemAllocPolicy>; using ItemVector = mozilla::Vector<ComponentItem, 0, SystemAllocPolicy>;
// -------------------------------------------------------------------------- // Utilities for accessing type information
// Gets a type from the component's type index space.
ComponentType getType(uint32_t typeIndex) const {
ComponentItem item = types_[typeIndex]; switch (item.kind()) { case ComponentItem::ItemKind::Defined: return definedTypes_[item.itemIndex()]; case ComponentItem::ItemKind::Import: return imports_[item.itemIndex()].externDesc().asType(); case ComponentItem::ItemKind::Export: return exports_[item.itemIndex()].externDesc().asType(); case ComponentItem::ItemKind::Alias:
MOZ_CRASH("should be impossible for now"); default:
MOZ_CRASH();
}
}
// Gets the type of a component func (not a core func). It is always safe to // call `.asFunc()` on the result.
ComponentType getTypeForFunc(uint32_t funcIndex) const {
ComponentItem item = funcs_[funcIndex]; switch (item.kind()) { case ComponentItem::ItemKind::Defined: return getType(definedFuncs_[item.itemIndex()].typeIndex()); case ComponentItem::ItemKind::Import: return imports_[item.itemIndex()].externDesc().asFunc(); case ComponentItem::ItemKind::Export: return exports_[item.itemIndex()].externDesc().asFunc(); case ComponentItem::ItemKind::Alias:
MOZ_CRASH("should be impossible for now"); default:
MOZ_CRASH();
}
}
// Gets the type of a core func (not a component func). const FuncType& getCoreFuncTypeForCoreFunc(uint32_t coreFuncIndex) const {
ComponentItem item = coreFuncs_[coreFuncIndex]; switch (item.kind()) { case ComponentItem::ItemKind::Defined: { // TODO(wasm-cm): Fix this when (canon lower) is supported.
MOZ_CRASH("should be impossible for now");
} break; case ComponentItem::ItemKind::Import: case ComponentItem::ItemKind::Export: // Core funcs cannot be imported or exported
MOZ_CRASH(); case ComponentItem::ItemKind::Alias: {
MOZ_ASSERT(item.aliasKind() == ComponentAliasKind::CoreExport);
SharedModule mod =
getCoreModuleForCoreInstance(item.aliasInstanceIndex());
uint32_t ft = mod->codeMeta().funcs[item.itemIndex()].typeIndex; return mod->codeMeta().types->type(ft).funcType();
} break; default:
MOZ_CRASH();
}
}
SharedModule getCoreModule(uint32_t modIndex) const {
ComponentItem item = coreModules_[modIndex]; switch (item.kind()) { case ComponentItem::ItemKind::Defined: return definedCoreModules_[item.itemIndex()]; case ComponentItem::ItemKind::Import: // TODO(wasm-cm): Fix when core module types are supported
MOZ_CRASH("should be impossible for now"); case ComponentItem::ItemKind::Export: { const ComponentExport& exp = exports_[item.itemIndex()];
MOZ_ASSERT(exp.externDesc().sort() == ComponentSort::CoreModule); return definedCoreModules_[exp.externDesc().asCoreModule()];
} break; case ComponentItem::ItemKind::Alias: // TODO(wasm-cm): Fix when nested components are supported
MOZ_CRASH("should be impossible for now"); default:
MOZ_CRASH();
}
}
SharedModule getCoreModuleForCoreInstance(uint32_t instanceIndex) const {
ComponentItem item = coreInstances_[instanceIndex]; switch (item.kind()) { case ComponentItem::ItemKind::Defined: { const CoreInstanceDesc& instance =
definedCoreInstances_[item.itemIndex()]; if (instance.is<CoreInstanceDescFromModule>()) { return getCoreModule(
instance.as<CoreInstanceDescFromModule>().moduleIndex);
} return instance.as<CoreInstanceDescFromInlineExports>().mod;
} break; case ComponentItem::ItemKind::Import: case ComponentItem::ItemKind::Export: // Core instances cannot be imported or exported
MOZ_CRASH(); case ComponentItem::ItemKind::Alias: // TODO(wasm-cm): Fix once nested components are supported
MOZ_CRASH("should be impossible for now"); default:
MOZ_CRASH();
}
}
size_t gcMallocBytesExcludingCode() const { // TODO(wasm-cm): Right now, this only sums up the sizes of the inner // modules, but this is not an accurate picture of a component's memory // footprint.
size_t total = 0; for (const SharedModule& module : definedCoreModules_) {
total += module->gcMallocBytesExcludingCode();
} return total;
}
size_t tier1CodeMemoryUsed() const { // TODO(wasm-cm): As above, this only sums up the memory for core modules, // and does not account for other potential code memory.
size_t total = 0; for (const SharedModule& module : definedCoreModules_) {
total += module->tier1CodeMemoryUsed();
} return total;
}
private: // JS API and JS::WasmComponent implementation:
JSObject* createObject(JSContext* cx) const override;
};
using MutableComponent = RefPtr<Component>; using SharedComponent = RefPtr<const Component>;
} // namespace wasm
} // namespace js
#endif// ENABLE_WASM_COMPONENTS
#endif// wasm_component_h
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet am 2026-09-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.