Skip to content

Discussion of alternative: byte-granularity deterministic cap #13

Description

@keithw

First off, apologies that I didn't see PR #12 until it was mentioned in today's meeting. From the April 23rd discussion, I had been expecting an issue thread on this and just didn't see it -- I'm sorry to keep applying stop energy to this.

My understanding is that this proposal is aimed at letting Wasm run (in a spec-conforming way) in environments with less than 64 KiB of memory (or, more rarely, less than some other integral number of 64-KiB pages). For this use case, my own opinion is that a deterministic "cap" on loads/stores would be simpler and less invasive, end-to-end, vs. plumbing custom page sizes through the tools and consumers. The "cap" would be a static declaration on a memory that requires the consumer to trap on loads and stores that go over some index. Syntactically, it could be part of limits or memtype, or it could be a new orthogonal element in a new section.

To me this seems like it would be a lot less invasive for consumers to implement than the current proposal. Unlike the current proposal:

  • It wouldn't (necessarily) change the memory type matching rules.
  • It wouldn't change the semantics of memory.size or memory.grow.
  • It wouldn't change the tool conventions, meaning:
    • no addition of __builtin_wasm_page_size
    • no new relocation type
    • no new linker behavior (the barrier to entry for writing a new WebAssembly linker seems high already -- I think there is only one implementation of this?)
  • It wouldn't add more magic to ".o" files. (Right now it's pretty nice that you can compile something with clang -c and the output in WAT, decoded by standard tools, is comprehensible as a Wasm module. The discussion in What is the toolchain integration story? #3 suggests that newly generated .o files will implicate this proposal pervasively, and knowledge of the tool conventions and non-standard sections will become more necessary to understand what the .o file is trying to do.)

In exchange for giving up all this, the alternative would

  • change the execution rules for memory loads and stores, requiring a trap if they are over the cap

From this point of view, the latter is a much shorter list. :-) I think this alternative would satisfy the "small-memory" use cases that I'm aware of, and I hope it's clear why it feels less invasive and easier for consumers and tools to deal with.

What I expect is that consumers in these small-memory embedded environments would refuse to instantiate a module unless it declares a sufficiently constraining set of "caps" on its memories and memory imports. Other consumers would probably just ignore the cap until an actual load/store is executed against a capped memory.

Downsides:

  • Custom page sizes is a lot more general and can handle a broader range of use cases. E.g. the "cap" alternative wouldn't help with the other use case given in the overview ("if an audio effects library operates upon blocks of 512 samples at a time, with 16-bit samples, it can use a 1 KiB page size to avoid fragmentation and over-allocation"). Custom page sizes basically subsumes the "cap" alternative.

Response: The view could be that the over-allocation is tolerable everywhere except small-memory environments, which are well-handled by the "cap." Or maybe that the audio effects library should be using 512-byte GC char arrays instead of 512-byte custom pages in a linear memory. But if we want to tackle these other scenarios with full generality, then yeah, custom page sizes are probably the way to go.

Two other downsides are given in the #12 overview:

  • "It fails to reuse existing Wasm concepts, like memory being composed of pages, increasing the effort required to spec the feature and imposing additional complexity burden on implementations."

Response: Memory would still be composed of pages, and they'd still be 64 KiB. The effort required to spec the feature, and the additional burden on implementations, seems vastly smaller given my two bulleted lists above. It would, however, add a new execution-time concept (the byte-granularity "cap") that doesn't exist today.

  • "Simultaneously, it provides less flexibility and generality than this proposal: Wasm cannot, for example, rely on memory.size to determine the "real" maximum addressable memory address."

Response: This is true. However, even today Wasm has no mechanism at execution-time to determine the min or max of a limits. Like the "cap", these numbers are static and don't change at runtime. If this is really desired, it seems doable to specify a new memory.limits const instruction that takes an index immediate, and probably a field immediate (min/max/cap/shared/etc.), and pushes the corresponding static value.

=====

Bottom line: for the particular goal of supporting small-memory environments, the "cap" feels a lot less invasive and challenging to implement than going to custom page sizes. I'm nervous about putting even more weight on the tools and tool-conventions, especially when lld seems to be the only implementation of these, it's not part of the Wasm spec, and the comprehensibility/accessibility of ".o" files is a nice thing to have. However, if there is a desire for the full flexibility and generality of custom page sizes for their own purposes (independent of the particular use-case of small-memory environments), then that's clearly the way to go.

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