Skip to content

Commit

Permalink
initial setup and overview
Browse files Browse the repository at this point in the history
  • Loading branch information
zapashcanon committed Feb 18, 2024
1 parent 0ba84fb commit b7328e6
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 13 deletions.
18 changes: 7 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
[![CI for specs](https://github.com/WebAssembly/gc/actions/workflows/ci-spec.yml/badge.svg)](https://github.com/WebAssembly/gc/actions/workflows/ci-spec.yml)
[![CI for interpreter & tests](https://github.com/WebAssembly/gc/actions/workflows/ci-interpreter.yml/badge.svg)](https://github.com/WebAssembly/gc/actions/workflows/ci-interpreter.yml)
[![CI for specs](https://github.com/WebAssembly/frozen-values/actions/workflows/ci-spec.yml/badge.svg)](https://github.com/WebAssembly/frozen-values/actions/workflows/ci-spec.yml)
[![CI for interpreter & tests](https://github.com/WebAssembly/frozen-values/actions/workflows/ci-interpreter.yml/badge.svg)](https://github.com/WebAssembly/frozen-values/actions/workflows/ci-interpreter.yml)

# GC Proposal for WebAssembly
# Frozen Values Proposal for WebAssembly

This repository is a clone of [github.com/WebAssembly/spec/](https://github.com/WebAssembly/spec/).
It is meant for discussion, prototype specification and implementation of a proposal to add garbage collection (GC) support to WebAssembly.
It is meant for discussion, prototype specification and implementation of a proposal to add frozen values support to WebAssembly.

* See the [overview](proposals/gc/Overview.md) for a high-level summary and rationale of the proposal. *Note:* the concrete details here are out of date.
* See the [overview](proposals/frozen-values/Overview.md) for a high-level summary and rationale of the proposal. *Note:* the concrete details here are out of date.

* See the [MVP](proposals/gc/MVP.md) for an up-to-date overview of the concrete language extensions that are proposed for the first stage of GC support in Wasm.
* See the [modified spec](https://webassembly.github.io/frozen-values/core) for the completed spec for the first-stage proposal described in MVP.md.

* See the [Post-MVP](proposals/gc/Post-MVP.md) for possible future extensions in later stages.

* See the [modified spec](https://webassembly.github.io/gc/core) for the completed spec for the first-stage proposal described in MVP.md.

This repository is based on the [function references proposal](proposals/function-references/Overview.md) as a baseline and includes all respective changes.
This repository is based on the [GC proposal](proposals/gc/Overview.md) as a baseline and includes all respective changes.

Original `README` from upstream repository follows...

Expand Down
4 changes: 2 additions & 2 deletions document/core/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@
logo = 'static/webassembly.png'

# The name of the GitHub repository this resides in
repo = 'gc'
repo = 'frozen-values'

# The name of the proposal it represents, if any
proposal = 'tail calls + function references + gc'
proposal = 'tail calls + function references + gc + frozen-values'

# The draft version string (clear out for release cuts)
draft = ' (Draft ' + date.today().strftime("%Y-%m-%d") + ')'
Expand Down
163 changes: 163 additions & 0 deletions proposals/frozen-values/Overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Frozen-value Proposal

## Summary

This proposal allows to build immutable values of a recursive type.


## Motivation

### Building recursive values

Let's say you have a recursive type `$t`, currently you can build a value of type `$t` like this:

```wat
(module
(rec
(type $t (struct (field $f (mut (ref null $t))))))
(func $loop (result (ref $t))
(local $l (ref $t))
(local.set $l (struct.new $t (ref.null $t)))
(struct.set $t $f (local.get $l) (local.get $l))
(local.get $l)
)
)
```

### Building immutable recursive values ?

Now, let us define a type `$t'` which is the same as `$t` but with an immutable field `$f`:

```wat
(module
(rec
(type $t (struct (field $f (mut (ref null $t))))))
(rec
(type $t' (struct (field $f (ref $t')))))
(func $loop (result (ref $t)) ... )
)
```

Currently, there's no way to build a value of type `$t'`.

### Globals

Similarly, a global needs to be nullable in some cases:

```wat
(module
(rec (type $t (freeze $t) (struct (field $f (ref $t))))))
(global $g (mut (ref null $t)) (ref.null $t))
(func $f (result (ref $t))
(ref.as_non_null (global.get $g))
)
(func $loop (result (ref $t)) ...)
(func $st
(global.set $g (call $loop))
(drop (call $f))
)
(start $st))
```

### The point ?

The same as immutable values in general:
- cleaner API / preserve code invariants ;
- avoid read barriers ;
- being more explicit about the use.

Could also avoid null checks and allow creating immutable arrays.

### Who might be interested ?

It would be useful in the two existing OCaml compiler [Wasocaml](https://github.com/OCamlPro/wasocaml) and [wasm_of_ocaml](https://github.com/ocaml-wasm/wasm_of_ocaml). [Hoot](https://gitlab.com/spritely/guile-hoot/) would be happy to experiment with the proposal.

## Overview

### Freezing

Our proposal allows to build immutable recursive values in the following way:

```wat
(module
(rec
(type $t freezable (struct (field $f (mut (ref null $t))))))
(rec
(type $t_freeze (freeze $t) (struct (field $f (ref $t_freeze)))))
(func $loop_tmp (result (ref $t)) ... )
(func $loop (result (ref $t_freeze))
(ref.freeze $t_freeze $t (call $loop_tmp))
)
)
```

### The idea

The *freezability* check can be similar to the sub-typing rules:
- there should be the same (or less ?) fields ;
- can remove `mut` annotations ;
- can remove `null` annotations ;
- fields should be (frozen versions of) subtypes (maybe also upcasts ?).

After the freeze, the freezable values should not be accessed:
- dynamic checks on freezable types accesses ;
- the freeze operation is expected to walk the value and flip a *frozen* bit ;
- trap if fields are still null at freeze time.

Heuristic: unfrozen values are seldom accessed, frozen ones can be accessed a lot

Freezing is not 'fixed number of hardware instruction', but the combined time of building then freezing is kind of an amortized version of it.


### Phases

In order to be able to freeze global we introduce phases:

```wat
(module
(global $g (mut (ref null $t)) freezable (ref.null $t))
(global $g_frozen (ref $t) (freeze $g) (phase 1))
(func $f (phase 1) (result (ref $t))
(global.get $g_frozen)
)
(func $loop (phase 0) (result (ref $t)) ...)
(func $st_0 (phase 0) (global.set $g (call $loop)))
(func $st_1 (phase 1) (drop (call $f)))
(start $st_0 (phase 0))
(start $st_1 (phase 1))
)
```

The idea:

- invariant: cannot call a function of phase $n$ before the end of the start of phase $n-1$ ;
- a function can only refer to values of phase less or equal than its own phase (ref and calls) ;
- each phase can have one start ;
- starts are run in phase order ;
- global are frozen at the end of the previous phase ;
- failure to freeze is a panic ;
- accessing an unfrozen global from a previous phase is a panic ;
- cannot export freezable global.

Also:

- if multiple start functions seems distasteful, we could have a `call_and_freeze` instruction moving to the next phase ;
- default phase is 0 ;
- global freeze can change the type of its contents ;
- encoding: not really thought, could be compact.

## Links

- [design issue](https://github.com/WebAssembly/design/issues/1493)
- [CG notes 2023-12-05](https://github.com/WebAssembly/meetings/blob/main/main/2023/CG-12-05.md#frozen-proposal)

0 comments on commit b7328e6

Please sign in to comment.