5411 Commits

Author SHA1 Message Date
Ivan Enderlin
bfa5821d98 test(interface-types) Update the test_executable_instruction macro.
It provides a better failure message.
2020-04-07 12:34:30 +02:00
Ivan Enderlin
2fffee32a5 fix(interface-types) Remove allocator index from string.lower_memory. 2020-04-07 12:34:07 +02:00
Syrus Akbary
bc757908cd
Merge pull request #1349 from wasmerio/feature/reorganized-tests
Move integration tests to `tests` dir in workspace root
2020-04-06 18:40:50 -07:00
Mark McCaskey
ade38aa391 Use CRANELIFT instead of CLIF in test env vars 2020-04-06 17:21:57 -07:00
Mark McCaskey
3579d0d445 Fix emtests and wasitests to use the correct backend 2020-04-06 16:47:06 -07:00
Mark McCaskey
b6011d5dc4 Only run runtime_core tests on Android 2020-04-06 14:13:54 -07:00
Mark McCaskey
9d312f4500 Add support for android in spectests 2020-04-06 12:35:08 -07:00
Mark McCaskey
4c29cd4af3 Merge branch 'master' into feature/reorganized-tests 2020-04-06 12:04:36 -07:00
Mark McCaskey
52cbb60743 Fix up tests for CI 2020-04-06 11:42:44 -07:00
bors[bot]
99f8c949d1
Merge #1354
1354: test(middleware-common) Remove an unused import r=MarkMcCaskey a=Hywan

This PR removes an unused import.

Co-authored-by: Ivan Enderlin <ivan.enderlin@hoa-project.net>
2020-04-06 17:40:35 +00:00
Syrus Akbary
c5c3ddcfbd
Merge pull request #1355 from Hywan/doc-changelog-1331
doc(changelog) Add #1331
2020-04-06 02:08:30 -07:00
Ivan Enderlin
4ba5d6e4ab doc(changelog) Add #1331. 2020-04-06 09:40:03 +02:00
Ivan Enderlin
ac3288db1c test(middleware-common) Remove an unused import. 2020-04-06 08:34:55 +02:00
bors[bot]
4d33020b35
Merge #1331
1331: feat(interface-types) Implement the `record` instructions r=Hywan a=Hywan

### Description

This PR implements the `record` WIT type, along with the `record.lift` and `record.lower` instructions.

With my current understanding of the draft/specification, here is how it works. Let's say we want to represent a Rust struct like the following:

```rust
struct S {
    x: String,
    y: i32
}
```

First declare a WIT type, such as:

```wat
(@interface type (record (field string) (field i32)))
```

The `record` type is supported by the binary encoder, the WAT encoder, the binary decoder, and the WAT decoder. A new `TypeKind` node has been introduced in the AST to differentiate a function type (`(@interface type (func (param …) (result …)))`) of a record type (see above).

Second, the `record.lower` transforms a host value (here Rust value, `S`) into a WIT value. In our implementation, a record value is defined as:

```rust
InterfaceValue::Record(Vec<InterfaceValue>)
```

Multiple mechanisms are used to type check a record value based on a record type. The code of the `record.lower` is pretty straightforward.

Because transforming a host value into a WIT value isn't obvious, a `Serializer` has been implemented, based on [`serde`](https://serde.rs/). This feature is behind the `serde` flag, which is turned on by default.

Serde is only used to cross the host/Wasm boundary, but it's not used to represent the value in memory or anything. It's only a shortcut to transform a host value into a WIT value, and vice versa.

Use the following code to transform `S` into a WIT value:

```rust
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct S {
    x: String,
    y: i32,
}

let host_value = S { x: "hello".to_string(), y: 42 };
let wit_value = to_interface_value(&host_value).unwrap();

assert_eq!(
    wit_value,
    InterfaceValue::Record(vec![
        InterfaceValue::String("hello".to_string()),
        InterfaceValue::I32(42),
    ])
);
```

Third, the `record.lift`  instruction does the opposite of `record.lower`: It transforms WIT values into a host value. To also facilitate the user experience, this PR contains a `Deserializer` implementation, still based on `serde`, with the `from_interface_values` function. It looks like this:

