Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wizer/src/component/rewrite.rs
2459 views
1
use crate::component::ComponentContext;
2
use crate::component::info::RawSection;
3
use crate::component::snapshot::ComponentSnapshot;
4
use crate::{FuncRenames, Wizer};
5
use wasm_encoder::reencode::{Reencode, ReencodeComponent};
6
7
impl Wizer {
8
/// Helper method which is the equivalent of [`Wizer::rewrite`], but for
9
/// components.
10
///
11
/// This effectively plumbs through all non-module sections as-is and
12
/// updates module sections with whatever [`Wizer::rewrite`] returns.
13
pub(crate) fn rewrite_component(
14
&self,
15
component: &mut ComponentContext<'_>,
16
snapshot: &ComponentSnapshot,
17
) -> Vec<u8> {
18
let mut encoder = wasm_encoder::Component::new();
19
let mut reencoder = Reencoder {
20
funcs: 0,
21
removed_func: None,
22
wizer: self,
23
};
24
25
let mut module_index = 0;
26
for section in component.sections.iter_mut() {
27
match section {
28
RawSection::Module(module) => {
29
let snapshot = snapshot
30
.modules
31
.iter()
32
.find(|(i, _)| *i == module_index)
33
.map(|(_, s)| s);
34
module_index += 1;
35
match snapshot {
36
// This module's snapshot is used for [`Wizer::rewrite`]
37
// and the results of that are spliced into the
38
// component.
39
Some(snapshot) => {
40
let rewritten_wasm =
41
self.rewrite(module, snapshot, &FuncRenames::default());
42
encoder.section(&wasm_encoder::RawSection {
43
id: wasm_encoder::ComponentSectionId::CoreModule as u8,
44
data: &rewritten_wasm,
45
});
46
}
47
48
// This module wasn't instantiated and has no snapshot,
49
// plumb it through as-is.
50
None => {
51
let mut module_encoder = wasm_encoder::Module::new();
52
for section in module.raw_sections() {
53
module_encoder.section(section);
54
}
55
encoder.section(&wasm_encoder::ModuleSection(&module_encoder));
56
}
57
}
58
}
59
RawSection::Raw(s) => {
60
reencoder.raw_section(&mut encoder, s);
61
}
62
}
63
}
64
65
encoder.finish()
66
}
67
}
68
69
struct Reencoder<'a> {
70
/// Number of defined functions encountered so far.
71
funcs: u32,
72
/// Index of the start function that's being removed, used to renumber all
73
/// other functions.
74
removed_func: Option<u32>,
75
/// Wizer configuration.
76
wizer: &'a Wizer,
77
}
78
79
impl Reencoder<'_> {
80
fn raw_section(
81
&mut self,
82
encoder: &mut wasm_encoder::Component,
83
section: &wasm_encoder::RawSection,
84
) {
85
match section.id {
86
// These can't define component functions so the sections are
87
// plumbed as-is.
88
id if id == wasm_encoder::ComponentSectionId::CoreCustom as u8
89
|| id == wasm_encoder::ComponentSectionId::CoreInstance as u8
90
|| id == wasm_encoder::ComponentSectionId::CoreType as u8
91
|| id == wasm_encoder::ComponentSectionId::Component as u8
92
|| id == wasm_encoder::ComponentSectionId::Type as u8 =>
93
{
94
encoder.section(section);
95
}
96
97
id if id == wasm_encoder::ComponentSectionId::CoreModule as u8 => {
98
panic!("should happen in caller");
99
}
100
id if id == wasm_encoder::ComponentSectionId::Start as u8 => {
101
// Component start sections aren't supported yet anyway
102
todo!()
103
}
104
105
// These sections all might affect or refer to component function
106
// indices so they're reencoded here, optionally updating function
107
// indices in case the index is higher than the one that we're
108
// removing.
109
id if id == wasm_encoder::ComponentSectionId::Instance as u8 => {
110
self.rewrite(
111
encoder,
112
section.data,
113
Self::parse_component_instance_section,
114
);
115
}
116
id if id == wasm_encoder::ComponentSectionId::Alias as u8 => {
117
self.rewrite(encoder, section.data, Self::parse_component_alias_section);
118
}
119
id if id == wasm_encoder::ComponentSectionId::CanonicalFunction as u8 => {
120
self.rewrite(
121
encoder,
122
section.data,
123
Self::parse_component_canonical_section,
124
);
125
}
126
id if id == wasm_encoder::ComponentSectionId::Import as u8 => {
127
self.rewrite(encoder, section.data, Self::parse_component_import_section);
128
}
129
id if id == wasm_encoder::ComponentSectionId::Export as u8 => {
130
self.rewrite(encoder, section.data, Self::parse_component_export_section);
131
}
132
other => panic!("unexpected component section id: {other}"),
133
}
134
}
135
136
fn rewrite<'a, T, S>(
137
&mut self,
138
encoder: &mut wasm_encoder::Component,
139
data: &'a [u8],
140
f: fn(&mut Self, dst: &mut S, wasmparser::SectionLimited<'a, T>) -> Result<(), Error>,
141
) where
142
T: wasmparser::FromReader<'a>,
143
S: Default + wasm_encoder::ComponentSection,
144
{
145
let mut section = S::default();
146
f(
147
self,
148
&mut section,
149
wasmparser::SectionLimited::new(wasmparser::BinaryReader::new(data, 0)).unwrap(),
150
)
151
.unwrap();
152
encoder.section(&section);
153
}
154
}
155
156
impl Reencode for Reencoder<'_> {
157
type Error = std::convert::Infallible;
158
}
159
type Error = wasm_encoder::reencode::Error<std::convert::Infallible>;
160
161
impl ReencodeComponent for Reencoder<'_> {
162
fn component_func_index(&mut self, original_index: u32) -> u32 {
163
match self.removed_func {
164
None => original_index,
165
Some(removed) => {
166
if original_index < removed {
167
original_index
168
} else if original_index == removed {
169
panic!("referenced removed function")
170
} else {
171
original_index - 1
172
}
173
}
174
}
175
}
176
177
fn parse_component_alias_section(
178
&mut self,
179
aliases: &mut wasm_encoder::ComponentAliasSection,
180
section: wasmparser::ComponentAliasSectionReader<'_>,
181
) -> Result<(), Error> {
182
for alias in section.clone() {
183
let alias = alias?;
184
if let wasmparser::ComponentAlias::InstanceExport {
185
kind: wasmparser::ComponentExternalKind::Func,
186
..
187
} = alias
188
{
189
self.funcs += 1;
190
}
191
}
192
193
wasm_encoder::reencode::component_utils::parse_component_alias_section(
194
self, aliases, section,
195
)
196
}
197
198
fn parse_component_canonical_section(
199
&mut self,
200
canonicals: &mut wasm_encoder::CanonicalFunctionSection,
201
section: wasmparser::ComponentCanonicalSectionReader<'_>,
202
) -> Result<(), Error> {
203
for canonical in section.clone() {
204
let canonical = canonical?;
205
if let wasmparser::CanonicalFunction::Lift { .. } = canonical {
206
self.funcs += 1;
207
}
208
}
209
210
wasm_encoder::reencode::component_utils::parse_component_canonical_section(
211
self, canonicals, section,
212
)
213
}
214
215
fn parse_component_import_section(
216
&mut self,
217
imports: &mut wasm_encoder::ComponentImportSection,
218
section: wasmparser::ComponentImportSectionReader<'_>,
219
) -> Result<(), Error> {
220
for import in section.clone() {
221
let import = import?;
222
if let wasmparser::ComponentExternalKind::Func = import.ty.kind() {
223
self.funcs += 1;
224
}
225
}
226
227
wasm_encoder::reencode::component_utils::parse_component_import_section(
228
self, imports, section,
229
)
230
}
231
232
fn parse_component_export_section(
233
&mut self,
234
exports: &mut wasm_encoder::ComponentExportSection,
235
section: wasmparser::ComponentExportSectionReader<'_>,
236
) -> Result<(), Error> {
237
for export in section {
238
let export = export?;
239
if !self.wizer.get_keep_init_func() && export.name.0 == self.wizer.get_init_func() {
240
self.removed_func = Some(self.funcs);
241
} else {
242
if export.kind == wasmparser::ComponentExternalKind::Func {
243
self.funcs += 1;
244
}
245
self.parse_component_export(exports, export)?;
246
}
247
}
248
Ok(())
249
}
250
}
251
252