Skip to content

Commit

Permalink
Merge pull request #29 from WebAssembly/core-split
Browse files Browse the repository at this point in the history
Split core definitions out into separate index spaces
  • Loading branch information
lukewagner authored May 27, 2022
2 parents 18399df + 49fb117 commit bcc2002
Show file tree
Hide file tree
Showing 8 changed files with 849 additions and 693 deletions.
343 changes: 190 additions & 153 deletions design/mvp/Binary.md

Large diffs are not rendered by default.

161 changes: 80 additions & 81 deletions design/mvp/CanonicalABI.md

Large diffs are not rendered by default.

901 changes: 511 additions & 390 deletions design/mvp/Explainer.md

Large diffs are not rendered by default.

25 changes: 12 additions & 13 deletions design/mvp/FutureFeatures.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,22 @@ serialization format, as this often incurs extra copying when the source or
destination language-runtime data structures don't precisely match the fixed
serialization format. A significant amount of work was spent designing a
language of [adapter functions] that provided fairly general programmatic
control over the process of serializing and deserializing interface-typed values.
control over the process of serializing and deserializing high-level values.
(The Interface Types Explainer currently contains a snapshot of this design.)
However, a significant amount of additional design work remained, including
(likely) changing the underlying semantic foundations from lazy evaluation to
algebraic effects.

