Skip to content

Commit 24d4808

Browse files
EkleogEkleog-NEAR
andauthored
[wasmparser] Reduce the size of TypeId for better validation performance (#844)
* Reduce the size of TypeId for better validation performance * Add a benchmark showcasing TypeId size reduction performance benefits * Reduce TypeId size further to 16 bytes Performance benefits are less obvious, but it gets us further away from a regression Co-authored-by: Léo Gaspard <[email protected]>
1 parent 2de95fe commit 24d4808

File tree

4 files changed

+84
-85
lines changed

4 files changed

+84
-85
lines changed
29.3 KB
Binary file not shown.

crates/wasmparser/src/validator/component.rs

Lines changed: 34 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,12 @@ impl ComponentState {
114114
check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
115115
}
116116

117-
current.core_types.push(TypeId {
118-
type_size: ty.type_size(),
119-
index: types.len(),
120-
type_index: Some(current.core_types.len()),
121-
is_core: true,
122-
});
117+
current.core_types.push(TypeId::new(
118+
ty.type_size(),
119+
types.len(),
120+
Some(current.core_types.len()),
121+
true,
122+
));
123123
types.push(ty);
124124

125125
Ok(())
@@ -142,12 +142,8 @@ impl ComponentState {
142142
exports: module.exports.clone(),
143143
});
144144

145-
self.core_modules.push(TypeId {
146-
type_size: ty.type_size(),
147-
index: types.len(),
148-
type_index: None,
149-
is_core: true,
150-
});
145+
self.core_modules
146+
.push(TypeId::new(ty.type_size(), types.len(), None, true));
151147

152148
types.push(ty);
153149

@@ -213,12 +209,12 @@ impl ComponentState {
213209
check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
214210
}
215211

216-
current.types.push(TypeId {
217-
type_size: ty.type_size(),
218-
index: types.len(),
219-
type_index: Some(current.types.len()),
220-
is_core: false,
221-
});
212+
current.types.push(TypeId::new(
213+
ty.type_size(),
214+
types.len(),
215+
Some(current.types.len()),
216+
false,
217+
));
222218
types.push(ty);
223219

224220
Ok(())
@@ -387,12 +383,8 @@ impl ComponentState {
387383

388384
let lowered_ty = Type::Func(info.into_func_type());
389385

390-
self.core_funcs.push(TypeId {
391-
type_size: lowered_ty.type_size(),
392-
index: types.len(),
393-
type_index: None,
394-
is_core: true,
395-
});
386+
self.core_funcs
387+
.push(TypeId::new(lowered_ty.type_size(), types.len(), None, true));
396388

397389
types.push(lowered_ty);
398390

@@ -406,12 +398,8 @@ impl ComponentState {
406398
exports: mem::take(&mut component.exports),
407399
});
408400

409-
self.components.push(TypeId {
410-
type_size: ty.type_size(),
411-
index: types.len(),
412-
type_index: None,
413-
is_core: false,
414-
});
401+
self.components
402+
.push(TypeId::new(ty.type_size(), types.len(), None, false));
415403

416404
types.push(ty);
417405
}
@@ -1079,12 +1067,7 @@ impl ComponentState {
10791067
kind: InstanceTypeKind::Instantiated(module_type_id),
10801068
});
10811069

1082-
let id = TypeId {
1083-
type_size: ty.type_size(),
1084-
index: types.len(),
1085-
type_index: None,
1086-
is_core: true,
1087-
};
1070+
let id = TypeId::new(ty.type_size(), types.len(), None, true);
10881071

10891072
types.push(ty);
10901073

@@ -1223,12 +1206,7 @@ impl ComponentState {
12231206
kind: ComponentInstanceTypeKind::Instantiated(component_type_id),
12241207
});
12251208

1226-
let id = TypeId {
1227-
type_size: ty.type_size(),
1228-
index: types.len(),
1229-
type_index: None,
1230-
is_core: false,
1231-
};
1209+
let id = TypeId::new(ty.type_size(), types.len(), None, false);
12321210

12331211
types.push(ty);
12341212

@@ -1330,12 +1308,7 @@ impl ComponentState {
13301308
kind: ComponentInstanceTypeKind::Exports(inst_exports),
13311309
});
13321310

1333-
let id = TypeId {
1334-
type_size: ty.type_size(),
1335-
index: types.len(),
1336-
type_index: None,
1337-
is_core: false,
1338-
};
1311+
let id = TypeId::new(ty.type_size(), types.len(), None, false);
13391312

13401313
types.push(ty);
13411314

@@ -1418,12 +1391,7 @@ impl ComponentState {
14181391
kind: InstanceTypeKind::Exports(inst_exports),
14191392
});
14201393

1421-
let id = TypeId {
1422-
type_size: ty.type_size(),
1423-
index: types.len(),
1424-
type_index: None,
1425-
is_core: true,
1426-
};
1394+
let id = TypeId::new(ty.type_size(), types.len(), None, true);
14271395

14281396
types.push(ty);
14291397

