-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Use precise alias regions for statically-known entity imports #14115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,12 +4,13 @@ use crate::module::{ | |
| }; | ||
| use crate::prelude::*; | ||
| use crate::{ | ||
| ConstExpr, ConstOp, DataIndex, DefinedFuncIndex, DefinedGlobalIndex, ElemIndex, | ||
| EngineOrModuleTypeIndex, EntityIndex, EntityType, FuncIndex, FuncKey, GlobalIndex, IndexType, | ||
| MemoryIndex, MemoryInitializer, ModuleInternedTypeIndex, ModuleStartup, ModuleTypesBuilder, | ||
| PanicOnOom as _, PassiveElemIndex, PrimaryMap, RuntimeDataIndex, StaticModuleIndex, TableIndex, | ||
| TableInitialValue, TableInitialization, Tag, TagIndex, Trap, Tunables, TypeConvert, TypeIndex, | ||
| WasmHeapTopType, WasmHeapType, WasmResult, WasmValType, WasmparserTypeConverter, | ||
| ConstExpr, ConstOp, DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, | ||
| DefinedTableIndex, ElemIndex, EngineOrModuleTypeIndex, EntityIndex, EntityType, FuncIndex, | ||
| FuncKey, GlobalIndex, IndexType, MemoryIndex, MemoryInitializer, ModuleInternedTypeIndex, | ||
| ModuleStartup, ModuleTypesBuilder, PanicOnOom as _, PassiveElemIndex, PrimaryMap, | ||
| RuntimeDataIndex, StaticModuleIndex, TableIndex, TableInitialValue, TableInitialization, Tag, | ||
| TagIndex, Trap, Tunables, TypeConvert, TypeIndex, WasmHeapTopType, WasmHeapType, WasmResult, | ||
| WasmValType, WasmparserTypeConverter, | ||
| }; | ||
| use alloc::borrow::Cow; | ||
| use cranelift_entity::SecondaryMap; | ||
|
|
@@ -72,6 +73,15 @@ impl From<FactInlineIntrinsic> for KnownFunc { | |
| } | ||
| } | ||
|
|
||
| /// A statically-known import of a core Wasm global, memory, or table. | ||
| #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
| pub struct KnownEntity<T> { | ||
| /// The module that defines this entity. | ||
| pub module: StaticModuleIndex, | ||
| /// The entity's index in the defining module's defined-entity index space. | ||
| pub index: T, | ||
| } | ||
|
|
||
| /// The result of translating via `ModuleEnvironment`. | ||
| /// | ||
| /// Function bodies are not yet translated, and data initializers have not yet | ||
|
|
@@ -107,6 +117,47 @@ pub struct ModuleTranslation<'data> { | |
| /// `FuncKey::FactInlineIntrinsic`s. | ||
| pub known_imported_functions: SecondaryMap<FuncIndex, Option<KnownFunc>>, | ||
|
|
||
| /// For each imported global, memory, or table, the single statically-known | ||
| /// defined entity that always satisfies that import, if any. | ||
| /// | ||
| /// This is used to access the entity via the defining module's precise | ||
| /// `AliasRegionKey::Defined{Global,Memory,Table}` region instead of the | ||
| /// conservative `AliasRegionKey::Public{Global,Memory,Table}` region that is | ||
| /// shared by every entity of that kind which crosses a module boundary. | ||
| /// | ||
| /// XXX: Being known requires more here than it does for functions: it is | ||
| /// not enough that *this* module's import is always the same entity, | ||
| /// *every* module that may import that entity must also always import that | ||
| /// same entity. Otherwise a function from one of those other modules, which | ||
| /// accesses the entity via the conservative region, could be inlined next | ||
| /// to one of our accesses via the precise region, and accessing the same | ||
| /// memory through two different alias regions is invalid. | ||
|
Comment on lines
+128
to
+134
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reading over this again I personally find this pretty confusing. I understand why this is the way it is, but in consider this I could imaging an alternative design where a module statically knows it imports a particular global and then has separate information on whether it's appropriate to use a statically known alias region for that global. Basically I could imagine a design where one axis of imports is "is it always this thing" and then another axis is "is that thing always known to all other modules as well". One example optimization with this is that if we know an import of a non-mutable global is always a particular global we can just inline the value everywhere. That's got nothing to do with alias regions, however, and by tying alias regions to this known-imports set we're unable to optimize some situations. I don't mean to place more work on this PR, but I want to explain my confusion with the phrasing/naming here. The "XXX" here seems to indicate that this is a strong requirement that these sets must always be different from the functions set, but I don't feel that fully describes the situation. Given all that, two questions:
|
||
| pub known_imported_globals: SecondaryMap<GlobalIndex, Option<KnownEntity<DefinedGlobalIndex>>>, | ||
|
|
||
| /// Same as `known_imported_globals`, but for memories. | ||
| pub known_imported_memories: SecondaryMap<MemoryIndex, Option<KnownEntity<DefinedMemoryIndex>>>, | ||
|
|
||
| /// Same as `known_imported_globals`, but for tables. | ||
| pub known_imported_tables: SecondaryMap<TableIndex, Option<KnownEntity<DefinedTableIndex>>>, | ||
|
|
||
| /// For each global defined by this module, whether every module that may | ||
| /// import this global always imports exactly this global. | ||
| /// | ||
| /// When this holds, accesses of the global may use its precise | ||
| /// `AliasRegionKey::DefinedGlobal` region even when the global is exported, | ||
| /// because every module that can reach it agrees on that same region. This | ||
| /// is vacuously true of globals that nothing in the component imports. | ||
| /// | ||
| /// This can only be determined by looking at the whole component, so it is | ||
| /// always `false` for standalone modules. | ||
| pub globals_known_to_importers: TryEntitySet<DefinedGlobalIndex>, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this drop the |
||
|
|
||
| /// Same as [`Self::globals_known_to_importers`], but for memories. | ||
| pub memories_known_to_importers: TryEntitySet<DefinedMemoryIndex>, | ||
|
|
||
| /// Same as [`Self::globals_known_to_importers`], but for tables. | ||
| pub tables_known_to_importers: TryEntitySet<DefinedTableIndex>, | ||
|
|
||
| /// A list of type signatures which are considered exported from this | ||
| /// module, or those that can possibly be called. This list is sorted, and | ||
| /// trampolines for each of these signatures are required. | ||
|
|
@@ -228,6 +279,12 @@ impl<'data> ModuleTranslation<'data> { | |
| wasm_module_offset: 0, | ||
| function_body_inputs: PrimaryMap::default(), | ||
| known_imported_functions: SecondaryMap::default(), | ||
| known_imported_globals: SecondaryMap::default(), | ||
| known_imported_memories: SecondaryMap::default(), | ||
| known_imported_tables: SecondaryMap::default(), | ||
| globals_known_to_importers: TryEntitySet::default(), | ||
| memories_known_to_importers: TryEntitySet::default(), | ||
| tables_known_to_importers: TryEntitySet::default(), | ||
| exported_signatures: Vec::default(), | ||
| debuginfo: DebugInfoData::default(), | ||
| has_unparsed_debuginfo: false, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.