Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Introducing struct.get_indirect and struct.set_indirect opcode #397

Open
@xujuntwt95329

Description

@xujuntwt95329

Purpose of this issue

Hi, in GC-05-16 meeting we have introduced our idea of adding struct.get_indirect and struct.set_indirect opcode to support language semantics like TypeScript's interface in WasmGC, we had some discussion during the meeting and PR for the meeting notes, and this issue is to continue the discussion.

Background

WasmGC opened the door for supporting high level managed language more efficiently than compiling the whole language runtime to WebAssembly, we are interested in exploring a solution to compile TypeScript to WasmGC. Our strategy is:

  • For those with explicit type information (like primitives, classes), we apply static compilation, and use wasm value types (i32, i64 ...) and WasmGC types to represent them
  • For those with any type, they are represented as an externref, and we introduced a libdyntype to support dynamic accessing and type checking on them, operation on these objects will be converted to API call to libdyntype

This provide the flexibility to the developer:

  • If performance matters, write more static type information to get a statically compiled module
  • If dynamic type is needed, any is also supported but they will pay for the performance influence

Problem

Most types work well based on the strategy above, but we encountered problem with interface. interface does not describe the layout of a concrete type, its just an un-ordered collection of field names and types. This means the actual object type holding by the interface is not known at compile time, so we have two solutions:

  1. treat interface as any (interface is heavily used in TypeScript, if we treat is as any, the performance impact may be huge)
  2. record some meta data of every static object type in wasm module, and calculate the field index according to the meta data and field name (preferred)

The option 2 is preferred because we can still represent objects using WasmGC types, and we can do further optimization to avoid searching the meta info in some scenarios (e.g. check a pre-assigned type-id). Option 2 needs to calculate the field index during runtime, but currently the struct.get/set opcode require the field index to be immediate.

Proposed Opcode

To accept field index calculated during runtime, we proposed the indirect version of struct access opcode:

name immediates stack signature
struct.get_indirect<_sx>? <ti> [anyref, i32] -> [ti]
struct.set_indirect<_sx>? <ti> [anyref, i32, ti] -> []

This require some runtime type checking:

  • Trap if ref is nul
  • Trap if ref is not a struct
  • Trap if index is invalid in the struct
  • Trap if type of the accessing field is not ti

Then we can use this opcode to access the field of interface:
image
image

Influence to runtime implementation

  1. performance:
    The proposed opcode will be slow due to several runtime checking, but this will not influence the performance of any other opcodes

  2. memory usage:
    To apply runtime checking, it is required that every GC object have a reference to its defined type. Since we already have RTT now, the only thing we need to add is a type index in RTT object, so the impact on memory should be low

Is there any workaround without the proposed opcode?

  1. Treat interface as any as mentioned option 1 above

    • The performance will be slow
  2. Compile whole language runtime into WebAssembly, and execute the source code in that "vm inside vm"

    • Can't use WasmGC's capabilities, need to compile interpreter, memory management logic all into wasm opcode
    • Large wasm module size

Metadata

Metadata

Assignees

No one assigned

    Labels

    Post-MVPIdeas for Post-MVP extensions

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions