/src/wasmer/lib/compiler-cranelift/src/config.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use crate::compiler::CraneliftCompiler; |
2 | | use cranelift_codegen::isa::{lookup, TargetIsa}; |
3 | | use cranelift_codegen::settings::{self, Configurable}; |
4 | | use cranelift_codegen::CodegenResult; |
5 | | use std::sync::Arc; |
6 | | use wasmer_compiler::{Compiler, CompilerConfig, Engine, EngineBuilder, ModuleMiddleware}; |
7 | | use wasmer_types::{Architecture, CpuFeature, Target}; |
8 | | |
9 | | // Runtime Environment |
10 | | |
11 | | /// Possible optimization levels for the Cranelift codegen backend. |
12 | | #[non_exhaustive] |
13 | | #[derive(Clone, Debug)] |
14 | | pub enum CraneliftOptLevel { |
15 | | /// No optimizations performed, minimizes compilation time by disabling most |
16 | | /// optimizations. |
17 | | None, |
18 | | /// Generates the fastest possible code, but may take longer. |
19 | | Speed, |
20 | | /// Similar to `speed`, but also performs transformations aimed at reducing |
21 | | /// code size. |
22 | | SpeedAndSize, |
23 | | } |
24 | | |
25 | | /// Global configuration options used to create an |
26 | | /// `wasmer_engine::Engine` and customize its behavior. |
27 | | /// |
28 | | /// This structure exposes a builder-like interface and is primarily |
29 | | /// consumed by `wasmer_engine::Engine::new`. |
30 | | #[derive(Debug, Clone)] |
31 | | pub struct Cranelift { |
32 | | enable_nan_canonicalization: bool, |
33 | | enable_verifier: bool, |
34 | | enable_pic: bool, |
35 | | opt_level: CraneliftOptLevel, |
36 | | /// The middleware chain. |
37 | | pub(crate) middlewares: Vec<Arc<dyn ModuleMiddleware>>, |
38 | | } |
39 | | |
40 | | impl Cranelift { |
41 | | /// Creates a new configuration object with the default configuration |
42 | | /// specified. |
43 | 5.00k | pub fn new() -> Self { |
44 | 5.00k | Self { |
45 | 5.00k | enable_nan_canonicalization: false, |
46 | 5.00k | enable_verifier: false, |
47 | 5.00k | opt_level: CraneliftOptLevel::Speed, |
48 | 5.00k | enable_pic: false, |
49 | 5.00k | middlewares: vec![], |
50 | 5.00k | } |
51 | 5.00k | } Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::new Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::new Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::new Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::new <wasmer_compiler_cranelift::config::Cranelift>::new Line | Count | Source | 43 | 5.00k | pub fn new() -> Self { | 44 | 5.00k | Self { | 45 | 5.00k | enable_nan_canonicalization: false, | 46 | 5.00k | enable_verifier: false, | 47 | 5.00k | opt_level: CraneliftOptLevel::Speed, | 48 | 5.00k | enable_pic: false, | 49 | 5.00k | middlewares: vec![], | 50 | 5.00k | } | 51 | 5.00k | } |
Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::new Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::new |
52 | | |
53 | | /// Enable NaN canonicalization. |
54 | | /// |
55 | | /// NaN canonicalization is useful when trying to run WebAssembly |
56 | | /// deterministically across different architectures. |
57 | 5.00k | pub fn canonicalize_nans(&mut self, enable: bool) -> &mut Self { |
58 | 5.00k | self.enable_nan_canonicalization = enable; |
59 | 5.00k | self |
60 | 5.00k | } Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::canonicalize_nans Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::canonicalize_nans <wasmer_compiler_cranelift::config::Cranelift>::canonicalize_nans Line | Count | Source | 57 | 5.00k | pub fn canonicalize_nans(&mut self, enable: bool) -> &mut Self { | 58 | 5.00k | self.enable_nan_canonicalization = enable; | 59 | 5.00k | self | 60 | 5.00k | } |
Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::canonicalize_nans Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::canonicalize_nans |
61 | | |
62 | | /// The optimization levels when optimizing the IR. |
63 | 0 | pub fn opt_level(&mut self, opt_level: CraneliftOptLevel) -> &mut Self { |
64 | 0 | self.opt_level = opt_level; |
65 | 0 | self |
66 | 0 | } Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::opt_level Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::opt_level |
67 | | |
68 | | /// Generates the ISA for the provided target |
69 | 10.0k | pub fn isa(&self, target: &Target) -> CodegenResult<Box<dyn TargetIsa>> { |
70 | 10.0k | let mut builder = |
71 | 10.0k | lookup(target.triple().clone()).expect("construct Cranelift ISA for triple"); |
72 | 10.0k | // Cpu Features |
73 | 10.0k | let cpu_features = target.cpu_features(); |
74 | 10.0k | if target.triple().architecture == Architecture::X86_64 |
75 | 10.0k | && !cpu_features.contains(CpuFeature::SSE2) |
76 | | { |
77 | 0 | panic!("x86 support requires SSE2"); |
78 | 10.0k | } |
79 | 10.0k | if cpu_features.contains(CpuFeature::SSE3) { |
80 | 10.0k | builder.enable("has_sse3").expect("should be valid flag"); |
81 | 10.0k | } |
82 | 10.0k | if cpu_features.contains(CpuFeature::SSSE3) { |
83 | 10.0k | builder.enable("has_ssse3").expect("should be valid flag"); |
84 | 10.0k | } |
85 | 10.0k | if cpu_features.contains(CpuFeature::SSE41) { |
86 | 10.0k | builder.enable("has_sse41").expect("should be valid flag"); |
87 | 10.0k | } |
88 | 10.0k | if cpu_features.contains(CpuFeature::SSE42) { |
89 | 10.0k | builder.enable("has_sse42").expect("should be valid flag"); |
90 | 10.0k | } |
91 | 10.0k | if cpu_features.contains(CpuFeature::POPCNT) { |
92 | 10.0k | builder.enable("has_popcnt").expect("should be valid flag"); |
93 | 10.0k | } |
94 | 10.0k | if cpu_features.contains(CpuFeature::AVX) { |
95 | 10.0k | builder.enable("has_avx").expect("should be valid flag"); |
96 | 10.0k | } |
97 | 10.0k | if cpu_features.contains(CpuFeature::BMI1) { |
98 | 10.0k | builder.enable("has_bmi1").expect("should be valid flag"); |
99 | 10.0k | } |
100 | 10.0k | if cpu_features.contains(CpuFeature::BMI2) { |
101 | 10.0k | builder.enable("has_bmi2").expect("should be valid flag"); |
102 | 10.0k | } |
103 | 10.0k | if cpu_features.contains(CpuFeature::AVX2) { |
104 | 10.0k | builder.enable("has_avx2").expect("should be valid flag"); |
105 | 10.0k | } |
106 | 10.0k | if cpu_features.contains(CpuFeature::AVX512DQ) { |
107 | 0 | builder |
108 | 0 | .enable("has_avx512dq") |
109 | 0 | .expect("should be valid flag"); |
110 | 10.0k | } |
111 | 10.0k | if cpu_features.contains(CpuFeature::AVX512VL) { |
112 | 0 | builder |
113 | 0 | .enable("has_avx512vl") |
114 | 0 | .expect("should be valid flag"); |
115 | 10.0k | } |
116 | 10.0k | if cpu_features.contains(CpuFeature::LZCNT) { |
117 | 10.0k | builder.enable("has_lzcnt").expect("should be valid flag"); |
118 | 10.0k | } |
119 | | |
120 | 10.0k | builder.finish(self.flags(target)) |
121 | 10.0k | } <wasmer_compiler_cranelift::config::Cranelift>::isa Line | Count | Source | 69 | 10.0k | pub fn isa(&self, target: &Target) -> CodegenResult<Box<dyn TargetIsa>> { | 70 | 10.0k | let mut builder = | 71 | 10.0k | lookup(target.triple().clone()).expect("construct Cranelift ISA for triple"); | 72 | 10.0k | // Cpu Features | 73 | 10.0k | let cpu_features = target.cpu_features(); | 74 | 10.0k | if target.triple().architecture == Architecture::X86_64 | 75 | 10.0k | && !cpu_features.contains(CpuFeature::SSE2) | 76 | | { | 77 | 0 | panic!("x86 support requires SSE2"); | 78 | 10.0k | } | 79 | 10.0k | if cpu_features.contains(CpuFeature::SSE3) { | 80 | 10.0k | builder.enable("has_sse3").expect("should be valid flag"); | 81 | 10.0k | } | 82 | 10.0k | if cpu_features.contains(CpuFeature::SSSE3) { | 83 | 10.0k | builder.enable("has_ssse3").expect("should be valid flag"); | 84 | 10.0k | } | 85 | 10.0k | if cpu_features.contains(CpuFeature::SSE41) { | 86 | 10.0k | builder.enable("has_sse41").expect("should be valid flag"); | 87 | 10.0k | } | 88 | 10.0k | if cpu_features.contains(CpuFeature::SSE42) { | 89 | 10.0k | builder.enable("has_sse42").expect("should be valid flag"); | 90 | 10.0k | } | 91 | 10.0k | if cpu_features.contains(CpuFeature::POPCNT) { | 92 | 10.0k | builder.enable("has_popcnt").expect("should be valid flag"); | 93 | 10.0k | } | 94 | 10.0k | if cpu_features.contains(CpuFeature::AVX) { | 95 | 10.0k | builder.enable("has_avx").expect("should be valid flag"); | 96 | 10.0k | } | 97 | 10.0k | if cpu_features.contains(CpuFeature::BMI1) { | 98 | 10.0k | builder.enable("has_bmi1").expect("should be valid flag"); | 99 | 10.0k | } | 100 | 10.0k | if cpu_features.contains(CpuFeature::BMI2) { | 101 | 10.0k | builder.enable("has_bmi2").expect("should be valid flag"); | 102 | 10.0k | } | 103 | 10.0k | if cpu_features.contains(CpuFeature::AVX2) { | 104 | 10.0k | builder.enable("has_avx2").expect("should be valid flag"); | 105 | 10.0k | } | 106 | 10.0k | if cpu_features.contains(CpuFeature::AVX512DQ) { | 107 | 0 | builder | 108 | 0 | .enable("has_avx512dq") | 109 | 0 | .expect("should be valid flag"); | 110 | 10.0k | } | 111 | 10.0k | if cpu_features.contains(CpuFeature::AVX512VL) { | 112 | 0 | builder | 113 | 0 | .enable("has_avx512vl") | 114 | 0 | .expect("should be valid flag"); | 115 | 10.0k | } | 116 | 10.0k | if cpu_features.contains(CpuFeature::LZCNT) { | 117 | 10.0k | builder.enable("has_lzcnt").expect("should be valid flag"); | 118 | 10.0k | } | 119 | | | 120 | 10.0k | builder.finish(self.flags(target)) | 121 | 10.0k | } |
Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::isa |
122 | | |
123 | | /// Generates the flags for the compiler |
124 | 10.0k | pub fn flags(&self, target: &Target) -> settings::Flags { |
125 | 10.0k | let is_riscv = matches!(target.triple().architecture, Architecture::Riscv64(_)); |
126 | 10.0k | let mut flags = settings::builder(); |
127 | 10.0k | |
128 | 10.0k | // Enable probestack |
129 | 10.0k | flags |
130 | 10.0k | .enable("enable_probestack") |
131 | 10.0k | .expect("should be valid flag"); |
132 | | |
133 | | // Only inline probestack is supported on AArch64 |
134 | 10.0k | if matches!(target.triple().architecture, Architecture::Aarch64(_)) { |
135 | 0 | flags |
136 | 0 | .set("probestack_strategy", "inline") |
137 | 0 | .expect("should be valid flag"); |
138 | 10.0k | } |
139 | | |
140 | | // There are two possible traps for division, and this way |
141 | | // we get the proper one if code traps. |
142 | 10.0k | flags |
143 | 10.0k | .enable("avoid_div_traps") |
144 | 10.0k | .expect("should be valid flag"); |
145 | 10.0k | |
146 | 10.0k | if self.enable_pic { |
147 | 0 | flags.enable("is_pic").expect("should be a valid flag"); |
148 | 10.0k | } |
149 | | |
150 | | // We set up libcall trampolines in engine-universal. |
151 | | // These trampolines are always reachable through short jumps. |
152 | 10.0k | flags |
153 | 10.0k | .enable("use_colocated_libcalls") |
154 | 10.0k | .expect("should be a valid flag"); |
155 | | |
156 | | // Invert cranelift's default-on verification to instead default off. |
157 | 10.0k | let enable_verifier = if self.enable_verifier { |
158 | 10.0k | "true" |
159 | | } else { |
160 | 0 | "false" |
161 | | }; |
162 | 10.0k | flags |
163 | 10.0k | .set("enable_verifier", enable_verifier) |
164 | 10.0k | .expect("should be valid flag"); |
165 | 10.0k | flags |
166 | 10.0k | .set("enable_safepoints", "true") |
167 | 10.0k | .expect("should be valid flag"); |
168 | 10.0k | |
169 | 10.0k | flags |
170 | 10.0k | .set( |
171 | 10.0k | "opt_level", |
172 | 10.0k | match self.opt_level { |
173 | 0 | CraneliftOptLevel::None => "none", |
174 | 10.0k | CraneliftOptLevel::Speed => "speed", |
175 | 0 | CraneliftOptLevel::SpeedAndSize => "speed_and_size", |
176 | | }, |
177 | | ) |
178 | 10.0k | .expect("should be valid flag"); |
179 | 10.0k | |
180 | 10.0k | if is_riscv { |
181 | 0 | flags |
182 | 0 | .set("enable_simd", "false") |
183 | 0 | .expect("should be valid flag"); |
184 | 10.0k | } else { |
185 | 10.0k | flags |
186 | 10.0k | .set("enable_simd", "true") |
187 | 10.0k | .expect("should be valid flag"); |
188 | 10.0k | } |
189 | | |
190 | 10.0k | let enable_nan_canonicalization = if self.enable_nan_canonicalization { |
191 | 10.0k | "true" |
192 | | } else { |
193 | 0 | "false" |
194 | | }; |
195 | 10.0k | flags |
196 | 10.0k | .set("enable_nan_canonicalization", enable_nan_canonicalization) |
197 | 10.0k | .expect("should be valid flag"); |
198 | 10.0k | |
199 | 10.0k | settings::Flags::new(flags) |
200 | 10.0k | } <wasmer_compiler_cranelift::config::Cranelift>::flags Line | Count | Source | 124 | 10.0k | pub fn flags(&self, target: &Target) -> settings::Flags { | 125 | 10.0k | let is_riscv = matches!(target.triple().architecture, Architecture::Riscv64(_)); | 126 | 10.0k | let mut flags = settings::builder(); | 127 | 10.0k | | 128 | 10.0k | // Enable probestack | 129 | 10.0k | flags | 130 | 10.0k | .enable("enable_probestack") | 131 | 10.0k | .expect("should be valid flag"); | 132 | | | 133 | | // Only inline probestack is supported on AArch64 | 134 | 10.0k | if matches!(target.triple().architecture, Architecture::Aarch64(_)) { | 135 | 0 | flags | 136 | 0 | .set("probestack_strategy", "inline") | 137 | 0 | .expect("should be valid flag"); | 138 | 10.0k | } | 139 | | | 140 | | // There are two possible traps for division, and this way | 141 | | // we get the proper one if code traps. | 142 | 10.0k | flags | 143 | 10.0k | .enable("avoid_div_traps") | 144 | 10.0k | .expect("should be valid flag"); | 145 | 10.0k | | 146 | 10.0k | if self.enable_pic { | 147 | 0 | flags.enable("is_pic").expect("should be a valid flag"); | 148 | 10.0k | } | 149 | | | 150 | | // We set up libcall trampolines in engine-universal. | 151 | | // These trampolines are always reachable through short jumps. | 152 | 10.0k | flags | 153 | 10.0k | .enable("use_colocated_libcalls") | 154 | 10.0k | .expect("should be a valid flag"); | 155 | | | 156 | | // Invert cranelift's default-on verification to instead default off. | 157 | 10.0k | let enable_verifier = if self.enable_verifier { | 158 | 10.0k | "true" | 159 | | } else { | 160 | 0 | "false" | 161 | | }; | 162 | 10.0k | flags | 163 | 10.0k | .set("enable_verifier", enable_verifier) | 164 | 10.0k | .expect("should be valid flag"); | 165 | 10.0k | flags | 166 | 10.0k | .set("enable_safepoints", "true") | 167 | 10.0k | .expect("should be valid flag"); | 168 | 10.0k | | 169 | 10.0k | flags | 170 | 10.0k | .set( | 171 | 10.0k | "opt_level", | 172 | 10.0k | match self.opt_level { | 173 | 0 | CraneliftOptLevel::None => "none", | 174 | 10.0k | CraneliftOptLevel::Speed => "speed", | 175 | 0 | CraneliftOptLevel::SpeedAndSize => "speed_and_size", | 176 | | }, | 177 | | ) | 178 | 10.0k | .expect("should be valid flag"); | 179 | 10.0k | | 180 | 10.0k | if is_riscv { | 181 | 0 | flags | 182 | 0 | .set("enable_simd", "false") | 183 | 0 | .expect("should be valid flag"); | 184 | 10.0k | } else { | 185 | 10.0k | flags | 186 | 10.0k | .set("enable_simd", "true") | 187 | 10.0k | .expect("should be valid flag"); | 188 | 10.0k | } | 189 | | | 190 | 10.0k | let enable_nan_canonicalization = if self.enable_nan_canonicalization { | 191 | 10.0k | "true" | 192 | | } else { | 193 | 0 | "false" | 194 | | }; | 195 | 10.0k | flags | 196 | 10.0k | .set("enable_nan_canonicalization", enable_nan_canonicalization) | 197 | 10.0k | .expect("should be valid flag"); | 198 | 10.0k | | 199 | 10.0k | settings::Flags::new(flags) | 200 | 10.0k | } |
Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift>::flags |
201 | | } |
202 | | |
203 | | impl CompilerConfig for Cranelift { |
204 | 0 | fn enable_pic(&mut self) { |
205 | 0 | self.enable_pic = true; |
206 | 0 | } Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::enable_pic Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::enable_pic Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::enable_pic Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::enable_pic Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::enable_pic |
207 | | |
208 | 5.00k | fn enable_verifier(&mut self) { |
209 | 5.00k | self.enable_verifier = true; |
210 | 5.00k | } Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::enable_verifier Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::enable_verifier Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::enable_verifier Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::enable_verifier <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::enable_verifier Line | Count | Source | 208 | 5.00k | fn enable_verifier(&mut self) { | 209 | 5.00k | self.enable_verifier = true; | 210 | 5.00k | } |
Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::enable_verifier Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::enable_verifier |
211 | | |
212 | 0 | fn canonicalize_nans(&mut self, enable: bool) { |
213 | 0 | self.enable_nan_canonicalization = enable; |
214 | 0 | } Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::canonicalize_nans Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::canonicalize_nans Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::canonicalize_nans Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::canonicalize_nans Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::canonicalize_nans |
215 | | |
216 | | /// Transform it into the compiler |
217 | 5.00k | fn compiler(self: Box<Self>) -> Box<dyn Compiler> { |
218 | 5.00k | Box::new(CraneliftCompiler::new(*self)) |
219 | 5.00k | } <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::compiler Line | Count | Source | 217 | 5.00k | fn compiler(self: Box<Self>) -> Box<dyn Compiler> { | 218 | 5.00k | Box::new(CraneliftCompiler::new(*self)) | 219 | 5.00k | } |
Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::compiler |
220 | | |
221 | | /// Pushes a middleware onto the back of the middleware chain. |
222 | 0 | fn push_middleware(&mut self, middleware: Arc<dyn ModuleMiddleware>) { |
223 | 0 | self.middlewares.push(middleware); |
224 | 0 | } Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::push_middleware Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as wasmer_compiler::compiler::CompilerConfig>::push_middleware |
225 | | } |
226 | | |
227 | | impl Default for Cranelift { |
228 | 5.00k | fn default() -> Self { |
229 | 5.00k | Self::new() |
230 | 5.00k | } Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as core::default::Default>::default Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as core::default::Default>::default Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as core::default::Default>::default Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as core::default::Default>::default <wasmer_compiler_cranelift::config::Cranelift as core::default::Default>::default Line | Count | Source | 228 | 5.00k | fn default() -> Self { | 229 | 5.00k | Self::new() | 230 | 5.00k | } |
Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as core::default::Default>::default Unexecuted instantiation: <wasmer_compiler_cranelift::config::Cranelift as core::default::Default>::default |
231 | | } |
232 | | |
233 | | impl From<Cranelift> for Engine { |
234 | 0 | fn from(config: Cranelift) -> Self { |
235 | 0 | EngineBuilder::new(config).engine() |
236 | 0 | } Unexecuted instantiation: <wasmer_compiler::engine::inner::Engine as core::convert::From<wasmer_compiler_cranelift::config::Cranelift>>::from Unexecuted instantiation: <wasmer_compiler::engine::inner::Engine as core::convert::From<wasmer_compiler_cranelift::config::Cranelift>>::from |
237 | | } |