Skip to content

Stabilize memory-releated std::arch::wasm32 intrinsics #56292

Closed
@alexcrichton

Description

@alexcrichton

This is a tracking issue where I'm going to propose that we stabilize two functions in the standard library:

These intrinsics are currently existing as memory::size and memory::grow, but I'm going to propose here that we don't do that and flatten them in the wasm32 module. As a reference, their signatures are:

fn memory_size(memory_index: u32) -> usize;
fn memory_grow(memory_index: u32, delta_pages: usize) -> isize;

Semantics

These two intrinsics represent instructions stabilized in the WebAssembly specification.

The memory.size instruction will return the current size, in WebAssembly pages, of the specified memory index. Currently only index 0 is allowed, the index is required to be a constant value, and the return value is an usize value. Note that usize is used instead of the spec's i32 for two reasons: this is more forward compatible with a possible wasm64 architecture and the return value is always an unsigned number.

The memory.grow instruction will grow the memory index specified by the given number of pages. The old size of memory, in pages, is returned. If the grow operation fails, then -1 is returned. LIke memory_size, the memory index is currently required to be 0 and must be a constant value. The delta may be a runtime value, however.

The binary encoding of these two instructions each have a reserved zero byte which is intended to be used to specify a different nonzero memory index in the future. As a recap, each WebAssembly module may have multiple "memory" instances, each assigned a unique index starting from zero. In the WebAssembly MVP, however, only at most one memory can be assigned with each wasm module, always located at index 0. (the memory may be omitted as well)

While the memory argument is currently required to be zero, it's expected that future versions of WebAssembly will no longer have this requirement and any u32 value can be specified. It's also worth noting that the zero byte in the encoding of memory.size and memory.grow may not only be exclusively used for new indices. Current proposals to WebAssembly have repurposed required zero bytes as flags fields in addition to specified more than nonzero indices. While I'm not aware of any proposal to do so, it may be possible that a future feature to WebAssembly will have more than just a memory index argument to these instructions.

Stabilization in Rust

Stabilization of these intrinsics would be a significant step for Rust on multiple axes:

  • Primarily these would be the first non-x86 intrinsics stabilized. This means it's the first architecture to have a stable std::arch module which isn't x86/x86_64.
  • Unlike x86 intrinsics, there is no prior art for how these intrinsics should be stabilized. Unlike x86/x86_64 the "vendor" (the WebAssembly specification) isn't giving us a document of functions with signatures.

Stabilization here will be paving a path forward for future stabilization of WebAssembly intrinsics, so it's good to consider conventions! It's unclear if the WebAssembly specification will, if ever, provide a document like Intel does for intrinsics with function names and function signatures for other languages to provide.

We've had some discussion on the naming of wasm intrinsics. We'd like to ensure that we match Clang (like we do for x86/x86_64), but Clang doesn't currently (AFAIK) have a naming convention beyond the __builtin_* internal defines it has today.

What I'm proposing here is basically a convention of:

  • We provide intrinsics for instructions not natively expressable in Rust. For example we don't give an i32.add intrinsic function as it's just a + b.
  • Intrinsic signatures match the effective signature of the instruction, to the best it can. Above the memory.grow and memory.size intrinsics are fairly simple.
  • Intrinsic names match the name of the wasm intstructions, with non-rust-identifier characters mapped to an underscore.

The thinking behind these set of conventions it that it should be very easy to figure out what each intrinsic does, just like it is for Intel. The Rust documentation would always link to the WebAssembly specification for stabilized intrinsics.

Additionally we won't have any sort of automatic verification of WebAssembly intrinsics just yet like we do for x86 intrinsics in the stdsimd repository. There's so few WebAssembly intrinsics it's thought that we can simply manually verify each intrinsic.

TODO items before stabilization is finalized

  • FCP (this issue)
  • Rename the intrinsics (if that's decided on)
  • Fix the "This is supported on MIPS only" message in documentation
  • Update documentation to link to WebAssembly specification
  • maybe flag functions as safe
  • Update documentation on behavior with nonzero indexes
  • Document the page size on these intrinsics.

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.disposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.finished-final-comment-periodThe final comment period is finished for this PR / Issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions