@@ -170,79 +170,105 @@ pub enum ChangeDiscriminant {
170170
171171impl BumpAllocSafe for ChangeDiscriminant {}
172172
173+// Allocation utilities to ensure that we only allocation sequences of `u32`s
174+// into the change list's bump arena without any padding. This helps maintain
175+// the invariants required for `Bump::each_allocated_chunk`'s safety.
176+impl ChangeList {
177+ // Allocate an opcode with zero immediates.
178+ fn op0(&self, discriminant: ChangeDiscriminant) {
179+ self.bump.alloc(discriminant as u32);
180+ }
181+
182+ // Note: no 1-immediate opcodes at this time.
183+
184+ // Allocate an opcode with two immediates.
185+ fn op2(&self, discriminant: ChangeDiscriminant, a: u32, b: u32) {
186+ self.bump.alloc([discriminant as u32, a, b]);
187+ }
188+
189+ // Note: no 3-immediates opcodes at this time.
190+
191+ // Allocate an opcode with four immediates.
192+ fn op4(&self, discriminant: ChangeDiscriminant, a: u32, b: u32, c: u32, d: u32) {
193+ self.bump.alloc([discriminant as u32, a, b, c, d]);
194+ }
195+}
196+
173197impl ChangeList {
174198 pub(crate) fn emit_set_text(&self, text: &str) {
175199 debug!("emit_set_text({:?})", text);
176− self.bump
177− .alloc((ChangeDiscriminant::SetText, text.as_ptr(), text.len()));
200+ self.op2(
201+ ChangeDiscriminant::SetText,
202+ text.as_ptr() as u32,
203+ text.len() as u32,
204+ );
178205 }
179206
180207 pub(crate) fn emit_remove_self_and_next_siblings(&self) {
181208 debug!("emit_remove_self_and_next_siblings()");
182− self.bump
183− .alloc(ChangeDiscriminant::RemoveSelfAndNextSiblings);
209+ self.op0(ChangeDiscriminant::RemoveSelfAndNextSiblings);
184210 }
185211
186212 pub(crate) fn emit_replace_with(&self) {
187213 debug!("emit_replace_with()");
188− self.bump.alloc(ChangeDiscriminant::ReplaceWith);
214+ self.op0(ChangeDiscriminant::ReplaceWith);
189215 }
190216
191217 pub(crate) fn emit_set_attribute(&self, name: &str, value: &str) {
192218 debug!("emit_set_attribute({:?}, {:?})", name, value);
193− self.bump.alloc((
219+ self.op4(
194220 ChangeDiscriminant::SetAttribute,
195− name.as_ptr(),
196− name.len(),
197− value.as_ptr(),
198− value.len(),
199− ));
221+ name.as_ptr() as u32,
222+ name.len() as u32,
223+ value.as_ptr() as u32,
224+ value.len() as u32,
225+ );
200226 }
201227
202228 pub(crate) fn emit_remove_attribute(&self, name: &str) {
203229 debug!("emit_remove_attribute({:?})", name);
204− self.bump.alloc((
230+ self.op2(
205231 ChangeDiscriminant::RemoveAttribute,
206− name.as_ptr(),
207− name.len(),
208− ));
232+ name.as_ptr() as u32,
233+ name.len() as u32,
234+ );
209235 }
210236
211237 pub(crate) fn emit_push_first_child(&self) {
212238 debug!("emit_push_first_child()");
213− self.bump.alloc(ChangeDiscriminant::PushFirstChild);
239+ self.op0(ChangeDiscriminant::PushFirstChild);
214240 }
215241
216242 pub(crate) fn emit_pop_push_next_sibling(&self) {
217243 debug!("emit_pop_push_next_sibling()");
218− self.bump.alloc(ChangeDiscriminant::PopPushNextSibling);
244+ self.op0(ChangeDiscriminant::PopPushNextSibling);
219245 }
220246
221247 pub(crate) fn emit_pop(&self) {
222248 debug!("emit_pop()");
223− self.bump.alloc(ChangeDiscriminant::Pop);
249+ self.op0(ChangeDiscriminant::Pop);
224250 }
225251
226252 pub(crate) fn emit_append_child(&self) {
227253 debug!("emit_append_child()");
228− self.bump.alloc(ChangeDiscriminant::AppendChild);
254+ self.op0(ChangeDiscriminant::AppendChild);
229255 }
230256
231257 pub(crate) fn emit_create_text_node(&self, text: &str) {
232258 debug!("emit_create_text_node({:?})", text);
233− self.bump.alloc((
259+ self.op2(
234260 ChangeDiscriminant::CreateTextNode,
235− text.as_ptr(),
236− text.len(),
237− ));
261+ text.as_ptr() as u32,
262+ text.len() as u32,
263+ );
238264 }
239265
240266 pub(crate) fn emit_create_element(&self, tag_name: &str) {
241267 debug!("emit_create_element({:?})", tag_name);
242− self.bump.alloc((
268+ self.op2(
243269 ChangeDiscriminant::CreateElement,
244− tag_name.as_ptr(),
245− tag_name.len(),
246− ));
270+ tag_name.as_ptr() as u32,
271+ tag_name.len() as u32,
272+ );
247273 }
248274}