```rust
let wit_values = vec![
    InterfaceValue::Record(vec![
        InterfaceValue::String("hello".to_string()),
        InterfaceValue::I32(42),
    ])
];
let host_value = from_interface_values::<S>(&wit_values).unwrap();

assert_eq!(
    host_value,
    S { x: "hello".to_string(), y: 42 },
);
```

With the `Serializer` and `Deserializer`, it's super easy for the user to send or receive values from WIT.

The `record.lift` and `record.lower` instructions are kind of basic. The `record.lift` instruction has a little trick to reduce vector allocations, but there is a documentation for that.

#### Opened questions

Records of dimension 1 do not raise any issue. With `record.lift`, all values on the stack (the WIT interpreter stack) are popped, and are used as record field values. Something like:

```
[stack]
i32(1)
i64(2),
string("hello")
record.lift <record_type>
```

generates

```
[stack]
record { i32(1), i64(2), string("hello") }
```

But it's not clear what happens with record of dimension > 1, for instance for a type like `record (field i32) (record (field i32) (field i32)) (field string)`, it is assumed (in this PR) that the stack must be like this:

```
[stack]
i32(1)
i32(2)
i32(3)
string("hello")
record.lift <record_type>
```

to generate:

```
[stack]
record { i32(1), record { i32(2), i32(3) }, string("hello") }
```

If we want the stack to contain an intermediate record, we should have something like this:

```
[stack]
i32(1)
i32(2)
i32(3)
record.lift <record_type_2>
string("hello")
record.lift <record_type_1>
```

But it would imply that `record_type_1` is defined as `record (field i32) (record (type record_type_2)) (field i32)`.

A sub-record defined by another record type isn't support, as it is not specified in the draft. I believe my assumption is fine enough for a first implementation of records in WIT.

### To do

- [x] Encode and decode record type (`(@interface type (record string i32))`):
  - [x] Binary encoder/decoder
  - [x] WAT encoder/decoder
- [x] Implement the `record.lift` instruction
- [x] Implement the `record.lower` instruction
- [x] Test
- [x] Documentation
- [x] Surprise!
  - [x] Serialize a Rust value to WIT values (useful for `record`s)
  - [x] Deserialize WIT values to a Rust value (useful for `record`s)

Co-authored-by: Ivan Enderlin <ivan.enderlin@hoa-project.net>
2020-04-06 06:17:45 +00:00
Ivan Enderlin
9f10b7ae50 doc(interface-types) Update from_interface_values's doc.
Using `InterfaceValue::Record` explicitely doesn't change anything
since values are flatten, but it's better for a usual reading to avoid
confusion.
2020-04-06 08:13:10 +02:00
Ivan Enderlin
27053d5ca6 doc(interface-types) Rewrite record_lift_ documentation. 2020-04-06 08:09:10 +02:00
Ivan Enderlin
c2b1b87f9a feat(interface-types) Use VecDeque to remove unsafe code. 2020-04-06 07:55:56 +02:00
Ivan Enderlin
4faf827dc9 feat(interface-types) Avoid clones by using owned items in an iterator.
`into_iter` owned the item, so no need to clone when moving them in
the stack.
2020-04-06 07:54:51 +02:00
Ivan Enderlin
4ad3d7f123 doc(interface-types) Explain a part of an algorithm. 2020-04-04 08:10:38 +02:00
Mark McCaskey
dfa6247075 Move spectests, wrap up test restructure 2020-04-03 14:24:40 -07:00
Ivan Enderlin
5119b6a58f feat(interface-types) Simplify FlattenInterfaceValueIterator with last_mut. 2020-04-03 16:22:26 +02:00
Ivan Enderlin
e4921bd496 feat(interface-types) Use Vec::last_mut to simplify code. 2020-04-03 16:20:22 +02:00
Ivan Enderlin
398d791c9f fix(interface-types) Also apply another lazy evaluation in the deserializer. 2020-04-03 16:19:07 +02:00
Ivan Enderlin
e160feb99a fix(interface-types) Use lazy evaluation in the deserializer. 2020-04-03 16:18:24 +02:00
Ivan Enderlin
d186142507 doc(interface-types) Fix a typo. 2020-04-03 16:16:53 +02:00
Ivan Enderlin
3159da5bfe feat(interface-types) Add the Vec1 type to represent a non-empty vector.
`Vec1` is used by `RecordType` to ensure that a record have at least 1
field. Then an `InterfaceValue::Record` is ensured to get at least one
value with the type-checking pass.
2020-04-03 16:13:44 +02:00
Ivan Enderlin
6cef1c244a doc(interface-types) Fix typos. 2020-04-03 14:46:59 +02:00
Mark McCaskey
513e6acbc1 Move emscripten-tests to tests dir + misc fixes 2020-04-02 16:51:58 -07:00
bors[bot]
1833af7eba
Merge #1350
1350: update blake3 to 0.3.1 r=syrusakbary a=oconnor663

