@@ -347,8 +347,14 @@ where
347347 let mut count = self . change_buffer . read :: < u64 > ( & mut index) ? as u32 ;
348348
349349 let mut cached_slot: u32 = u32:: MAX ;
350- // We keep a bunch of cached internal pointers. They are safe to use as long as we don't
351- // modify their parent vector and keep a unique borrow to `self` overall.
350+ // Cached elements for the current span.
351+ //
352+ // When applying span operations, we cache the last span index (cached_slot) and the
353+ // corresponding elements in `deffered_meta`, `deferred_metrics`, and `span`. We use direct
354+ // pointers to save intermediate dereferences.
355+ //
356+ // They are safe to use as long as we don't modify their parent vector and keep a unique
357+ // borrow to `self` overall.
352358 //
353359 // Using mutable references instead would be better, but is not possible (or very hard)
354360 // given we iterate and nest calls to different submethods taking a `&mut self`.
@@ -368,14 +374,19 @@ where
368374 self . interpret_operation ( & mut index, & op) ?;
369375 }
370376 _ => {
371- self . interpret_operation_cached (
372- & mut index,
373- & op,
374- & mut cached_slot,
375- & mut cached_span_ptr,
376- & mut cached_deferred_meta,
377- & mut cached_deferred_metrics,
378- ) ?;
377+ // SAFETY: at the first iteration of the loop, all pointers are null and
378+ // `*cached_slot` is `u32::MAX`. In subsequent iterations,
379+ // `interpret_operation_cached` maintains its own safety invariant.
380+ unsafe {
381+ self . interpret_operation_cached (
382+ & mut index,
383+ & op,
384+ & mut cached_slot,
385+ & mut cached_span_ptr,
386+ & mut cached_deferred_meta,
387+ & mut cached_deferred_metrics,
388+ ) ?;
389+ }
379390 }
380391 }
381392 count -= 1 ;
@@ -387,7 +398,15 @@ where
387398 Ok ( ( ) )
388399 }
389400
390- fn interpret_operation_cached (
401+ /// # Safety
402+ ///
403+ /// The pointer arguments provided to this function: `*cached_slot`, `*cached_span_ptr`,
404+ /// `*cached_deferred_meta` and `*cached_deferred_metrics` must either:
405+ ///
406+ /// - be all `null` if `*cached_slot` is `u32::MAX`
407+ /// - point to `self.spans[*cached_slot]`, `self.deferred_meta[*cached_slot]` and
408+ /// `self.deferred_metrics[*cached_slot]` respectively otherwise.
409+ unsafe fn interpret_operation_cached (
391410 & mut self ,
392411 index : & mut usize ,
393412 op : & BufferedOperation ,
@@ -418,13 +437,9 @@ where
418437 // modified during this function (no inserts/removes).
419438 let span = unsafe { & mut * span_ptr } ;
420439
421- // SAFETY:
422- //
423- // - `cached_deferred_xxx`: they point to writable memory (derived from self), and we don't
424- // modify, move nor drop the parent `deferred_xxx` vec, so the pointer should remain
425- // valid.
426- // - `xxx_unchecked`: we rely on the encoder side to write the correct arguments to an
427- // opcode.
440+ // SAFETY: `cached_deferred_xxx`: they point to writable memory, and we don't shrink, move
441+ // nor drop the parent `deferred_xxx` vec, so the pointers remain valid. We keep a mutable
442+ // borrow on `self`, which ensures ownership/uniqueness.
428443 match op. opcode {
429444 OpCode :: SetMetaAttr => {
430445 let key_id: u32 = self . get_num_arg ( index) ?;
@@ -439,25 +454,25 @@ where
439454 dm. insert ( key_id, val) ;
440455 }
441456 OpCode :: SetServiceName => {
442- span. service = unsafe { self . get_string_arg_unchecked ( index) } ;
457+ span. service = self . get_string_arg ( index) ? ;
443458 }
444459 OpCode :: SetResourceName => {
445- span. resource = unsafe { self . get_string_arg_unchecked ( index) } ;
460+ span. resource = self . get_string_arg ( index) ? ;
446461 }
447462 OpCode :: SetError => {
448- span. error = unsafe { self . get_num_arg_unchecked ( index) } ;
463+ span. error = self . get_num_arg ( index) ? ;
449464 }
450465 OpCode :: SetStart => {
451- span. start = unsafe { self . get_num_arg_unchecked ( index) } ;
466+ span. start = self . get_num_arg ( index) ? ;
452467 }
453468 OpCode :: SetDuration => {
454- span. duration = unsafe { self . get_num_arg_unchecked ( index) } ;
469+ span. duration = self . get_num_arg ( index) ? ;
455470 }
456471 OpCode :: SetType => {
457- span. r#type = unsafe { self . get_string_arg_unchecked ( index) } ;
472+ span. r#type = self . get_string_arg ( index) ? ;
458473 }
459474 OpCode :: SetName => {
460- span. name = unsafe { self . get_string_arg_unchecked ( index) } ;
475+ span. name = self . get_string_arg ( index) ? ;
461476 }
462477 OpCode :: SetTraceMetaAttr => {
463478 let name = self . get_string_arg ( index) ?;
@@ -514,31 +529,10 @@ where
514529 . ok_or ( ChangeBufferError :: StringNotFound ( num) )
515530 }
516531
517- /// # Safety
518- ///
519- /// Caller must ensure `*index + size_of::<T::Tex>() <= self.change_buffer.len`.
520- #[ inline( always) ]
521- unsafe fn get_string_arg_unchecked ( & self , index : & mut usize ) -> T :: Text {
522- let num: u32 = self . change_buffer . read_unchecked ( index) ;
523- self . string_table
524- . get_unchecked ( num as usize )
525- . clone ( )
526- . unwrap_unchecked ( )
527- }
528-
529532 fn get_num_arg < U : Copy + FromBytes > ( & self , index : & mut usize ) -> Result < U > {
530533 self . change_buffer . read ( index)
531534 }
532535
533- /// # Safety
534- ///
535- /// Caller must ensure `*index + size_of::<U>() <= self.change_buffer.len`.
536- #[ inline( always) ]
537- unsafe fn get_num_arg_unchecked < U : Copy + FromBytes > ( & self , index : & mut usize ) -> U {
538- // Safety: this function's pre-condition
539- unsafe { self . change_buffer . read_unchecked ( index) }
540- }
541-
542536 fn get_span_mut ( & mut self , slot : u32 ) -> Result < & mut Span < T > > {
543537 self . spans
544538 . get_mut ( slot as usize )
0 commit comments