@@ -1638,12 +1606,12 @@ impl ComponentState {
16381606
let current = components.last_mut().unwrap();
16391607
check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
16401608

1641-
current.core_types.push(TypeId {
1642-
type_size: ty.type_size,
1643-
index: ty.index,
1644-
type_index: Some(current.core_types.len()),
1645-
is_core: true,
1646-
});
1609+
current.core_types.push(TypeId::new(
1610+
ty.type_size as usize,
1611+
ty.index,
1612+
Some(current.core_types.len()),
1613+
true,
1614+
));
16471615

16481616
Ok(())
16491617
}
@@ -1655,12 +1623,12 @@ impl ComponentState {
16551623
let current = components.last_mut().unwrap();
16561624
check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
16571625

1658-
current.types.push(TypeId {
1659-
type_size: ty.type_size,
1660-
index: ty.index,
1661-
type_index: Some(current.types.len()),
1662-
is_core: false,
1663-
});
1626+
current.types.push(TypeId::new(
1627+
ty.type_size as usize,
1628+
ty.index,
1629+
Some(current.types.len()),
1630+
false,
1631+
));
16641632

16651633
Ok(())
16661634
}

crates/wasmparser/src/validator/core.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -489,12 +489,12 @@ impl Module {
489489
check_max(self.types.len(), 1, MAX_WASM_TYPES, "types", offset)?;
490490
}
491491

492-
self.types.push(TypeId {
493-
type_size: ty.type_size(),
494-
index: types.len(),
495-
type_index: Some(self.types.len()),
496-
is_core: true,
497-
});
492+
self.types.push(TypeId::new(
493+
ty.type_size(),
494+
types.len(),
495+
Some(self.types.len()),
496+
true,
497+
));
498498
types.push(ty);
499499
Ok(())
500500
}

crates/wasmparser/src/validator/types.rs

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -324,21 +324,52 @@ fn push_primitive_wasm_types(ty: &PrimitiveValType, lowered_types: &mut LoweredT
324324
/// Represents a unique identifier for a type known to a [`crate::Validator`].
325325
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
326326
pub struct TypeId {
327+
/// The index into the global list of types.
328+
pub(crate) index: usize,
327329
/// The effective type size for the type.
328330
///
329331
/// This is stored as part of the ID to avoid having to recurse through
330332
/// the global type list when calculating type sizes.
331-
pub(crate) type_size: usize,
332-
/// The index into the global list of types.
333-
pub(crate) index: usize,
334-
/// The original type index.
333+
pub(crate) type_size: u32,
334+
/// Metadata about the type hash, used to avoid two isomorphic types from
335+
/// being considered as equal for Eq and Hash.
335336
///
336-
/// This will be `None` for implicitly defined types, e.g. types for
337-
/// modules definitions, component definitions, instantiations, and function
338-
/// lowerings.
339-
pub(crate) type_index: Option<usize>,
340-
/// Whether or not the type is a core type.
341-
pub(crate) is_core: bool,
337+
/// This contains:
338+
/// - Bit (1 << 31): True iff the type is a core type
339+
/// - Bit (1 << 30): False iff the type is implicitly defined, eg. types
340+
/// for module definitions, component definitions, instantiations and
341+
/// function lowerings.
342+
/// - Other bits: if (1 << 62) is not true, then the type index
343+
pub(crate) type_hash: u32,
344+
}
345+
346+
impl TypeId {
347+
pub(crate) fn new(
348+
type_size: usize,
349+
index: usize,
350+
type_index: Option<usize>,
351+
is_core: bool,
352+
) -> TypeId {
353+
let mut type_hash = 0;
354+
if is_core {
355+
type_hash |= 1 << 31;
356+
}
357+
if let Some(type_index) = type_index {
358+
type_hash |= 1 << 30;
359+
let type_index: u32 = type_index
360+
.try_into()
361+
.expect("failed converting usize to u32");
362+
if type_index & (0b11 << 30) != 0 {
363+
panic!("type index bigger than 2**30");
364+
}
365+
type_hash |= type_index;
366+
}
367+
TypeId {
368+
type_size: type_size.try_into().expect("too big type"),
369+
index,
370+
type_hash,
371+
}
372+
}
342373
}
343374

344375
/// A unified type definition for validating WebAssembly modules and components.
@@ -520,7 +551,7 @@ impl ComponentValType {
520551
pub(crate) fn type_size(&self) -> usize {
521552
match self {
522553
Self::Primitive(_) => 1,
523-
Self::Type(id) => id.type_size,
554+
Self::Type(id) => id.type_size as usize,
524555
}
525556
}
526557
}
@@ -592,7 +623,7 @@ impl EntityType {
592623

593624
pub(crate) fn type_size(&self) -> usize {
594625
match self {
595-
Self::Func(id) | Self::Tag(id) => id.type_size,
626+
Self::Func(id) | Self::Tag(id) => id.type_size as usize,
596627
Self::Table(_) | Self::Memory(_) | Self::Global(_) => 1,
597628
}
598629
}
@@ -800,7 +831,7 @@ impl ComponentEntityType {
800831
| Self::Func(ty)
801832
| Self::Type(ty)
802833
| Self::Instance(ty)
803-
| Self::Component(ty) => ty.type_size,
834+
| Self::Component(ty) => ty.type_size as usize,
804835
Self::Value(ty) => ty.type_size(),
805836
}
806837
}

0 commit comments

Comments
 (0)