172004aadSNick Fitzgerald //! Evaluating const expressions.
272004aadSNick Fitzgerald 
3a727985cSAlex Crichton use crate::prelude::*;
4d1397130SAlex Crichton use crate::runtime::vm;
5cc8d04f4SAlex Crichton use crate::store::{Asyncness, AutoAssertNoGc, InstanceId, StoreOpaque, StoreResourceLimiter};
6a727985cSAlex Crichton #[cfg(feature = "gc")]
7fc3302a0SAlex Crichton use crate::{
8aef5eeb5SAlex Crichton     AnyRef, ArrayRef, ArrayRefPre, ArrayType, ExternRef, I31, StructRef, StructRefPre, StructType,
9fc3302a0SAlex Crichton };
10aef5eeb5SAlex Crichton use crate::{OpaqueRootScope, Val};
11*a6f4bd2fSAlex Crichton use wasmtime_environ::{ConstExpr, ConstOp, FuncIndex, GlobalConstValue, GlobalIndex};
12a727985cSAlex Crichton #[cfg(feature = "gc")]
13def5998eSAlex Crichton use wasmtime_environ::{VMSharedTypeIndex, WasmCompositeInnerType, WasmCompositeType, WasmSubType};
1472004aadSNick Fitzgerald 
1572004aadSNick Fitzgerald /// An interpreter for const expressions.
1672004aadSNick Fitzgerald ///
1772004aadSNick Fitzgerald /// This can be reused across many const expression evaluations to reuse
1872004aadSNick Fitzgerald /// allocated resources, if any.
1972004aadSNick Fitzgerald pub struct ConstExprEvaluator {
20aef5eeb5SAlex Crichton     stack: Vec<Val>,
21d1397130SAlex Crichton     simple: Val,
22d1397130SAlex Crichton }
23d1397130SAlex Crichton 
24d1397130SAlex Crichton impl Default for ConstExprEvaluator {
default() -> ConstExprEvaluator25d1397130SAlex Crichton     fn default() -> ConstExprEvaluator {
26d1397130SAlex Crichton         ConstExprEvaluator {
27d1397130SAlex Crichton             stack: Vec::new(),
28d1397130SAlex Crichton             simple: Val::I32(0),
29d1397130SAlex Crichton         }
30d1397130SAlex Crichton     }
3172004aadSNick Fitzgerald }
3272004aadSNick Fitzgerald 
3372004aadSNick Fitzgerald /// The context within which a particular const expression is evaluated.
34aad93a48SAlex Crichton pub struct ConstEvalContext {
35aad93a48SAlex Crichton     pub(crate) instance: InstanceId,
36cc8d04f4SAlex Crichton     pub(crate) asyncness: Asyncness,
3772004aadSNick Fitzgerald }
3872004aadSNick Fitzgerald 
39aad93a48SAlex Crichton impl ConstEvalContext {
4072004aadSNick Fitzgerald     /// Create a new context.
new(instance: InstanceId, asyncness: Asyncness) -> Self41cc8d04f4SAlex Crichton     pub fn new(instance: InstanceId, asyncness: Asyncness) -> Self {
42cc8d04f4SAlex Crichton         Self {
43cc8d04f4SAlex Crichton             instance,
44cc8d04f4SAlex Crichton             asyncness,
45cc8d04f4SAlex Crichton         }
4672004aadSNick Fitzgerald     }
4772004aadSNick Fitzgerald 
global_get(&mut self, store: &mut StoreOpaque, index: GlobalIndex) -> Result<Val>48aef5eeb5SAlex Crichton     fn global_get(&mut self, store: &mut StoreOpaque, index: GlobalIndex) -> Result<Val> {
49aef5eeb5SAlex Crichton         let id = store.id();
50aef5eeb5SAlex Crichton         Ok(store
51aef5eeb5SAlex Crichton             .instance_mut(self.instance)
52aef5eeb5SAlex Crichton             .get_exported_global(id, index)
53aef5eeb5SAlex Crichton             ._get(&mut AutoAssertNoGc::new(store)))
5472004aadSNick Fitzgerald     }
5572004aadSNick Fitzgerald 
ref_func(&mut self, store: &mut StoreOpaque, index: FuncIndex) -> Result<Val>56aef5eeb5SAlex Crichton     fn ref_func(&mut self, store: &mut StoreOpaque, index: FuncIndex) -> Result<Val> {
57aef5eeb5SAlex Crichton         let id = store.id();
5899ecf728SChris Fallin         let (instance, registry) = store.instance_and_module_registry_mut(self.instance);
59aef5eeb5SAlex Crichton         // SAFETY: `id` is the correct store-owner of the function being looked
60aef5eeb5SAlex Crichton         // up
6199ecf728SChris Fallin         let func = unsafe { instance.get_exported_func(registry, id, index) };
62aef5eeb5SAlex Crichton         Ok(func.into())
6372004aadSNick Fitzgerald     }
64128e6b8fSNick Fitzgerald 
65128e6b8fSNick Fitzgerald     #[cfg(feature = "gc")]
struct_fields_len(&self, store: &mut StoreOpaque, shared_ty: VMSharedTypeIndex) -> usize66aef5eeb5SAlex Crichton     fn struct_fields_len(&self, store: &mut StoreOpaque, shared_ty: VMSharedTypeIndex) -> usize {
67cb235ecfSNick Fitzgerald         let struct_ty = StructType::from_shared_type_index(store.engine(), shared_ty);
68cb235ecfSNick Fitzgerald         let fields = struct_ty.fields();
69cb235ecfSNick Fitzgerald         fields.len()
70128e6b8fSNick Fitzgerald     }
71128e6b8fSNick Fitzgerald 
72128e6b8fSNick Fitzgerald     #[cfg(feature = "gc")]
struct_new( &mut self, store: &mut StoreOpaque, limiter: Option<&mut StoreResourceLimiter<'_>>, shared_ty: VMSharedTypeIndex, fields: &[Val], ) -> Result<Val>73d1397130SAlex Crichton     async fn struct_new(
74128e6b8fSNick Fitzgerald         &mut self,
75aef5eeb5SAlex Crichton         store: &mut StoreOpaque,
76155ea7fcSAlex Crichton         limiter: Option<&mut StoreResourceLimiter<'_>>,
77cb235ecfSNick Fitzgerald         shared_ty: VMSharedTypeIndex,
78aef5eeb5SAlex Crichton         fields: &[Val],
79aef5eeb5SAlex Crichton     ) -> Result<Val> {
80128e6b8fSNick Fitzgerald         let struct_ty = StructType::from_shared_type_index(store.engine(), shared_ty);
81128e6b8fSNick Fitzgerald         let allocator = StructRefPre::_new(store, struct_ty);
82cc8d04f4SAlex Crichton         let struct_ref =
83cc8d04f4SAlex Crichton             StructRef::_new_async(store, limiter, &allocator, &fields, self.asyncness).await?;
84aef5eeb5SAlex Crichton         Ok(Val::AnyRef(Some(struct_ref.into())))
85128e6b8fSNick Fitzgerald     }
86128e6b8fSNick Fitzgerald 
87128e6b8fSNick Fitzgerald     #[cfg(feature = "gc")]
struct_new_default( &mut self, store: &mut StoreOpaque, limiter: Option<&mut StoreResourceLimiter<'_>>, shared_ty: VMSharedTypeIndex, ) -> Result<Val>88d1397130SAlex Crichton     async fn struct_new_default(
89128e6b8fSNick Fitzgerald         &mut self,
90aef5eeb5SAlex Crichton         store: &mut StoreOpaque,
91155ea7fcSAlex Crichton         limiter: Option<&mut StoreResourceLimiter<'_>>,
92cb235ecfSNick Fitzgerald         shared_ty: VMSharedTypeIndex,
93aef5eeb5SAlex Crichton     ) -> Result<Val> {
94aad93a48SAlex Crichton         let module = store
95aad93a48SAlex Crichton             .instance(self.instance)
96128e6b8fSNick Fitzgerald             .runtime_module()
97128e6b8fSNick Fitzgerald             .expect("should never be allocating a struct type defined in a dummy module");
98128e6b8fSNick Fitzgerald 
99128e6b8fSNick Fitzgerald         let borrowed = module
100128e6b8fSNick Fitzgerald             .engine()
101128e6b8fSNick Fitzgerald             .signatures()
102128e6b8fSNick Fitzgerald             .borrow(shared_ty)
103128e6b8fSNick Fitzgerald             .expect("should have a registered type for struct");
104128e6b8fSNick Fitzgerald         let WasmSubType {
10538845a02SAndrew Brown             composite_type:
10638845a02SAndrew Brown                 WasmCompositeType {
10738845a02SAndrew Brown                     shared: false,
10838845a02SAndrew Brown                     inner: WasmCompositeInnerType::Struct(struct_ty),
10938845a02SAndrew Brown                 },
110128e6b8fSNick Fitzgerald             ..
111128e6b8fSNick Fitzgerald         } = &*borrowed
112128e6b8fSNick Fitzgerald         else {
113128e6b8fSNick Fitzgerald             unreachable!("registered type should be a struct");
114128e6b8fSNick Fitzgerald         };
115128e6b8fSNick Fitzgerald 
116128e6b8fSNick Fitzgerald         let fields = struct_ty
117128e6b8fSNick Fitzgerald             .fields
118128e6b8fSNick Fitzgerald             .iter()
119128e6b8fSNick Fitzgerald             .map(|ty| match &ty.element_type {
120128e6b8fSNick Fitzgerald                 wasmtime_environ::WasmStorageType::I8 | wasmtime_environ::WasmStorageType::I16 => {
121aef5eeb5SAlex Crichton                     Val::I32(0)
122128e6b8fSNick Fitzgerald                 }
123128e6b8fSNick Fitzgerald                 wasmtime_environ::WasmStorageType::Val(v) => match v {
124aef5eeb5SAlex Crichton                     wasmtime_environ::WasmValType::I32 => Val::I32(0),
125aef5eeb5SAlex Crichton                     wasmtime_environ::WasmValType::I64 => Val::I64(0),
126aef5eeb5SAlex Crichton                     wasmtime_environ::WasmValType::F32 => Val::F32(0.0f32.to_bits()),
127aef5eeb5SAlex Crichton                     wasmtime_environ::WasmValType::F64 => Val::F64(0.0f64.to_bits()),
128aef5eeb5SAlex Crichton                     wasmtime_environ::WasmValType::V128 => Val::V128(0u128.into()),
129128e6b8fSNick Fitzgerald                     wasmtime_environ::WasmValType::Ref(r) => {
130128e6b8fSNick Fitzgerald                         assert!(r.nullable);
131aef5eeb5SAlex Crichton                         Val::null_top(r.heap_type.top())
132128e6b8fSNick Fitzgerald                     }
133128e6b8fSNick Fitzgerald                 },
134128e6b8fSNick Fitzgerald             })
135aef5eeb5SAlex Crichton             .collect::<smallvec::SmallVec<[_; 8]>>();
136128e6b8fSNick Fitzgerald 
137155ea7fcSAlex Crichton         self.struct_new(store, limiter, shared_ty, &fields).await
138128e6b8fSNick Fitzgerald     }
13972004aadSNick Fitzgerald }
14072004aadSNick Fitzgerald 
14172004aadSNick Fitzgerald impl ConstExprEvaluator {
142d1397130SAlex Crichton     /// Same as [`Self::eval`] except that this is specifically intended for
143d1397130SAlex Crichton     /// integral constant expression.
14472004aadSNick Fitzgerald     ///
145d1397130SAlex Crichton     /// # Panics
146d1397130SAlex Crichton     ///
147d1397130SAlex Crichton     /// Panics if `ConstExpr` contains GC ops (e.g. it's not for an integral
148d1397130SAlex Crichton     /// type).
eval_int( &mut self, store: &mut StoreOpaque, context: &mut ConstEvalContext, expr: &ConstExpr, ) -> Result<&Val>149d1397130SAlex Crichton     pub fn eval_int(
150d1397130SAlex Crichton         &mut self,
151d1397130SAlex Crichton         store: &mut StoreOpaque,
152d1397130SAlex Crichton         context: &mut ConstEvalContext,
153d1397130SAlex Crichton         expr: &ConstExpr,
154d1397130SAlex Crichton     ) -> Result<&Val> {
155d1397130SAlex Crichton         // Try to evaluate a simple expression first before doing the more
156d1397130SAlex Crichton         // complicated eval loop below.
157d1397130SAlex Crichton         if self.try_simple(expr).is_some() {
158d1397130SAlex Crichton             return Ok(&self.simple);
159d1397130SAlex Crichton         }
160d1397130SAlex Crichton 
161d1397130SAlex Crichton         // Note that `assert_ready` here should be valid as production of an
162d1397130SAlex Crichton         // integer cannot involve GC meaning that async operations aren't used.
163d1397130SAlex Crichton         let mut scope = OpaqueRootScope::new(store);
164155ea7fcSAlex Crichton         vm::assert_ready(self.eval_loop(&mut scope, None, context, expr))
165d1397130SAlex Crichton     }
166d1397130SAlex Crichton 
167d1397130SAlex Crichton     /// Attempts to peek into `expr` to see if it's trivial to evaluate, e.g.
168d1397130SAlex Crichton     /// for `i32.const N`.
169d1397130SAlex Crichton     #[inline]
try_simple(&mut self, expr: &ConstExpr) -> Option<&Val>170d1397130SAlex Crichton     pub fn try_simple(&mut self, expr: &ConstExpr) -> Option<&Val> {
171*a6f4bd2fSAlex Crichton         match expr.const_eval()? {
172*a6f4bd2fSAlex Crichton             GlobalConstValue::I32(i) => Some(self.return_one(Val::I32(i))),
173*a6f4bd2fSAlex Crichton             GlobalConstValue::I64(i) => Some(self.return_one(Val::I64(i))),
174*a6f4bd2fSAlex Crichton             GlobalConstValue::F32(f) => Some(self.return_one(Val::F32(f))),
175*a6f4bd2fSAlex Crichton             GlobalConstValue::F64(f) => Some(self.return_one(Val::F64(f))),
176*a6f4bd2fSAlex Crichton             GlobalConstValue::V128(i) => Some(self.return_one(Val::V128(i.into()))),
177d1397130SAlex Crichton         }
178d1397130SAlex Crichton     }
179d1397130SAlex Crichton 
180d1397130SAlex Crichton     /// Evaluate the given const expression in the given context.
181aef5eeb5SAlex Crichton     ///
182aef5eeb5SAlex Crichton     /// Note that the `store` argument is an `OpaqueRootScope` which is used to
183aef5eeb5SAlex Crichton     /// require that a GC rooting scope external to evaluation of this constant
184aef5eeb5SAlex Crichton     /// is required. Constant expression evaluation may perform GC allocations
185aef5eeb5SAlex Crichton     /// and itself trigger a GC meaning that all references must be rooted,
186aef5eeb5SAlex Crichton     /// hence the external requirement of a rooting scope.
187aef5eeb5SAlex Crichton     ///
188d1397130SAlex Crichton     /// # Panics
18972004aadSNick Fitzgerald     ///
190d1397130SAlex Crichton     /// This function will panic if `expr` is an invalid constant expression.
eval( &mut self, store: &mut OpaqueRootScope<&mut StoreOpaque>, limiter: Option<&mut StoreResourceLimiter<'_>>, context: &mut ConstEvalContext, expr: &ConstExpr, ) -> Result<&Val>191d1397130SAlex Crichton     pub async fn eval(
19272004aadSNick Fitzgerald         &mut self,
193aef5eeb5SAlex Crichton         store: &mut OpaqueRootScope<&mut StoreOpaque>,
194155ea7fcSAlex Crichton         limiter: Option<&mut StoreResourceLimiter<'_>>,
195aad93a48SAlex Crichton         context: &mut ConstEvalContext,
19672004aadSNick Fitzgerald         expr: &ConstExpr,
197aef5eeb5SAlex Crichton     ) -> Result<&Val> {
198d1397130SAlex Crichton         // Same structure as `eval_int` above, except using `.await` and with a
199d1397130SAlex Crichton         // slightly different type signature here for this function.
200d1397130SAlex Crichton         if self.try_simple(expr).is_some() {
201d1397130SAlex Crichton             return Ok(&self.simple);
202aef5eeb5SAlex Crichton         }
203155ea7fcSAlex Crichton         self.eval_loop(store, limiter, context, expr).await
204aef5eeb5SAlex Crichton     }
205aef5eeb5SAlex Crichton 
206d1397130SAlex Crichton     #[inline]
return_one(&mut self, val: Val) -> &Val207d1397130SAlex Crichton     fn return_one(&mut self, val: Val) -> &Val {
208d1397130SAlex Crichton         self.simple = val;
209d1397130SAlex Crichton         &self.simple
210aef5eeb5SAlex Crichton     }
211aef5eeb5SAlex Crichton 
212d1397130SAlex Crichton     #[cold]
eval_loop( &mut self, store: &mut OpaqueRootScope<&mut StoreOpaque>, mut limiter: Option<&mut StoreResourceLimiter<'_>>, context: &mut ConstEvalContext, expr: &ConstExpr, ) -> Result<&Val>213d1397130SAlex Crichton     async fn eval_loop(
214aef5eeb5SAlex Crichton         &mut self,
215aef5eeb5SAlex Crichton         store: &mut OpaqueRootScope<&mut StoreOpaque>,
216155ea7fcSAlex Crichton         mut limiter: Option<&mut StoreResourceLimiter<'_>>,
217aef5eeb5SAlex Crichton         context: &mut ConstEvalContext,
218d1397130SAlex Crichton         expr: &ConstExpr,
219aef5eeb5SAlex Crichton     ) -> Result<&Val> {
220d1397130SAlex Crichton         log::trace!("evaluating const expr: {expr:?}");
221818966f3SNick Fitzgerald 
22272004aadSNick Fitzgerald         self.stack.clear();
22372004aadSNick Fitzgerald 
224155ea7fcSAlex Crichton         // On GC-less builds ensure that this is always considered used an
225155ea7fcSAlex Crichton         // needed-mutable.
226155ea7fcSAlex Crichton         let _ = &mut limiter;
227155ea7fcSAlex Crichton 
228d1397130SAlex Crichton         for op in expr.ops() {
229956ca003SNick Fitzgerald             log::trace!("const-evaluating op: {op:?}");
23072004aadSNick Fitzgerald             match op {
231aef5eeb5SAlex Crichton                 ConstOp::I32Const(i) => self.stack.push(Val::I32(*i)),
232aef5eeb5SAlex Crichton                 ConstOp::I64Const(i) => self.stack.push(Val::I64(*i)),
233aef5eeb5SAlex Crichton                 ConstOp::F32Const(f) => self.stack.push(Val::F32(*f)),
234aef5eeb5SAlex Crichton                 ConstOp::F64Const(f) => self.stack.push(Val::F64(*f)),
235aef5eeb5SAlex Crichton                 ConstOp::V128Const(v) => self.stack.push(Val::V128((*v).into())),
236aef5eeb5SAlex Crichton                 ConstOp::GlobalGet(g) => self.stack.push(context.global_get(store, *g)?),
237aef5eeb5SAlex Crichton                 ConstOp::RefNull(ty) => self.stack.push(Val::null_top(*ty)),
238aef5eeb5SAlex Crichton                 ConstOp::RefFunc(f) => self.stack.push(context.ref_func(store, *f)?),
239aef5eeb5SAlex Crichton                 #[cfg(feature = "gc")]
240128e6b8fSNick Fitzgerald                 ConstOp::RefI31 => {
241aef5eeb5SAlex Crichton                     let i = self.pop()?.unwrap_i32();
24272004aadSNick Fitzgerald                     let i31 = I31::wrapping_i32(i);
243aef5eeb5SAlex Crichton                     let r = AnyRef::_from_i31(&mut AutoAssertNoGc::new(store), i31);
244aef5eeb5SAlex Crichton                     self.stack.push(Val::AnyRef(Some(r)));
24572004aadSNick Fitzgerald                 }
246aef5eeb5SAlex Crichton                 #[cfg(not(feature = "gc"))]
247aef5eeb5SAlex Crichton                 ConstOp::RefI31 => panic!("should not have validated"),
248128e6b8fSNick Fitzgerald                 ConstOp::I32Add => {
249aef5eeb5SAlex Crichton                     let b = self.pop()?.unwrap_i32();
250aef5eeb5SAlex Crichton                     let a = self.pop()?.unwrap_i32();
251aef5eeb5SAlex Crichton                     self.stack.push(Val::I32(a.wrapping_add(b)));
252766620e4SAlex Crichton                 }
253128e6b8fSNick Fitzgerald                 ConstOp::I32Sub => {
254aef5eeb5SAlex Crichton                     let b = self.pop()?.unwrap_i32();
255aef5eeb5SAlex Crichton                     let a = self.pop()?.unwrap_i32();
256aef5eeb5SAlex Crichton                     self.stack.push(Val::I32(a.wrapping_sub(b)));
257766620e4SAlex Crichton                 }
258128e6b8fSNick Fitzgerald                 ConstOp::I32Mul => {
259aef5eeb5SAlex Crichton                     let b = self.pop()?.unwrap_i32();
260aef5eeb5SAlex Crichton                     let a = self.pop()?.unwrap_i32();
261aef5eeb5SAlex Crichton                     self.stack.push(Val::I32(a.wrapping_mul(b)));
262766620e4SAlex Crichton                 }
263128e6b8fSNick Fitzgerald                 ConstOp::I64Add => {
264aef5eeb5SAlex Crichton                     let b = self.pop()?.unwrap_i64();
265aef5eeb5SAlex Crichton                     let a = self.pop()?.unwrap_i64();
266aef5eeb5SAlex Crichton                     self.stack.push(Val::I64(a.wrapping_add(b)));
267766620e4SAlex Crichton                 }
268128e6b8fSNick Fitzgerald                 ConstOp::I64Sub => {
269aef5eeb5SAlex Crichton                     let b = self.pop()?.unwrap_i64();
270aef5eeb5SAlex Crichton                     let a = self.pop()?.unwrap_i64();
271aef5eeb5SAlex Crichton                     self.stack.push(Val::I64(a.wrapping_sub(b)));
272766620e4SAlex Crichton                 }
273128e6b8fSNick Fitzgerald                 ConstOp::I64Mul => {
274aef5eeb5SAlex Crichton                     let b = self.pop()?.unwrap_i64();
275aef5eeb5SAlex Crichton                     let a = self.pop()?.unwrap_i64();
276aef5eeb5SAlex Crichton                     self.stack.push(Val::I64(a.wrapping_mul(b)));
277766620e4SAlex Crichton                 }
278128e6b8fSNick Fitzgerald 
279128e6b8fSNick Fitzgerald                 #[cfg(not(feature = "gc"))]
280ec3b2d22SNick Fitzgerald                 ConstOp::StructNew { .. }
281ec3b2d22SNick Fitzgerald                 | ConstOp::StructNewDefault { .. }
282ec3b2d22SNick Fitzgerald                 | ConstOp::ArrayNew { .. }
283ec3b2d22SNick Fitzgerald                 | ConstOp::ArrayNewDefault { .. }
284fc3302a0SAlex Crichton                 | ConstOp::ArrayNewFixed { .. }
285fc3302a0SAlex Crichton                 | ConstOp::ExternConvertAny
286fc3302a0SAlex Crichton                 | ConstOp::AnyConvertExtern => {
287128e6b8fSNick Fitzgerald                     bail!(
288128e6b8fSNick Fitzgerald                         "const expr evaluation error: struct operations are not \
289128e6b8fSNick Fitzgerald                          supported without the `gc` feature"
290128e6b8fSNick Fitzgerald                     )
291128e6b8fSNick Fitzgerald                 }
292128e6b8fSNick Fitzgerald 
293128e6b8fSNick Fitzgerald                 #[cfg(feature = "gc")]
294128e6b8fSNick Fitzgerald                 ConstOp::StructNew { struct_type_index } => {
295aad93a48SAlex Crichton                     let interned_type_index = store.instance(context.instance).env_module().types
296cb235ecfSNick Fitzgerald                         [*struct_type_index]
297cb235ecfSNick Fitzgerald                         .unwrap_engine_type_index();
298aef5eeb5SAlex Crichton                     let len = context.struct_fields_len(store, interned_type_index);
299128e6b8fSNick Fitzgerald 
300128e6b8fSNick Fitzgerald                     if self.stack.len() < len {
301128e6b8fSNick Fitzgerald                         bail!(
302128e6b8fSNick Fitzgerald                             "const expr evaluation error: expected at least {len} values on the stack, found {}",
303128e6b8fSNick Fitzgerald                             self.stack.len()
304128e6b8fSNick Fitzgerald                         )
305128e6b8fSNick Fitzgerald                     }
306128e6b8fSNick Fitzgerald 
307128e6b8fSNick Fitzgerald                     let start = self.stack.len() - len;
308d1397130SAlex Crichton                     let s = context
309155ea7fcSAlex Crichton                         .struct_new(
310155ea7fcSAlex Crichton                             store,
311155ea7fcSAlex Crichton                             limiter.as_deref_mut(),
312155ea7fcSAlex Crichton                             interned_type_index,
313155ea7fcSAlex Crichton                             &self.stack[start..],
314155ea7fcSAlex Crichton                         )
315d1397130SAlex Crichton                         .await?;
316128e6b8fSNick Fitzgerald                     self.stack.truncate(start);
317128e6b8fSNick Fitzgerald                     self.stack.push(s);
318128e6b8fSNick Fitzgerald                 }
319128e6b8fSNick Fitzgerald 
320128e6b8fSNick Fitzgerald                 #[cfg(feature = "gc")]
321128e6b8fSNick Fitzgerald                 ConstOp::StructNewDefault { struct_type_index } => {
322aad93a48SAlex Crichton                     let ty = store.instance(context.instance).env_module().types
323aad93a48SAlex Crichton                         [*struct_type_index]
324cb235ecfSNick Fitzgerald                         .unwrap_engine_type_index();
325155ea7fcSAlex Crichton                     self.stack.push(
326155ea7fcSAlex Crichton                         context
327155ea7fcSAlex Crichton                             .struct_new_default(store, limiter.as_deref_mut(), ty)
328155ea7fcSAlex Crichton                             .await?,
329155ea7fcSAlex Crichton                     );
330128e6b8fSNick Fitzgerald                 }
331ec3b2d22SNick Fitzgerald 
332ec3b2d22SNick Fitzgerald                 #[cfg(feature = "gc")]
333ec3b2d22SNick Fitzgerald                 ConstOp::ArrayNew { array_type_index } => {
334aad93a48SAlex Crichton                     let ty = store.instance(context.instance).env_module().types[*array_type_index]
335cb235ecfSNick Fitzgerald                         .unwrap_engine_type_index();
336cb235ecfSNick Fitzgerald                     let ty = ArrayType::from_shared_type_index(store.engine(), ty);
337ec3b2d22SNick Fitzgerald 
338aef5eeb5SAlex Crichton                     let len = self.pop()?.unwrap_i32().cast_unsigned();
339ec3b2d22SNick Fitzgerald 
340aef5eeb5SAlex Crichton                     let elem = self.pop()?;
341ec3b2d22SNick Fitzgerald 
342aef5eeb5SAlex Crichton                     let pre = ArrayRefPre::_new(store, ty);
343cc8d04f4SAlex Crichton                     let array = ArrayRef::_new_async(
344cc8d04f4SAlex Crichton                         store,
345cc8d04f4SAlex Crichton                         limiter.as_deref_mut(),
346cc8d04f4SAlex Crichton                         &pre,
347cc8d04f4SAlex Crichton                         &elem,
348cc8d04f4SAlex Crichton                         len,
349cc8d04f4SAlex Crichton                         context.asyncness,
350cc8d04f4SAlex Crichton                     )
351155ea7fcSAlex Crichton                     .await?;
352ec3b2d22SNick Fitzgerald 
353aef5eeb5SAlex Crichton                     self.stack.push(Val::AnyRef(Some(array.into())));
354ec3b2d22SNick Fitzgerald                 }
355ec3b2d22SNick Fitzgerald 
356ec3b2d22SNick Fitzgerald                 #[cfg(feature = "gc")]
357ec3b2d22SNick Fitzgerald                 ConstOp::ArrayNewDefault { array_type_index } => {
358aad93a48SAlex Crichton                     let ty = store.instance(context.instance).env_module().types[*array_type_index]
359cb235ecfSNick Fitzgerald                         .unwrap_engine_type_index();
360cb235ecfSNick Fitzgerald                     let ty = ArrayType::from_shared_type_index(store.engine(), ty);
361ec3b2d22SNick Fitzgerald 
362aef5eeb5SAlex Crichton                     let len = self.pop()?.unwrap_i32().cast_unsigned();
363ec3b2d22SNick Fitzgerald 
364ec3b2d22SNick Fitzgerald                     let elem = Val::default_for_ty(ty.element_type().unpack())
365ec3b2d22SNick Fitzgerald                         .expect("type should have a default value");
366ec3b2d22SNick Fitzgerald 
367aef5eeb5SAlex Crichton                     let pre = ArrayRefPre::_new(store, ty);
368cc8d04f4SAlex Crichton                     let array = ArrayRef::_new_async(
369cc8d04f4SAlex Crichton                         store,
370cc8d04f4SAlex Crichton                         limiter.as_deref_mut(),
371cc8d04f4SAlex Crichton                         &pre,
372cc8d04f4SAlex Crichton                         &elem,
373cc8d04f4SAlex Crichton                         len,
374cc8d04f4SAlex Crichton                         context.asyncness,
375cc8d04f4SAlex Crichton                     )
376155ea7fcSAlex Crichton                     .await?;
377ec3b2d22SNick Fitzgerald 
378aef5eeb5SAlex Crichton                     self.stack.push(Val::AnyRef(Some(array.into())));
379ec3b2d22SNick Fitzgerald                 }
380ec3b2d22SNick Fitzgerald 
381ec3b2d22SNick Fitzgerald                 #[cfg(feature = "gc")]
382ec3b2d22SNick Fitzgerald                 ConstOp::ArrayNewFixed {
383ec3b2d22SNick Fitzgerald                     array_type_index,
384ec3b2d22SNick Fitzgerald                     array_size,
385ec3b2d22SNick Fitzgerald                 } => {
386aad93a48SAlex Crichton                     let ty = store.instance(context.instance).env_module().types[*array_type_index]
387cb235ecfSNick Fitzgerald                         .unwrap_engine_type_index();
388cb235ecfSNick Fitzgerald                     let ty = ArrayType::from_shared_type_index(store.engine(), ty);
389ec3b2d22SNick Fitzgerald 
390ec3b2d22SNick Fitzgerald                     let array_size = usize::try_from(*array_size).unwrap();
391ec3b2d22SNick Fitzgerald                     if self.stack.len() < array_size {
392ec3b2d22SNick Fitzgerald                         bail!(
393ec3b2d22SNick Fitzgerald                             "const expr evaluation error: expected at least {array_size} values on the stack, found {}",
394ec3b2d22SNick Fitzgerald                             self.stack.len()
395ec3b2d22SNick Fitzgerald                         )
396ec3b2d22SNick Fitzgerald                     }
397ec3b2d22SNick Fitzgerald 
398ec3b2d22SNick Fitzgerald                     let start = self.stack.len() - array_size;
399ec3b2d22SNick Fitzgerald 
400ec3b2d22SNick Fitzgerald                     let elems = self
401ec3b2d22SNick Fitzgerald                         .stack
402ec3b2d22SNick Fitzgerald                         .drain(start..)
403aef5eeb5SAlex Crichton                         .collect::<smallvec::SmallVec<[_; 8]>>();
404ec3b2d22SNick Fitzgerald 
405aef5eeb5SAlex Crichton                     let pre = ArrayRefPre::_new(store, ty);
406cc8d04f4SAlex Crichton                     let array = ArrayRef::_new_fixed_async(
407cc8d04f4SAlex Crichton                         store,
408cc8d04f4SAlex Crichton                         limiter.as_deref_mut(),
409cc8d04f4SAlex Crichton                         &pre,
410cc8d04f4SAlex Crichton                         &elems,
411cc8d04f4SAlex Crichton                         context.asyncness,
412cc8d04f4SAlex Crichton                     )
413155ea7fcSAlex Crichton                     .await?;
414ec3b2d22SNick Fitzgerald 
415aef5eeb5SAlex Crichton                     self.stack.push(Val::AnyRef(Some(array.into())));
416ec3b2d22SNick Fitzgerald                 }
417fc3302a0SAlex Crichton 
418fc3302a0SAlex Crichton                 #[cfg(feature = "gc")]
419fc3302a0SAlex Crichton                 ConstOp::ExternConvertAny => {
420aef5eeb5SAlex Crichton                     let mut store = AutoAssertNoGc::new(store);
421aef5eeb5SAlex Crichton                     let result = match self.pop()?.unwrap_anyref() {
422aef5eeb5SAlex Crichton                         Some(anyref) => Some(ExternRef::_convert_any(&mut store, *anyref)?),
423aef5eeb5SAlex Crichton                         None => None,
424fc3302a0SAlex Crichton                     };
425aef5eeb5SAlex Crichton                     self.stack.push(Val::ExternRef(result));
426fc3302a0SAlex Crichton                 }
427fc3302a0SAlex Crichton 
428fc3302a0SAlex Crichton                 #[cfg(feature = "gc")]
429fc3302a0SAlex Crichton                 ConstOp::AnyConvertExtern => {
430aef5eeb5SAlex Crichton                     let mut store = AutoAssertNoGc::new(store);
431aef5eeb5SAlex Crichton                     let result = match self.pop()?.unwrap_externref() {
432aef5eeb5SAlex Crichton                         Some(externref) => Some(AnyRef::_convert_extern(&mut store, *externref)?),
433aef5eeb5SAlex Crichton                         None => None,
434fc3302a0SAlex Crichton                     };
435aef5eeb5SAlex Crichton                     self.stack.push(result.into());
436fc3302a0SAlex Crichton                 }
43772004aadSNick Fitzgerald             }
43872004aadSNick Fitzgerald         }
43972004aadSNick Fitzgerald 
44072004aadSNick Fitzgerald         if self.stack.len() == 1 {
441818966f3SNick Fitzgerald             log::trace!("const expr evaluated to {:?}", self.stack[0]);
442aef5eeb5SAlex Crichton             Ok(&self.stack[0])
44372004aadSNick Fitzgerald         } else {
44472004aadSNick Fitzgerald             bail!(
44572004aadSNick Fitzgerald                 "const expr evaluation error: expected 1 resulting value, found {}",
44672004aadSNick Fitzgerald                 self.stack.len()
44772004aadSNick Fitzgerald             )
44872004aadSNick Fitzgerald         }
44972004aadSNick Fitzgerald     }
45072004aadSNick Fitzgerald 
pop(&mut self) -> Result<Val>451aef5eeb5SAlex Crichton     fn pop(&mut self) -> Result<Val> {
45272004aadSNick Fitzgerald         self.stack.pop().ok_or_else(|| {
453ff33e949SNick Fitzgerald             format_err!(
45472004aadSNick Fitzgerald                 "const expr evaluation error: attempted to pop from an empty \
45572004aadSNick Fitzgerald                  evaluation stack"
45672004aadSNick Fitzgerald             )
45772004aadSNick Fitzgerald         })
45872004aadSNick Fitzgerald     }
45972004aadSNick Fitzgerald }
460