cfallin opened issue #3900:
In #3897, we discovered that Wasmtime's checking of a serialized/AOT-compiled module's flags for compatibility was not running if the runtime was not built with the compiler included. #3899 hardcodes some checks in a way that still works without Cranelift, so solves the immediate problem, but is not an ideal fix.
Ultimately we should be able to talk about the settings/configuration for the compiler without actually including the compiler itself. In the same way that
Target
is a type defined in a separate crate (target-lexicon
), we should create a new cratecranelift-settings
that lives at the bottom of the crate dependency DAG, and can be used without Cranelift itself. (It will probably depend on the settings stuff that is generated bycranelift-codegen
's meta crate currently, so we'll have to figure out how to split things apart appropriately.)This crate should have a way of comparing flags as well. Each flag has some property of "ABI compatibility" which is a sort of subtyping relation: for some flags, code generated with that flag taking on one value is compatible with the runtime assuming the flag has another value. For example, optimization level or regalloc selection don't affect the generated code-to-runtime interface. Nor should settings that affect whether certain ISA extensions are enabled. But, for example, the existence of safepoints in the generated code does affect the runtime; if code is generated without these, its execution will be incorrect if the runtime is providing reftypes.
So we should have a
CompilerFlags
and it should support a partial order relation which computes this compatibility.Then, the
cranelift-native
crate can generate some flags that correspond to the maximum CPU features on the host, andwasmtime-cranelift
can also generate aCompilerFlags
, indicating which flags are required for a given Wasmtime config (e.g., safepoints, or fuel or epoch instrumentation, etc.). We should also have a way to merge flags; this is a "meet" on the lattice induced by the partial ordering relation above.Then finally, wasmtime's compatibility checks and compile-time flag selection can use this infrastructure, rather than the hardcoded feature-compatibility matrices encoded into the
Engine
and serialization logic.
cfallin edited issue #3900:
In #3897, we discovered that Wasmtime's checking of a serialized/AOT-compiled module's flags for compatibility was not running if the runtime was not built with the compiler included. #3899 hardcodes some checks in a way that still works without Cranelift, so solves the immediate problem, but is not an ideal fix.
Ultimately we should be able to talk about the settings/configuration for the compiler without actually including the compiler itself. In the same way that
Target
is a type defined in a separate crate (target-lexicon
), we should create a new cratecranelift-settings
that lives at the bottom of the crate dependency DAG, and can be used without Cranelift itself. (It will probably depend on the settings stuff that is generated bycranelift-codegen
's meta crate currently, so we'll have to figure out how to split things apart appropriately.)This crate should have a way of comparing flags as well. Each flag has some property of "ABI compatibility" which is a sort of subtyping relation: for some flags, code generated with that flag taking on one value is compatible with the runtime assuming the flag has another value. For example, optimization level or regalloc selection don't affect the generated code-to-runtime interface. Nor should settings that affect whether certain ISA extensions are enabled. But, for example, the existence of safepoints in the generated code does affect the runtime; if code is generated without these, its execution will be incorrect if the runtime is providing reftypes.
So we should have a
CompilerFlags
and it should support a partial order relation which computes this compatibility.Then, the
cranelift-native
crate can generate some flags that correspond to the maximum CPU features on the host, andwasmtime-cranelift
can also generate aCompilerFlags
, indicating which flags are required for a given Wasmtime config (e.g., safepoints, or fuel or epoch instrumentation, etc.). We should also have a way to merge flags; this is a "meet" on the lattice induced by the partial ordering relation above. (Slight subtlety: the lattice is a product lattice of an individual lattice per flag; each individual flag also needs a "top" (don't care) and "bottom" (conflict) value.)Then finally, wasmtime's compatibility checks and compile-time flag selection can use this infrastructure, rather than the hardcoded feature-compatibility matrices encoded into the
Engine
and serialization logic.
alexcrichton commented on issue #3900:
One thing worth pointing out is that prior to https://github.com/bytecodealliance/wasmtime/pull/3899 we actually had no checks at all that when a
Module
was instantiated that the compiler settings configured in theEngine
were actually compatible with the host platform (e.g. enabled CPU features were actually available), and this was also one thing that #3899 wanted to fix.Another thing I think worth considering is that prior to #3899 when a serialized module was loaded from disk into a Wasmtime with Cranelift enabled we'd compare all the compilation settings to ensure that they exactly match the current compiler. There wasn't actually any form of subtyping/etc in the sense of testing whether code is ABI-compatible. Personally I think such a heuristic is good enough as I don't think we know of any use case of having specifically different compiler settings and still being able to load the module into compatible engines.
One example of this is that you mentioned epochs/fuel and those aren't actually related to cranelift compiler settings, that's more of Wasmtime's own
Tunables
which is serialized/deserialized and tested for absolute equality. While most of those settings matter for runtime code settings such asgenerate_address_map
ordynamic_memory_growth_reserve
don't actually affect anything and modules compiled with one version of those settings could be loaded into engines with a different version of the setting.All that to say that the main issue with #3899 was dealing with the fact that we have to rationalize cranelift flags in the face of cranelift not being available. The logic I implemented in #3899 was my best attempt to interpret cranelift settings, but if we had a separate crate I think we could largely get away with everything having to be configured exactly the same way. I suspect we don't need to implement per-configuration-setting "is this compatible with other values at the ABI level" configuration (as that would probably be sort of a pain to maintain in the limit as well). All of this would still require extraction to a separate crate though so I think that has to happen regardless, I'm mostly just pointing out that I don't think the subtyping aspect is strictly necessary (or rather I'd like to modify things to ensure that it's not strictly necessary).
alexcrichton labeled issue #3900:
In #3897, we discovered that Wasmtime's checking of a serialized/AOT-compiled module's flags for compatibility was not running if the runtime was not built with the compiler included. #3899 hardcodes some checks in a way that still works without Cranelift, so solves the immediate problem, but is not an ideal fix.
Ultimately we should be able to talk about the settings/configuration for the compiler without actually including the compiler itself. In the same way that
Target
is a type defined in a separate crate (target-lexicon
), we should create a new cratecranelift-settings
that lives at the bottom of the crate dependency DAG, and can be used without Cranelift itself. (It will probably depend on the settings stuff that is generated bycranelift-codegen
's meta crate currently, so we'll have to figure out how to split things apart appropriately.)This crate should have a way of comparing flags as well. Each flag has some property of "ABI compatibility" which is a sort of subtyping relation: for some flags, code generated with that flag taking on one value is compatible with the runtime assuming the flag has another value. For example, optimization level or regalloc selection don't affect the generated code-to-runtime interface. Nor should settings that affect whether certain ISA extensions are enabled. But, for example, the existence of safepoints in the generated code does affect the runtime; if code is generated without these, its execution will be incorrect if the runtime is providing reftypes.
So we should have a
CompilerFlags
and it should support a partial order relation which computes this compatibility.Then, the
cranelift-native
crate can generate some flags that correspond to the maximum CPU features on the host, andwasmtime-cranelift
can also generate aCompilerFlags
, indicating which flags are required for a given Wasmtime config (e.g., safepoints, or fuel or epoch instrumentation, etc.). We should also have a way to merge flags; this is a "meet" on the lattice induced by the partial ordering relation above. (Slight subtlety: the lattice is a product lattice of an individual lattice per flag; each individual flag also needs a "top" (don't care) and "bottom" (conflict) value.)Then finally, wasmtime's compatibility checks and compile-time flag selection can use this infrastructure, rather than the hardcoded feature-compatibility matrices encoded into the
Engine
and serialization logic.
cfallin labeled issue #3900:
In #3897, we discovered that Wasmtime's checking of a serialized/AOT-compiled module's flags for compatibility was not running if the runtime was not built with the compiler included. #3899 hardcodes some checks in a way that still works without Cranelift, so solves the immediate problem, but is not an ideal fix.
Ultimately we should be able to talk about the settings/configuration for the compiler without actually including the compiler itself. In the same way that
Target
is a type defined in a separate crate (target-lexicon
), we should create a new cratecranelift-settings
that lives at the bottom of the crate dependency DAG, and can be used without Cranelift itself. (It will probably depend on the settings stuff that is generated bycranelift-codegen
's meta crate currently, so we'll have to figure out how to split things apart appropriately.)This crate should have a way of comparing flags as well. Each flag has some property of "ABI compatibility" which is a sort of subtyping relation: for some flags, code generated with that flag taking on one value is compatible with the runtime assuming the flag has another value. For example, optimization level or regalloc selection don't affect the generated code-to-runtime interface. Nor should settings that affect whether certain ISA extensions are enabled. But, for example, the existence of safepoints in the generated code does affect the runtime; if code is generated without these, its execution will be incorrect if the runtime is providing reftypes.
So we should have a
CompilerFlags
and it should support a partial order relation which computes this compatibility.Then, the
cranelift-native
crate can generate some flags that correspond to the maximum CPU features on the host, andwasmtime-cranelift
can also generate aCompilerFlags
, indicating which flags are required for a given Wasmtime config (e.g., safepoints, or fuel or epoch instrumentation, etc.). We should also have a way to merge flags; this is a "meet" on the lattice induced by the partial ordering relation above. (Slight subtlety: the lattice is a product lattice of an individual lattice per flag; each individual flag also needs a "top" (don't care) and "bottom" (conflict) value.)Then finally, wasmtime's compatibility checks and compile-time flag selection can use this infrastructure, rather than the hardcoded feature-compatibility matrices encoded into the
Engine
and serialization logic.
Last updated: Nov 22 2024 at 16:03 UTC