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