Version 0.3.0 caused problems because it required a C compiler with
AVX-512 support, which broke Android x86 cross-compilation. Version
0.3.1 automatically falls back to a pure Rust build when the C compiler
either doesn't exist or doesn't support the flags we need.

Co-authored-by: Jack O'Connor <oconnor663@gmail.com>
2020-04-02 15:11:41 +00:00
Jack O'Connor
aca0bd11c0 update blake3 to 0.3.1
Version 0.3.0 caused problems because it required a C compiler with
AVX-512 support, which broke Android x86 cross-compilation. Version
0.3.1 automatically falls back to a pure Rust build when the C compiler
either doesn't exist or doesn't support the flags we need.
2020-04-02 11:02:49 -04:00
Ivan Enderlin
2011fda31d chore(interface-types) Split the serde module…
… into `serde/ser.rs` and `serde/de.rs`. I like smaller files.
2020-04-02 16:46:23 +02:00
Ivan Enderlin
be66ac8aa4 doc(interface-types) Improve serde module documentation. 2020-04-02 16:41:03 +02:00
Ivan Enderlin
010b10d7b0 chore(cargo) Update Cargo.lock. 2020-04-02 16:39:40 +02:00
Ivan Enderlin
e385bf66c7 feat(interface-types) Make unwraps safe by introducing more errors. 2020-04-02 16:38:40 +02:00
Ivan Enderlin
b0af014339 doc(interface-types) Update an example. 2020-04-02 16:29:52 +02:00
Ivan Enderlin
ee0596d2c3 feat(interface-types) Restrict supported type in the Deserializer.
`seq`, `map` and `tuple` for instance are not supported officially. It
was fun to play with it at the beginning, but it is time to remove it
to match the `Serializer` implementation.
2020-04-02 16:26:24 +02:00
Ivan Enderlin
d6f7e3ff02 doc(interface-types) Describe to_interface_value. 2020-04-02 15:59:07 +02:00
Ivan Enderlin
f9832fecaf feat(interface-types) Implement a serializer for WIT values. 2020-04-02 15:54:39 +02:00
Ivan Enderlin
8868d640fa feat(interface-types) Rename from_values to from_interface_values. 2020-04-02 13:56:20 +02:00
Ivan Enderlin
7b182416df feat(interface-types) Make serde optional behind a feature flag. 2020-04-02 13:53:10 +02:00
Ivan Enderlin
f8507533fb fix(interface-types) Fix a git-merge issue. 2020-04-02 12:16:30 +02:00
Ivan Enderlin
bac56a6e0b Merge branch 'master' into feat-interface-types-record-instructions 2020-04-02 12:10:01 +02:00
Ivan Enderlin
8f8c5f1bc8 chore(interface-types) Improve code readabilit of the record.lift instruction. 2020-04-02 12:06:54 +02:00
Ivan Enderlin
0023eea275 feat(interface-types) Implement the record.lower instruction. 2020-04-02 12:06:27 +02:00
Ivan Enderlin
11687c57ca feat(interface-types) Encodes/decodes the record.lower instruction. 2020-04-02 12:05:22 +02:00
Ivan Enderlin
b8ef82d1d0 test(interface-types) Rename test cases. 2020-04-02 11:59:35 +02:00
Ivan Enderlin
a1551b52af test(interface-types) Rename a test case. 2020-04-02 11:58:05 +02:00
Ivan Enderlin
aab82c122d feat(interface-types) Implement From<&Vec<InterfaceValue>> for RecordType. 2020-04-02 11:55:54 +02:00
Ivan Enderlin
3411ac7a1c feat(interface-types) Move serde::InterfaceTypeIterator into values::FlattenInterfaceValueIterator. 2020-04-02 11:55:20 +02:00
Ivan Enderlin
5ba6fda1c9 chore(interface-types) Improve code readibility of string instructions. 2020-04-02 11:51:34 +02:00