Skip to content

Extending descriptor struct types to have host fields #40

@eqrion

Description

@eqrion

The explainer describes a method for customizing the JS behavior of a descriptor struct using a 'designated value' where when the first field is an immutable externref, the JS-API would dynamically inspect it to see if it's a WebAssembly.DescriptorOptions value and if so it would customize the behavior of the descriptor.

This works, but it has some downsides:

  1. Runtimes do not know statically if the first field will be the DO or not. This requires a dynamic check during allocation and separate behavior for both cases.
  2. Codegen also cannot assume that this field has any special layout or meaning and so we're stuck with duplicating the contents of the DO into the rest of the rtt/map/shape. The DO is also effectively dead after allocation but we are forced to keep it around.
  3. Misuse of this API results in a failures far away from the problem that caused it. If a user accidentally fails to use a DO, no error can happen when creating the descriptor, and instead the object will just act wrong later in weird ways. It'd be really nice if they could get an immediate error in this case.

I don't think these issues are necessarily hard blocks, but enough of a smell that I'd like to propose a tweak that would solve these problems.

What if we tweaked the type definition of descriptor struct types so that it could specify a prefix of the fields as being for the 'host'?

e.g.

(type $foo.rtt (describes $foo (struct (host-fields N) (field ...))))

or with some syntax sugar:

(type $foo.rtt (describes $foo (struct (host field ...) (field ...))))

Host fields act the same as regular fields, and can only exist on descriptors. The key difference is that when you allocate a descriptor, the N host fields are passed to a host hook which can perform validation of the host fields and possibly fail.

This would let hosts, like the JS-API, give special meaning to some of the fields on a descriptor struct without worrying about accidentally capturing normal fields. So we could define the convention that the first host field is always the prototype object, and later add additional host fields. We would not necessarily need the DO object anymore.

The host hook would let runtimes eagerly validate the fields and fail if e.g. the prototype is not an object. This (plus the static addition to the type) would enable us to put the host fields in different parts of the rtt/map/shape. Doing a struct.get of a the first host field would know that the prototype is always stored in a different slot than normal.

I think the best way to rationalize this addition is that descriptor structs are exactly the same as engine rtt/map/shape objects, which already have fields for things like prototypes. The very small addition we need to core wasm is just a way to statically describe a struct field as being one of the fields.

cc @lukewagner @tlively @jakobkummerow @rossberg

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