In pursuit of a timely MVP and as part of the overall [scoping and layering proposal],
the goal of avoiding a fixed serialization format was dropped from the MVP, by
instead defining a [Canonical ABI](CanonicalABI.md) in the MVP. However, the
current design of [function definitions](Explainer.md#function-definitions)
anticipates a future extension whereby function bodies can contain not just the
fixed Canonical ABI-following `canon.lift` and `canon.lower` but,
alternatively, general adapter function code.
In pursuit of a timely MVP and as part of the overall [scoping and layering
proposal], the goal of avoiding a fixed serialization format was dropped from
the MVP by instead defining a [Canonical ABI](CanonicalABI.md) in the MVP.
However, the current design anticipates a future extension whereby lifting and
lowering functions can be generated not just from `canon lift` and `canon
lower`, but, alternatively, general-purpose serialization/deserialization code.

In this future state, `canon.lift` and `canon.lower` could be specified by
simple expansion into the adapter code, making these instructions effectively
macros. However, even in this future state, there is still concrete value in
In this future state, `canon lift` and `canon lower` could be specified by
simple expansion into the general-purpose code, making these instructions
effectively macros. However, even in this future state, there is still value in
having a fixedly-defined Canonical ABI as it allows more-aggressive
optimization of calls between components (which both use the Canonical ABI) and
between a component and the host (which often must use a fixed ABI for calling
Expand All @@ -53,8 +52,8 @@ Additionally, having two similar-but-different, partially-overlapping concepts
makes the whole proposal harder to explain. Thus, the MVP drops the concept of
"adapter modules", including only shared-nothing "components". However, if
concrete future use cases emerged for creating modules that partially used
interface types and partially shared linear memory, "adapter modules" could be
added as a future feature.
shared-nothing component values and partially shared linear memory, "adapter
modules" could be added as a future feature.


## Shared-everything Module Linking in Core WebAssembly
Expand Down
6 changes: 3 additions & 3 deletions design/mvp/Subtyping.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ But roughly speaking:

| Type | Subtyping |
| ------------------------- | --------- |
| `unit` | every interface type is a subtype of `unit` |
| `unit` | every value type is a subtype of `unit` |
| `bool` | |
| `s8`, `s16`, `s32`, `s64`, `u8`, `u16`, `u32`, `u64` | lossless coercions are allowed |
| `float32`, `float64` | `float32 <: float64` |
Expand All @@ -20,5 +20,5 @@ But roughly speaking:
| `union` | `T <: (union ... T ...)` |
| `func` | parameter names must match in order; contravariant parameter subtyping; superfluous parameters can be ignored in the subtype; `option` parameters can be ignored in the supertype; covariant result subtyping |

The remaining specialized interface types inherit their subtyping from their
fundamental interface types.
The remaining specialized value types inherit their subtyping from their
fundamental value types.
76 changes: 38 additions & 38 deletions design/mvp/canonical-abi/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,74 +19,74 @@ def trap_if(cond):
if cond:
raise Trap()

class InterfaceType: pass
class Unit(InterfaceType): pass
class Bool(InterfaceType): pass
class S8(InterfaceType): pass
class U8(InterfaceType): pass
class S16(InterfaceType): pass
class U16(InterfaceType): pass
class S32(InterfaceType): pass
class U32(InterfaceType): pass
class S64(InterfaceType): pass
class U64(InterfaceType): pass
class Float32(InterfaceType): pass
class Float64(InterfaceType): pass
class Char(InterfaceType): pass
class String(InterfaceType): pass
class ValType: pass
class Unit(ValType): pass
class Bool(ValType): pass
class S8(ValType): pass
class U8(ValType): pass
class S16(ValType): pass
class U16(ValType): pass
class S32(ValType): pass
class U32(ValType): pass
class S64(ValType): pass
class U64(ValType): pass
class Float32(ValType): pass
class Float64(ValType): pass
class Char(ValType): pass
class String(ValType): pass

@dataclass
class List(InterfaceType):
t: InterfaceType
class List(ValType):
t: ValType

@dataclass
class Field:
label: str
t: InterfaceType
t: ValType

@dataclass
class Record(InterfaceType):
class Record(ValType):
fields: [Field]

@dataclass
class Tuple(InterfaceType):
ts: [InterfaceType]
class Tuple(ValType):
ts: [ValType]

@dataclass
class Flags(InterfaceType):
class Flags(ValType):
labels: [str]

@dataclass
class Case:
label: str
t: InterfaceType
t: ValType
refines: str = None

@dataclass
class Variant(InterfaceType):
class Variant(ValType):
cases: [Case]

@dataclass
class Enum(InterfaceType):
class Enum(ValType):
labels: [str]

@dataclass
class Union(InterfaceType):
ts: [InterfaceType]
class Union(ValType):
ts: [ValType]

@dataclass
class Option(InterfaceType):
t: InterfaceType
class Option(ValType):
t: ValType

@dataclass
class Expected(InterfaceType):
ok: InterfaceType
error: InterfaceType
class Expected(ValType):
ok: ValType
error: ValType

@dataclass
class Func:
params: [InterfaceType]
result: InterfaceType
params: [ValType]
result: ValType

### Despecialization

Expand Down Expand Up @@ -603,9 +603,9 @@ def flatten(functype, context):
flat_results = flatten_type(functype.result)
if len(flat_results) > MAX_FLAT_RESULTS:
match context:
case 'canon.lift':
case 'lift':
flat_results = ['i32']
case 'canon.lower':
case 'lower':
flat_params += ['i32']
flat_results = []

Expand Down Expand Up @@ -869,7 +869,7 @@ def lower(opts, max_flat, vs, ts, out_param = None):
flat_vals += lower_flat(opts, vs[i], ts[i])
return flat_vals

### `canon.lift`
### `lift`

class Instance:
may_leave = True
Expand Down Expand Up @@ -898,7 +898,7 @@ def post_return():

return (result, post_return)

### `canon.lower`
### `lower`

def canon_lower(caller_opts, caller_instance, callee, functype, flat_args):
trap_if(not caller_instance.may_leave)
Expand Down
4 changes: 2 additions & 2 deletions design/mvp/canonical-abi/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,13 +312,13 @@ def test_flatten(t, params, results):

if len(results) > definitions.MAX_FLAT_RESULTS:
expect['results'] = ['i32']
got = flatten(t, 'canon.lift')
got = flatten(t, 'lift')
assert(got == expect)

if len(results) > definitions.MAX_FLAT_RESULTS:
expect['params'] += ['i32']
expect['results'] = []
got = flatten(t, 'canon.lower')
got = flatten(t, 'lower')
assert(got == expect)

test_flatten(Func([U8(),Float32(),Float64()],Unit()), ['i32','f32','f64'], [])
Expand Down
26 changes: 13 additions & 13 deletions design/mvp/examples/SharedEverythingDynamicLinking.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,11 @@ would look like:
(with "libc" (instance $libc))
(with "libzip" (instance $libzip))
))
(func (export "zip") (canon.lift
(func (param (list u8)) (result (list u8)))
(memory (memory $libc "memory")) (realloc (func $libc "realloc"))
(func $zip (param (list u8)) (result (list u8)) (canon lift
(func $main "zip")
(memory (memory $libc "memory")) (realloc (func $libc "realloc"))
))
(export "zip" (func $zip))
)
```
Here, `zipper` links its own private module code (`$Main`) with the shareable
Expand Down Expand Up @@ -236,11 +236,11 @@ component-aware `clang`, the resulting component would look like:
(with "libc" (instance $libc))
(with "libimg" (instance $libimg))
))
(func (export "transform") (canon.lift
(func (param (list u8)) (result (list u8)))
(memory (memory $libc "memory")) (realloc (func $libc "realloc"))
(func $transform (param (list u8)) (result (list u8)) (canon lift
(func $main "transform")
(memory (memory $libc "memory")) (realloc (func $libc "realloc"))
))
(export "transform" (func $transform))
)
```
Here, we see the general pattern emerging of the dependency DAG between
Expand Down Expand Up @@ -283,24 +283,24 @@ components. The resulting component could look like:
))
(instance $libc (instantiate (module $Libc)))
(func $zip (canon.lower
(memory (memory $libc "memory")) (realloc (func $libc "realloc"))
(func $zip (canon lower
(func $zipper "zip")
))
(func $transform (canon.lower
(memory (memory $libc "memory")) (realloc (func $libc "realloc"))
))
(func $transform (canon lower
(func $imgmgk "transform")
(memory (memory $libc "memory")) (realloc (func $libc "realloc"))
))
(instance $main (instantiate (module $Main)
(with "libc" (instance $libc))
(with "zipper" (instance (export "zip" (func $zipper "zip"))))
(with "imgmgk" (instance (export "transform" (func $imgmgk "transform"))))
))
(func (export "run") (canon.lift
(func (param string) (result string))
(memory (memory $libc "memory")) (realloc (func $libc "realloc"))
(func $run (param string) (result string) (canon lift
(func $main "run")
(memory (memory $libc "memory")) (realloc (func $libc "realloc"))
))
(export "run" (func $run))
)
```
Note here that `$Libc` is passed to the nested `zipper` and `imgmgk` instances
Expand Down

0 comments on commit bcc2002

Please sign in to comment.