Skip to content

Commit

Permalink
Initial wast support for components (#529)
Browse files Browse the repository at this point in the history
* Remove `ItemRef::Outer`.

* Remove `ItemRef::exports`.

* Remove pre-component-model nested-module and nested-instance support.

* Parsing for the new component model spec.

Remove tests/local/deep.wastfor now; that'll need to be adapted.

* Add a testsuite.

* Factor out code common to modules and components.

* Change the modulearg/componentarg form of `import` to `with`.

* Rename `ComponentType` to `ComponentTypeField`.

* Rename `ComponentModuleType` to `ComponentType`.

This more closely matches the AST documentation.

* Parsing, encoding, and resolution for all intertypes.

* Disable the parse-component.rs tests for now.

* Delete `peek4`, which didn't end up being needed.

* Make `expand_type_use` set `visited` to true.

Previously, visited was getting set by the aliases pass. That's been
removed, as it was primarily supporting the old module linking
implementation. So now we need to set `visited` for types that have
already been expanded.

* Guard `visited` with `#[cfg(wast_check_exhaustive)]`.

* Fix syntax.

* Move parsing of the opening '(' out of several `parse` functions.

* Revise the lookahead for `ModuleArg` and `ComponentArg`.

This avoids needed to define an `RParen` that can be peeked for.

* Reuse the existing `Namespace` rather than having a separate copy.

* Implement `Encode` for `Component`.

* Fix the type of `aliases`.

* Set type uses' `visited` fields.

It was previously being set by the aliases pass, but that's removed now.
So now make sure it's set for all type uses.

* Fully remove the process_imports_early mechanism.

* Implement outer-name lookup.

* Encoding for canon.lower and canon.lift.

* Put components support behind a cargo feature.

* Revert "Put components support behind a cargo feature."

This reverts commit d446204.

* wip

* More resolution of merge conflicts

* Fix more tests

* Start running tests

* Simplify the testing harness

This commit aims to simplify the test harness as it has grown quite
complicated over the years. The original intention was to simplify
insertion of component handling into the wast test harness and it
snowballed into some other improvements first that I wanted to get out
of the way. Namely here the improvements are:

* All `*.wasm` files are removed from the test suite. They're either
  translated to `*.wat` or `*.wast` files since the `module binary`
  form can encode any binary (with comments) as well.

* The difference between `AssertMalformed` and `AssertInvalid` is
  removed and the same arm now handles both of these directives. Perhaps
  one day in the spec test suite these meant something different but
  nowadays the tests seem inconsistent enough that there's no clear
  distinction between the two (e.g. the error "must happen in this
  phase" vs another). In general I don't think precisely where an error
  pops up is too important and we already have a few cases of
  divergence, so as long as things are rejected with the right error
  message I figure it's ok.

* The `match` for wast directives is now exhaustive to ensure handling
  of any new directives that are added.

* The `WastDirective::QuoteModule` directive is merged directly into
  `WastDirective::Module`. Additionally `QuoteModule` now has a helper
  `encode` method to avoid the need to actually match on the module
  itself and delegate appropriately (e.g. the parsing is baked into the
  `wast` crate now.

* Support for `*.txt` tests are removed since this is a vestige of
  wabt-based testing.

* Support for tests with `invalid` in the name are removed now that
  they're all transitioned to `*.wast` tests and can use the normal
  testing harness.

Overall I'm hoping that this will make it easier to replace the `module`
argument of `assert_malformed` and `assert_invalid` with a `Wat`
perhaps, and similarly replacing the `Module` directive with `Wat` or
something like that too. That way the test harness here won't need any
changes to update for components since by-and-large the testing simply
takes an input, encodes it, and then tests the result or the error that
pops out.

* Represent modules in `*.wast` as `Wat` structures

This will make it easier to slot in component support since `Wat` will
have a variant that uses components.

* Move some panics to TODO errors

* More progress on getting very-nested.wast to pass

* More work to getting bits and bobs implemented

* Improve the `dump` implementation w.r.t. imports and printed names
* More things going through resolution all the way
* Expansion of inline imports/exports as well as type uses
* A few `*.dump` tests being added testing expansion

* Remove inner `id` fields from types

Instead use the name of the type within the definition source, and
manage the stack in the `TypeField` resolution

* Get `a.wast` test passing

* Get some of import.wast and string.wast passing

* Reimplement outer aliases

* Refactor the loop to avoid duplicate work in a few locations
* Configure the `id` of the injected `Alias` so it's automatically
  registered with the name so multiple outer aliases to the same name
  only inject one outer alias.
* Fix a bug where the index resolved was the outer component's index,
  not the index of the new alias in the current scope.

* wasmparser: enforce effective type size limits for validation.

This commit reintroduces the effective type size limit in the validator that
existed with the prior module linking proposal.

With the limit enforced, an upper bound is placed on how much work the
validator will do when performing subtype checks.

This also fixes type, import, and export limit enforcement in module,
component, and instance types.

Fixes #580.

* Fix error message on very-nested

* More tests working with the component model

* Implement alias desugaring

* Get some more tests passing

* Get types.wast passing

* Tweak parsing for the string test a bit

* Fix some doc links

* Fix benchmark for the component model

* Get alias.wast test workign

* Get intertype.wast working

* "Fix" the module-link.wast test

* Get start.wast working again

I am not really certain what the syntax for the `(start)` function
should be but this seems to be at least a reasonable-ish starting point

* "Fix" virtualize.wast for now

* Fix some features

* Fix a missing expansion

* Undo some changes in the `wat` crate

* Remove the nascent `component-model` feature

I don't think this will be necessary any more

* Fix merge conflict

* Uncomment a fixed test

* Handle some miscellaneous items here and there

* Add FIXME issues to all TODOs
* Remove name support in the binary encoding for components to get
  re-added at a later date.
* Remove `ComponentArg::Type` as there are no tests. I don't know what
  this is for and it can be re-added if necessary.
* Change some `todo!` macros to `unreachable!` as they should
  legitimately never be hit.

* Update tests for the fix of #586

* Remove some dead code

* Review comments

Co-authored-by: Alex Crichton <alex@alexcrichton.com>
Co-authored-by: Peter Huene <phuene@fastly.com>
  • Loading branch information
3 people committed May 16, 2022
1 parent e60282a commit f18c859
Show file tree
Hide file tree
Showing 58 changed files with 6,147 additions and 1,746 deletions.
108 changes: 108 additions & 0 deletions crates/wast/src/component/alias.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use crate::core;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::{Id, Index, NameAnnotation, Span};

/// An `alias` statement used to juggle indices with nested components.
#[derive(Debug, Clone)]
pub struct Alias<'a> {
/// Where this `alias` was defined.
pub span: Span,
/// An identifier that this alias is resolved with (optionally) for name
/// resolution.
pub id: Option<Id<'a>>,
/// An optional name for this alias stored in the custom `name` section.
pub name: Option<NameAnnotation<'a>>,
/// The target of this alias.
pub target: AliasTarget<'a>,
/// The kind of item that's being aliased.
pub kind: AliasKind,
}

/// aliaskind ::= (module <id>?)
/// | (component <id>?)
/// | (instance <id>?)
/// | (func <id>?)
/// | (value <id>?)
/// | (type <id>?)
/// | (table <id>?)
/// | (memory <id>?)
/// | (global <id>?)
/// | ... other Post-MVP Core definition kinds
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum AliasKind {
Module,
Component,
Instance,
Value,
ExportKind(core::ExportKind),
}

impl<'a> Parse<'a> for AliasKind {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<core::ExportKind>() {
let kind = parser.parse::<core::ExportKind>()?;
Ok(AliasKind::ExportKind(kind))
} else if l.peek::<kw::module>() {
parser.parse::<kw::module>()?;
Ok(AliasKind::Module)
} else if l.peek::<kw::component>() {
parser.parse::<kw::component>()?;
Ok(AliasKind::Component)
} else if l.peek::<kw::instance>() {
parser.parse::<kw::instance>()?;
Ok(AliasKind::Instance)
} else if l.peek::<kw::value>() {
parser.parse::<kw::value>()?;
Ok(AliasKind::Value)
} else {
Err(l.error())
}
}
}

/// aliastarget ::= export <instanceidx> <name>
/// | outer <outeridx> <idx>
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum AliasTarget<'a> {
Export {
instance: Index<'a>,
export: &'a str,
},
Outer {
/// The number of enclosing components to skip.
outer: Index<'a>,
/// An index into the target component's `aliaskind` index space.
index: Index<'a>,
},
}

impl<'a> Parse<'a> for Alias<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::alias>()?.0;
let target = if parser.parse::<Option<kw::outer>>()?.is_some() {
AliasTarget::Outer {
outer: parser.parse()?,
index: parser.parse()?,
}
} else {
parser.parse::<kw::export>()?;
AliasTarget::Export {
instance: parser.parse::<Index<'a>>()?,
export: parser.parse()?,
}
};
let (kind, id, name) = parser.parens(|p| Ok((p.parse()?, p.parse()?, p.parse()?)))?;

Ok(Alias {
span,
id,
name,
kind,
target,
})
}
}

0 comments on commit f18c859

Please sign in to comment.