Next Generation WASM Microkernel Operating System
at trap_handler 141 lines 5.0 kB view raw
1// Copyright 2025 Jonas Kruckenberg 2// 3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or 4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or 5// http://opensource.org/licenses/MIT>, at your option. This file may not be 6// copied, modified, or distributed except according to those terms. 7 8use crate::wasm::indices::{FuncIndex, GlobalIndex, TypeIndex}; 9use anyhow::bail; 10use smallvec::SmallVec; 11 12/// A constant expression. 13/// 14/// These are used to initialize globals, table elements, etc... 15#[derive(Clone, Debug, Eq, PartialEq, Hash)] 16pub struct ConstExpr { 17 ops: SmallVec<[ConstOp; 2]>, 18} 19 20impl ConstExpr { 21 /// Create a new const expression from a `wasmparser` const expression. 22 /// 23 /// Returns the new const expression as well as the escaping function 24 /// indices that appeared in `ref.func` instructions, if any. 25 pub fn from_wasmparser( 26 expr: &wasmparser::ConstExpr<'_>, 27 ) -> crate::Result<(Self, SmallVec<[FuncIndex; 1]>)> { 28 let mut iter = expr 29 .get_operators_reader() 30 .into_iter_with_offsets() 31 .peekable(); 32 33 let mut ops = SmallVec::<[ConstOp; 2]>::new(); 34 let mut escaped = SmallVec::<[FuncIndex; 1]>::new(); 35 while let Some(res) = iter.next() { 36 let (op, offset) = res?; 37 38 // If we reach an `end` instruction, and there are no more 39 // instructions after that, then we are done reading this const 40 // expression. 41 if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() { 42 break; 43 } 44 45 // Track any functions that appear in `ref.func` so that callers can 46 // make sure to flag them as escaping. 47 if let wasmparser::Operator::RefFunc { function_index } = &op { 48 escaped.push(FuncIndex::from_u32(*function_index)); 49 } 50 51 ops.push(ConstOp::from_wasmparser(op, offset)?); 52 } 53 Ok((Self { ops }, escaped)) 54 } 55 56 pub fn ops(&self) -> impl ExactSizeIterator<Item = ConstOp> + use<'_> { 57 self.ops.iter().copied() 58 } 59} 60 61/// The subset of Wasm opcodes that are constant. 62#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] 63pub enum ConstOp { 64 I32Const(i32), 65 I64Const(i64), 66 F32Const(u32), 67 F64Const(u64), 68 V128Const(u128), 69 GlobalGet(GlobalIndex), 70 RefI31, 71 RefNull, 72 RefFunc(FuncIndex), 73 I32Add, 74 I32Sub, 75 I32Mul, 76 I64Add, 77 I64Sub, 78 I64Mul, 79 StructNew { 80 struct_type_index: TypeIndex, 81 }, 82 StructNewDefault { 83 struct_type_index: TypeIndex, 84 }, 85 ArrayNew { 86 array_type_index: TypeIndex, 87 }, 88 ArrayNewDefault { 89 array_type_index: TypeIndex, 90 }, 91 ArrayNewFixed { 92 array_type_index: TypeIndex, 93 array_size: u32, 94 }, 95} 96 97impl ConstOp { 98 /// Convert a `wasmparser::Operator` to a `ConstOp`. 99 pub fn from_wasmparser(op: wasmparser::Operator<'_>, offset: usize) -> crate::Result<Self> { 100 use wasmparser::Operator as O; 101 Ok(match op { 102 O::I32Const { value } => Self::I32Const(value), 103 O::I64Const { value } => Self::I64Const(value), 104 O::F32Const { value } => Self::F32Const(value.bits()), 105 O::F64Const { value } => Self::F64Const(value.bits()), 106 O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())), 107 O::RefNull { hty: _ } => Self::RefNull, 108 O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)), 109 O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)), 110 O::RefI31 => Self::RefI31, 111 O::I32Add => Self::I32Add, 112 O::I32Sub => Self::I32Sub, 113 O::I32Mul => Self::I32Mul, 114 O::I64Add => Self::I64Add, 115 O::I64Sub => Self::I64Sub, 116 O::I64Mul => Self::I64Mul, 117 O::StructNew { struct_type_index } => Self::StructNew { 118 struct_type_index: TypeIndex::from_u32(struct_type_index), 119 }, 120 O::StructNewDefault { struct_type_index } => Self::StructNewDefault { 121 struct_type_index: TypeIndex::from_u32(struct_type_index), 122 }, 123 O::ArrayNew { array_type_index } => Self::ArrayNew { 124 array_type_index: TypeIndex::from_u32(array_type_index), 125 }, 126 O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault { 127 array_type_index: TypeIndex::from_u32(array_type_index), 128 }, 129 O::ArrayNewFixed { 130 array_type_index, 131 array_size, 132 } => Self::ArrayNewFixed { 133 array_type_index: TypeIndex::from_u32(array_type_index), 134 array_size, 135 }, 136 op => { 137 bail!("unsupported opcode in const expression at offset {offset:#x}: {op:?}"); 138 } 139 }) 140 } 141}