Skip to content

Acceptable costs for the removal of unsafe code? #648

Open
@dilr

Description

@dilr

I would like to remove instances of unsafe in the code-base that aren't essential for performance or functionality. As per the contributor guidelines, this isn't a bug fix, so I'd like to ask what sort of changes would be acceptable in a PR before I do too much work. I've already done a bit just to see if it is even worthwhile, so I have some idea of what I might ask for:

  1. May I turn transitive dependencies into direct dependencies? See example 1 if this is unclear
  2. May I pull in small direct dependencies that Uiua does not currently transitively depend on? See example 3 for why.
  3. How much may I change to the structure of the code? I ask as I realize this is mostly a one person project, and changes to the structure of the code imposes a burden on you as a reviewer. See example 2 for the sort of thing I am thinking of.
  4. How important is debug mode performance? I fully intend to keep or improve release mode performance by checking that the llvm-ir or assembly does the same thing as the old unsafe code. (for structural changes at least) However, the debug mode code won't always work the same. See example 2 again for details. I can benchmark on the tests to make sure performance doesn't completely tank in debug mode, but I don't think all functionality and usage patterns are covered by the tests.

Examples of changes I've tried or want to try:

  1. bytemuck is directly or transitively used by 'cosmic-text', 'skrifra', 'arboard', and 'viuer'. All of these are optional dependencies either for features or for display to the terminal or graphical window. If I pull bytemuck in as a direct dependency, I can safely remove all but one instance of mem::transmute. This requires no structural changes to the code.
  2. I can avoid the need to do a pointer cast from a value::Value to a value::Repr which is currently done in Value::shape, Value::meta_mut, and several similar functions. I can do this by moving the logic for the management of array::Array.meta into a wrapper object ArrayMetaHolder (to monomorphize the meta pointer management code), and then using val_as_array!(self, |arr| &mut arr.meta).meta_mut() and friends to get the shape and metadata from the array inside the value. I've checked the llvm-ir emitted by the rust compiler in release mode for several of the functions which inline Value::meta_mut and friends. I can confirm that in release mode the compiler realizes that checking the discriminant of Value is unnecessary and unconditionally offsets the Value pointer to the location of the shape or meta fields, which I assume was the point of casting Value to Repr in the first place. However, in debug mode what is generated is a switch on the discriminant to a bunch of identical blocks of code which all set the pointer value to the same thing. After the switch statement ArrayMetaHolder::meta_mut and friends are called if needed.
  3. The last transmute bytemuck cannot eliminate is in Array::convert. It checks if we are converting to an array of the same type via TypeId, and transmutes Array<T> to Array<U> if T == U. This is essentially a specialization of the convert function when T == U. If I could pull in the castaway crate, I could replace this specialization with safe code. (To be clear, I haven't tried this yet) It also means that further specializations of generic functions for concrete types could be added to the codebase without needing to worry that much if the specialization is sound. See the discussion in the rust issue tracker about the 'min-specialization' and 'specialization' unstable features for why this sort of thing is tricky to do soundly in general. The castaway crate implements a known safe subset of specializations.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions