зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1823476 - Update wast vendor dependency. r=supply-chain-reviewers
Updated wast=55.0.0. And also wasm-smith to avoid duplicate copy of wasm-encoder. Differential Revision: https://phabricator.services.mozilla.com/D173217
This commit is contained in:
Родитель
39d1882677
Коммит
4d09764c66
|
@ -6159,18 +6159,18 @@ version = "0.2.100"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.23.0"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c3e4bc09095436c8e7584d86d33e6c3ee67045af8fb262cbb9cc321de553428"
|
||||
checksum = "4eff853c4f09eec94d76af527eddad4e9de13b11d6286a1ef7134bc30135a2b7"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-smith"
|
||||
version = "0.12.2"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "411278ee8e89067a252a3a6d6d578038251f9c0a1d4c088adf4162ad13e97b04"
|
||||
checksum = "549cb78be46f43ad6746402871336cb6a989127fb847e93eb6ba0817647485a6"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"flagset",
|
||||
|
@ -6182,9 +6182,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.100.0"
|
||||
version = "0.102.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64b20236ab624147dfbb62cf12a19aaf66af0e41b8398838b66e997d07d269d4"
|
||||
checksum = "48134de3d7598219ab9eaf6b91b15d8e50d31da76b8519fe4ecfcec2cf35104b"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"url",
|
||||
|
@ -6192,9 +6192,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "53.0.0"
|
||||
version = "55.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8244fa24196b1d8fd3ca4a96a3a164c40f846498c5deab6caf414c67340ca4af"
|
||||
checksum = "4984d3e1406571f4930ba5cf79bd70f75f41d0e87e17506e0bd19b0e5d085f05"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
"memchr",
|
||||
|
|
|
@ -5,6 +5,6 @@ authors = ["Christian Holler"]
|
|||
license = "MPL-2.0"
|
||||
|
||||
[dependencies]
|
||||
wasm-smith = "0.12.2"
|
||||
wasm-smith = "0.12.5"
|
||||
arbitrary = { version = "1.0.0", features = ["derive"] }
|
||||
libc = "0.2"
|
||||
|
|
|
@ -19,4 +19,4 @@ gluesmith = ['jsrust_shared/gluesmith']
|
|||
jsrust_shared = { path = "./shared" }
|
||||
# Workaround for https://github.com/rust-lang/rust/issues/58393
|
||||
mozglue-static = { path = "../../../mozglue/static/rust" }
|
||||
wast = { version = "53.0.0" }
|
||||
wast = { version = "55.0.0" }
|
||||
|
|
|
@ -197,24 +197,48 @@ criteria = "safe-to-deploy"
|
|||
version = "0.23.0"
|
||||
notes = "The Bytecode Alliance is the author of this crate."
|
||||
|
||||
[[audits.bytecode-alliance.audits.wasm-encoder]]
|
||||
who = "Alex Crichton <alex@alexcrichton.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.25.0"
|
||||
notes = "The Bytecode Alliance is the author of this crate."
|
||||
|
||||
[[audits.bytecode-alliance.audits.wasm-smith]]
|
||||
who = "Alex Crichton <alex@alexcrichton.com>"
|
||||
criteria = "safe-to-run"
|
||||
version = "0.12.2"
|
||||
notes = "The Bytecode Alliance is the author of this crate."
|
||||
|
||||
[[audits.bytecode-alliance.audits.wasm-smith]]
|
||||
who = "Alex Crichton <alex@alexcrichton.com>"
|
||||
criteria = "safe-to-run"
|
||||
version = "0.12.5"
|
||||
notes = "The Bytecode Alliance is the author of this crate."
|
||||
|
||||
[[audits.bytecode-alliance.audits.wasmparser]]
|
||||
who = "Alex Crichton <alex@alexcrichton.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.100.0"
|
||||
notes = "The Bytecode Alliance is the author of this crate."
|
||||
|
||||
[[audits.bytecode-alliance.audits.wasmparser]]
|
||||
who = "Alex Crichton <alex@alexcrichton.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.102.0"
|
||||
notes = "The Bytecode Alliance is the author of this crate."
|
||||
|
||||
[[audits.bytecode-alliance.audits.wast]]
|
||||
who = "Alex Crichton <alex@alexcrichton.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "53.0.0"
|
||||
notes = "The Bytecode Alliance is the author of this crate."
|
||||
|
||||
[[audits.bytecode-alliance.audits.wast]]
|
||||
who = "Alex Crichton <alex@alexcrichton.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "55.0.0"
|
||||
notes = "The Bytecode Alliance is the author of this crate."
|
||||
|
||||
[[audits.chromeos.audits.fastrand]]
|
||||
who = "George Burgess IV <gbiv@google.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"fefb25e72fb204befadd0bedd4b998538a04bdbec2c28d4f70ef725a0de35a17","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"ac016c4843a7e1a5737255b39418732783592222dc518020730edf9dd46a1c13","src/component.rs":"c84b64b732fa84222452e13589ec187d62bee55098ca9e5b299810791b972906","src/component/aliases.rs":"be5215154b872ed5664f3bfe2aa1391f36a2575aa9d53971ab61868a1c446e9d","src/component/canonicals.rs":"8b270caef4e0f1e2b62af5b27560ac370399d11ce411aae6b811dddeaedb7750","src/component/components.rs":"07b8cae3a400e1955cc39d142569910b4fef2136021053d0ddbd6404d810aa52","src/component/exports.rs":"9a685fb44af0cfefbb2e92ddb0259955766cf6d1c0022830a865f92426ce0f7b","src/component/imports.rs":"41414a4cb71d79404e8721a985dd1d3a7df287f6417b4cab017d12e9aef31c43","src/component/instances.rs":"c86f24e466aeb6889413f32d95e039a90a1e20d2e5a0505339aa81fc086a8c24","src/component/modules.rs":"9e80907e72360fae4d8057b6b0e7a6b58edd7ba6aba6e63ba17346518e169617","src/component/names.rs":"7b651284ffdf147aabf1e01226f34ddc8bbe3d38a2dcd26ca0fc15ad24002b6f","src/component/start.rs":"4055553d5c99c99abbc01bb8abb928ecb8b909d148b647a9977fbd444bb464a3","src/component/types.rs":"885e26ce451a50ff48ab472161d8923c0195406180f36588c1d38c79181dee51","src/core.rs":"492e5ce8de8e0c0bfe55fdad62d0b8825ed88b4a01f4e1dcffae60020f27aea0","src/core/code.rs":"0dd762215e487f76d138dd6507679c24bfd747531d989baaa78d7e2382f099e4","src/core/custom.rs":"df2d6a8c5a64603822301522e9df4344022226301df846941d95930f1f4d99c4","src/core/data.rs":"c9d59eab2ab811bd950da52e6766c7df2367986c7a3a0d94d7aeb47d86f203ac","src/core/elements.rs":"361eba770b0bd6129e5b96f3081b022c5fa74640730d1d0501a33d93fea7d707","src/core/exports.rs":"f37351587cd0cfa7608f94e0fcbfa09d41c7df1d123c47825992c364d5d9ff11","src/core/functions.rs":"c18b9872ac0c21048a3ce32e5e44e8e702f97a57fa1b3a07bdd98c7f6c820f09","src/core/globals.rs":"560d8e8c818d968cd8a101ab3c639f723b1c754716aa1178d1c4570efd84d010","src/core/imports.rs":"782bbc2e70b379831f85716c0f50c0221d1487c8cba26e8845028b2ae1962c0c","src/core/linking.rs":"5c7d5bce822fad92dc096ceafde878c6d25869004ca26dde1378e78ae37071c9","src/core/memories.rs":"840d15fcd9bd4a668298491c6a91455b145c5c7ff1adf8c769aaf49d6c664d3a","src/core/names.rs":"1337a5ab769e1a1b83113041d6fc59652db34a01ef44f14a2641b3748c216dc1","src/core/producers.rs":"e96156e2b87a4e9162b918b8f9cae870c5abc9410835651d74ac54f0ff2665e7","src/core/start.rs":"a01d4a91bcd93048977ccafc6af160357297450395bf598351f5a3e6d322e0de","src/core/tables.rs":"f87a9761002e93c8e04e646cdf19fb5d012b190a4dbba542e8bfe1cfc606b545","src/core/tags.rs":"26d58904871d92f395eed67d4c25f0914b337d213bab2288011abe3ad31fa12b","src/core/types.rs":"42125c08577c418237982980fd13eb9a21e63b52674c0820c2df2e61b5f454fc","src/lib.rs":"aaec7fa68ae0764721d7b4b6d0d935ea60380c6268cbd512480fee2f7a61b755","src/raw.rs":"a6a72cfe8f88ea6476eccee4acf362030ba2d2e5710215bc4f13cde7de6d71ae"},"package":"1c3e4bc09095436c8e7584d86d33e6c3ee67045af8fb262cbb9cc321de553428"}
|
||||
{"files":{"Cargo.toml":"b96ee82a5f62db5b6f57000e3f1fdab6872b1bed6d36350e9af08d90984b47af","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"ac016c4843a7e1a5737255b39418732783592222dc518020730edf9dd46a1c13","src/component.rs":"b07b239571c54100a258da3fb00d9155c85d3750f93cc24d408ebc17301f3e66","src/component/aliases.rs":"be5215154b872ed5664f3bfe2aa1391f36a2575aa9d53971ab61868a1c446e9d","src/component/canonicals.rs":"8b270caef4e0f1e2b62af5b27560ac370399d11ce411aae6b811dddeaedb7750","src/component/components.rs":"07b8cae3a400e1955cc39d142569910b4fef2136021053d0ddbd6404d810aa52","src/component/exports.rs":"9a685fb44af0cfefbb2e92ddb0259955766cf6d1c0022830a865f92426ce0f7b","src/component/imports.rs":"41414a4cb71d79404e8721a985dd1d3a7df287f6417b4cab017d12e9aef31c43","src/component/instances.rs":"75e0ec12a578aa22d78053add818a960373171ff10c3619ca1e8058ded277a41","src/component/modules.rs":"9e80907e72360fae4d8057b6b0e7a6b58edd7ba6aba6e63ba17346518e169617","src/component/names.rs":"7b651284ffdf147aabf1e01226f34ddc8bbe3d38a2dcd26ca0fc15ad24002b6f","src/component/start.rs":"4055553d5c99c99abbc01bb8abb928ecb8b909d148b647a9977fbd444bb464a3","src/component/types.rs":"02982d0b7962462f0b083ade9a639216cc040775a0426ad431afbf9fbedf664b","src/core.rs":"7b02ef53a430693cfadcfd83f3aa9f556062eb9b9408e661ead5364e2150cd5e","src/core/code.rs":"b340cb948d1e28e8bd369353c729674146bcc28508bbb427a8d249af4fd491fe","src/core/custom.rs":"df2d6a8c5a64603822301522e9df4344022226301df846941d95930f1f4d99c4","src/core/data.rs":"c9d59eab2ab811bd950da52e6766c7df2367986c7a3a0d94d7aeb47d86f203ac","src/core/elements.rs":"76ab78bed1956fad030821b267a115511a99c61f33f2c6e588b5a8d4ee9b4204","src/core/exports.rs":"f37351587cd0cfa7608f94e0fcbfa09d41c7df1d123c47825992c364d5d9ff11","src/core/functions.rs":"c18b9872ac0c21048a3ce32e5e44e8e702f97a57fa1b3a07bdd98c7f6c820f09","src/core/globals.rs":"560d8e8c818d968cd8a101ab3c639f723b1c754716aa1178d1c4570efd84d010","src/core/imports.rs":"782bbc2e70b379831f85716c0f50c0221d1487c8cba26e8845028b2ae1962c0c","src/core/linking.rs":"5c7d5bce822fad92dc096ceafde878c6d25869004ca26dde1378e78ae37071c9","src/core/memories.rs":"840d15fcd9bd4a668298491c6a91455b145c5c7ff1adf8c769aaf49d6c664d3a","src/core/names.rs":"1337a5ab769e1a1b83113041d6fc59652db34a01ef44f14a2641b3748c216dc1","src/core/producers.rs":"e96156e2b87a4e9162b918b8f9cae870c5abc9410835651d74ac54f0ff2665e7","src/core/start.rs":"a01d4a91bcd93048977ccafc6af160357297450395bf598351f5a3e6d322e0de","src/core/tables.rs":"d5ae8c92c8707332eda6be6e5649f2f8042a1c6242494b0174cbee5e1971cace","src/core/tags.rs":"26d58904871d92f395eed67d4c25f0914b337d213bab2288011abe3ad31fa12b","src/core/types.rs":"988175ad3a47f4aca29c7fad9d594b54c5a5717fedf7ecd6296fbb45cb058999","src/lib.rs":"aaec7fa68ae0764721d7b4b6d0d935ea60380c6268cbd512480fee2f7a61b755","src/raw.rs":"a6a72cfe8f88ea6476eccee4acf362030ba2d2e5710215bc4f13cde7de6d71ae"},"package":"4eff853c4f09eec94d76af527eddad4e9de13b11d6286a1ef7134bc30135a2b7"}
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "wasm-encoder"
|
||||
version = "0.23.0"
|
||||
version = "0.25.0"
|
||||
authors = ["Nick Fitzgerald <fitzgen@gmail.com>"]
|
||||
description = """
|
||||
A low-level WebAssembly encoder.
|
||||
|
|
|
@ -42,6 +42,12 @@ const INSTANCE_SORT: u8 = 0x05;
|
|||
pub trait ComponentSection: Encode {
|
||||
/// Gets the section identifier for this section.
|
||||
fn id(&self) -> u8;
|
||||
|
||||
/// Appends this section to the specified destination list of bytes.
|
||||
fn append_to_component(&self, dst: &mut Vec<u8>) {
|
||||
dst.push(self.id());
|
||||
self.encode(dst);
|
||||
}
|
||||
}
|
||||
|
||||
/// Known section identifiers of WebAssembly components.
|
||||
|
@ -101,13 +107,19 @@ pub struct Component {
|
|||
}
|
||||
|
||||
impl Component {
|
||||
/// The 8-byte header at the beginning of all components.
|
||||
#[rustfmt::skip]
|
||||
pub const HEADER: [u8; 8] = [
|
||||
// Magic
|
||||
0x00, 0x61, 0x73, 0x6D,
|
||||
// Version
|
||||
0x0c, 0x00, 0x01, 0x00,
|
||||
];
|
||||
|
||||
/// Begin writing a new `Component`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
bytes: vec![
|
||||
0x00, 0x61, 0x73, 0x6D, // magic (`\0asm`)
|
||||
0x0c, 0x00, 0x01, 0x00, // version
|
||||
],
|
||||
bytes: Self::HEADER.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,17 +59,18 @@ impl InstanceSection {
|
|||
}
|
||||
|
||||
/// Define an instance by instantiating a core module.
|
||||
pub fn instantiate<'a, A>(&mut self, module_index: u32, args: A) -> &mut Self
|
||||
pub fn instantiate<A, S>(&mut self, module_index: u32, args: A) -> &mut Self
|
||||
where
|
||||
A: IntoIterator<Item = (&'a str, ModuleArg)>,
|
||||
A: IntoIterator<Item = (S, ModuleArg)>,
|
||||
A::IntoIter: ExactSizeIterator,
|
||||
S: AsRef<str>,
|
||||
{
|
||||
let args = args.into_iter();
|
||||
self.bytes.push(0x00);
|
||||
module_index.encode(&mut self.bytes);
|
||||
args.len().encode(&mut self.bytes);
|
||||
for (name, arg) in args {
|
||||
name.encode(&mut self.bytes);
|
||||
name.as_ref().encode(&mut self.bytes);
|
||||
arg.encode(&mut self.bytes);
|
||||
}
|
||||
self.num_added += 1;
|
||||
|
@ -77,16 +78,17 @@ impl InstanceSection {
|
|||
}
|
||||
|
||||
/// Define an instance by exporting core WebAssembly items.
|
||||
pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self
|
||||
pub fn export_items<E, S>(&mut self, exports: E) -> &mut Self
|
||||
where
|
||||
E: IntoIterator<Item = (&'a str, ExportKind, u32)>,
|
||||
E: IntoIterator<Item = (S, ExportKind, u32)>,
|
||||
E::IntoIter: ExactSizeIterator,
|
||||
S: AsRef<str>,
|
||||
{
|
||||
let exports = exports.into_iter();
|
||||
self.bytes.push(0x01);
|
||||
exports.len().encode(&mut self.bytes);
|
||||
for (name, kind, index) in exports {
|
||||
name.encode(&mut self.bytes);
|
||||
name.as_ref().encode(&mut self.bytes);
|
||||
kind.encode(&mut self.bytes);
|
||||
index.encode(&mut self.bytes);
|
||||
}
|
||||
|
@ -146,17 +148,18 @@ impl ComponentInstanceSection {
|
|||
}
|
||||
|
||||
/// Define an instance by instantiating a component.
|
||||
pub fn instantiate<'a, A>(&mut self, component_index: u32, args: A) -> &mut Self
|
||||
pub fn instantiate<A, S>(&mut self, component_index: u32, args: A) -> &mut Self
|
||||
where
|
||||
A: IntoIterator<Item = (&'a str, ComponentExportKind, u32)>,
|
||||
A: IntoIterator<Item = (S, ComponentExportKind, u32)>,
|
||||
A::IntoIter: ExactSizeIterator,
|
||||
S: AsRef<str>,
|
||||
{
|
||||
let args = args.into_iter();
|
||||
self.bytes.push(0x00);
|
||||
component_index.encode(&mut self.bytes);
|
||||
args.len().encode(&mut self.bytes);
|
||||
for (name, kind, index) in args {
|
||||
name.encode(&mut self.bytes);
|
||||
name.as_ref().encode(&mut self.bytes);
|
||||
kind.encode(&mut self.bytes);
|
||||
index.encode(&mut self.bytes);
|
||||
}
|
||||
|
|
|
@ -92,9 +92,9 @@ impl<'a> CoreTypeEncoder<'a> {
|
|||
|
||||
self.0.push(0x60);
|
||||
params.len().encode(self.0);
|
||||
self.0.extend(params.map(u8::from));
|
||||
params.for_each(|p| p.encode(self.0));
|
||||
results.len().encode(self.0);
|
||||
self.0.extend(results.map(u8::from));
|
||||
results.for_each(|p| p.encode(self.0));
|
||||
}
|
||||
|
||||
/// Define a module type.
|
||||
|
|
|
@ -48,6 +48,12 @@ pub(crate) const CORE_TAG_SORT: u8 = 0x04;
|
|||
pub trait Section: Encode {
|
||||
/// Gets the section identifier for this section.
|
||||
fn id(&self) -> u8;
|
||||
|
||||
/// Appends this section to the specified destination list of bytes.
|
||||
fn append_to(&self, dst: &mut Vec<u8>) {
|
||||
dst.push(self.id());
|
||||
self.encode(dst);
|
||||
}
|
||||
}
|
||||
|
||||
/// Known section identifiers of WebAssembly modules.
|
||||
|
@ -110,16 +116,20 @@ pub struct Module {
|
|||
}
|
||||
|
||||
impl Module {
|
||||
/// The 8-byte header at the beginning of all core wasm modules.
|
||||
#[rustfmt::skip]
|
||||
pub const HEADER: [u8; 8] = [
|
||||
// Magic
|
||||
0x00, 0x61, 0x73, 0x6D,
|
||||
// Version
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
/// Begin writing a new `Module`.
|
||||
#[rustfmt::skip]
|
||||
pub fn new() -> Self {
|
||||
Module {
|
||||
bytes: vec![
|
||||
// Magic
|
||||
0x00, 0x61, 0x73, 0x6D,
|
||||
// Version
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
],
|
||||
bytes: Self::HEADER.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{encode_section, Encode, Section, SectionId, ValType};
|
||||
use crate::{encode_section, Encode, HeapType, Section, SectionId, ValType};
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// An encoder for the code section.
|
||||
|
@ -318,9 +318,13 @@ pub enum Instruction<'a> {
|
|||
Br(u32),
|
||||
BrIf(u32),
|
||||
BrTable(Cow<'a, [u32]>, u32),
|
||||
BrOnNull(u32),
|
||||
BrOnNonNull(u32),
|
||||
Return,
|
||||
Call(u32),
|
||||
CallRef(HeapType),
|
||||
CallIndirect { ty: u32, table: u32 },
|
||||
ReturnCallRef(HeapType),
|
||||
ReturnCall(u32),
|
||||
ReturnCallIndirect { ty: u32, table: u32 },
|
||||
Throw(u32),
|
||||
|
@ -513,9 +517,10 @@ pub enum Instruction<'a> {
|
|||
|
||||
// Reference types instructions.
|
||||
TypedSelect(ValType),
|
||||
RefNull(ValType),
|
||||
RefNull(HeapType),
|
||||
RefIsNull,
|
||||
RefFunc(u32),
|
||||
RefAsNonNull,
|
||||
|
||||
// Bulk memory instructions.
|
||||
TableInit { elem_index: u32, table: u32 },
|
||||
|
@ -764,15 +769,17 @@ pub enum Instruction<'a> {
|
|||
F64x2ConvertLowI32x4U,
|
||||
F32x4DemoteF64x2Zero,
|
||||
F64x2PromoteLowF32x4,
|
||||
|
||||
// Relaxed simd proposal
|
||||
I8x16RelaxedSwizzle,
|
||||
I32x4RelaxedTruncSatF32x4S,
|
||||
I32x4RelaxedTruncSatF32x4U,
|
||||
I32x4RelaxedTruncSatF64x2SZero,
|
||||
I32x4RelaxedTruncSatF64x2UZero,
|
||||
F32x4RelaxedFma,
|
||||
F32x4RelaxedFnma,
|
||||
F64x2RelaxedFma,
|
||||
F64x2RelaxedFnma,
|
||||
I32x4RelaxedTruncF32x4S,
|
||||
I32x4RelaxedTruncF32x4U,
|
||||
I32x4RelaxedTruncF64x2SZero,
|
||||
I32x4RelaxedTruncF64x2UZero,
|
||||
F32x4RelaxedMadd,
|
||||
F32x4RelaxedNmadd,
|
||||
F64x2RelaxedMadd,
|
||||
F64x2RelaxedNmadd,
|
||||
I8x16RelaxedLaneselect,
|
||||
I16x8RelaxedLaneselect,
|
||||
I32x4RelaxedLaneselect,
|
||||
|
@ -782,9 +789,8 @@ pub enum Instruction<'a> {
|
|||
F64x2RelaxedMin,
|
||||
F64x2RelaxedMax,
|
||||
I16x8RelaxedQ15mulrS,
|
||||
I16x8DotI8x16I7x16S,
|
||||
I32x4DotI8x16I7x16AddS,
|
||||
F32x4RelaxedDotBf16x8AddF32x4,
|
||||
I16x8RelaxedDotI8x16I7x16S,
|
||||
I32x4RelaxedDotI8x16I7x16AddS,
|
||||
|
||||
// Atomic instructions (the threads proposal)
|
||||
MemoryAtomicNotify(MemArg),
|
||||
|
@ -905,16 +911,33 @@ impl Encode for Instruction<'_> {
|
|||
ls.encode(sink);
|
||||
l.encode(sink);
|
||||
}
|
||||
Instruction::BrOnNull(l) => {
|
||||
sink.push(0xD4);
|
||||
l.encode(sink);
|
||||
}
|
||||
Instruction::BrOnNonNull(l) => {
|
||||
sink.push(0xD6);
|
||||
l.encode(sink);
|
||||
}
|
||||
Instruction::Return => sink.push(0x0F),
|
||||
Instruction::Call(f) => {
|
||||
sink.push(0x10);
|
||||
f.encode(sink);
|
||||
}
|
||||
Instruction::CallRef(ty) => {
|
||||
sink.push(0x14);
|
||||
ty.encode(sink);
|
||||
}
|
||||
Instruction::CallIndirect { ty, table } => {
|
||||
sink.push(0x11);
|
||||
ty.encode(sink);
|
||||
table.encode(sink);
|
||||
}
|
||||
Instruction::ReturnCallRef(ty) => {
|
||||
sink.push(0x15);
|
||||
ty.encode(sink);
|
||||
}
|
||||
|
||||
Instruction::ReturnCall(f) => {
|
||||
sink.push(0x12);
|
||||
f.encode(sink);
|
||||
|
@ -1290,6 +1313,7 @@ impl Encode for Instruction<'_> {
|
|||
sink.push(0xd2);
|
||||
f.encode(sink);
|
||||
}
|
||||
Instruction::RefAsNonNull => sink.push(0xD3),
|
||||
|
||||
// Bulk memory instructions.
|
||||
Instruction::TableInit { elem_index, table } => {
|
||||
|
@ -2347,35 +2371,35 @@ impl Encode for Instruction<'_> {
|
|||
sink.push(0xFD);
|
||||
0x100u32.encode(sink);
|
||||
}
|
||||
Instruction::I32x4RelaxedTruncSatF32x4S => {
|
||||
Instruction::I32x4RelaxedTruncF32x4S => {
|
||||
sink.push(0xFD);
|
||||
0x101u32.encode(sink);
|
||||
}
|
||||
Instruction::I32x4RelaxedTruncSatF32x4U => {
|
||||
Instruction::I32x4RelaxedTruncF32x4U => {
|
||||
sink.push(0xFD);
|
||||
0x102u32.encode(sink);
|
||||
}
|
||||
Instruction::I32x4RelaxedTruncSatF64x2SZero => {
|
||||
Instruction::I32x4RelaxedTruncF64x2SZero => {
|
||||
sink.push(0xFD);
|
||||
0x103u32.encode(sink);
|
||||
}
|
||||
Instruction::I32x4RelaxedTruncSatF64x2UZero => {
|
||||
Instruction::I32x4RelaxedTruncF64x2UZero => {
|
||||
sink.push(0xFD);
|
||||
0x104u32.encode(sink);
|
||||
}
|
||||
Instruction::F32x4RelaxedFma => {
|
||||
Instruction::F32x4RelaxedMadd => {
|
||||
sink.push(0xFD);
|
||||
0x105u32.encode(sink);
|
||||
}
|
||||
Instruction::F32x4RelaxedFnma => {
|
||||
Instruction::F32x4RelaxedNmadd => {
|
||||
sink.push(0xFD);
|
||||
0x106u32.encode(sink);
|
||||
}
|
||||
Instruction::F64x2RelaxedFma => {
|
||||
Instruction::F64x2RelaxedMadd => {
|
||||
sink.push(0xFD);
|
||||
0x107u32.encode(sink);
|
||||
}
|
||||
Instruction::F64x2RelaxedFnma => {
|
||||
Instruction::F64x2RelaxedNmadd => {
|
||||
sink.push(0xFD);
|
||||
0x108u32.encode(sink);
|
||||
}
|
||||
|
@ -2415,18 +2439,14 @@ impl Encode for Instruction<'_> {
|
|||
sink.push(0xFD);
|
||||
0x111u32.encode(sink);
|
||||
}
|
||||
Instruction::I16x8DotI8x16I7x16S => {
|
||||
Instruction::I16x8RelaxedDotI8x16I7x16S => {
|
||||
sink.push(0xFD);
|
||||
0x112u32.encode(sink);
|
||||
}
|
||||
Instruction::I32x4DotI8x16I7x16AddS => {
|
||||
Instruction::I32x4RelaxedDotI8x16I7x16AddS => {
|
||||
sink.push(0xFD);
|
||||
0x113u32.encode(sink);
|
||||
}
|
||||
Instruction::F32x4RelaxedDotBf16x8AddF32x4 => {
|
||||
sink.push(0xFD);
|
||||
0x114u32.encode(sink);
|
||||
}
|
||||
|
||||
// Atmoic instructions from the thread proposal
|
||||
Instruction::MemoryAtomicNotify(memarg) => {
|
||||
|
@ -2801,7 +2821,7 @@ impl ConstExpr {
|
|||
}
|
||||
|
||||
/// Create a constant expression containing a single `ref.null` instruction.
|
||||
pub fn ref_null(ty: ValType) -> Self {
|
||||
pub fn ref_null(ty: HeapType) -> Self {
|
||||
Self::new_insn(Instruction::RefNull(ty))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{encode_section, ConstExpr, Encode, Section, SectionId, ValType};
|
||||
use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId};
|
||||
|
||||
/// An encoder for the element section.
|
||||
///
|
||||
|
@ -9,12 +9,12 @@ use crate::{encode_section, ConstExpr, Encode, Section, SectionId, ValType};
|
|||
/// ```
|
||||
/// use wasm_encoder::{
|
||||
/// Elements, ElementSection, Module, TableSection, TableType,
|
||||
/// ValType, ConstExpr
|
||||
/// RefType, ConstExpr
|
||||
/// };
|
||||
///
|
||||
/// let mut tables = TableSection::new();
|
||||
/// tables.table(TableType {
|
||||
/// element_type: ValType::FuncRef,
|
||||
/// element_type: RefType::FUNCREF,
|
||||
/// minimum: 128,
|
||||
/// maximum: None,
|
||||
/// });
|
||||
|
@ -22,7 +22,7 @@ use crate::{encode_section, ConstExpr, Encode, Section, SectionId, ValType};
|
|||
/// let mut elements = ElementSection::new();
|
||||
/// let table_index = 0;
|
||||
/// let offset = ConstExpr::i32_const(42);
|
||||
/// let element_type = ValType::FuncRef;
|
||||
/// let element_type = RefType::FUNCREF;
|
||||
/// let functions = Elements::Functions(&[
|
||||
/// // Function indices...
|
||||
/// ]);
|
||||
|
@ -80,7 +80,7 @@ pub struct ElementSegment<'a> {
|
|||
/// The element segment's mode.
|
||||
pub mode: ElementMode<'a>,
|
||||
/// The element segment's type.
|
||||
pub element_type: ValType,
|
||||
pub element_type: RefType,
|
||||
/// This segment's elements.
|
||||
pub elements: Elements<'a>,
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ impl ElementSection {
|
|||
&mut self,
|
||||
table_index: Option<u32>,
|
||||
offset: &ConstExpr,
|
||||
element_type: ValType,
|
||||
element_type: RefType,
|
||||
elements: Elements<'_>,
|
||||
) -> &mut Self {
|
||||
self.segment(ElementSegment {
|
||||
|
@ -187,7 +187,7 @@ impl ElementSection {
|
|||
/// Encode a passive element segment.
|
||||
///
|
||||
/// Passive segments are part of the bulk memory proposal.
|
||||
pub fn passive<'a>(&mut self, element_type: ValType, elements: Elements<'a>) -> &mut Self {
|
||||
pub fn passive<'a>(&mut self, element_type: RefType, elements: Elements<'a>) -> &mut Self {
|
||||
self.segment(ElementSegment {
|
||||
mode: ElementMode::Passive,
|
||||
element_type,
|
||||
|
@ -198,7 +198,7 @@ impl ElementSection {
|
|||
/// Encode a declared element segment.
|
||||
///
|
||||
/// Declared segments are part of the bulk memory proposal.
|
||||
pub fn declared<'a>(&mut self, element_type: ValType, elements: Elements<'a>) -> &mut Self {
|
||||
pub fn declared<'a>(&mut self, element_type: RefType, elements: Elements<'a>) -> &mut Self {
|
||||
self.segment(ElementSegment {
|
||||
mode: ElementMode::Declared,
|
||||
element_type,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{encode_section, Encode, Section, SectionId, ValType};
|
||||
use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId};
|
||||
|
||||
/// An encoder for the table section.
|
||||
///
|
||||
|
@ -7,11 +7,11 @@ use crate::{encode_section, Encode, Section, SectionId, ValType};
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use wasm_encoder::{Module, TableSection, TableType, ValType};
|
||||
/// use wasm_encoder::{Module, TableSection, TableType, RefType};
|
||||
///
|
||||
/// let mut tables = TableSection::new();
|
||||
/// tables.table(TableType {
|
||||
/// element_type: ValType::FuncRef,
|
||||
/// element_type: RefType::FUNCREF,
|
||||
/// minimum: 128,
|
||||
/// maximum: None,
|
||||
/// });
|
||||
|
@ -49,6 +49,18 @@ impl TableSection {
|
|||
self.num_added += 1;
|
||||
self
|
||||
}
|
||||
|
||||
/// Define a table with an explicit initialization expression.
|
||||
///
|
||||
/// Note that this is part of the function-references proposal.
|
||||
pub fn table_with_init(&mut self, table_type: TableType, init: &ConstExpr) -> &mut Self {
|
||||
self.bytes.push(0x40);
|
||||
self.bytes.push(0x00);
|
||||
table_type.encode(&mut self.bytes);
|
||||
init.encode(&mut self.bytes);
|
||||
self.num_added += 1;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode for TableSection {
|
||||
|
@ -67,7 +79,7 @@ impl Section for TableSection {
|
|||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct TableType {
|
||||
/// The table's element type.
|
||||
pub element_type: ValType,
|
||||
pub element_type: RefType,
|
||||
/// Minimum size, in elements, of this table
|
||||
pub minimum: u32,
|
||||
/// Maximum size, in elements, of this table
|
||||
|
|
|
@ -2,41 +2,120 @@ use crate::{encode_section, Encode, Section, SectionId};
|
|||
|
||||
/// The type of a core WebAssembly value.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
#[repr(u8)]
|
||||
pub enum ValType {
|
||||
/// The `i32` type.
|
||||
I32 = 0x7F,
|
||||
I32,
|
||||
/// The `i64` type.
|
||||
I64 = 0x7E,
|
||||
I64,
|
||||
/// The `f32` type.
|
||||
F32 = 0x7D,
|
||||
F32,
|
||||
/// The `f64` type.
|
||||
F64 = 0x7C,
|
||||
F64,
|
||||
/// The `v128` type.
|
||||
///
|
||||
/// Part of the SIMD proposal.
|
||||
V128 = 0x7B,
|
||||
/// The `funcref` type.
|
||||
V128,
|
||||
/// A reference type.
|
||||
///
|
||||
/// Part of the reference types proposal when used anywhere other than a
|
||||
/// table's element type.
|
||||
FuncRef = 0x70,
|
||||
/// The `externref` type.
|
||||
///
|
||||
/// Part of the reference types proposal.
|
||||
ExternRef = 0x6F,
|
||||
/// The `funcref` and `externref` type fall into this category and the full
|
||||
/// generalization here is due to the implementation of the
|
||||
/// function-references proposal.
|
||||
Ref(RefType),
|
||||
}
|
||||
|
||||
impl From<ValType> for u8 {
|
||||
#[inline]
|
||||
fn from(t: ValType) -> u8 {
|
||||
t as u8
|
||||
}
|
||||
impl ValType {
|
||||
/// Alias for the `funcref` type in WebAssembly
|
||||
pub const FUNCREF: ValType = ValType::Ref(RefType::FUNCREF);
|
||||
/// Alias for the `externref` type in WebAssembly
|
||||
pub const EXTERNREF: ValType = ValType::Ref(RefType::EXTERNREF);
|
||||
}
|
||||
|
||||
impl Encode for ValType {
|
||||
fn encode(&self, sink: &mut Vec<u8>) {
|
||||
sink.push(*self as u8);
|
||||
match self {
|
||||
ValType::I32 => sink.push(0x7F),
|
||||
ValType::I64 => sink.push(0x7E),
|
||||
ValType::F32 => sink.push(0x7D),
|
||||
ValType::F64 => sink.push(0x7C),
|
||||
ValType::V128 => sink.push(0x7B),
|
||||
ValType::Ref(rt) => rt.encode(sink),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A reference type.
|
||||
///
|
||||
/// This is largely part of the function references proposal for WebAssembly but
|
||||
/// additionally is used by the `funcref` and `externref` types. The full
|
||||
/// generality of this type is only exercised with function-references.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct RefType {
|
||||
pub nullable: bool,
|
||||
pub heap_type: HeapType,
|
||||
}
|
||||
|
||||
impl RefType {
|
||||
/// Alias for the `funcref` type in WebAssembly
|
||||
pub const FUNCREF: RefType = RefType {
|
||||
nullable: true,
|
||||
heap_type: HeapType::Func,
|
||||
};
|
||||
|
||||
/// Alias for the `externref` type in WebAssembly
|
||||
pub const EXTERNREF: RefType = RefType {
|
||||
nullable: true,
|
||||
heap_type: HeapType::Extern,
|
||||
};
|
||||
}
|
||||
|
||||
impl Encode for RefType {
|
||||
fn encode(&self, sink: &mut Vec<u8>) {
|
||||
if self.nullable {
|
||||
// Favor the original encodings of `funcref` and `externref` where
|
||||
// possible
|
||||
match self.heap_type {
|
||||
HeapType::Func => return sink.push(0x70),
|
||||
HeapType::Extern => return sink.push(0x6f),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if self.nullable {
|
||||
sink.push(0x6C);
|
||||
} else {
|
||||
sink.push(0x6B);
|
||||
}
|
||||
self.heap_type.encode(sink);
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RefType> for ValType {
|
||||
fn from(ty: RefType) -> ValType {
|
||||
ValType::Ref(ty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Part of the function references proposal.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
pub enum HeapType {
|
||||
/// A function reference. When nullable, equivalent to `funcref`
|
||||
Func,
|
||||
/// An extern reference. When nullable, equivalent to `externref`
|
||||
Extern,
|
||||
/// A reference to a particular index in a table.
|
||||
TypedFunc(u32),
|
||||
}
|
||||
|
||||
impl Encode for HeapType {
|
||||
fn encode(&self, sink: &mut Vec<u8>) {
|
||||
match self {
|
||||
HeapType::Func => sink.push(0x70),
|
||||
HeapType::Extern => sink.push(0x6F),
|
||||
// Note that this is encoded as a signed type rather than unsigned
|
||||
// as it's decoded as an s33
|
||||
HeapType::TypedFunc(i) => i64::from(*i).encode(sink),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,9 +170,9 @@ impl TypeSection {
|
|||
|
||||
self.bytes.push(0x60);
|
||||
params.len().encode(&mut self.bytes);
|
||||
self.bytes.extend(params.map(u8::from));
|
||||
params.for_each(|p| p.encode(&mut self.bytes));
|
||||
results.len().encode(&mut self.bytes);
|
||||
self.bytes.extend(results.map(u8::from));
|
||||
results.for_each(|p| p.encode(&mut self.bytes));
|
||||
self.num_added += 1;
|
||||
self
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"b99b0bed493c2364e7dd63d34be429a7858d1066b19b59bc0fd9cb5d51d9b5f4","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"9202d01e78acf04e38e23e162a91c20ece8968f6172c87bfa6f18bf0b3f27d74","benches/corpus.rs":"2df29556be0799f0cb1f32c8d0ae5ba0c4b9815cf4d59a8b71744d926c0693a0","src/component.rs":"8cb11020b03ef2f5b8a78bd71694334362df1777541ba5247c430f0dd7ac1673","src/component/encode.rs":"09eddb96b5b607a87673714208c6d43b247ec4870168661d27d2c3ce92c43afd","src/config.rs":"3d33dea22d53081504e13fea4b5c99898624f26ed03013a831bae0c9759823fc","src/core.rs":"1412d51c92f998054fd87381becd433641f0261407796cec28372c1ae3c3f873","src/core/code_builder.rs":"5c36773e5c5a43ceb1dcd5243a1e64a392021ed890c6953a4c789018fff3df11","src/core/code_builder/no_traps.rs":"e004030a038916e748b716e0b08f340fc8d4451cd7057416f6299c870cc01156","src/core/encode.rs":"b8599fc907573827ff5e85108421a9c74a031fc57de502c22e021bb9986af58c","src/core/terminate.rs":"d24af5206a13aee7d6a6ea900ccdf088c09d053c36026cf1607cc38c972b3ba9","src/lib.rs":"77ed926d64d325a73613f1c307db39c65c428a1eafae114033c73a60da586fd3","tests/component.rs":"54c69ebdda583207f9f0467a600ee0ca87fbee6b365e97ec3deff7b46bd6af06","tests/core.rs":"b3f51e9c81685f1ee23a01df3f1f48876f416d33db4aeb1e6609aaba9d7bb77a"},"package":"411278ee8e89067a252a3a6d6d578038251f9c0a1d4c088adf4162ad13e97b04"}
|
||||
{"files":{"Cargo.toml":"3fab85439f91b5b0dfc20abd90cabf4a9f29ab1c422ab1308851c344302d32b3","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"9202d01e78acf04e38e23e162a91c20ece8968f6172c87bfa6f18bf0b3f27d74","benches/corpus.rs":"2df29556be0799f0cb1f32c8d0ae5ba0c4b9815cf4d59a8b71744d926c0693a0","src/component.rs":"32f93aac210f70fbc3f870c400993f4e7ff780ca6e111453a4dc4545906887e8","src/component/encode.rs":"09eddb96b5b607a87673714208c6d43b247ec4870168661d27d2c3ce92c43afd","src/config.rs":"3d33dea22d53081504e13fea4b5c99898624f26ed03013a831bae0c9759823fc","src/core.rs":"40949add77c2b90e9f3fc0ce6862a7c83ac03d5dd9babde5abee536d6fe074e6","src/core/code_builder.rs":"60e407a758ff58aafdcf4eb4e9141aca2ab7c7fe09d6644bc6e31043f88d0d69","src/core/code_builder/no_traps.rs":"e595dbde06551f5f8b23e03cfac0634beacab08e6243c66d6ffda95079212b24","src/core/encode.rs":"b4cc82895e3c3afe26e2e62bbdd63c44e7c1f091133e49f0eaf7e7ec22400e40","src/core/terminate.rs":"d24af5206a13aee7d6a6ea900ccdf088c09d053c36026cf1607cc38c972b3ba9","src/lib.rs":"77ed926d64d325a73613f1c307db39c65c428a1eafae114033c73a60da586fd3","tests/component.rs":"54c69ebdda583207f9f0467a600ee0ca87fbee6b365e97ec3deff7b46bd6af06","tests/core.rs":"da9e27e7057a7cd9435666d4bd4d57cec03b0d5d74bad289373db7beb8a2e1a6"},"package":"549cb78be46f43ad6746402871336cb6a989127fb847e93eb6ba0817647485a6"}
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "wasm-smith"
|
||||
version = "0.12.2"
|
||||
version = "0.12.5"
|
||||
authors = ["Nick Fitzgerald <fitzgen@gmail.com>"]
|
||||
exclude = ["/benches/corpus"]
|
||||
description = "A WebAssembly test case generator"
|
||||
|
@ -50,10 +50,10 @@ features = ["derive"]
|
|||
optional = true
|
||||
|
||||
[dependencies.wasm-encoder]
|
||||
version = "0.23.0"
|
||||
version = "0.25.0"
|
||||
|
||||
[dependencies.wasmparser]
|
||||
version = "0.100.0"
|
||||
version = "0.102.0"
|
||||
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.3.3"
|
||||
|
|
|
@ -1868,7 +1868,7 @@ fn inverse_scalar_canonical_abi_for(
|
|||
.cloned(),
|
||||
ValType::F32 => Ok(ComponentValType::Primitive(PrimitiveValType::Float32)),
|
||||
ValType::F64 => Ok(ComponentValType::Primitive(PrimitiveValType::Float64)),
|
||||
ValType::V128 | ValType::FuncRef | ValType::ExternRef => {
|
||||
ValType::V128 | ValType::Ref(_) => {
|
||||
unreachable!("not used in canonical ABI")
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ use std::marker;
|
|||
use std::ops::Range;
|
||||
use std::rc::Rc;
|
||||
use std::str::{self, FromStr};
|
||||
use wasm_encoder::{BlockType, ConstExpr, ExportKind, ValType};
|
||||
use wasm_encoder::{BlockType, ConstExpr, ExportKind, HeapType, RefType, ValType};
|
||||
pub(crate) use wasm_encoder::{GlobalType, MemoryType, TableType};
|
||||
|
||||
// NB: these constants are used to control the rate at which various events
|
||||
|
@ -285,7 +285,7 @@ pub(crate) struct TagType {
|
|||
#[derive(Debug)]
|
||||
struct ElementSegment {
|
||||
kind: ElementKind,
|
||||
ty: ValType,
|
||||
ty: RefType,
|
||||
items: Elements,
|
||||
}
|
||||
|
||||
|
@ -655,7 +655,7 @@ impl Module {
|
|||
|
||||
wasmparser::TypeRef::Table(table_ty) => {
|
||||
let table_ty = TableType {
|
||||
element_type: convert_type(table_ty.element_type),
|
||||
element_type: convert_reftype(table_ty.element_type),
|
||||
minimum: table_ty.initial,
|
||||
maximum: table_ty.maximum,
|
||||
};
|
||||
|
@ -879,14 +879,13 @@ impl Module {
|
|||
ValType::F32 => ConstExpr::f32_const(u.arbitrary()?),
|
||||
ValType::F64 => ConstExpr::f64_const(u.arbitrary()?),
|
||||
ValType::V128 => ConstExpr::v128_const(u.arbitrary()?),
|
||||
ValType::ExternRef => ConstExpr::ref_null(ValType::ExternRef),
|
||||
ValType::FuncRef => {
|
||||
if num_funcs > 0 && u.arbitrary()? {
|
||||
ValType::Ref(ty) => {
|
||||
assert!(ty.nullable);
|
||||
if ty.heap_type == HeapType::Func && num_funcs > 0 && u.arbitrary()? {
|
||||
let func = u.int_in_range(0..=num_funcs - 1)?;
|
||||
return Ok(GlobalInitExpr::FuncRef(func));
|
||||
} else {
|
||||
ConstExpr::ref_null(ValType::FuncRef)
|
||||
}
|
||||
ConstExpr::ref_null(ty.heap_type)
|
||||
}
|
||||
}))
|
||||
}));
|
||||
|
@ -1073,7 +1072,7 @@ impl Module {
|
|||
continue;
|
||||
}
|
||||
|
||||
let dst = if ty.element_type == ValType::FuncRef {
|
||||
let dst = if ty.element_type == RefType::FUNCREF {
|
||||
&mut funcrefs
|
||||
} else {
|
||||
&mut externrefs
|
||||
|
@ -1081,7 +1080,7 @@ impl Module {
|
|||
let minimum = ty.minimum;
|
||||
// If the first table is a funcref table then it's a candidate for
|
||||
// the MVP encoding of element segments.
|
||||
if i == 0 && ty.element_type == ValType::FuncRef {
|
||||
if i == 0 && ty.element_type == RefType::FUNCREF {
|
||||
dst.push(Box::new(move |u| {
|
||||
arbitrary_active_elem(u, minimum, None, disallow_traps, ty)
|
||||
}));
|
||||
|
@ -1105,10 +1104,10 @@ impl Module {
|
|||
|
||||
let mut choices = Vec::new();
|
||||
if !funcrefs.is_empty() {
|
||||
choices.push((&funcrefs, ValType::FuncRef));
|
||||
choices.push((&funcrefs, RefType::FUNCREF));
|
||||
}
|
||||
if !externrefs.is_empty() {
|
||||
choices.push((&externrefs, ValType::ExternRef));
|
||||
choices.push((&externrefs, RefType::EXTERNREF));
|
||||
}
|
||||
|
||||
if choices.is_empty() {
|
||||
|
@ -1133,13 +1132,13 @@ impl Module {
|
|||
// Pick whether we're going to use expression elements or
|
||||
// indices. Note that externrefs must use expressions,
|
||||
// and functions without reference types must use indices.
|
||||
let items = if ty == ValType::ExternRef
|
||||
let items = if ty == RefType::EXTERNREF
|
||||
|| (self.config.reference_types_enabled() && u.arbitrary()?)
|
||||
{
|
||||
let mut init = vec![];
|
||||
arbitrary_loop(u, self.config.min_elements(), max, |u| {
|
||||
init.push(
|
||||
if ty == ValType::ExternRef || func_max == 0 || u.arbitrary()? {
|
||||
if ty == RefType::EXTERNREF || func_max == 0 || u.arbitrary()? {
|
||||
None
|
||||
} else {
|
||||
Some(u.int_in_range(0..=func_max - 1)?)
|
||||
|
@ -1381,8 +1380,8 @@ pub(crate) fn configured_valtypes(config: &dyn Config) -> Vec<ValType> {
|
|||
valtypes.push(ValType::V128);
|
||||
}
|
||||
if config.reference_types_enabled() {
|
||||
valtypes.push(ValType::ExternRef);
|
||||
valtypes.push(ValType::FuncRef);
|
||||
valtypes.push(ValType::EXTERNREF);
|
||||
valtypes.push(ValType::FUNCREF);
|
||||
}
|
||||
valtypes
|
||||
}
|
||||
|
@ -1431,9 +1430,9 @@ pub(crate) fn arbitrary_table_type(u: &mut Unstructured, config: &dyn Config) ->
|
|||
}
|
||||
Ok(TableType {
|
||||
element_type: if config.reference_types_enabled() {
|
||||
*u.choose(&[ValType::FuncRef, ValType::ExternRef])?
|
||||
*u.choose(&[RefType::FUNCREF, RefType::EXTERNREF])?
|
||||
} else {
|
||||
ValType::FuncRef
|
||||
RefType::FUNCREF
|
||||
},
|
||||
minimum,
|
||||
maximum,
|
||||
|
@ -1634,8 +1633,18 @@ fn convert_type(parsed_type: wasmparser::ValType) -> ValType {
|
|||
F32 => ValType::F32,
|
||||
F64 => ValType::F64,
|
||||
V128 => ValType::V128,
|
||||
FuncRef => ValType::FuncRef,
|
||||
ExternRef => ValType::ExternRef,
|
||||
Ref(ty) => ValType::Ref(convert_reftype(ty)),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_reftype(ty: wasmparser::RefType) -> RefType {
|
||||
wasm_encoder::RefType {
|
||||
nullable: ty.nullable,
|
||||
heap_type: match ty.heap_type {
|
||||
wasmparser::HeapType::Func => wasm_encoder::HeapType::Func,
|
||||
wasmparser::HeapType::Extern => wasm_encoder::HeapType::Extern,
|
||||
wasmparser::HeapType::TypedFunc(i) => wasm_encoder::HeapType::TypedFunc(i.into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use arbitrary::{Result, Unstructured};
|
|||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::convert::TryFrom;
|
||||
use std::rc::Rc;
|
||||
use wasm_encoder::{BlockType, MemArg};
|
||||
use wasm_encoder::{BlockType, MemArg, RefType};
|
||||
mod no_traps;
|
||||
|
||||
macro_rules! instructions {
|
||||
|
@ -350,10 +350,10 @@ instructions! {
|
|||
(Some(simd_v128_v128_on_stack), i8x16_swizzle, Vector),
|
||||
(Some(simd_v128_v128_on_stack_relaxed), i8x16_relaxed_swizzle, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack), v128_bitselect, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), i8x16_laneselect, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), i16x8_laneselect, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), i32x4_laneselect, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), i64x2_laneselect, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), i8x16_relaxed_laneselect, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), i16x8_relaxed_laneselect, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), i32x4_relaxed_laneselect, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), i64x2_relaxed_laneselect, Vector),
|
||||
(Some(simd_v128_v128_on_stack), i8x16_eq, Vector),
|
||||
(Some(simd_v128_v128_on_stack), i8x16_ne, Vector),
|
||||
(Some(simd_v128_v128_on_stack), i8x16_lt_s, Vector),
|
||||
|
@ -544,22 +544,21 @@ instructions! {
|
|||
(Some(simd_v128_on_stack), f64x2_convert_low_i32x4u, Vector),
|
||||
(Some(simd_v128_on_stack), f32x4_demote_f64x2_zero, Vector),
|
||||
(Some(simd_v128_on_stack), f64x2_promote_low_f32x4, Vector),
|
||||
(Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_sat_f32x4s, Vector),
|
||||
(Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_sat_f32x4u, Vector),
|
||||
(Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_sat_f64x2s_zero, Vector),
|
||||
(Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_sat_f64x2u_zero, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), f32x4_fma, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), f32x4_fnma, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), f64x2_fma, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), f64x2_fnma, Vector),
|
||||
(Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_f32x4s, Vector),
|
||||
(Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_f32x4u, Vector),
|
||||
(Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_f64x2s_zero, Vector),
|
||||
(Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_f64x2u_zero, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), f32x4_relaxed_madd, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), f32x4_relaxed_nmadd, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), f64x2_relaxed_madd, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), f64x2_relaxed_nmadd, Vector),
|
||||
(Some(simd_v128_v128_on_stack_relaxed), f32x4_relaxed_min, Vector),
|
||||
(Some(simd_v128_v128_on_stack_relaxed), f32x4_relaxed_max, Vector),
|
||||
(Some(simd_v128_v128_on_stack_relaxed), f64x2_relaxed_min, Vector),
|
||||
(Some(simd_v128_v128_on_stack_relaxed), f64x2_relaxed_max, Vector),
|
||||
(Some(simd_v128_v128_on_stack_relaxed), i16x8_relaxed_q15mulr_s, Vector),
|
||||
(Some(simd_v128_v128_on_stack_relaxed), i16x8_dot_i8x16_i7x16_s, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), i32x4_dot_i8x16_i7x16_add_s, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), f32x4_relaxed_dot_bf16x8_add_f32x4, Vector),
|
||||
(Some(simd_v128_v128_on_stack_relaxed), i16x8_relaxed_dot_i8x16_i7x16_s, Vector),
|
||||
(Some(simd_v128_v128_v128_on_stack_relaxed), i32x4_relaxed_dot_i8x16_i7x16_add_s, Vector),
|
||||
}
|
||||
|
||||
pub(crate) struct CodeBuilderAllocations {
|
||||
|
@ -694,7 +693,7 @@ impl CodeBuilderAllocations {
|
|||
let mut table_tys = Vec::new();
|
||||
for (i, table) in module.tables.iter().enumerate() {
|
||||
table_tys.push(table.element_type);
|
||||
if table.element_type == ValType::FuncRef {
|
||||
if table.element_type == RefType::FUNCREF {
|
||||
funcref_tables.push(i as u32);
|
||||
}
|
||||
}
|
||||
|
@ -1107,8 +1106,10 @@ fn arbitrary_val(ty: ValType, u: &mut Unstructured<'_>) -> Instruction {
|
|||
ValType::F32 => Instruction::F32Const(u.arbitrary().unwrap_or(0.0)),
|
||||
ValType::F64 => Instruction::F64Const(u.arbitrary().unwrap_or(0.0)),
|
||||
ValType::V128 => Instruction::V128Const(u.arbitrary().unwrap_or(0)),
|
||||
ValType::ExternRef => Instruction::RefNull(ValType::ExternRef),
|
||||
ValType::FuncRef => Instruction::RefNull(ValType::FuncRef),
|
||||
ValType::Ref(ty) => {
|
||||
assert!(ty.nullable);
|
||||
Instruction::RefNull(ty.heap_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1789,9 +1790,7 @@ fn select(
|
|||
let ty = t.or(u);
|
||||
builder.allocs.operands.push(ty);
|
||||
match ty {
|
||||
Some(ty @ ValType::ExternRef) | Some(ty @ ValType::FuncRef) => {
|
||||
instructions.push(Instruction::TypedSelect(ty))
|
||||
}
|
||||
Some(ty @ ValType::Ref(_)) => instructions.push(Instruction::TypedSelect(ty)),
|
||||
Some(ValType::I32) | Some(ValType::I64) | Some(ValType::F32) | Some(ValType::F64)
|
||||
| Some(ValType::V128) | None => instructions.push(Instruction::Select),
|
||||
}
|
||||
|
@ -4510,9 +4509,9 @@ fn ref_null(
|
|||
builder: &mut CodeBuilder,
|
||||
instructions: &mut Vec<Instruction>,
|
||||
) -> Result<()> {
|
||||
let ty = *u.choose(&[ValType::ExternRef, ValType::FuncRef])?;
|
||||
builder.push_operands(&[ty]);
|
||||
instructions.push(Instruction::RefNull(ty));
|
||||
let ty = *u.choose(&[RefType::EXTERNREF, RefType::FUNCREF])?;
|
||||
builder.push_operands(&[ty.into()]);
|
||||
instructions.push(Instruction::RefNull(ty.heap_type));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -4528,7 +4527,7 @@ fn ref_func(
|
|||
instructions: &mut Vec<Instruction>,
|
||||
) -> Result<()> {
|
||||
let i = *u.choose(&builder.allocs.referenced_functions)?;
|
||||
builder.push_operands(&[ValType::FuncRef]);
|
||||
builder.push_operands(&[ValType::FUNCREF]);
|
||||
instructions.push(Instruction::RefFunc(i));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -4536,7 +4535,7 @@ fn ref_func(
|
|||
#[inline]
|
||||
fn ref_is_null_valid(module: &Module, builder: &mut CodeBuilder) -> bool {
|
||||
module.config.reference_types_enabled()
|
||||
&& (builder.type_on_stack(ValType::ExternRef) || builder.type_on_stack(ValType::FuncRef))
|
||||
&& (builder.type_on_stack(ValType::EXTERNREF) || builder.type_on_stack(ValType::FUNCREF))
|
||||
}
|
||||
|
||||
fn ref_is_null(
|
||||
|
@ -4556,9 +4555,9 @@ fn table_fill_valid(module: &Module, builder: &mut CodeBuilder) -> bool {
|
|||
module.config.reference_types_enabled()
|
||||
&& module.config.bulk_memory_enabled()
|
||||
&& !module.config.disallow_traps() // Non-trapping table fill generation not yet implemented
|
||||
&& [ValType::ExternRef, ValType::FuncRef].iter().any(|ty| {
|
||||
&& [ValType::EXTERNREF, ValType::FUNCREF].iter().any(|ty| {
|
||||
builder.types_on_stack(&[ValType::I32, *ty, ValType::I32])
|
||||
&& module.tables.iter().any(|t| t.element_type == *ty)
|
||||
&& module.tables.iter().any(|t| *ty == t.element_type.into())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -4580,9 +4579,9 @@ fn table_fill(
|
|||
fn table_set_valid(module: &Module, builder: &mut CodeBuilder) -> bool {
|
||||
module.config.reference_types_enabled()
|
||||
&& !module.config.disallow_traps() // Non-trapping table.set generation not yet implemented
|
||||
&& [ValType::ExternRef, ValType::FuncRef].iter().any(|ty| {
|
||||
&& [ValType::EXTERNREF, ValType::FUNCREF].iter().any(|ty| {
|
||||
builder.types_on_stack(&[ValType::I32, *ty])
|
||||
&& module.tables.iter().any(|t| t.element_type == *ty)
|
||||
&& module.tables.iter().any(|t| *ty == t.element_type.into())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -4616,7 +4615,7 @@ fn table_get(
|
|||
builder.pop_operands(&[ValType::I32]);
|
||||
let idx = u.int_in_range(0..=module.tables.len() - 1)?;
|
||||
let ty = module.tables[idx].element_type;
|
||||
builder.push_operands(&[ty]);
|
||||
builder.push_operands(&[ty.into()]);
|
||||
instructions.push(Instruction::TableGet(idx as u32));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -4641,9 +4640,9 @@ fn table_size(
|
|||
#[inline]
|
||||
fn table_grow_valid(module: &Module, builder: &mut CodeBuilder) -> bool {
|
||||
module.config.reference_types_enabled()
|
||||
&& [ValType::ExternRef, ValType::FuncRef].iter().any(|ty| {
|
||||
&& [ValType::EXTERNREF, ValType::FUNCREF].iter().any(|ty| {
|
||||
builder.types_on_stack(&[*ty, ValType::I32])
|
||||
&& module.tables.iter().any(|t| t.element_type == *ty)
|
||||
&& module.tables.iter().any(|t| *ty == t.element_type.into())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -4732,17 +4731,17 @@ fn elem_drop(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn pop_reference_type(builder: &mut CodeBuilder) -> ValType {
|
||||
if builder.type_on_stack(ValType::ExternRef) {
|
||||
builder.pop_operands(&[ValType::ExternRef]);
|
||||
ValType::ExternRef
|
||||
fn pop_reference_type(builder: &mut CodeBuilder) -> RefType {
|
||||
if builder.type_on_stack(ValType::EXTERNREF) {
|
||||
builder.pop_operands(&[ValType::EXTERNREF]);
|
||||
RefType::EXTERNREF
|
||||
} else {
|
||||
builder.pop_operands(&[ValType::FuncRef]);
|
||||
ValType::FuncRef
|
||||
builder.pop_operands(&[ValType::FUNCREF]);
|
||||
RefType::FUNCREF
|
||||
}
|
||||
}
|
||||
|
||||
fn table_index(ty: ValType, u: &mut Unstructured, module: &Module) -> Result<u32> {
|
||||
fn table_index(ty: RefType, u: &mut Unstructured, module: &Module) -> Result<u32> {
|
||||
let tables = module
|
||||
.tables
|
||||
.iter()
|
||||
|
@ -5332,32 +5331,25 @@ simd_unop!(F32x4DemoteF64x2Zero, f32x4_demote_f64x2_zero);
|
|||
simd_unop!(F64x2PromoteLowF32x4, f64x2_promote_low_f32x4);
|
||||
simd_ternop!(V128Bitselect, v128_bitselect);
|
||||
simd_binop!(I8x16RelaxedSwizzle, i8x16_relaxed_swizzle);
|
||||
simd_unop!(I32x4RelaxedTruncSatF32x4S, i32x4_relaxed_trunc_sat_f32x4s);
|
||||
simd_unop!(I32x4RelaxedTruncSatF32x4U, i32x4_relaxed_trunc_sat_f32x4u);
|
||||
simd_unop!(
|
||||
I32x4RelaxedTruncSatF64x2SZero,
|
||||
i32x4_relaxed_trunc_sat_f64x2s_zero
|
||||
);
|
||||
simd_unop!(
|
||||
I32x4RelaxedTruncSatF64x2UZero,
|
||||
i32x4_relaxed_trunc_sat_f64x2u_zero
|
||||
);
|
||||
simd_ternop!(F32x4RelaxedFma, f32x4_fma);
|
||||
simd_ternop!(F32x4RelaxedFnma, f32x4_fnma);
|
||||
simd_ternop!(F64x2RelaxedFma, f64x2_fma);
|
||||
simd_ternop!(F64x2RelaxedFnma, f64x2_fnma);
|
||||
simd_ternop!(I8x16RelaxedLaneselect, i8x16_laneselect);
|
||||
simd_ternop!(I16x8RelaxedLaneselect, i16x8_laneselect);
|
||||
simd_ternop!(I32x4RelaxedLaneselect, i32x4_laneselect);
|
||||
simd_ternop!(I64x2RelaxedLaneselect, i64x2_laneselect);
|
||||
simd_unop!(I32x4RelaxedTruncF32x4S, i32x4_relaxed_trunc_f32x4s);
|
||||
simd_unop!(I32x4RelaxedTruncF32x4U, i32x4_relaxed_trunc_f32x4u);
|
||||
simd_unop!(I32x4RelaxedTruncF64x2SZero, i32x4_relaxed_trunc_f64x2s_zero);
|
||||
simd_unop!(I32x4RelaxedTruncF64x2UZero, i32x4_relaxed_trunc_f64x2u_zero);
|
||||
simd_ternop!(F32x4RelaxedMadd, f32x4_relaxed_madd);
|
||||
simd_ternop!(F32x4RelaxedNmadd, f32x4_relaxed_nmadd);
|
||||
simd_ternop!(F64x2RelaxedMadd, f64x2_relaxed_madd);
|
||||
simd_ternop!(F64x2RelaxedNmadd, f64x2_relaxed_nmadd);
|
||||
simd_ternop!(I8x16RelaxedLaneselect, i8x16_relaxed_laneselect);
|
||||
simd_ternop!(I16x8RelaxedLaneselect, i16x8_relaxed_laneselect);
|
||||
simd_ternop!(I32x4RelaxedLaneselect, i32x4_relaxed_laneselect);
|
||||
simd_ternop!(I64x2RelaxedLaneselect, i64x2_relaxed_laneselect);
|
||||
simd_binop!(F32x4RelaxedMin, f32x4_relaxed_min);
|
||||
simd_binop!(F32x4RelaxedMax, f32x4_relaxed_max);
|
||||
simd_binop!(F64x2RelaxedMin, f64x2_relaxed_min);
|
||||
simd_binop!(F64x2RelaxedMax, f64x2_relaxed_max);
|
||||
simd_binop!(I16x8RelaxedQ15mulrS, i16x8_relaxed_q15mulr_s);
|
||||
simd_binop!(I16x8DotI8x16I7x16S, i16x8_dot_i8x16_i7x16_s);
|
||||
simd_ternop!(I32x4DotI8x16I7x16AddS, i32x4_dot_i8x16_i7x16_add_s);
|
||||
simd_binop!(I16x8RelaxedDotI8x16I7x16S, i16x8_relaxed_dot_i8x16_i7x16_s);
|
||||
simd_ternop!(
|
||||
F32x4RelaxedDotBf16x8AddF32x4,
|
||||
f32x4_relaxed_dot_bf16x8_add_f32x4
|
||||
I32x4RelaxedDotI8x16I7x16AddS,
|
||||
i32x4_relaxed_dot_i8x16_i7x16_add_s
|
||||
);
|
||||
|
|
|
@ -399,7 +399,10 @@ fn dummy_value_inst<'a>(ty: ValType) -> Instruction<'a> {
|
|||
ValType::F32 => Instruction::F32Const(0.0),
|
||||
ValType::F64 => Instruction::F64Const(0.0),
|
||||
ValType::V128 => Instruction::V128Const(0),
|
||||
ValType::FuncRef | ValType::ExternRef => Instruction::RefNull(ty),
|
||||
ValType::Ref(ty) => {
|
||||
assert!(ty.nullable);
|
||||
Instruction::RefNull(ty.heap_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -636,6 +639,6 @@ fn size_of_type_in_memory(ty: ValType) -> u64 {
|
|||
ValType::F32 => 4,
|
||||
ValType::F64 => 8,
|
||||
ValType::V128 => 16,
|
||||
ValType::FuncRef | ValType::ExternRef => panic!("not a memory type"),
|
||||
ValType::Ref(_) => panic!("not a memory type"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,10 +152,10 @@ impl Module {
|
|||
// TODO(nagisa): generate global.get of imported ref globals too.
|
||||
match e {
|
||||
Some(i) => match el.ty {
|
||||
ValType::FuncRef => wasm_encoder::ConstExpr::ref_func(*i),
|
||||
RefType::FUNCREF => wasm_encoder::ConstExpr::ref_func(*i),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => wasm_encoder::ConstExpr::ref_null(el.ty),
|
||||
None => wasm_encoder::ConstExpr::ref_null(el.ty.heap_type),
|
||||
}
|
||||
}));
|
||||
wasm_encoder::Elements::Expressions(&exps)
|
||||
|
|
|
@ -151,7 +151,7 @@ fn smoke_test_imports_config() {
|
|||
*seen = true
|
||||
}
|
||||
(Some((seen, I::Table(t))), TypeRef::Table(tt))
|
||||
if *t == tt.element_type =>
|
||||
if *t == ValType::Ref(tt.element_type) =>
|
||||
{
|
||||
*seen = true
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ fn import_config(
|
|||
("env", "pipo", Func(&[I32], &[I32])),
|
||||
("env", "popo", Func(&[], &[I32, I32])),
|
||||
("env", "mem", Memory),
|
||||
("env", "tbl", Table(FuncRef)),
|
||||
("env", "tbl", Table(ValType::FUNCREF)),
|
||||
("vars", "g", Global(I64)),
|
||||
("tags", "tag1", Tag(&[I32])),
|
||||
]
|
||||
|
@ -300,6 +300,7 @@ fn parser_features_from_config(config: &impl Config) -> WasmFeatures {
|
|||
floats: true,
|
||||
extended_const: false,
|
||||
component_model: false,
|
||||
function_references: false,
|
||||
memory_control: false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.lock":"430baae8cea83da0463cc95ec996de0437beb083ac5173cf876f6d7d12103429","Cargo.toml":"9261b35e9cdb0ee22b78849c060aafef729e356884aa6186be48acf8ca9fe015","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"1c3b4f8db61a673ee2f7dc66118b1008ce8d1a7d0f5197fbe87f1271b23de3bd","benches/benchmark.rs":"09254d9d4d19ec102e1e19ee025f0542b9b2b84e014adc49e51e9024274301ac","examples/simple.rs":"e9eb076367cc0932e2a32651372defa4a27ef800f47fad28c0ef840ba8ea7e08","src/binary_reader.rs":"84a18c2955ce3a76ebdc1eb1aa56087a97e9f0c24e2c2b0598078778ccae73b7","src/lib.rs":"2ebd0a6222060c7ae306b641ce1d11cbec389c3d1eda1b3219a53d80452e19e1","src/limits.rs":"f9590aba36c682a16b9036a151cd1140393624e54c7b4b190487639923b15a52","src/parser.rs":"b65b995296ed03a5b4d31c6459f2f3430ff685e50fec397c44f91b1364de5aaf","src/readers.rs":"406bf0cf694ed364c9c53cd25eb27a8e3fa97d099994f3e2a640747c49abf74b","src/readers/component.rs":"c259628ca3f09ff904f7e920aeec261b657f7a197c99b520a6a7d3e918b9fb3b","src/readers/component/aliases.rs":"72f3339cb452c1b055bd080281fe4923d132c280da112fcd1182594811b87494","src/readers/component/canonicals.rs":"c36e9bffc2e1ed752586189903eec77ea9897ae265e020096a9b92c467be26d9","src/readers/component/exports.rs":"f2c76e4be5045f1d099fd89dedf20e2f4817f046ea1e64bde7ca8f3ea9b2cdc6","src/readers/component/imports.rs":"725a688f2ab4306dbb421fe92ffff9373e3c88632557e352529f297bb2b96e0e","src/readers/component/instances.rs":"bca614178da3337e8c71a6ec431f12157a8cccc15411a0222bbc0106926a3ad5","src/readers/component/names.rs":"3f5dac9db8668b18cd6721cd780e6aba9b223b404c9d1173d09efe4e6b4d3a8a","src/readers/component/start.rs":"8e1e5d8aa5ece26d42251449cadcce0546c4d995f1641941b8a31ed4bc6ac761","src/readers/component/types.rs":"878fdf8f3d6a1c1387fd92b34838d8e79cee039710366bd5ea6739448d468a7a","src/readers/core.rs":"b1dbe0ffe61af1e6da4104de687009bcaa71fd3137300896159abbcfd903b800","src/readers/core/code.rs":"e14884ac83f5644c813c8196aabcb6a5539d3d2860f251c064481f61b0e0ffed","src/readers/core/custom.rs":"f80d3a994e8778a912319834228cbb772c65a4b6b1f25b41fe00d220d388831f","src/readers/core/data.rs":"c1fcda7b548b15be40b3dd1f667d97c30c543867f2dc4734b590846beefe3ae3","src/readers/core/elements.rs":"f3ed0c28b044f1fe51a576e3b5baf93f5aa896e7fefd8432eaf14b59073eb7f6","src/readers/core/exports.rs":"50dc1ee51b73f03f24077f7c290bca756966563cedbad9e49d735d60f60c91db","src/readers/core/functions.rs":"b5bbc7f7b7a429187376f63c695a9f1cbf92e515dba840ac876fa60f7290da34","src/readers/core/globals.rs":"d23f99a3adc9593652a5efd4dc81e8f014f57e776b49717dabbdcd0a811a96b1","src/readers/core/imports.rs":"4d247e8cac0b3cef7425d93f7a7f2412b2ae8979da944080d565415499e27e87","src/readers/core/init.rs":"ec6717063b0b7f2e9aa17ae52083019cee52594bf5a8b6858f2d77b10d7a0639","src/readers/core/memories.rs":"351f816d663b7d17546dc3b19ce0e43f406ce743289219a3758f7c837903fa6d","src/readers/core/names.rs":"408ebf052170bf0dc874b3158bb31089a891c3735cb35df2976e0b1e9791febb","src/readers/core/operators.rs":"46e927f6db9db9097217c5485da3a7b89e638730def809d177897f39356f5f52","src/readers/core/producers.rs":"4b42b7e1c9e22e7e2913d9da2291b491dc2d4fea417503d7ce99ad33c7beb439","src/readers/core/tables.rs":"87f11101c81c53ccbe5b112c1b49e008ebc651c6d18cd80a1bcd995051193cdf","src/readers/core/tags.rs":"c1dcfeb973195da9708549bcc2df4dd8ff282fe802c15a603bebc8a856f70949","src/readers/core/types.rs":"aa8cf5a56f5b2ad5155ab110ea1058a7f9d72729c0aac4bc87d870267949b9f8","src/resources.rs":"f87a31420b2e7f377e4ffe16d9d9eb23abbb377e35a75756425941aa707dc775","src/validator.rs":"e1e93bf6bfdfc5ec9d157c3cbb30ff704e4aa4e68911d0372e4bfe017b30d24b","src/validator/component.rs":"c91c15defdb84aeb73b356803df62cb8850776e6ecfbec858104fc67c12cd65a","src/validator/core.rs":"628bee96b2e3520f125ce0073f9ff9440320d96f9c5e6f4a13d667202270311b","src/validator/func.rs":"d98940cc1210bea6acbea514face78e23f8357ad3746c920fb32d17f169ba9dc","src/validator/operators.rs":"7b325c2e0e40dfc378cbfcf5f5c2f292de64a652ed7385f493a722e16dc8d392","src/validator/types.rs":"4f0edbe37c12e0c030069106437f38797f3f4e8af1312420b53de5f620b0a4f8"},"package":"64b20236ab624147dfbb62cf12a19aaf66af0e41b8398838b66e997d07d269d4"}
|
||||
{"files":{"Cargo.lock":"ef76d24da3e4c9b0e0034844c4d3fa21f84ddb56af9f3134222046aaf26a48d3","Cargo.toml":"f1f05638e3da3d7304ccb0a41ef0a9889224bc5dc92352c634a553c6fa27d4bd","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"1c3b4f8db61a673ee2f7dc66118b1008ce8d1a7d0f5197fbe87f1271b23de3bd","benches/benchmark.rs":"b8417fbd86058b76f3ff15426075f9afee25b9f90155bbd9a2d774f4bad0af04","examples/simple.rs":"e9eb076367cc0932e2a32651372defa4a27ef800f47fad28c0ef840ba8ea7e08","src/binary_reader.rs":"1b1f0e1d831a716875ed578380f96b4b60245f0c6a4f43e2407c50fc94e50e6d","src/lib.rs":"d64774abb8d193f6a177130ffca94ce9fd199535fb6177dcb9910c4af7602082","src/limits.rs":"0c4dc6b96b35a320a8cff8269c0b55acd56f1f7b8a093c4885e04b9835441458","src/parser.rs":"b65b995296ed03a5b4d31c6459f2f3430ff685e50fec397c44f91b1364de5aaf","src/readers.rs":"406bf0cf694ed364c9c53cd25eb27a8e3fa97d099994f3e2a640747c49abf74b","src/readers/component.rs":"c259628ca3f09ff904f7e920aeec261b657f7a197c99b520a6a7d3e918b9fb3b","src/readers/component/aliases.rs":"72f3339cb452c1b055bd080281fe4923d132c280da112fcd1182594811b87494","src/readers/component/canonicals.rs":"c36e9bffc2e1ed752586189903eec77ea9897ae265e020096a9b92c467be26d9","src/readers/component/exports.rs":"f2c76e4be5045f1d099fd89dedf20e2f4817f046ea1e64bde7ca8f3ea9b2cdc6","src/readers/component/imports.rs":"725a688f2ab4306dbb421fe92ffff9373e3c88632557e352529f297bb2b96e0e","src/readers/component/instances.rs":"bca614178da3337e8c71a6ec431f12157a8cccc15411a0222bbc0106926a3ad5","src/readers/component/names.rs":"3f5dac9db8668b18cd6721cd780e6aba9b223b404c9d1173d09efe4e6b4d3a8a","src/readers/component/start.rs":"8e1e5d8aa5ece26d42251449cadcce0546c4d995f1641941b8a31ed4bc6ac761","src/readers/component/types.rs":"878fdf8f3d6a1c1387fd92b34838d8e79cee039710366bd5ea6739448d468a7a","src/readers/core.rs":"b1dbe0ffe61af1e6da4104de687009bcaa71fd3137300896159abbcfd903b800","src/readers/core/code.rs":"53f49986febb27f4cb67f4495e7b369fc80e2f70908e1e831750698dd15fe37f","src/readers/core/custom.rs":"f80d3a994e8778a912319834228cbb772c65a4b6b1f25b41fe00d220d388831f","src/readers/core/data.rs":"c1fcda7b548b15be40b3dd1f667d97c30c543867f2dc4734b590846beefe3ae3","src/readers/core/elements.rs":"197d3427fcf0fa8a3eb654e62dfa53159e6bc5cb160e75a06cf394f821bddef5","src/readers/core/exports.rs":"50dc1ee51b73f03f24077f7c290bca756966563cedbad9e49d735d60f60c91db","src/readers/core/functions.rs":"b5bbc7f7b7a429187376f63c695a9f1cbf92e515dba840ac876fa60f7290da34","src/readers/core/globals.rs":"d23f99a3adc9593652a5efd4dc81e8f014f57e776b49717dabbdcd0a811a96b1","src/readers/core/imports.rs":"4d247e8cac0b3cef7425d93f7a7f2412b2ae8979da944080d565415499e27e87","src/readers/core/init.rs":"ec6717063b0b7f2e9aa17ae52083019cee52594bf5a8b6858f2d77b10d7a0639","src/readers/core/memories.rs":"351f816d663b7d17546dc3b19ce0e43f406ce743289219a3758f7c837903fa6d","src/readers/core/names.rs":"408ebf052170bf0dc874b3158bb31089a891c3735cb35df2976e0b1e9791febb","src/readers/core/operators.rs":"46e927f6db9db9097217c5485da3a7b89e638730def809d177897f39356f5f52","src/readers/core/producers.rs":"4b42b7e1c9e22e7e2913d9da2291b491dc2d4fea417503d7ce99ad33c7beb439","src/readers/core/tables.rs":"cbe5b35893bd3929354b4487b344062ce6b540e6a70bde6eddf05a07a68574e9","src/readers/core/tags.rs":"c1dcfeb973195da9708549bcc2df4dd8ff282fe802c15a603bebc8a856f70949","src/readers/core/types.rs":"266a6c37ecdea656c235001b56b15564ad7777c23849a3f6e08ce63272347c7e","src/resources.rs":"b38b564ee425a392a30fb7440b50afa9e91be5ee933e4933b843e18c212a5871","src/validator.rs":"0dc406f1a61cf646719fa2d88675eae4d8c52c23cc3a4a222b6671cd25f84465","src/validator/component.rs":"4ca4d2d3c800e212a68e30577eead6bb69b2e7604f6d774d4f51f2aaa2f87084","src/validator/core.rs":"143f1a531485d411eb459fe608a64ca21f772740cbebe51e9f336e30ce3d1424","src/validator/func.rs":"63b66b7bb274be4115d8a26bce9b73128de0c079bd3318423288fadc1361fdb4","src/validator/operators.rs":"39b3bd04898b02b9dbd1d42c5727c79439593f5ef8fbf3c33fcc789d0b5be91a","src/validator/types.rs":"9ee9fb8a8afa0580c3e71bf9b39bd28c14b2a21f2d9acbb92e7d8ec14615ade2","tests/big-module.rs":"1f9241a4504d0421f6a5c759e3c688c87994fe04668b1d4e8912cedd98f2bd17"},"package":"48134de3d7598219ab9eaf6b91b15d8e50d31da76b8519fe4ecfcec2cf35104b"}
|
|
@ -274,6 +274,12 @@ version = "1.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.139"
|
||||
|
@ -637,9 +643,18 @@ version = "0.2.84"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eff853c4f09eec94d76af527eddad4e9de13b11d6286a1ef7134bc30135a2b7"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.100.0"
|
||||
version = "0.102.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"criterion",
|
||||
|
@ -647,6 +662,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"rayon",
|
||||
"url",
|
||||
"wasm-encoder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "wasmparser"
|
||||
version = "0.100.0"
|
||||
version = "0.102.0"
|
||||
authors = ["Yury Delendik <ydelendik@mozilla.com>"]
|
||||
exclude = ["benches/*.wasm"]
|
||||
description = """
|
||||
|
@ -49,3 +49,6 @@ version = "1.13.0"
|
|||
|
||||
[dev-dependencies.rayon]
|
||||
version = "1.3"
|
||||
|
||||
[dev-dependencies.wasm-encoder]
|
||||
version = "0.25.0"
|
||||
|
|
|
@ -4,7 +4,10 @@ use once_cell::unsync::Lazy;
|
|||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use wasmparser::{DataKind, ElementKind, Parser, Payload, Validator, VisitOperator, WasmFeatures};
|
||||
use wasmparser::{
|
||||
DataKind, ElementKind, HeapType, Parser, Payload, ValType, Validator, VisitOperator,
|
||||
WasmFeatures,
|
||||
};
|
||||
|
||||
/// A benchmark input.
|
||||
pub struct BenchmarkInput {
|
||||
|
@ -251,6 +254,7 @@ fn define_benchmarks(c: &mut Criterion) {
|
|||
mutable_global: true,
|
||||
saturating_float_to_int: true,
|
||||
sign_extension: true,
|
||||
function_references: true,
|
||||
memory_control: true,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -686,21 +686,21 @@ impl<'a> BinaryReader<'a> {
|
|||
}
|
||||
|
||||
// Check for a block type of form [] -> [t].
|
||||
if let Some(ty) = ValType::from_byte(b) {
|
||||
self.position += 1;
|
||||
return Ok(BlockType::Type(ty));
|
||||
if ValType::is_valtype_byte(b) {
|
||||
return Ok(BlockType::Type(self.read()?));
|
||||
}
|
||||
|
||||
// Not empty or a singular type, so read the function type index
|
||||
let idx = self.read_var_s33()?;
|
||||
if idx < 0 || idx > (std::u32::MAX as i64) {
|
||||
return Err(BinaryReaderError::new(
|
||||
"invalid function type",
|
||||
self.original_position(),
|
||||
));
|
||||
match u32::try_from(idx) {
|
||||
Ok(idx) => Ok(BlockType::FuncType(idx)),
|
||||
Err(_) => {
|
||||
return Err(BinaryReaderError::new(
|
||||
"invalid function type",
|
||||
self.original_position(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(BlockType::FuncType(idx as u32))
|
||||
}
|
||||
|
||||
/// Visit the next available operator with the specified [`VisitOperator`] instance.
|
||||
|
@ -778,6 +778,8 @@ impl<'a> BinaryReader<'a> {
|
|||
}
|
||||
0x12 => visitor.visit_return_call(self.read_var_u32()?),
|
||||
0x13 => visitor.visit_return_call_indirect(self.read_var_u32()?, self.read_var_u32()?),
|
||||
0x14 => visitor.visit_call_ref(self.read()?),
|
||||
0x15 => visitor.visit_return_call_ref(self.read()?),
|
||||
0x18 => visitor.visit_delegate(self.read_var_u32()?),
|
||||
0x19 => visitor.visit_catch_all(),
|
||||
0x1a => visitor.visit_drop(),
|
||||
|
@ -971,6 +973,9 @@ impl<'a> BinaryReader<'a> {
|
|||
0xd0 => visitor.visit_ref_null(self.read()?),
|
||||
0xd1 => visitor.visit_ref_is_null(),
|
||||
0xd2 => visitor.visit_ref_func(self.read_var_u32()?),
|
||||
0xd3 => visitor.visit_ref_as_non_null(),
|
||||
0xd4 => visitor.visit_br_on_null(self.read_var_u32()?),
|
||||
0xd6 => visitor.visit_br_on_non_null(self.read_var_u32()?),
|
||||
|
||||
0xfc => self.visit_0xfc_operator(pos, visitor)?,
|
||||
0xfd => self.visit_0xfd_operator(pos, visitor)?,
|
||||
|
@ -1347,14 +1352,14 @@ impl<'a> BinaryReader<'a> {
|
|||
0xfe => visitor.visit_f64x2_convert_low_i32x4_s(),
|
||||
0xff => visitor.visit_f64x2_convert_low_i32x4_u(),
|
||||
0x100 => visitor.visit_i8x16_relaxed_swizzle(),
|
||||
0x101 => visitor.visit_i32x4_relaxed_trunc_sat_f32x4_s(),
|
||||
0x102 => visitor.visit_i32x4_relaxed_trunc_sat_f32x4_u(),
|
||||
0x103 => visitor.visit_i32x4_relaxed_trunc_sat_f64x2_s_zero(),
|
||||
0x104 => visitor.visit_i32x4_relaxed_trunc_sat_f64x2_u_zero(),
|
||||
0x105 => visitor.visit_f32x4_relaxed_fma(),
|
||||
0x106 => visitor.visit_f32x4_relaxed_fnma(),
|
||||
0x107 => visitor.visit_f64x2_relaxed_fma(),
|
||||
0x108 => visitor.visit_f64x2_relaxed_fnma(),
|
||||
0x101 => visitor.visit_i32x4_relaxed_trunc_f32x4_s(),
|
||||
0x102 => visitor.visit_i32x4_relaxed_trunc_f32x4_u(),
|
||||
0x103 => visitor.visit_i32x4_relaxed_trunc_f64x2_s_zero(),
|
||||
0x104 => visitor.visit_i32x4_relaxed_trunc_f64x2_u_zero(),
|
||||
0x105 => visitor.visit_f32x4_relaxed_madd(),
|
||||
0x106 => visitor.visit_f32x4_relaxed_nmadd(),
|
||||
0x107 => visitor.visit_f64x2_relaxed_madd(),
|
||||
0x108 => visitor.visit_f64x2_relaxed_nmadd(),
|
||||
0x109 => visitor.visit_i8x16_relaxed_laneselect(),
|
||||
0x10a => visitor.visit_i16x8_relaxed_laneselect(),
|
||||
0x10b => visitor.visit_i32x4_relaxed_laneselect(),
|
||||
|
@ -1364,9 +1369,8 @@ impl<'a> BinaryReader<'a> {
|
|||
0x10f => visitor.visit_f64x2_relaxed_min(),
|
||||
0x110 => visitor.visit_f64x2_relaxed_max(),
|
||||
0x111 => visitor.visit_i16x8_relaxed_q15mulr_s(),
|
||||
0x112 => visitor.visit_i16x8_dot_i8x16_i7x16_s(),
|
||||
0x113 => visitor.visit_i32x4_dot_i8x16_i7x16_add_s(),
|
||||
0x114 => visitor.visit_f32x4_relaxed_dot_bf16x8_add_f32x4(),
|
||||
0x112 => visitor.visit_i16x8_relaxed_dot_i8x16_i7x16_s(),
|
||||
0x113 => visitor.visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(),
|
||||
|
||||
_ => bail!(pos, "unknown 0xfd subopcode: 0x{code:x}"),
|
||||
})
|
||||
|
|
|
@ -174,7 +174,7 @@ macro_rules! for_each_operator {
|
|||
@mvp I64Const { value: i64 } => visit_i64_const
|
||||
@mvp F32Const { value: $crate::Ieee32 } => visit_f32_const
|
||||
@mvp F64Const { value: $crate::Ieee64 } => visit_f64_const
|
||||
@reference_types RefNull { ty: $crate::ValType } => visit_ref_null
|
||||
@reference_types RefNull { hty: $crate::HeapType } => visit_ref_null
|
||||
@reference_types RefIsNull => visit_ref_is_null
|
||||
@reference_types RefFunc { function_index: u32 } => visit_ref_func
|
||||
@mvp I32Eqz => visit_i32_eqz
|
||||
|
@ -658,14 +658,14 @@ macro_rules! for_each_operator {
|
|||
// Relaxed SIMD operators
|
||||
// https://github.com/WebAssembly/relaxed-simd
|
||||
@relaxed_simd I8x16RelaxedSwizzle => visit_i8x16_relaxed_swizzle
|
||||
@relaxed_simd I32x4RelaxedTruncSatF32x4S => visit_i32x4_relaxed_trunc_sat_f32x4_s
|
||||
@relaxed_simd I32x4RelaxedTruncSatF32x4U => visit_i32x4_relaxed_trunc_sat_f32x4_u
|
||||
@relaxed_simd I32x4RelaxedTruncSatF64x2SZero => visit_i32x4_relaxed_trunc_sat_f64x2_s_zero
|
||||
@relaxed_simd I32x4RelaxedTruncSatF64x2UZero => visit_i32x4_relaxed_trunc_sat_f64x2_u_zero
|
||||
@relaxed_simd F32x4RelaxedFma => visit_f32x4_relaxed_fma
|
||||
@relaxed_simd F32x4RelaxedFnma => visit_f32x4_relaxed_fnma
|
||||
@relaxed_simd F64x2RelaxedFma => visit_f64x2_relaxed_fma
|
||||
@relaxed_simd F64x2RelaxedFnma => visit_f64x2_relaxed_fnma
|
||||
@relaxed_simd I32x4RelaxedTruncF32x4S => visit_i32x4_relaxed_trunc_f32x4_s
|
||||
@relaxed_simd I32x4RelaxedTruncF32x4U => visit_i32x4_relaxed_trunc_f32x4_u
|
||||
@relaxed_simd I32x4RelaxedTruncF64x2SZero => visit_i32x4_relaxed_trunc_f64x2_s_zero
|
||||
@relaxed_simd I32x4RelaxedTruncF64x2UZero => visit_i32x4_relaxed_trunc_f64x2_u_zero
|
||||
@relaxed_simd F32x4RelaxedMadd => visit_f32x4_relaxed_madd
|
||||
@relaxed_simd F32x4RelaxedNmadd => visit_f32x4_relaxed_nmadd
|
||||
@relaxed_simd F64x2RelaxedMadd => visit_f64x2_relaxed_madd
|
||||
@relaxed_simd F64x2RelaxedNmadd => visit_f64x2_relaxed_nmadd
|
||||
@relaxed_simd I8x16RelaxedLaneselect => visit_i8x16_relaxed_laneselect
|
||||
@relaxed_simd I16x8RelaxedLaneselect => visit_i16x8_relaxed_laneselect
|
||||
@relaxed_simd I32x4RelaxedLaneselect => visit_i32x4_relaxed_laneselect
|
||||
|
@ -675,9 +675,15 @@ macro_rules! for_each_operator {
|
|||
@relaxed_simd F64x2RelaxedMin => visit_f64x2_relaxed_min
|
||||
@relaxed_simd F64x2RelaxedMax => visit_f64x2_relaxed_max
|
||||
@relaxed_simd I16x8RelaxedQ15mulrS => visit_i16x8_relaxed_q15mulr_s
|
||||
@relaxed_simd I16x8DotI8x16I7x16S => visit_i16x8_dot_i8x16_i7x16_s
|
||||
@relaxed_simd I32x4DotI8x16I7x16AddS => visit_i32x4_dot_i8x16_i7x16_add_s
|
||||
@relaxed_simd F32x4RelaxedDotBf16x8AddF32x4 => visit_f32x4_relaxed_dot_bf16x8_add_f32x4
|
||||
@relaxed_simd I16x8RelaxedDotI8x16I7x16S => visit_i16x8_relaxed_dot_i8x16_i7x16_s
|
||||
@relaxed_simd I32x4RelaxedDotI8x16I7x16AddS => visit_i32x4_relaxed_dot_i8x16_i7x16_add_s
|
||||
|
||||
// Typed Function references
|
||||
@function_references CallRef { hty: $crate::HeapType } => visit_call_ref
|
||||
@function_references ReturnCallRef { hty: $crate::HeapType } => visit_return_call_ref
|
||||
@function_references RefAsNonNull => visit_ref_as_non_null
|
||||
@function_references BrOnNull { relative_depth: u32 } => visit_br_on_null
|
||||
@function_references BrOnNonNull { relative_depth: u32 } => visit_br_on_non_null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -37,9 +37,9 @@ pub const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE;
|
|||
|
||||
// Component-related limits
|
||||
pub const MAX_WASM_MODULE_SIZE: usize = 1024 * 1024 * 1024; //= 1 GiB
|
||||
pub const MAX_WASM_MODULE_TYPE_DECLS: usize = 1000;
|
||||
pub const MAX_WASM_COMPONENT_TYPE_DECLS: usize = 1000;
|
||||
pub const MAX_WASM_INSTANCE_TYPE_DECLS: usize = 1000;
|
||||
pub const MAX_WASM_MODULE_TYPE_DECLS: usize = 100_000;
|
||||
pub const MAX_WASM_COMPONENT_TYPE_DECLS: usize = 100_000;
|
||||
pub const MAX_WASM_INSTANCE_TYPE_DECLS: usize = 100_000;
|
||||
pub const MAX_WASM_RECORD_FIELDS: usize = 1000;
|
||||
pub const MAX_WASM_VARIANT_CASES: usize = 1000;
|
||||
pub const MAX_WASM_TUPLE_TYPES: usize = 1000;
|
||||
|
@ -50,7 +50,7 @@ pub const MAX_WASM_INSTANTIATION_EXPORTS: usize = 1000;
|
|||
pub const MAX_WASM_CANONICAL_OPTIONS: usize = 10;
|
||||
pub const MAX_WASM_INSTANTIATION_ARGS: usize = 1000;
|
||||
pub const MAX_WASM_START_ARGS: usize = 1000;
|
||||
pub const MAX_WASM_TYPE_SIZE: u32 = 100_000;
|
||||
pub const MAX_WASM_TYPE_SIZE: u32 = 1_000_000;
|
||||
pub const MAX_WASM_MODULES: usize = 1_000;
|
||||
pub const MAX_WASM_COMPONENTS: usize = 1_000;
|
||||
pub const MAX_WASM_INSTANCES: usize = 1_000;
|
||||
|
|
|
@ -51,7 +51,7 @@ impl<'a> FunctionBody<'a> {
|
|||
let count = reader.read_var_u32()?;
|
||||
for _ in 0..count {
|
||||
reader.read_var_u32()?;
|
||||
reader.read_var_u32()?;
|
||||
reader.read::<ValType>()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
*/
|
||||
|
||||
use crate::{
|
||||
BinaryReader, BinaryReaderError, ConstExpr, ExternalKind, FromReader, Result, SectionLimited,
|
||||
ValType,
|
||||
BinaryReader, BinaryReaderError, ConstExpr, ExternalKind, FromReader, RefType, Result,
|
||||
SectionLimited,
|
||||
};
|
||||
use std::ops::Range;
|
||||
|
||||
|
@ -27,7 +27,7 @@ pub struct Element<'a> {
|
|||
/// The initial elements of the element segment.
|
||||
pub items: ElementItems<'a>,
|
||||
/// The type of the elements.
|
||||
pub ty: ValType,
|
||||
pub ty: RefType,
|
||||
/// The range of the the element segment.
|
||||
pub range: Range<usize>,
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ impl<'a> FromReader<'a> for Element<'a> {
|
|||
reader.read()?
|
||||
} else {
|
||||
match reader.read()? {
|
||||
ExternalKind::Func => ValType::FuncRef,
|
||||
ExternalKind::Func => RefType::FUNCREF,
|
||||
_ => {
|
||||
return Err(BinaryReaderError::new(
|
||||
"only the function external type is supported in elem segment",
|
||||
|
@ -117,7 +117,7 @@ impl<'a> FromReader<'a> for Element<'a> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
ValType::FuncRef
|
||||
RefType::FUNCREF
|
||||
};
|
||||
// FIXME(#188) ideally wouldn't have to do skips here
|
||||
let data = reader.skip(|reader| {
|
||||
|
|
|
@ -13,10 +13,55 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::{BinaryReader, FromReader, Result, SectionLimited, TableType};
|
||||
use crate::{BinaryReader, ConstExpr, FromReader, Result, SectionLimited, TableType};
|
||||
|
||||
/// A reader for the table section of a WebAssembly module.
|
||||
pub type TableSectionReader<'a> = SectionLimited<'a, TableType>;
|
||||
pub type TableSectionReader<'a> = SectionLimited<'a, Table<'a>>;
|
||||
|
||||
/// Type information about a table defined in the table section of a WebAssembly
|
||||
/// module.
|
||||
#[derive(Debug)]
|
||||
pub struct Table<'a> {
|
||||
/// The type of this table, including its element type and its limits.
|
||||
pub ty: TableType,
|
||||
/// The initialization expression for the table.
|
||||
pub init: TableInit<'a>,
|
||||
}
|
||||
|
||||
/// Different modes of initializing a table.
|
||||
#[derive(Debug)]
|
||||
pub enum TableInit<'a> {
|
||||
/// The table is initialized to all null elements.
|
||||
RefNull,
|
||||
/// Each element in the table is initialized with the specified constant
|
||||
/// expression.
|
||||
Expr(ConstExpr<'a>),
|
||||
}
|
||||
|
||||
impl<'a> FromReader<'a> for Table<'a> {
|
||||
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
|
||||
let has_init_expr = if reader.peek()? == 0x40 {
|
||||
reader.read_u8()?;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if has_init_expr {
|
||||
if reader.read_u8()? != 0x00 {
|
||||
bail!(reader.original_position() - 1, "invalid table encoding");
|
||||
}
|
||||
}
|
||||
|
||||
let ty = reader.read::<TableType>()?;
|
||||
let init = if has_init_expr {
|
||||
TableInit::Expr(reader.read()?)
|
||||
} else {
|
||||
TableInit::RefNull
|
||||
};
|
||||
Ok(Table { ty, init })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromReader<'a> for TableType {
|
||||
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
|
||||
|
|
|
@ -30,43 +30,180 @@ pub enum ValType {
|
|||
F64,
|
||||
/// The value type is v128.
|
||||
V128,
|
||||
/// The value type is a function reference.
|
||||
FuncRef,
|
||||
/// The value type is an extern reference.
|
||||
ExternRef,
|
||||
/// The value type is a reference. Which type of reference is decided by
|
||||
/// RefType. This is a change in syntax from the function references proposal,
|
||||
/// which now provides FuncRef and ExternRef as sugar for the generic ref
|
||||
/// construct.
|
||||
Ref(RefType),
|
||||
}
|
||||
|
||||
/// A reference type. When the function references feature is disabled, this
|
||||
/// only represents funcref and externref, using the following format:
|
||||
/// RefType { nullable: true, heap_type: Func | Extern })
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[repr(packed)]
|
||||
pub struct RefType {
|
||||
/// Whether it's nullable
|
||||
pub nullable: bool,
|
||||
/// The relevant heap type
|
||||
pub heap_type: HeapType,
|
||||
}
|
||||
|
||||
impl RefType {
|
||||
/// Alias for the wasm `funcref` type.
|
||||
pub const FUNCREF: RefType = RefType {
|
||||
nullable: true,
|
||||
heap_type: HeapType::Func,
|
||||
};
|
||||
/// Alias for the wasm `externref` type.
|
||||
pub const EXTERNREF: RefType = RefType {
|
||||
nullable: true,
|
||||
heap_type: HeapType::Extern,
|
||||
};
|
||||
}
|
||||
|
||||
impl From<RefType> for ValType {
|
||||
fn from(ty: RefType) -> ValType {
|
||||
ValType::Ref(ty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Used as a performance optimization in HeapType. Call `.into()` to get the u32
|
||||
// A u16 forces 2-byte alignment, which forces HeapType to be 4 bytes,
|
||||
// which forces ValType to 5 bytes. This newtype is annotated as unaligned to
|
||||
// store the necessary bits compactly
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[repr(packed)]
|
||||
pub struct PackedIndex(u16);
|
||||
|
||||
impl TryFrom<u32> for PackedIndex {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(idx: u32) -> Result<PackedIndex, ()> {
|
||||
idx.try_into().map(PackedIndex).map_err(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PackedIndex> for u32 {
|
||||
fn from(x: PackedIndex) -> u32 {
|
||||
x.0 as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// A heap type from function references. When the proposal is disabled, Index
|
||||
/// is an invalid type.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum HeapType {
|
||||
/// Function type index
|
||||
/// Note: [PackedIndex] may need to be unpacked
|
||||
TypedFunc(PackedIndex),
|
||||
/// From reference types
|
||||
Func,
|
||||
/// From reference types
|
||||
Extern,
|
||||
}
|
||||
|
||||
impl ValType {
|
||||
/// Alias for the wasm `funcref` type.
|
||||
pub const FUNCREF: ValType = ValType::Ref(RefType::FUNCREF);
|
||||
/// Alias for the wasm `externref` type.
|
||||
pub const EXTERNREF: ValType = ValType::Ref(RefType::EXTERNREF);
|
||||
|
||||
/// Returns whether this value type is a "reference type".
|
||||
///
|
||||
/// Only reference types are allowed in tables, for example, and with some
|
||||
/// instructions. Current reference types include `funcref` and `externref`.
|
||||
pub fn is_reference_type(&self) -> bool {
|
||||
matches!(self, ValType::FuncRef | ValType::ExternRef)
|
||||
matches!(self, ValType::Ref(_))
|
||||
}
|
||||
/// Whether the type is defaultable according to function references
|
||||
/// spec. This amounts to whether it's a non-nullable ref
|
||||
pub fn is_defaultable(&self) -> bool {
|
||||
!matches!(
|
||||
self,
|
||||
ValType::Ref(RefType {
|
||||
nullable: false,
|
||||
..
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn from_byte(byte: u8) -> Option<ValType> {
|
||||
pub(crate) fn is_valtype_byte(byte: u8) -> bool {
|
||||
match byte {
|
||||
0x7F => Some(ValType::I32),
|
||||
0x7E => Some(ValType::I64),
|
||||
0x7D => Some(ValType::F32),
|
||||
0x7C => Some(ValType::F64),
|
||||
0x7B => Some(ValType::V128),
|
||||
0x70 => Some(ValType::FuncRef),
|
||||
0x6F => Some(ValType::ExternRef),
|
||||
_ => None,
|
||||
0x7F | 0x7E | 0x7D | 0x7C | 0x7B | 0x70 | 0x6F | 0x6B | 0x6C => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromReader<'a> for ValType {
|
||||
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
|
||||
match ValType::from_byte(reader.peek()?) {
|
||||
Some(ty) => {
|
||||
match reader.peek()? {
|
||||
0x7F => {
|
||||
reader.position += 1;
|
||||
Ok(ty)
|
||||
Ok(ValType::I32)
|
||||
}
|
||||
0x7E => {
|
||||
reader.position += 1;
|
||||
Ok(ValType::I64)
|
||||
}
|
||||
0x7D => {
|
||||
reader.position += 1;
|
||||
Ok(ValType::F32)
|
||||
}
|
||||
0x7C => {
|
||||
reader.position += 1;
|
||||
Ok(ValType::F64)
|
||||
}
|
||||
0x7B => {
|
||||
reader.position += 1;
|
||||
Ok(ValType::V128)
|
||||
}
|
||||
0x70 | 0x6F | 0x6B | 0x6C => Ok(ValType::Ref(reader.read()?)),
|
||||
_ => bail!(reader.original_position(), "invalid value type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromReader<'a> for RefType {
|
||||
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
|
||||
match reader.read()? {
|
||||
0x70 => Ok(RefType::FUNCREF),
|
||||
0x6F => Ok(RefType::EXTERNREF),
|
||||
byte @ (0x6B | 0x6C) => Ok(RefType {
|
||||
nullable: byte == 0x6C,
|
||||
heap_type: reader.read()?,
|
||||
}),
|
||||
_ => bail!(reader.original_position(), "malformed reference type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromReader<'a> for HeapType {
|
||||
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
|
||||
match reader.peek()? {
|
||||
0x70 => {
|
||||
reader.position += 1;
|
||||
Ok(HeapType::Func)
|
||||
}
|
||||
0x6F => {
|
||||
reader.position += 1;
|
||||
Ok(HeapType::Extern)
|
||||
}
|
||||
_ => {
|
||||
let idx = match u32::try_from(reader.read_var_s33()?) {
|
||||
Ok(idx) => idx,
|
||||
Err(_) => {
|
||||
bail!(reader.original_position(), "invalid function heap type",);
|
||||
}
|
||||
};
|
||||
match idx.try_into() {
|
||||
Ok(packed) => Ok(HeapType::TypedFunc(packed)),
|
||||
Err(_) => {
|
||||
bail!(reader.original_position(), "function index too large");
|
||||
}
|
||||
}
|
||||
}
|
||||
None => bail!(reader.original_position(), "invalid value type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +279,7 @@ impl FuncType {
|
|||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct TableType {
|
||||
/// The table's element type.
|
||||
pub element_type: ValType,
|
||||
pub element_type: RefType,
|
||||
/// Initial size of this table, in elements.
|
||||
pub initial: u32,
|
||||
/// Optional maximum size of the table, in elements.
|
||||
|
|
|
@ -13,7 +13,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::{FuncType, GlobalType, MemoryType, TableType, ValType};
|
||||
use crate::{
|
||||
BinaryReaderError, FuncType, GlobalType, HeapType, MemoryType, RefType, TableType, ValType,
|
||||
WasmFeatures,
|
||||
};
|
||||
use std::ops::Range;
|
||||
|
||||
/// Types that qualify as Wasm function types for validation purposes.
|
||||
|
@ -208,10 +211,44 @@ pub trait WasmModuleResources {
|
|||
fn global_at(&self, at: u32) -> Option<GlobalType>;
|
||||
/// Returns the `FuncType` associated with the given type index.
|
||||
fn func_type_at(&self, type_idx: u32) -> Option<&Self::FuncType>;
|
||||
/// Returns the type index associated with the given function
|
||||
/// index. type_of_function = func_type_at(type_index_of_function)
|
||||
fn type_index_of_function(&self, func_idx: u32) -> Option<u32>;
|
||||
/// Returns the `FuncType` associated with the given function index.
|
||||
fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType>;
|
||||
/// Returns the element type at the given index.
|
||||
fn element_type_at(&self, at: u32) -> Option<ValType>;
|
||||
fn element_type_at(&self, at: u32) -> Option<RefType>;
|
||||
/// Under the function references proposal, returns whether t1 <=
|
||||
/// t2. Otherwise, returns whether t1 == t2
|
||||
fn matches(&self, t1: ValType, t2: ValType) -> bool;
|
||||
/// Check a value type. This requires using func_type_at to check references
|
||||
fn check_value_type(
|
||||
&self,
|
||||
t: ValType,
|
||||
features: &WasmFeatures,
|
||||
offset: usize,
|
||||
) -> Result<(), BinaryReaderError>;
|
||||
|
||||
/// Checks that a `HeapType` is valid, notably its function index if one is
|
||||
/// used.
|
||||
fn check_heap_type(
|
||||
&self,
|
||||
heap_type: HeapType,
|
||||
features: &WasmFeatures,
|
||||
offset: usize,
|
||||
) -> Result<(), BinaryReaderError> {
|
||||
// Delegate to the generic value type validation which will have the
|
||||
// same validity checks.
|
||||
self.check_value_type(
|
||||
RefType {
|
||||
nullable: true,
|
||||
heap_type,
|
||||
}
|
||||
.into(),
|
||||
features,
|
||||
offset,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the number of elements.
|
||||
fn element_count(&self) -> u32;
|
||||
|
@ -243,12 +280,26 @@ where
|
|||
fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> {
|
||||
T::func_type_at(self, at)
|
||||
}
|
||||
fn type_index_of_function(&self, func_idx: u32) -> Option<u32> {
|
||||
T::type_index_of_function(self, func_idx)
|
||||
}
|
||||
fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType> {
|
||||
T::type_of_function(self, func_idx)
|
||||
}
|
||||
fn element_type_at(&self, at: u32) -> Option<ValType> {
|
||||
fn check_value_type(
|
||||
&self,
|
||||
t: ValType,
|
||||
features: &WasmFeatures,
|
||||
offset: usize,
|
||||
) -> Result<(), BinaryReaderError> {
|
||||
T::check_value_type(self, t, features, offset)
|
||||
}
|
||||
fn element_type_at(&self, at: u32) -> Option<RefType> {
|
||||
T::element_type_at(self, at)
|
||||
}
|
||||
fn matches(&self, t1: ValType, t2: ValType) -> bool {
|
||||
T::matches(self, t1, t2)
|
||||
}
|
||||
|
||||
fn element_count(&self) -> u32 {
|
||||
T::element_count(self)
|
||||
|
@ -287,14 +338,31 @@ where
|
|||
T::func_type_at(self, type_idx)
|
||||
}
|
||||
|
||||
fn type_index_of_function(&self, func_idx: u32) -> Option<u32> {
|
||||
T::type_index_of_function(self, func_idx)
|
||||
}
|
||||
|
||||
fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType> {
|
||||
T::type_of_function(self, func_idx)
|
||||
}
|
||||
|
||||
fn element_type_at(&self, at: u32) -> Option<ValType> {
|
||||
fn check_value_type(
|
||||
&self,
|
||||
t: ValType,
|
||||
features: &WasmFeatures,
|
||||
offset: usize,
|
||||
) -> Result<(), BinaryReaderError> {
|
||||
T::check_value_type(self, t, features, offset)
|
||||
}
|
||||
|
||||
fn element_type_at(&self, at: u32) -> Option<RefType> {
|
||||
T::element_type_at(self, at)
|
||||
}
|
||||
|
||||
fn matches(&self, t1: ValType, t2: ValType) -> bool {
|
||||
T::matches(self, t1, t2)
|
||||
}
|
||||
|
||||
fn element_count(&self) -> u32 {
|
||||
T::element_count(self)
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
*/
|
||||
|
||||
use crate::{
|
||||
limits::*, BinaryReaderError, Encoding, FromReader, FunctionBody, Parser, Payload, Result,
|
||||
SectionLimited, ValType, WASM_COMPONENT_VERSION, WASM_MODULE_VERSION,
|
||||
limits::*, BinaryReaderError, Encoding, FromReader, FunctionBody, HeapType, Parser, Payload,
|
||||
Result, SectionLimited, ValType, WASM_COMPONENT_VERSION, WASM_MODULE_VERSION,
|
||||
};
|
||||
use std::mem;
|
||||
use std::ops::Range;
|
||||
|
@ -240,11 +240,17 @@ pub struct WasmFeatures {
|
|||
pub extended_const: bool,
|
||||
/// The WebAssembly component model proposal.
|
||||
pub component_model: bool,
|
||||
/// The WebAssembly typed function references proposal
|
||||
pub function_references: bool,
|
||||
/// The WebAssembly memory control proposal
|
||||
pub memory_control: bool,
|
||||
}
|
||||
|
||||
impl WasmFeatures {
|
||||
/// NOTE: This only checks that the value type corresponds to the feature set!!
|
||||
///
|
||||
/// To check that reference types are valid, we need access to the module
|
||||
/// types. Use module.check_value_type.
|
||||
pub(crate) fn check_value_type(&self, ty: ValType) -> Result<(), &'static str> {
|
||||
match ty {
|
||||
ValType::I32 | ValType::I64 => Ok(()),
|
||||
|
@ -255,9 +261,21 @@ impl WasmFeatures {
|
|||
Err("floating-point support is disabled")
|
||||
}
|
||||
}
|
||||
ValType::FuncRef | ValType::ExternRef => {
|
||||
ValType::Ref(r) => {
|
||||
if self.reference_types {
|
||||
Ok(())
|
||||
if !self.function_references {
|
||||
match (r.heap_type, r.nullable) {
|
||||
(_, false) => {
|
||||
Err("function references required for non-nullable types")
|
||||
}
|
||||
(HeapType::TypedFunc(_), _) => {
|
||||
Err("function references required for index reference types")
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
Err("reference types support is not enabled")
|
||||
}
|
||||
|
@ -284,6 +302,7 @@ impl Default for WasmFeatures {
|
|||
memory64: false,
|
||||
extended_const: false,
|
||||
component_model: false,
|
||||
function_references: false,
|
||||
memory_control: false,
|
||||
|
||||
// On-by-default features (phase 4 or greater).
|
||||
|
@ -515,8 +534,9 @@ impl Validator {
|
|||
if !self.features.component_model {
|
||||
bail!(
|
||||
range.start,
|
||||
"unknown binary version: {num:#x}, \
|
||||
note: the WebAssembly component model feature is not enabled",
|
||||
"unknown binary version and encoding combination: {num:#x} and 0x1, \
|
||||
note: encoded as a component but the WebAssembly component model feature \
|
||||
is not enabled - enable the feature to allow component validation",
|
||||
);
|
||||
}
|
||||
if num == WASM_COMPONENT_VERSION {
|
||||
|
@ -623,9 +643,7 @@ impl Validator {
|
|||
state.module.assert_mut().tables.reserve(count as usize);
|
||||
Ok(())
|
||||
},
|
||||
|state, features, _, ty, offset| {
|
||||
state.module.assert_mut().add_table(ty, features, offset)
|
||||
},
|
||||
|state, features, types, table, offset| state.add_table(table, features, types, offset),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1169,13 +1187,13 @@ impl Validator {
|
|||
|components, _, count, offset| {
|
||||
let current = components.last_mut().unwrap();
|
||||
check_max(
|
||||
current.exports.len(),
|
||||
current.externs.len(),
|
||||
count,
|
||||
MAX_WASM_EXPORTS,
|
||||
"exports",
|
||||
"imports and exports",
|
||||
offset,
|
||||
)?;
|
||||
current.exports.reserve(count as usize);
|
||||
current.externs.reserve(count as usize);
|
||||
Ok(())
|
||||
},
|
||||
|components, types, _, export, offset| {
|
||||
|
@ -1351,7 +1369,7 @@ impl Validator {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{GlobalType, MemoryType, TableType, ValType, Validator, WasmFeatures};
|
||||
use crate::{GlobalType, MemoryType, RefType, TableType, ValType, Validator, WasmFeatures};
|
||||
use anyhow::Result;
|
||||
|
||||
#[test]
|
||||
|
@ -1420,7 +1438,7 @@ mod tests {
|
|||
Some(TableType {
|
||||
initial: 10,
|
||||
maximum: None,
|
||||
element_type: ValType::FuncRef,
|
||||
element_type: RefType::FUNCREF,
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -1448,7 +1466,7 @@ mod tests {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
assert_eq!(types.element_at(0), Some(ValType::FuncRef));
|
||||
assert_eq!(types.element_at(0), Some(RefType::FUNCREF));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -64,8 +64,8 @@ pub(crate) struct ComponentState {
|
|||
pub instances: Vec<TypeId>,
|
||||
pub components: Vec<TypeId>,
|
||||
|
||||
pub imports: IndexMap<KebabString, (Option<Url>, ComponentEntityType)>,
|
||||
pub exports: IndexMap<KebabString, (Option<Url>, ComponentEntityType)>,
|
||||
/// A set of all imports and exports since they share the same namespace.
|
||||
pub externs: IndexMap<KebabString, (Option<Url>, ComponentEntityType, ExternKind)>,
|
||||
|
||||
// Note: URL validation requires unique URLs by byte comparison, so
|
||||
// strings are used here and the URLs are not normalized.
|
||||
|
@ -76,6 +76,20 @@ pub(crate) struct ComponentState {
|
|||
type_size: u32,
|
||||
}
|
||||
|
||||
pub enum ExternKind {
|
||||
Import,
|
||||
Export,
|
||||
}
|
||||
|
||||
impl ExternKind {
|
||||
fn desc(&self) -> &'static str {
|
||||
match self {
|
||||
ExternKind::Import => "import",
|
||||
ExternKind::Export => "export",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentState {
|
||||
pub fn type_count(&self) -> usize {
|
||||
self.core_types.len() + self.types.len()
|
||||
|
@ -218,13 +232,14 @@ impl ComponentState {
|
|||
self.add_entity(entity, false, offset)?;
|
||||
let name = to_kebab_str(import.name, "import", offset)?;
|
||||
|
||||
match self.imports.entry(name.to_owned()) {
|
||||
match self.externs.entry(name.to_owned()) {
|
||||
Entry::Occupied(e) => {
|
||||
bail!(
|
||||
offset,
|
||||
"import name `{name}` conflicts with previous import name `{prev}`",
|
||||
"import name `{name}` conflicts with previous {desc} name `{prev}`",
|
||||
name = import.name,
|
||||
prev = e.key()
|
||||
prev = e.key(),
|
||||
desc = e.get().2.desc(),
|
||||
);
|
||||
}
|
||||
Entry::Vacant(e) => {
|
||||
|
@ -236,7 +251,7 @@ impl ComponentState {
|
|||
}
|
||||
|
||||
self.type_size = combine_type_sizes(self.type_size, entity.type_size(), offset)?;
|
||||
e.insert((url, entity));
|
||||
e.insert((url, entity, ExternKind::Import));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,18 +304,25 @@ impl ComponentState {
|
|||
check_limit: bool,
|
||||
) -> Result<()> {
|
||||
if check_limit {
|
||||
check_max(self.exports.len(), 1, MAX_WASM_EXPORTS, "exports", offset)?;
|
||||
check_max(
|
||||
self.externs.len(),
|
||||
1,
|
||||
MAX_WASM_EXPORTS,
|
||||
"imports and exports",
|
||||
offset,
|
||||
)?;
|
||||
}
|
||||
self.add_entity(ty, true, offset)?;
|
||||
|
||||
let name = to_kebab_str(name, "export", offset)?;
|
||||
|
||||
match self.exports.entry(name.to_owned()) {
|
||||
match self.externs.entry(name.to_owned()) {
|
||||
Entry::Occupied(e) => {
|
||||
bail!(
|
||||
offset,
|
||||
"export name `{name}` conflicts with previous export name `{prev}`",
|
||||
prev = e.key()
|
||||
"export name `{name}` conflicts with previous {desc} name `{prev}`",
|
||||
prev = e.key(),
|
||||
desc = e.get().2.desc(),
|
||||
);
|
||||
}
|
||||
Entry::Vacant(e) => {
|
||||
|
@ -312,7 +334,7 @@ impl ComponentState {
|
|||
}
|
||||
|
||||
self.type_size = combine_type_sizes(self.type_size, ty.type_size(), offset)?;
|
||||
e.insert((url, ty));
|
||||
e.insert((url, ty, ExternKind::Export));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,12 +410,7 @@ impl ComponentState {
|
|||
}
|
||||
|
||||
pub fn add_component(&mut self, component: &mut Self, types: &mut TypeAlloc) {
|
||||
let ty = Type::Component(ComponentType {
|
||||
type_size: component.type_size,
|
||||
imports: mem::take(&mut component.imports),
|
||||
exports: mem::take(&mut component.exports),
|
||||
});
|
||||
|
||||
let ty = Type::Component(component.take_component_type());
|
||||
let id = types.push_anon(ty);
|
||||
self.components.push(id);
|
||||
}
|
||||
|
@ -848,13 +865,9 @@ impl ComponentState {
|
|||
};
|
||||
}
|
||||
|
||||
let state = components.pop().unwrap();
|
||||
let mut state = components.pop().unwrap();
|
||||
|
||||
Ok(ComponentType {
|
||||
type_size: state.type_size,
|
||||
imports: state.imports,
|
||||
exports: state.exports,
|
||||
})
|
||||
Ok(state.take_component_type())
|
||||
}
|
||||
|
||||
fn create_instance_type(
|
||||
|
@ -889,7 +902,16 @@ impl ComponentState {
|
|||
|
||||
Ok(ComponentInstanceType {
|
||||
type_size: state.type_size,
|
||||
kind: ComponentInstanceTypeKind::Defined(state.exports),
|
||||
kind: ComponentInstanceTypeKind::Defined(
|
||||
state
|
||||
.externs
|
||||
.into_iter()
|
||||
.filter_map(|(name, (url, ty, kind))| match kind {
|
||||
ExternKind::Export => Some((name, (url, ty))),
|
||||
ExternKind::Import => None,
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1134,7 +1156,16 @@ impl ComponentState {
|
|||
)?;
|
||||
}
|
||||
ComponentExternalKind::Type => {
|
||||
// Type arguments are ignored
|
||||
let ty = self.type_at(component_arg.index, false, offset)?;
|
||||
insert_arg(
|
||||
component_arg.name,
|
||||
ComponentEntityType::Type {
|
||||
referenced: ty,
|
||||
created: ty,
|
||||
},
|
||||
&mut args,
|
||||
offset,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1149,13 +1180,13 @@ impl ComponentState {
|
|||
| (ComponentEntityType::Component(_), ComponentEntityType::Component(_))
|
||||
| (ComponentEntityType::Instance(_), ComponentEntityType::Instance(_))
|
||||
| (ComponentEntityType::Func(_), ComponentEntityType::Func(_))
|
||||
| (ComponentEntityType::Value(_), ComponentEntityType::Value(_)) => {}
|
||||
| (ComponentEntityType::Value(_), ComponentEntityType::Value(_))
|
||||
| (ComponentEntityType::Type { .. }, ComponentEntityType::Type { .. }) => {}
|
||||
_ => {
|
||||
bail!(
|
||||
offset,
|
||||
"expected component instantiation argument \
|
||||
`{name}` to be of type `{}`",
|
||||
expected.desc()
|
||||
"expected component instantiation argument `{name}` to be a {desc}",
|
||||
desc = expected.desc()
|
||||
)
|
||||
}
|
||||
};
|
||||
|
@ -1163,8 +1194,7 @@ impl ComponentState {
|
|||
if !ComponentEntityType::internal_is_subtype_of(arg, types, expected, types) {
|
||||
bail!(
|
||||
offset,
|
||||
"{} type mismatch for component instantiation argument `{name}`",
|
||||
expected.desc(),
|
||||
"type mismatch for component instantiation argument `{name}`"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2024,6 +2054,25 @@ impl ComponentState {
|
|||
None => bail!(offset, "unknown memory {idx}: memory index out of bounds"),
|
||||
}
|
||||
}
|
||||
|
||||
fn take_component_type(&mut self) -> ComponentType {
|
||||
let mut ty = ComponentType {
|
||||
type_size: self.type_size,
|
||||
imports: Default::default(),
|
||||
exports: Default::default(),
|
||||
};
|
||||
|
||||
for (name, (url, t, kind)) in mem::take(&mut self.externs) {
|
||||
let map = match kind {
|
||||
ExternKind::Import => &mut ty.imports,
|
||||
ExternKind::Export => &mut ty.exports,
|
||||
};
|
||||
let prev = map.insert(name, (url, t));
|
||||
assert!(prev.is_none());
|
||||
}
|
||||
|
||||
ty
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ComponentState {
|
||||
|
@ -2042,10 +2091,9 @@ impl Default for ComponentState {
|
|||
values: Default::default(),
|
||||
instances: Default::default(),
|
||||
components: Default::default(),
|
||||
imports: Default::default(),
|
||||
exports: Default::default(),
|
||||
import_urls: Default::default(),
|
||||
externs: Default::default(),
|
||||
export_urls: Default::default(),
|
||||
import_urls: Default::default(),
|
||||
has_start: Default::default(),
|
||||
type_size: 1,
|
||||
}
|
||||
|
|
|
@ -2,27 +2,20 @@
|
|||
//!
|
||||
use super::{
|
||||
check_max, combine_type_sizes,
|
||||
operators::{OperatorValidator, OperatorValidatorAllocations},
|
||||
operators::{ty_to_str, OperatorValidator, OperatorValidatorAllocations},
|
||||
types::{EntityType, Type, TypeAlloc, TypeId, TypeList},
|
||||
};
|
||||
use crate::limits::*;
|
||||
use crate::validator::core::arc::MaybeOwned;
|
||||
use crate::{
|
||||
BinaryReaderError, ConstExpr, Data, DataKind, Element, ElementKind, ExternalKind, FuncType,
|
||||
Global, GlobalType, MemoryType, Result, TableType, TagType, TypeRef, ValType, VisitOperator,
|
||||
WasmFeatures, WasmModuleResources,
|
||||
Global, GlobalType, HeapType, MemoryType, RefType, Result, Table, TableInit, TableType,
|
||||
TagType, TypeRef, ValType, VisitOperator, WasmFeatures, WasmFuncType, WasmModuleResources,
|
||||
};
|
||||
use indexmap::IndexMap;
|
||||
use std::mem;
|
||||
use std::{collections::HashSet, sync::Arc};
|
||||
|
||||
fn check_value_type(ty: ValType, features: &WasmFeatures, offset: usize) -> Result<()> {
|
||||
match features.check_value_type(ty) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => Err(BinaryReaderError::new(e, offset)),
|
||||
}
|
||||
}
|
||||
|
||||
// Section order for WebAssembly modules.
|
||||
//
|
||||
// Component sections are unordered and allow for duplicates,
|
||||
|
@ -140,12 +133,43 @@ impl ModuleState {
|
|||
offset: usize,
|
||||
) -> Result<()> {
|
||||
self.module
|
||||
.check_global_type(&global.ty, features, offset)?;
|
||||
.check_global_type(&global.ty, features, types, offset)?;
|
||||
self.check_const_expr(&global.init_expr, global.ty.content_type, features, types)?;
|
||||
self.module.assert_mut().globals.push(global.ty);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_table(
|
||||
&mut self,
|
||||
table: Table<'_>,
|
||||
features: &WasmFeatures,
|
||||
types: &TypeList,
|
||||
offset: usize,
|
||||
) -> Result<()> {
|
||||
self.module
|
||||
.check_table_type(&table.ty, features, types, offset)?;
|
||||
|
||||
match &table.init {
|
||||
TableInit::RefNull => {
|
||||
if !table.ty.element_type.nullable {
|
||||
bail!(offset, "type mismatch: non-defaultable element type");
|
||||
}
|
||||
}
|
||||
TableInit::Expr(expr) => {
|
||||
if !features.function_references {
|
||||
bail!(
|
||||
offset,
|
||||
"tables with expression initializers require \
|
||||
the function-references proposal"
|
||||
);
|
||||
}
|
||||
self.check_const_expr(expr, table.ty.element_type.into(), features, types)?;
|
||||
}
|
||||
}
|
||||
self.module.assert_mut().tables.push(table.ty);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_data_segment(
|
||||
&mut self,
|
||||
data: Data,
|
||||
|
@ -174,11 +198,9 @@ impl ModuleState {
|
|||
) -> Result<()> {
|
||||
// the `funcref` value type is allowed all the way back to the MVP, so
|
||||
// don't check it here
|
||||
if e.ty != ValType::FuncRef {
|
||||
check_value_type(e.ty, features, offset)?;
|
||||
}
|
||||
if !e.ty.is_reference_type() {
|
||||
return Err(BinaryReaderError::new("malformed reference type", offset));
|
||||
if e.ty != RefType::FUNCREF {
|
||||
self.module
|
||||
.check_value_type(ValType::Ref(e.ty), features, types, offset)?;
|
||||
}
|
||||
match e.kind {
|
||||
ElementKind::Active {
|
||||
|
@ -186,9 +208,16 @@ impl ModuleState {
|
|||
offset_expr,
|
||||
} => {
|
||||
let table = self.module.table_at(table_index, offset)?;
|
||||
if e.ty != table.element_type {
|
||||
if !self
|
||||
.module
|
||||
.matches(ValType::Ref(e.ty), ValType::Ref(table.element_type), types)
|
||||
{
|
||||
return Err(BinaryReaderError::new(
|
||||
"invalid element type for table type",
|
||||
format!(
|
||||
"type mismatch: invalid element type `{}` for table type `{}`",
|
||||
ty_to_str(e.ty.into()),
|
||||
ty_to_str(table.element_type.into()),
|
||||
),
|
||||
offset,
|
||||
));
|
||||
}
|
||||
|
@ -217,15 +246,16 @@ impl ModuleState {
|
|||
};
|
||||
match e.items {
|
||||
crate::ElementItems::Functions(reader) => {
|
||||
validate_count(reader.count())?;
|
||||
let count = reader.count();
|
||||
if !e.ty.nullable && count <= 0 {
|
||||
return Err(BinaryReaderError::new(
|
||||
"a non-nullable element must come with an initialization expression",
|
||||
offset,
|
||||
));
|
||||
}
|
||||
validate_count(count)?;
|
||||
for f in reader.into_iter_with_offsets() {
|
||||
let (offset, f) = f?;
|
||||
if e.ty != ValType::FuncRef {
|
||||
return Err(BinaryReaderError::new(
|
||||
"type mismatch: segment does not have funcref type",
|
||||
offset,
|
||||
));
|
||||
}
|
||||
self.module.get_func_type(f, types, offset)?;
|
||||
self.module.assert_mut().function_references.insert(f);
|
||||
}
|
||||
|
@ -233,7 +263,7 @@ impl ModuleState {
|
|||
crate::ElementItems::Expressions(reader) => {
|
||||
validate_count(reader.count())?;
|
||||
for expr in reader {
|
||||
self.check_const_expr(&expr?, e.ty, features, types)?;
|
||||
self.check_const_expr(&expr?, ValType::Ref(e.ty), features, types)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -448,7 +478,7 @@ pub(crate) struct Module {
|
|||
pub tables: Vec<TableType>,
|
||||
pub memories: Vec<MemoryType>,
|
||||
pub globals: Vec<GlobalType>,
|
||||
pub element_types: Vec<ValType>,
|
||||
pub element_types: Vec<RefType>,
|
||||
pub data_count: Option<u32>,
|
||||
// Stores indexes into `types`.
|
||||
pub functions: Vec<u32>,
|
||||
|
@ -473,7 +503,7 @@ impl Module {
|
|||
let ty = match ty {
|
||||
crate::Type::Func(t) => {
|
||||
for ty in t.params().iter().chain(t.results()) {
|
||||
check_value_type(*ty, features, offset)?;
|
||||
self.check_value_type(*ty, features, types, offset)?;
|
||||
}
|
||||
if t.results().len() > 1 && !features.multi_value {
|
||||
return Err(BinaryReaderError::new(
|
||||
|
@ -586,17 +616,6 @@ impl Module {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_table(
|
||||
&mut self,
|
||||
ty: TableType,
|
||||
features: &WasmFeatures,
|
||||
offset: usize,
|
||||
) -> Result<()> {
|
||||
self.check_table_type(&ty, features, offset)?;
|
||||
self.tables.push(ty);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_memory(
|
||||
&mut self,
|
||||
ty: MemoryType,
|
||||
|
@ -651,7 +670,7 @@ impl Module {
|
|||
EntityType::Func(self.types[*type_index as usize])
|
||||
}
|
||||
TypeRef::Table(t) => {
|
||||
self.check_table_type(t, features, offset)?;
|
||||
self.check_table_type(t, features, types, offset)?;
|
||||
EntityType::Table(*t)
|
||||
}
|
||||
TypeRef::Memory(t) => {
|
||||
|
@ -663,7 +682,7 @@ impl Module {
|
|||
EntityType::Tag(self.types[t.func_type_idx as usize])
|
||||
}
|
||||
TypeRef::Global(t) => {
|
||||
self.check_global_type(t, features, offset)?;
|
||||
self.check_global_type(t, features, types, offset)?;
|
||||
EntityType::Global(*t)
|
||||
}
|
||||
})
|
||||
|
@ -673,20 +692,15 @@ impl Module {
|
|||
&self,
|
||||
ty: &TableType,
|
||||
features: &WasmFeatures,
|
||||
types: &TypeList,
|
||||
offset: usize,
|
||||
) -> Result<()> {
|
||||
// the `funcref` value type is allowed all the way back to the MVP, so
|
||||
// don't check it here
|
||||
if ty.element_type != ValType::FuncRef {
|
||||
check_value_type(ty.element_type, features, offset)?;
|
||||
if ty.element_type != RefType::FUNCREF {
|
||||
self.check_value_type(ValType::Ref(ty.element_type), features, types, offset)?
|
||||
}
|
||||
|
||||
if !ty.element_type.is_reference_type() {
|
||||
return Err(BinaryReaderError::new(
|
||||
"element is not reference type",
|
||||
offset,
|
||||
));
|
||||
}
|
||||
self.check_limits(ty.initial, ty.maximum, offset)?;
|
||||
if ty.initial > MAX_WASM_TABLE_ENTRIES as u32 {
|
||||
return Err(BinaryReaderError::new(
|
||||
|
@ -766,6 +780,100 @@ impl Module {
|
|||
.collect::<Result<_>>()
|
||||
}
|
||||
|
||||
fn check_value_type(
|
||||
&self,
|
||||
ty: ValType,
|
||||
features: &WasmFeatures,
|
||||
types: &TypeList,
|
||||
offset: usize,
|
||||
) -> Result<()> {
|
||||
match features.check_value_type(ty) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => Err(BinaryReaderError::new(e, offset)),
|
||||
}?;
|
||||
// The above only checks the value type for features.
|
||||
// We must check it if it's a reference.
|
||||
match ty {
|
||||
ValType::Ref(rt) => {
|
||||
self.check_ref_type(rt, types, offset)?;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_ref_type(&self, ty: RefType, types: &TypeList, offset: usize) -> Result<()> {
|
||||
// Check that the heap type is valid
|
||||
match ty.heap_type {
|
||||
HeapType::Func | HeapType::Extern => (),
|
||||
HeapType::TypedFunc(type_index) => {
|
||||
// Just check that the index is valid
|
||||
self.func_type_at(type_index.into(), types, offset)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn eq_valtypes(&self, ty1: ValType, ty2: ValType, types: &TypeList) -> bool {
|
||||
match (ty1, ty2) {
|
||||
(ValType::Ref(rt1), ValType::Ref(rt2)) => {
|
||||
rt1.nullable == rt2.nullable
|
||||
&& match (rt1.heap_type, rt2.heap_type) {
|
||||
(HeapType::Func, HeapType::Func) => true,
|
||||
(HeapType::Extern, HeapType::Extern) => true,
|
||||
(HeapType::TypedFunc(n1), HeapType::TypedFunc(n2)) => {
|
||||
let n1 = self.func_type_at(n1.into(), types, 0).unwrap();
|
||||
let n2 = self.func_type_at(n2.into(), types, 0).unwrap();
|
||||
self.eq_fns(n1, n2, types)
|
||||
}
|
||||
(_, _) => false,
|
||||
}
|
||||
}
|
||||
_ => ty1 == ty2,
|
||||
}
|
||||
}
|
||||
fn eq_fns(&self, f1: &impl WasmFuncType, f2: &impl WasmFuncType, types: &TypeList) -> bool {
|
||||
f1.len_inputs() == f2.len_inputs()
|
||||
&& f2.len_outputs() == f2.len_outputs()
|
||||
&& f1
|
||||
.inputs()
|
||||
.zip(f2.inputs())
|
||||
.all(|(t1, t2)| self.eq_valtypes(t1, t2, types))
|
||||
&& f1
|
||||
.outputs()
|
||||
.zip(f2.outputs())
|
||||
.all(|(t1, t2)| self.eq_valtypes(t1, t2, types))
|
||||
}
|
||||
|
||||
pub(crate) fn matches(&self, ty1: ValType, ty2: ValType, types: &TypeList) -> bool {
|
||||
fn matches_null(null1: bool, null2: bool) -> bool {
|
||||
(null1 == null2) || null2
|
||||
}
|
||||
|
||||
let matches_heap = |ty1: HeapType, ty2: HeapType, types: &TypeList| -> bool {
|
||||
match (ty1, ty2) {
|
||||
(HeapType::TypedFunc(n1), HeapType::TypedFunc(n2)) => {
|
||||
// Check whether the defined types are (structurally) equivalent.
|
||||
let n1 = self.func_type_at(n1.into(), types, 0).unwrap();
|
||||
let n2 = self.func_type_at(n2.into(), types, 0).unwrap();
|
||||
self.eq_fns(n1, n2, types)
|
||||
}
|
||||
(HeapType::TypedFunc(_), HeapType::Func) => true,
|
||||
(_, _) => ty1 == ty2,
|
||||
}
|
||||
};
|
||||
|
||||
let matches_ref = |ty1: RefType, ty2: RefType, types: &TypeList| -> bool {
|
||||
matches_heap(ty1.heap_type, ty2.heap_type, types)
|
||||
&& matches_null(ty1.nullable, ty2.nullable)
|
||||
};
|
||||
|
||||
match (ty1, ty2) {
|
||||
(ValType::Ref(rt1), ValType::Ref(rt2)) => matches_ref(rt1, rt2, types),
|
||||
(_, _) => ty1 == ty2,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_tag_type(
|
||||
&self,
|
||||
ty: &TagType,
|
||||
|
@ -793,9 +901,10 @@ impl Module {
|
|||
&self,
|
||||
ty: &GlobalType,
|
||||
features: &WasmFeatures,
|
||||
types: &TypeList,
|
||||
offset: usize,
|
||||
) -> Result<()> {
|
||||
check_value_type(ty.content_type, features, offset)
|
||||
self.check_value_type(ty.content_type, features, types, offset)
|
||||
}
|
||||
|
||||
fn check_limits<T>(&self, initial: T, maximum: Option<T>, offset: usize) -> Result<()>
|
||||
|
@ -974,14 +1083,27 @@ impl WasmModuleResources for OperatorValidatorResources<'_> {
|
|||
)
|
||||
}
|
||||
|
||||
fn type_of_function(&self, at: u32) -> Option<&Self::FuncType> {
|
||||
self.func_type_at(*self.module.functions.get(at as usize)?)
|
||||
fn type_index_of_function(&self, at: u32) -> Option<u32> {
|
||||
self.module.functions.get(at as usize).cloned()
|
||||
}
|
||||
|
||||
fn element_type_at(&self, at: u32) -> Option<ValType> {
|
||||
fn type_of_function(&self, at: u32) -> Option<&Self::FuncType> {
|
||||
self.func_type_at(self.type_index_of_function(at)?)
|
||||
}
|
||||
|
||||
fn check_value_type(&self, t: ValType, features: &WasmFeatures, offset: usize) -> Result<()> {
|
||||
self.module
|
||||
.check_value_type(t, features, self.types, offset)
|
||||
}
|
||||
|
||||
fn element_type_at(&self, at: u32) -> Option<RefType> {
|
||||
self.module.element_types.get(at as usize).cloned()
|
||||
}
|
||||
|
||||
fn matches(&self, t1: ValType, t2: ValType) -> bool {
|
||||
self.module.matches(t1, t2, self.types)
|
||||
}
|
||||
|
||||
fn element_count(&self) -> u32 {
|
||||
self.module.element_types.len() as u32
|
||||
}
|
||||
|
@ -1030,14 +1152,27 @@ impl WasmModuleResources for ValidatorResources {
|
|||
)
|
||||
}
|
||||
|
||||
fn type_of_function(&self, at: u32) -> Option<&Self::FuncType> {
|
||||
self.func_type_at(*self.0.functions.get(at as usize)?)
|
||||
fn type_index_of_function(&self, at: u32) -> Option<u32> {
|
||||
self.0.functions.get(at as usize).cloned()
|
||||
}
|
||||
|
||||
fn element_type_at(&self, at: u32) -> Option<ValType> {
|
||||
fn type_of_function(&self, at: u32) -> Option<&Self::FuncType> {
|
||||
self.func_type_at(self.type_index_of_function(at)?)
|
||||
}
|
||||
|
||||
fn check_value_type(&self, t: ValType, features: &WasmFeatures, offset: usize) -> Result<()> {
|
||||
self.0
|
||||
.check_value_type(t, features, self.0.snapshot.as_ref().unwrap(), offset)
|
||||
}
|
||||
|
||||
fn element_type_at(&self, at: u32) -> Option<RefType> {
|
||||
self.0.element_types.get(at as usize).cloned()
|
||||
}
|
||||
|
||||
fn matches(&self, t1: ValType, t2: ValType) -> bool {
|
||||
self.0.matches(t1, t2, self.0.snapshot.as_ref().unwrap())
|
||||
}
|
||||
|
||||
fn element_count(&self) -> u32 {
|
||||
self.0.element_types.len() as u32
|
||||
}
|
||||
|
|
|
@ -119,7 +119,8 @@ impl<T: WasmModuleResources> FuncValidator<T> {
|
|||
/// This should be used if the application is already reading local
|
||||
/// definitions and there's no need to re-parse the function again.
|
||||
pub fn define_locals(&mut self, offset: usize, count: u32, ty: ValType) -> Result<()> {
|
||||
self.validator.define_locals(offset, count, ty)
|
||||
self.validator
|
||||
.define_locals(offset, count, ty, &self.resources)
|
||||
}
|
||||
|
||||
/// Validates the next operator in a function.
|
||||
|
@ -269,10 +270,24 @@ mod tests {
|
|||
fn func_type_at(&self, _type_idx: u32) -> Option<&Self::FuncType> {
|
||||
Some(&EmptyFuncType)
|
||||
}
|
||||
fn type_index_of_function(&self, _at: u32) -> Option<u32> {
|
||||
todo!()
|
||||
}
|
||||
fn type_of_function(&self, _func_idx: u32) -> Option<&Self::FuncType> {
|
||||
todo!()
|
||||
}
|
||||
fn element_type_at(&self, _at: u32) -> Option<ValType> {
|
||||
fn check_value_type(
|
||||
&self,
|
||||
_t: ValType,
|
||||
_features: &WasmFeatures,
|
||||
_offset: usize,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn element_type_at(&self, _at: u32) -> Option<crate::RefType> {
|
||||
todo!()
|
||||
}
|
||||
fn matches(&self, _t1: ValType, _t2: ValType) -> bool {
|
||||
todo!()
|
||||
}
|
||||
fn element_count(&self) -> u32 {
|
||||
|
|
|
@ -23,25 +23,30 @@
|
|||
// the various methods here.
|
||||
|
||||
use crate::{
|
||||
limits::MAX_WASM_FUNCTION_LOCALS, BinaryReaderError, BlockType, BrTable, Ieee32, Ieee64,
|
||||
MemArg, Result, ValType, VisitOperator, WasmFeatures, WasmFuncType, WasmModuleResources, V128,
|
||||
limits::MAX_WASM_FUNCTION_LOCALS, BinaryReaderError, BlockType, BrTable, HeapType, Ieee32,
|
||||
Ieee64, MemArg, RefType, Result, ValType, VisitOperator, WasmFeatures, WasmFuncType,
|
||||
WasmModuleResources, V128,
|
||||
};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
pub(crate) struct OperatorValidator {
|
||||
pub(super) locals: Locals,
|
||||
pub(super) local_inits: Vec<bool>,
|
||||
|
||||
// This is a list of flags for wasm features which are used to gate various
|
||||
// instructions.
|
||||
pub(crate) features: WasmFeatures,
|
||||
|
||||
// Temporary storage used during the validation of `br_table`.
|
||||
br_table_tmp: Vec<Option<ValType>>,
|
||||
br_table_tmp: Vec<MaybeType>,
|
||||
|
||||
/// The `control` list is the list of blocks that we're currently in.
|
||||
control: Vec<Frame>,
|
||||
/// The `operands` is the current type stack.
|
||||
operands: Vec<Option<ValType>>,
|
||||
operands: Vec<MaybeType>,
|
||||
/// When local_inits is modified, the relevant index is recorded here to be
|
||||
/// undone when control pops
|
||||
inits: Vec<u32>,
|
||||
|
||||
/// Offset of the `end` instruction which emptied the `control` stack, which
|
||||
/// must be the end of the function.
|
||||
|
@ -92,6 +97,8 @@ pub struct Frame {
|
|||
pub height: usize,
|
||||
/// Whether this frame is unreachable so far.
|
||||
pub unreachable: bool,
|
||||
/// The number of initializations in the stack at the time of its creation
|
||||
pub init_height: usize,
|
||||
}
|
||||
|
||||
/// The kind of a control flow [`Frame`].
|
||||
|
@ -133,25 +140,55 @@ struct OperatorValidatorTemp<'validator, 'resources, T> {
|
|||
|
||||
#[derive(Default)]
|
||||
pub struct OperatorValidatorAllocations {
|
||||
br_table_tmp: Vec<Option<ValType>>,
|
||||
br_table_tmp: Vec<MaybeType>,
|
||||
control: Vec<Frame>,
|
||||
operands: Vec<Option<ValType>>,
|
||||
operands: Vec<MaybeType>,
|
||||
local_inits: Vec<bool>,
|
||||
inits: Vec<u32>,
|
||||
locals_first: Vec<ValType>,
|
||||
locals_all: Vec<(u32, ValType)>,
|
||||
}
|
||||
|
||||
/// Type storage within the validator.
|
||||
///
|
||||
/// This is used to manage the operand stack and notably isn't just `ValType` to
|
||||
/// handle unreachable code and the "bottom" type.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum MaybeType {
|
||||
Bot,
|
||||
HeapBot,
|
||||
Type(ValType),
|
||||
}
|
||||
|
||||
// The validator is pretty performance-sensitive and `MaybeType` is the main
|
||||
// unit of storage, so assert that it doesn't exceed 4 bytes which is the
|
||||
// current expected size.
|
||||
const _: () = {
|
||||
assert!(std::mem::size_of::<MaybeType>() == 4);
|
||||
};
|
||||
|
||||
impl From<ValType> for MaybeType {
|
||||
fn from(ty: ValType) -> MaybeType {
|
||||
MaybeType::Type(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl OperatorValidator {
|
||||
fn new(features: &WasmFeatures, allocs: OperatorValidatorAllocations) -> Self {
|
||||
let OperatorValidatorAllocations {
|
||||
br_table_tmp,
|
||||
control,
|
||||
operands,
|
||||
local_inits,
|
||||
inits,
|
||||
locals_first,
|
||||
locals_all,
|
||||
} = allocs;
|
||||
debug_assert!(br_table_tmp.is_empty());
|
||||
debug_assert!(control.is_empty());
|
||||
debug_assert!(operands.is_empty());
|
||||
debug_assert!(local_inits.is_empty());
|
||||
debug_assert!(inits.is_empty());
|
||||
debug_assert!(locals_first.is_empty());
|
||||
debug_assert!(locals_all.is_empty());
|
||||
OperatorValidator {
|
||||
|
@ -160,6 +197,8 @@ impl OperatorValidator {
|
|||
first: locals_first,
|
||||
all: locals_all,
|
||||
},
|
||||
local_inits,
|
||||
inits,
|
||||
features: *features,
|
||||
br_table_tmp,
|
||||
operands,
|
||||
|
@ -189,6 +228,7 @@ impl OperatorValidator {
|
|||
block_type: BlockType::FuncType(ty),
|
||||
height: 0,
|
||||
unreachable: false,
|
||||
init_height: 0,
|
||||
});
|
||||
let params = OperatorValidatorTemp {
|
||||
// This offset is used by the `func_type_at` and `inputs`.
|
||||
|
@ -200,6 +240,7 @@ impl OperatorValidator {
|
|||
.inputs();
|
||||
for ty in params {
|
||||
ret.locals.define(1, ty);
|
||||
ret.local_inits.push(true);
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
|
@ -218,14 +259,19 @@ impl OperatorValidator {
|
|||
block_type: BlockType::Type(ty),
|
||||
height: 0,
|
||||
unreachable: false,
|
||||
init_height: 0,
|
||||
});
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn define_locals(&mut self, offset: usize, count: u32, ty: ValType) -> Result<()> {
|
||||
self.features
|
||||
.check_value_type(ty)
|
||||
.map_err(|e| BinaryReaderError::new(e, offset))?;
|
||||
pub fn define_locals(
|
||||
&mut self,
|
||||
offset: usize,
|
||||
count: u32,
|
||||
ty: ValType,
|
||||
resources: &impl WasmModuleResources,
|
||||
) -> Result<()> {
|
||||
resources.check_value_type(ty, &self.features, offset)?;
|
||||
if count == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -235,6 +281,8 @@ impl OperatorValidator {
|
|||
offset,
|
||||
));
|
||||
}
|
||||
self.local_inits
|
||||
.resize(self.local_inits.len() + count as usize, ty.is_defaultable());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -254,7 +302,10 @@ impl OperatorValidator {
|
|||
///
|
||||
/// A `depth` of 0 will refer to the last operand on the stack.
|
||||
pub fn peek_operand_at(&self, depth: usize) -> Option<Option<ValType>> {
|
||||
self.operands.iter().rev().nth(depth).copied()
|
||||
Some(match self.operands.iter().rev().nth(depth)? {
|
||||
MaybeType::Type(t) => Some(*t),
|
||||
MaybeType::Bot | MaybeType::HeapBot => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the number of frames on the control flow stack.
|
||||
|
@ -314,6 +365,8 @@ impl OperatorValidator {
|
|||
br_table_tmp: truncate(self.br_table_tmp),
|
||||
control: truncate(self.control),
|
||||
operands: truncate(self.operands),
|
||||
local_inits: truncate(self.local_inits),
|
||||
inits: truncate(self.inits),
|
||||
locals_first: truncate(self.locals.first),
|
||||
locals_all: truncate(self.locals.all),
|
||||
}
|
||||
|
@ -341,7 +394,7 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
/// Otherwise the push operation always succeeds.
|
||||
fn push_operand<T>(&mut self, ty: T) -> Result<()>
|
||||
where
|
||||
T: Into<Option<ValType>>,
|
||||
T: Into<MaybeType>,
|
||||
{
|
||||
let maybe_ty = ty.into();
|
||||
self.operands.push(maybe_ty);
|
||||
|
@ -355,7 +408,7 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
/// simply that something is needed to be popped.
|
||||
///
|
||||
/// If `expected` is `Some(T)` then this will be guaranteed to return
|
||||
/// `Some(T)`, and it will only return success if the current block is
|
||||
/// `T`, and it will only return success if the current block is
|
||||
/// unreachable or if `T` was found at the top of the operand stack.
|
||||
///
|
||||
/// If `expected` is `None` then it indicates that something must be on the
|
||||
|
@ -366,7 +419,7 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
/// matches `expected`. If `None` is returned then it means that `None` was
|
||||
/// expected and a type was successfully popped, but its exact type is
|
||||
/// indeterminate because the current block is unreachable.
|
||||
fn pop_operand(&mut self, expected: Option<ValType>) -> Result<Option<ValType>> {
|
||||
fn pop_operand(&mut self, expected: Option<ValType>) -> Result<MaybeType> {
|
||||
// This method is one of the hottest methods in the validator so to
|
||||
// improve codegen this method contains a fast-path success case where
|
||||
// if the top operand on the stack is as expected it's returned
|
||||
|
@ -378,17 +431,18 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
// matched against the state of the world to see if we could actually
|
||||
// pop it. If we shouldn't have popped it then it's passed to the slow
|
||||
// path to get pushed back onto the stack.
|
||||
let popped = if let Some(actual_ty) = self.operands.pop() {
|
||||
if actual_ty == expected {
|
||||
if let Some(control) = self.control.last() {
|
||||
if self.operands.len() >= control.height {
|
||||
return Ok(actual_ty);
|
||||
let popped = match self.operands.pop() {
|
||||
Some(MaybeType::Type(actual_ty)) => {
|
||||
if Some(actual_ty) == expected {
|
||||
if let Some(control) = self.control.last() {
|
||||
if self.operands.len() >= control.height {
|
||||
return Ok(MaybeType::Type(actual_ty));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(MaybeType::Type(actual_ty))
|
||||
}
|
||||
Some(actual_ty)
|
||||
} else {
|
||||
None
|
||||
other => other,
|
||||
};
|
||||
|
||||
self._pop_operand(expected, popped)
|
||||
|
@ -401,17 +455,17 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
fn _pop_operand(
|
||||
&mut self,
|
||||
expected: Option<ValType>,
|
||||
popped: Option<Option<ValType>>,
|
||||
) -> Result<Option<ValType>> {
|
||||
popped: Option<MaybeType>,
|
||||
) -> Result<MaybeType> {
|
||||
self.operands.extend(popped);
|
||||
let control = match self.control.last() {
|
||||
Some(c) => c,
|
||||
None => return Err(self.err_beyond_end(self.offset)),
|
||||
};
|
||||
let actual = if self.operands.len() == control.height {
|
||||
if control.unreachable {
|
||||
None
|
||||
} else {
|
||||
let actual = if self.operands.len() == control.height && control.unreachable {
|
||||
MaybeType::Bot
|
||||
} else {
|
||||
if self.operands.len() == control.height {
|
||||
let desc = match expected {
|
||||
Some(ty) => ty_to_str(ty),
|
||||
None => "a type",
|
||||
|
@ -420,23 +474,59 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
self.offset,
|
||||
"type mismatch: expected {desc} but nothing on stack"
|
||||
)
|
||||
} else {
|
||||
self.operands.pop().unwrap()
|
||||
}
|
||||
} else {
|
||||
self.operands.pop().unwrap()
|
||||
};
|
||||
if let (Some(actual_ty), Some(expected_ty)) = (actual, expected) {
|
||||
if actual_ty != expected_ty {
|
||||
bail!(
|
||||
self.offset,
|
||||
"type mismatch: expected {}, found {}",
|
||||
ty_to_str(expected_ty),
|
||||
ty_to_str(actual_ty)
|
||||
)
|
||||
if let Some(expected) = expected {
|
||||
match (actual, expected) {
|
||||
// The bottom type matches all expectations
|
||||
(MaybeType::Bot, _)
|
||||
// The "heap bottom" type only matches other references types,
|
||||
// but not any integer types.
|
||||
| (MaybeType::HeapBot, ValType::Ref(_)) => {}
|
||||
|
||||
// Use the `matches` predicate to test if a found type matches
|
||||
// the expectation.
|
||||
(MaybeType::Type(actual), expected) => {
|
||||
if !self.resources.matches(actual, expected) {
|
||||
bail!(
|
||||
self.offset,
|
||||
"type mismatch: expected {}, found {}",
|
||||
ty_to_str(expected),
|
||||
ty_to_str(actual)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// A "heap bottom" type cannot match any numeric types.
|
||||
(
|
||||
MaybeType::HeapBot,
|
||||
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128,
|
||||
) => {
|
||||
bail!(
|
||||
self.offset,
|
||||
"type mismatche: expected {}, found heap type",
|
||||
ty_to_str(expected)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(actual)
|
||||
}
|
||||
|
||||
fn pop_ref(&mut self) -> Result<Option<RefType>> {
|
||||
match self.pop_operand(None)? {
|
||||
MaybeType::Bot | MaybeType::HeapBot => Ok(None),
|
||||
MaybeType::Type(ValType::Ref(rt)) => Ok(Some(rt)),
|
||||
MaybeType::Type(ty) => bail!(
|
||||
self.offset,
|
||||
"type mismatch: expected ref but found {}",
|
||||
ty_to_str(ty)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetches the type for the local at `idx`, returning an error if it's out
|
||||
/// of bounds.
|
||||
fn local(&self, idx: u32) -> Result<ValType> {
|
||||
|
@ -473,11 +563,13 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
// Push a new frame which has a snapshot of the height of the current
|
||||
// operand stack.
|
||||
let height = self.operands.len();
|
||||
let init_height = self.inits.len();
|
||||
self.control.push(Frame {
|
||||
kind,
|
||||
block_type: ty,
|
||||
height,
|
||||
unreachable: false,
|
||||
init_height,
|
||||
});
|
||||
// All of the parameters are now also available in this control frame,
|
||||
// so we push them here in order.
|
||||
|
@ -500,6 +592,12 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
};
|
||||
let ty = frame.block_type;
|
||||
let height = frame.height;
|
||||
let init_height = frame.init_height;
|
||||
|
||||
// reset_locals in the spec
|
||||
for init in self.inits.split_off(init_height) {
|
||||
self.local_inits[init as usize] = false;
|
||||
}
|
||||
|
||||
// Pop all the result types, in reverse order, from the operand stack.
|
||||
// These types will, possibly, be transferred to the next frame.
|
||||
|
@ -587,10 +685,9 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
fn check_block_type(&self, ty: BlockType) -> Result<()> {
|
||||
match ty {
|
||||
BlockType::Empty => Ok(()),
|
||||
BlockType::Type(ty) => self
|
||||
.features
|
||||
.check_value_type(ty)
|
||||
.map_err(|e| BinaryReaderError::new(e, self.offset)),
|
||||
BlockType::Type(t) => self
|
||||
.resources
|
||||
.check_value_type(t, &self.features, self.offset),
|
||||
BlockType::FuncType(idx) => {
|
||||
if !self.features.multi_value {
|
||||
bail!(
|
||||
|
@ -608,13 +705,25 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
/// Validates a `call` instruction, ensuring that the function index is
|
||||
/// in-bounds and the right types are on the stack to call the function.
|
||||
fn check_call(&mut self, function_index: u32) -> Result<()> {
|
||||
let ty = match self.resources.type_of_function(function_index) {
|
||||
let ty = match self.resources.type_index_of_function(function_index) {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
bail!(
|
||||
self.offset,
|
||||
"unknown function {}: function index out of bounds",
|
||||
function_index
|
||||
"unknown function {function_index}: function index out of bounds",
|
||||
);
|
||||
}
|
||||
};
|
||||
self.check_call_ty(ty)
|
||||
}
|
||||
|
||||
fn check_call_ty(&mut self, type_index: u32) -> Result<()> {
|
||||
let ty = match self.resources.func_type_at(type_index) {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
bail!(
|
||||
self.offset,
|
||||
"unknown type {type_index}: type index out of bounds",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@ -634,10 +743,13 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
bail!(self.offset, "unknown table: table index out of bounds");
|
||||
}
|
||||
Some(tab) => {
|
||||
if tab.element_type != ValType::FuncRef {
|
||||
if !self
|
||||
.resources
|
||||
.matches(ValType::Ref(tab.element_type), ValType::FUNCREF)
|
||||
{
|
||||
bail!(
|
||||
self.offset,
|
||||
"indirect calls must go through a table of funcref"
|
||||
"indirect calls must go through a table with type <= funcref",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -780,14 +892,6 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
self.check_v128_binary_op()
|
||||
}
|
||||
|
||||
/// Checks a [`V128`] binary operator.
|
||||
fn check_v128_relaxed_binary_op(&mut self) -> Result<()> {
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
self.push_operand(ValType::V128)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks a [`V128`] binary operator.
|
||||
fn check_v128_unary_op(&mut self) -> Result<()> {
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
|
@ -801,15 +905,8 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
self.check_v128_unary_op()
|
||||
}
|
||||
|
||||
/// Checks a [`V128`] binary operator.
|
||||
fn check_v128_relaxed_unary_op(&mut self) -> Result<()> {
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
self.push_operand(ValType::V128)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks a [`V128`] relaxed ternary operator.
|
||||
fn check_v128_relaxed_ternary_op(&mut self) -> Result<()> {
|
||||
fn check_v128_ternary_op(&mut self) -> Result<()> {
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
|
@ -879,15 +976,31 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R
|
|||
}
|
||||
}
|
||||
|
||||
fn ty_to_str(ty: ValType) -> &'static str {
|
||||
pub fn ty_to_str(ty: ValType) -> &'static str {
|
||||
match ty {
|
||||
ValType::I32 => "i32",
|
||||
ValType::I64 => "i64",
|
||||
ValType::F32 => "f32",
|
||||
ValType::F64 => "f64",
|
||||
ValType::V128 => "v128",
|
||||
ValType::FuncRef => "funcref",
|
||||
ValType::ExternRef => "externref",
|
||||
ValType::FUNCREF => "funcref",
|
||||
ValType::EXTERNREF => "externref",
|
||||
ValType::Ref(RefType {
|
||||
nullable: false,
|
||||
heap_type: HeapType::Func,
|
||||
}) => "(ref func)",
|
||||
ValType::Ref(RefType {
|
||||
nullable: false,
|
||||
heap_type: HeapType::Extern,
|
||||
}) => "(ref extern)",
|
||||
ValType::Ref(RefType {
|
||||
nullable: false,
|
||||
heap_type: HeapType::TypedFunc(_),
|
||||
}) => "(ref $type)",
|
||||
ValType::Ref(RefType {
|
||||
nullable: true,
|
||||
heap_type: HeapType::TypedFunc(_),
|
||||
}) => "(ref null $type)",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -936,6 +1049,7 @@ macro_rules! validate_proposal {
|
|||
(desc sign_extension) => ("sign extension operations");
|
||||
(desc exceptions) => ("exceptions");
|
||||
(desc tail_call) => ("tail calls");
|
||||
(desc function_references) => ("function references");
|
||||
(desc memory_control) => ("memory control");
|
||||
}
|
||||
|
||||
|
@ -1009,11 +1123,13 @@ where
|
|||
}
|
||||
// Start a new frame and push `exnref` value.
|
||||
let height = self.operands.len();
|
||||
let init_height = self.inits.len();
|
||||
self.control.push(Frame {
|
||||
kind: FrameKind::Catch,
|
||||
block_type: frame.block_type,
|
||||
height,
|
||||
unreachable: false,
|
||||
init_height,
|
||||
});
|
||||
// Push exception argument types.
|
||||
let ty = self.tag_at(index)?;
|
||||
|
@ -1071,11 +1187,13 @@ where
|
|||
bail!(self.offset, "catch_all found outside of a `try` block");
|
||||
}
|
||||
let height = self.operands.len();
|
||||
let init_height = self.inits.len();
|
||||
self.control.push(Frame {
|
||||
kind: FrameKind::CatchAll,
|
||||
block_type: frame.block_type,
|
||||
height,
|
||||
unreachable: false,
|
||||
init_height,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1162,6 +1280,39 @@ where
|
|||
self.check_return()?;
|
||||
Ok(())
|
||||
}
|
||||
fn visit_call_ref(&mut self, hty: HeapType) -> Self::Output {
|
||||
self.resources
|
||||
.check_heap_type(hty, &self.features, self.offset)?;
|
||||
// If `None` is popped then that means a "bottom" type was popped which
|
||||
// is always considered equivalent to the `hty` tag.
|
||||
if let Some(rt) = self.pop_ref()? {
|
||||
let expected = RefType {
|
||||
nullable: true,
|
||||
heap_type: hty,
|
||||
};
|
||||
if !self
|
||||
.resources
|
||||
.matches(ValType::Ref(rt), ValType::Ref(expected))
|
||||
{
|
||||
bail!(
|
||||
self.offset,
|
||||
"type mismatch: funcref on stack does not match specified type",
|
||||
);
|
||||
}
|
||||
}
|
||||
match hty {
|
||||
HeapType::TypedFunc(type_index) => self.check_call_ty(type_index.into())?,
|
||||
_ => bail!(
|
||||
self.offset,
|
||||
"type mismatch: instruction requires function reference type",
|
||||
),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn visit_return_call_ref(&mut self, hty: HeapType) -> Self::Output {
|
||||
self.visit_call_ref(hty)?;
|
||||
self.check_return()
|
||||
}
|
||||
fn visit_call_indirect(
|
||||
&mut self,
|
||||
index: u32,
|
||||
|
@ -1190,36 +1341,42 @@ where
|
|||
self.pop_operand(Some(ValType::I32))?;
|
||||
let ty1 = self.pop_operand(None)?;
|
||||
let ty2 = self.pop_operand(None)?;
|
||||
fn is_num(ty: Option<ValType>) -> bool {
|
||||
matches!(
|
||||
ty,
|
||||
Some(ValType::I32)
|
||||
| Some(ValType::I64)
|
||||
| Some(ValType::F32)
|
||||
| Some(ValType::F64)
|
||||
| Some(ValType::V128)
|
||||
| None
|
||||
)
|
||||
}
|
||||
if !is_num(ty1) || !is_num(ty2) {
|
||||
bail!(
|
||||
self.offset,
|
||||
"type mismatch: select only takes integral types"
|
||||
)
|
||||
}
|
||||
if ty1 != ty2 && ty1.is_some() && ty2.is_some() {
|
||||
bail!(
|
||||
self.offset,
|
||||
"type mismatch: select operands have different types"
|
||||
)
|
||||
}
|
||||
self.push_operand(ty1.or(ty2))?;
|
||||
|
||||
let ty = match (ty1, ty2) {
|
||||
// All heap-related types aren't allowed with the `select`
|
||||
// instruction
|
||||
(MaybeType::HeapBot, _)
|
||||
| (_, MaybeType::HeapBot)
|
||||
| (MaybeType::Type(ValType::Ref(_)), _)
|
||||
| (_, MaybeType::Type(ValType::Ref(_))) => {
|
||||
bail!(
|
||||
self.offset,
|
||||
"type mismatch: select only takes integral types"
|
||||
)
|
||||
}
|
||||
|
||||
// If one operand is the "bottom" type then whatever the other
|
||||
// operand is is the result of the `select`
|
||||
(MaybeType::Bot, t) | (t, MaybeType::Bot) => t,
|
||||
|
||||
// Otherwise these are two integral types and they must match for
|
||||
// `select` to typecheck.
|
||||
(t @ MaybeType::Type(t1), MaybeType::Type(t2)) => {
|
||||
if t1 != t2 {
|
||||
bail!(
|
||||
self.offset,
|
||||
"type mismatch: select operands have different types"
|
||||
);
|
||||
}
|
||||
t
|
||||
}
|
||||
};
|
||||
self.push_operand(ty)?;
|
||||
Ok(())
|
||||
}
|
||||
fn visit_typed_select(&mut self, ty: ValType) -> Self::Output {
|
||||
self.features
|
||||
.check_value_type(ty)
|
||||
.map_err(|e| BinaryReaderError::new(e, self.offset))?;
|
||||
self.resources
|
||||
.check_value_type(ty, &self.features, self.offset)?;
|
||||
self.pop_operand(Some(ValType::I32))?;
|
||||
self.pop_operand(Some(ty))?;
|
||||
self.pop_operand(Some(ty))?;
|
||||
|
@ -1228,17 +1385,29 @@ where
|
|||
}
|
||||
fn visit_local_get(&mut self, local_index: u32) -> Self::Output {
|
||||
let ty = self.local(local_index)?;
|
||||
if !self.local_inits[local_index as usize] {
|
||||
bail!(self.offset, "uninitialized local: {}", local_index);
|
||||
}
|
||||
self.push_operand(ty)?;
|
||||
Ok(())
|
||||
}
|
||||
fn visit_local_set(&mut self, local_index: u32) -> Self::Output {
|
||||
let ty = self.local(local_index)?;
|
||||
self.pop_operand(Some(ty))?;
|
||||
if !self.local_inits[local_index as usize] {
|
||||
self.local_inits[local_index as usize] = true;
|
||||
self.inits.push(local_index);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn visit_local_tee(&mut self, local_index: u32) -> Self::Output {
|
||||
let ty = self.local(local_index)?;
|
||||
self.pop_operand(Some(ty))?;
|
||||
if !self.local_inits[local_index as usize] {
|
||||
self.local_inits[local_index as usize] = true;
|
||||
self.inits.push(local_index);
|
||||
}
|
||||
|
||||
self.push_operand(ty)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2049,43 +2218,119 @@ where
|
|||
fn visit_atomic_fence(&mut self) -> Self::Output {
|
||||
Ok(())
|
||||
}
|
||||
fn visit_ref_null(&mut self, ty: ValType) -> Self::Output {
|
||||
self.features
|
||||
.check_value_type(ty)
|
||||
.map_err(|e| BinaryReaderError::new(e, self.offset))?;
|
||||
if !ty.is_reference_type() {
|
||||
bail!(self.offset, "invalid non-reference type in ref.null");
|
||||
fn visit_ref_null(&mut self, heap_type: HeapType) -> Self::Output {
|
||||
self.resources
|
||||
.check_heap_type(heap_type, &self.features, self.offset)?;
|
||||
self.push_operand(ValType::Ref(RefType {
|
||||
nullable: true,
|
||||
heap_type,
|
||||
}))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit_ref_as_non_null(&mut self) -> Self::Output {
|
||||
let ty = match self.pop_ref()? {
|
||||
Some(ty) => MaybeType::Type(ValType::Ref(RefType {
|
||||
nullable: false,
|
||||
heap_type: ty.heap_type,
|
||||
})),
|
||||
None => MaybeType::HeapBot,
|
||||
};
|
||||
self.push_operand(ty)?;
|
||||
Ok(())
|
||||
}
|
||||
fn visit_br_on_null(&mut self, relative_depth: u32) -> Self::Output {
|
||||
let ty = match self.pop_ref()? {
|
||||
None => MaybeType::HeapBot,
|
||||
Some(ty) => MaybeType::Type(ValType::Ref(RefType {
|
||||
nullable: false,
|
||||
heap_type: ty.heap_type,
|
||||
})),
|
||||
};
|
||||
let (ft, kind) = self.jump(relative_depth)?;
|
||||
for ty in self.label_types(ft, kind)?.rev() {
|
||||
self.pop_operand(Some(ty))?;
|
||||
}
|
||||
for ty in self.label_types(ft, kind)? {
|
||||
self.push_operand(ty)?;
|
||||
}
|
||||
self.push_operand(ty)?;
|
||||
Ok(())
|
||||
}
|
||||
fn visit_ref_is_null(&mut self) -> Self::Output {
|
||||
match self.pop_operand(None)? {
|
||||
None => {}
|
||||
Some(t) => {
|
||||
if !t.is_reference_type() {
|
||||
fn visit_br_on_non_null(&mut self, relative_depth: u32) -> Self::Output {
|
||||
let ty = self.pop_ref()?;
|
||||
let (ft, kind) = self.jump(relative_depth)?;
|
||||
let mut lts = self.label_types(ft, kind)?;
|
||||
match (lts.next_back(), ty) {
|
||||
(None, _) => bail!(
|
||||
self.offset,
|
||||
"type mismatch: br_on_non_null target has no label types",
|
||||
),
|
||||
(Some(ValType::Ref(_)), None) => {}
|
||||
(Some(rt1 @ ValType::Ref(_)), Some(rt0)) => {
|
||||
// Switch rt0, our popped type, to a non-nullable type and
|
||||
// perform the match because if the branch is taken it's a
|
||||
// non-null value.
|
||||
let ty = RefType {
|
||||
nullable: false,
|
||||
heap_type: rt0.heap_type,
|
||||
};
|
||||
if !self.resources.matches(ty.into(), rt1) {
|
||||
bail!(
|
||||
self.offset,
|
||||
"type mismatch: invalid reference type in ref.is_null"
|
||||
);
|
||||
"type mismatch: expected {} but found {}",
|
||||
ty_to_str(rt0.into()),
|
||||
ty_to_str(rt1)
|
||||
)
|
||||
}
|
||||
}
|
||||
(Some(_), _) => bail!(
|
||||
self.offset,
|
||||
"type mismatch: br_on_non_null target does not end with heap type",
|
||||
),
|
||||
}
|
||||
for ty in self.label_types(ft, kind)?.rev().skip(1) {
|
||||
self.pop_operand(Some(ty))?;
|
||||
}
|
||||
for ty in lts {
|
||||
self.push_operand(ty)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn visit_ref_is_null(&mut self) -> Self::Output {
|
||||
self.pop_ref()?;
|
||||
self.push_operand(ValType::I32)?;
|
||||
Ok(())
|
||||
}
|
||||
fn visit_ref_func(&mut self, function_index: u32) -> Self::Output {
|
||||
if self.resources.type_of_function(function_index).is_none() {
|
||||
bail!(
|
||||
let type_index = match self.resources.type_index_of_function(function_index) {
|
||||
Some(idx) => idx,
|
||||
None => bail!(
|
||||
self.offset,
|
||||
"unknown function {}: function index out of bounds",
|
||||
function_index,
|
||||
);
|
||||
}
|
||||
),
|
||||
};
|
||||
if !self.resources.is_function_referenced(function_index) {
|
||||
bail!(self.offset, "undeclared function reference");
|
||||
}
|
||||
self.push_operand(ValType::FuncRef)?;
|
||||
|
||||
// FIXME(#924) this should not be conditional based on enabled
|
||||
// proposals.
|
||||
if self.features.function_references {
|
||||
let heap_type = HeapType::TypedFunc(match type_index.try_into() {
|
||||
Ok(packed) => packed,
|
||||
Err(_) => {
|
||||
bail!(self.offset, "type index of `ref.func` target too large")
|
||||
}
|
||||
});
|
||||
self.push_operand(ValType::Ref(RefType {
|
||||
nullable: false,
|
||||
heap_type,
|
||||
}))?;
|
||||
} else {
|
||||
self.push_operand(ValType::FUNCREF)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn visit_v128_load(&mut self, memarg: MemArg) -> Self::Output {
|
||||
|
@ -2296,24 +2541,6 @@ where
|
|||
fn visit_f64x2_pmax(&mut self) -> Self::Output {
|
||||
self.check_v128_fbinary_op()
|
||||
}
|
||||
fn visit_f32x4_relaxed_min(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_binary_op()
|
||||
}
|
||||
fn visit_f32x4_relaxed_max(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_binary_op()
|
||||
}
|
||||
fn visit_f64x2_relaxed_min(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_binary_op()
|
||||
}
|
||||
fn visit_f64x2_relaxed_max(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_binary_op()
|
||||
}
|
||||
fn visit_i16x8_relaxed_q15mulr_s(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_binary_op()
|
||||
}
|
||||
fn visit_i16x8_dot_i8x16_i7x16_s(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_binary_op()
|
||||
}
|
||||
fn visit_i8x16_eq(&mut self) -> Self::Output {
|
||||
self.check_v128_binary_op()
|
||||
}
|
||||
|
@ -2737,18 +2964,6 @@ where
|
|||
fn visit_i32x4_extadd_pairwise_i16x8_u(&mut self) -> Self::Output {
|
||||
self.check_v128_unary_op()
|
||||
}
|
||||
fn visit_i32x4_relaxed_trunc_sat_f32x4_s(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_unary_op()
|
||||
}
|
||||
fn visit_i32x4_relaxed_trunc_sat_f32x4_u(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_unary_op()
|
||||
}
|
||||
fn visit_i32x4_relaxed_trunc_sat_f64x2_s_zero(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_unary_op()
|
||||
}
|
||||
fn visit_i32x4_relaxed_trunc_sat_f64x2_u_zero(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_unary_op()
|
||||
}
|
||||
fn visit_v128_bitselect(&mut self) -> Self::Output {
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
|
@ -2756,35 +2971,68 @@ where
|
|||
self.push_operand(ValType::V128)?;
|
||||
Ok(())
|
||||
}
|
||||
fn visit_f32x4_relaxed_fma(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_ternary_op()
|
||||
fn visit_i8x16_relaxed_swizzle(&mut self) -> Self::Output {
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
self.push_operand(ValType::V128)?;
|
||||
Ok(())
|
||||
}
|
||||
fn visit_f32x4_relaxed_fnma(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_ternary_op()
|
||||
fn visit_i32x4_relaxed_trunc_f32x4_s(&mut self) -> Self::Output {
|
||||
self.check_v128_unary_op()
|
||||
}
|
||||
fn visit_f64x2_relaxed_fma(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_ternary_op()
|
||||
fn visit_i32x4_relaxed_trunc_f32x4_u(&mut self) -> Self::Output {
|
||||
self.check_v128_unary_op()
|
||||
}
|
||||
fn visit_f64x2_relaxed_fnma(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_ternary_op()
|
||||
fn visit_i32x4_relaxed_trunc_f64x2_s_zero(&mut self) -> Self::Output {
|
||||
self.check_v128_unary_op()
|
||||
}
|
||||
fn visit_i32x4_relaxed_trunc_f64x2_u_zero(&mut self) -> Self::Output {
|
||||
self.check_v128_unary_op()
|
||||
}
|
||||
fn visit_f32x4_relaxed_madd(&mut self) -> Self::Output {
|
||||
self.check_v128_ternary_op()
|
||||
}
|
||||
fn visit_f32x4_relaxed_nmadd(&mut self) -> Self::Output {
|
||||
self.check_v128_ternary_op()
|
||||
}
|
||||
fn visit_f64x2_relaxed_madd(&mut self) -> Self::Output {
|
||||
self.check_v128_ternary_op()
|
||||
}
|
||||
fn visit_f64x2_relaxed_nmadd(&mut self) -> Self::Output {
|
||||
self.check_v128_ternary_op()
|
||||
}
|
||||
fn visit_i8x16_relaxed_laneselect(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_ternary_op()
|
||||
self.check_v128_ternary_op()
|
||||
}
|
||||
fn visit_i16x8_relaxed_laneselect(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_ternary_op()
|
||||
self.check_v128_ternary_op()
|
||||
}
|
||||
fn visit_i32x4_relaxed_laneselect(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_ternary_op()
|
||||
self.check_v128_ternary_op()
|
||||
}
|
||||
fn visit_i64x2_relaxed_laneselect(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_ternary_op()
|
||||
self.check_v128_ternary_op()
|
||||
}
|
||||
fn visit_i32x4_dot_i8x16_i7x16_add_s(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_ternary_op()
|
||||
fn visit_f32x4_relaxed_min(&mut self) -> Self::Output {
|
||||
self.check_v128_binary_op()
|
||||
}
|
||||
fn visit_f32x4_relaxed_dot_bf16x8_add_f32x4(&mut self) -> Self::Output {
|
||||
self.check_v128_relaxed_ternary_op()
|
||||
fn visit_f32x4_relaxed_max(&mut self) -> Self::Output {
|
||||
self.check_v128_binary_op()
|
||||
}
|
||||
fn visit_f64x2_relaxed_min(&mut self) -> Self::Output {
|
||||
self.check_v128_binary_op()
|
||||
}
|
||||
fn visit_f64x2_relaxed_max(&mut self) -> Self::Output {
|
||||
self.check_v128_binary_op()
|
||||
}
|
||||
fn visit_i16x8_relaxed_q15mulr_s(&mut self) -> Self::Output {
|
||||
self.check_v128_binary_op()
|
||||
}
|
||||
fn visit_i16x8_relaxed_dot_i8x16_i7x16_s(&mut self) -> Self::Output {
|
||||
self.check_v128_binary_op()
|
||||
}
|
||||
fn visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(&mut self) -> Self::Output {
|
||||
self.check_v128_ternary_op()
|
||||
}
|
||||
fn visit_v128_any_true(&mut self) -> Self::Output {
|
||||
self.check_v128_bitmask_op()
|
||||
|
@ -2855,12 +3103,6 @@ where
|
|||
self.push_operand(ValType::V128)?;
|
||||
Ok(())
|
||||
}
|
||||
fn visit_i8x16_relaxed_swizzle(&mut self) -> Self::Output {
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
self.push_operand(ValType::V128)?;
|
||||
Ok(())
|
||||
}
|
||||
fn visit_i8x16_shuffle(&mut self, lanes: [u8; 16]) -> Self::Output {
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
self.pop_operand(Some(ValType::V128))?;
|
||||
|
@ -3070,7 +3312,10 @@ where
|
|||
(Some(a), Some(b)) => (a, b),
|
||||
_ => bail!(self.offset, "table index out of bounds"),
|
||||
};
|
||||
if src.element_type != dst.element_type {
|
||||
if !self.resources.matches(
|
||||
ValType::Ref(src.element_type),
|
||||
ValType::Ref(dst.element_type),
|
||||
) {
|
||||
bail!(self.offset, "type mismatch");
|
||||
}
|
||||
self.pop_operand(Some(ValType::I32))?;
|
||||
|
@ -3084,7 +3329,7 @@ where
|
|||
None => bail!(self.offset, "table index out of bounds"),
|
||||
};
|
||||
self.pop_operand(Some(ValType::I32))?;
|
||||
self.push_operand(ty)?;
|
||||
self.push_operand(ValType::Ref(ty))?;
|
||||
Ok(())
|
||||
}
|
||||
fn visit_table_set(&mut self, table: u32) -> Self::Output {
|
||||
|
@ -3092,7 +3337,7 @@ where
|
|||
Some(ty) => ty.element_type,
|
||||
None => bail!(self.offset, "table index out of bounds"),
|
||||
};
|
||||
self.pop_operand(Some(ty))?;
|
||||
self.pop_operand(Some(ValType::Ref(ty)))?;
|
||||
self.pop_operand(Some(ValType::I32))?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -3102,7 +3347,7 @@ where
|
|||
None => bail!(self.offset, "table index out of bounds"),
|
||||
};
|
||||
self.pop_operand(Some(ValType::I32))?;
|
||||
self.pop_operand(Some(ty))?;
|
||||
self.pop_operand(Some(ValType::Ref(ty)))?;
|
||||
self.push_operand(ValType::I32)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -3119,7 +3364,7 @@ where
|
|||
None => bail!(self.offset, "table index out of bounds"),
|
||||
};
|
||||
self.pop_operand(Some(ValType::I32))?;
|
||||
self.pop_operand(Some(ty))?;
|
||||
self.pop_operand(Some(ValType::Ref(ty)))?;
|
||||
self.pop_operand(Some(ValType::I32))?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
use super::{component::ComponentState, core::Module};
|
||||
use crate::{
|
||||
ComponentExport, ComponentImport, Export, ExternalKind, FuncType, GlobalType, Import,
|
||||
MemoryType, PrimitiveValType, TableType, TypeRef, ValType,
|
||||
Export, ExternalKind, FuncType, GlobalType, Import, MemoryType, PrimitiveValType, RefType,
|
||||
TableType, TypeRef, ValType,
|
||||
};
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use std::collections::HashMap;
|
||||
|
@ -1477,7 +1477,7 @@ impl<'a> TypesRef<'a> {
|
|||
///
|
||||
/// Returns `None` if the type index is out of bounds or the type has not
|
||||
/// been parsed yet.
|
||||
pub fn element_at(&self, index: u32) -> Option<ValType> {
|
||||
pub fn element_at(&self, index: u32) -> Option<RefType> {
|
||||
match &self.kind {
|
||||
TypesRefKind::Module(module) => module.element_types.get(index as usize).copied(),
|
||||
TypesRefKind::Component(_) => None,
|
||||
|
@ -1615,29 +1615,12 @@ impl<'a> TypesRef<'a> {
|
|||
}
|
||||
|
||||
/// Gets the component entity type for the given component import.
|
||||
pub fn component_entity_type_from_import(
|
||||
&self,
|
||||
import: &ComponentImport,
|
||||
) -> Option<ComponentEntityType> {
|
||||
pub fn component_entity_type_of_extern(&self, name: &str) -> Option<ComponentEntityType> {
|
||||
match &self.kind {
|
||||
TypesRefKind::Module(_) => None,
|
||||
TypesRefKind::Component(component) => {
|
||||
let key = KebabStr::new(import.name)?;
|
||||
Some(component.imports.get(key)?.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the component entity type from the given component export.
|
||||
pub fn component_entity_type_from_export(
|
||||
&self,
|
||||
export: &ComponentExport,
|
||||
) -> Option<ComponentEntityType> {
|
||||
match &self.kind {
|
||||
TypesRefKind::Module(_) => None,
|
||||
TypesRefKind::Component(component) => {
|
||||
let key = KebabStr::new(export.name)?;
|
||||
Some(component.exports.get(key)?.1)
|
||||
let key = KebabStr::new(name)?;
|
||||
Some(component.externs.get(key)?.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1785,8 +1768,11 @@ impl Types {
|
|||
/// Gets the type of an element segment at the given element segment index.
|
||||
///
|
||||
/// Returns `None` if the index is out of bounds.
|
||||
pub fn element_at(&self, index: u32) -> Option<ValType> {
|
||||
self.as_ref().element_at(index)
|
||||
pub fn element_at(&self, index: u32) -> Option<RefType> {
|
||||
match &self.kind {
|
||||
TypesKind::Module(module) => module.element_types.get(index as usize).copied(),
|
||||
TypesKind::Component(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the count of element segments.
|
||||
|
@ -1897,20 +1883,10 @@ impl Types {
|
|||
self.as_ref().entity_type_from_export(export)
|
||||
}
|
||||
|
||||
/// Gets the component entity type for the given component import.
|
||||
pub fn component_entity_type_from_import(
|
||||
&self,
|
||||
import: &ComponentImport,
|
||||
) -> Option<ComponentEntityType> {
|
||||
self.as_ref().component_entity_type_from_import(import)
|
||||
}
|
||||
|
||||
/// Gets the component entity type from the given component export.
|
||||
pub fn component_entity_type_from_export(
|
||||
&self,
|
||||
export: &ComponentExport,
|
||||
) -> Option<ComponentEntityType> {
|
||||
self.as_ref().component_entity_type_from_export(export)
|
||||
/// Gets the component entity type for the given component import or export
|
||||
/// name.
|
||||
pub fn component_entity_type_of_extern(&self, name: &str) -> Option<ComponentEntityType> {
|
||||
self.as_ref().component_entity_type_of_extern(name)
|
||||
}
|
||||
|
||||
/// Attempts to lookup the type id that `ty` is an alias of.
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
use wasm_encoder::*;
|
||||
#[test]
|
||||
fn big_type_indices() {
|
||||
const N: u32 = 100_000;
|
||||
let mut module = Module::new();
|
||||
let mut types = TypeSection::new();
|
||||
for _ in 0..N {
|
||||
types.function([], []);
|
||||
}
|
||||
module.section(&types);
|
||||
let mut funcs = FunctionSection::new();
|
||||
funcs.function(N - 1);
|
||||
module.section(&funcs);
|
||||
|
||||
let mut elems = ElementSection::new();
|
||||
elems.declared(RefType::FUNCREF, Elements::Functions(&[0]));
|
||||
module.section(&elems);
|
||||
|
||||
let mut code = CodeSection::new();
|
||||
let mut body = Function::new([]);
|
||||
body.instruction(&Instruction::RefFunc(0));
|
||||
body.instruction(&Instruction::Drop);
|
||||
body.instruction(&Instruction::End);
|
||||
code.function(&body);
|
||||
module.section(&code);
|
||||
|
||||
let wasm = module.finish();
|
||||
|
||||
wasmparser::Validator::default()
|
||||
.validate_all(&wasm)
|
||||
.unwrap();
|
||||
}
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "wast"
|
||||
version = "53.0.0"
|
||||
version = "55.0.0"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
description = """
|
||||
Customizable Rust parsers for the WebAssembly Text formats WAT and WAST
|
||||
|
@ -37,7 +37,7 @@ version = "2.4.1"
|
|||
version = "0.1.9"
|
||||
|
||||
[dependencies.wasm-encoder]
|
||||
version = "0.23.0"
|
||||
version = "0.25.0"
|
||||
|
||||
[dev-dependencies.anyhow]
|
||||
version = "1.0.58"
|
||||
|
|
|
@ -552,17 +552,32 @@ impl From<core::ValType<'_>> for wasm_encoder::ValType {
|
|||
core::ValType::F32 => Self::F32,
|
||||
core::ValType::F64 => Self::F64,
|
||||
core::ValType::V128 => Self::V128,
|
||||
core::ValType::Ref(r) => r.into(),
|
||||
core::ValType::Ref(r) => Self::Ref(r.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<core::RefType<'_>> for wasm_encoder::ValType {
|
||||
impl From<core::RefType<'_>> for wasm_encoder::RefType {
|
||||
fn from(r: core::RefType<'_>) -> Self {
|
||||
match r.heap {
|
||||
core::HeapType::Func => Self::FuncRef,
|
||||
core::HeapType::Extern => Self::ExternRef,
|
||||
_ => {
|
||||
wasm_encoder::RefType {
|
||||
nullable: r.nullable,
|
||||
heap_type: r.heap.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<core::HeapType<'_>> for wasm_encoder::HeapType {
|
||||
fn from(r: core::HeapType<'_>) -> Self {
|
||||
match r {
|
||||
core::HeapType::Func => Self::Func,
|
||||
core::HeapType::Extern => Self::Extern,
|
||||
core::HeapType::Index(Index::Num(i, _)) => Self::TypedFunc(i),
|
||||
core::HeapType::Index(_) => panic!("unresolved index"),
|
||||
core::HeapType::Any
|
||||
| core::HeapType::Eq
|
||||
| core::HeapType::Struct
|
||||
| core::HeapType::Array
|
||||
| core::HeapType::I31 => {
|
||||
todo!("encoding of GC proposal types not yet implemented")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -241,8 +241,11 @@ impl<'a> Encode for HeapType<'a> {
|
|||
HeapType::Struct => e.push(0x67),
|
||||
HeapType::Array => e.push(0x66),
|
||||
HeapType::I31 => e.push(0x6a),
|
||||
HeapType::Index(index) => {
|
||||
index.encode(e);
|
||||
// Note that this is encoded as a signed leb128 so be sure to cast
|
||||
// to an i64 first
|
||||
HeapType::Index(Index::Num(n, _)) => i64::from(*n).encode(e),
|
||||
HeapType::Index(Index::Id(n)) => {
|
||||
panic!("unresolved index in emission: {:?}", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -427,8 +430,14 @@ impl Encode for Table<'_> {
|
|||
fn encode(&self, e: &mut Vec<u8>) {
|
||||
assert!(self.exports.names.is_empty());
|
||||
match &self.kind {
|
||||
TableKind::Normal { ty, init_expr: None } => ty.encode(e),
|
||||
TableKind::Normal { ty, init_expr: Some(init_expr) } => {
|
||||
TableKind::Normal {
|
||||
ty,
|
||||
init_expr: None,
|
||||
} => ty.encode(e),
|
||||
TableKind::Normal {
|
||||
ty,
|
||||
init_expr: Some(init_expr),
|
||||
} => {
|
||||
e.push(0x40);
|
||||
e.push(0x00);
|
||||
ty.encode(e);
|
||||
|
|
|
@ -1145,14 +1145,14 @@ instructions! {
|
|||
|
||||
// Relaxed SIMD proposal
|
||||
I8x16RelaxedSwizzle : [0xfd, 0x100]: "i8x16.relaxed_swizzle",
|
||||
I32x4RelaxedTruncSatF32x4S : [0xfd, 0x101]: "i32x4.relaxed_trunc_sat_f32x4_s" | "i32x4.relaxed_trunc_f32x4_s",
|
||||
I32x4RelaxedTruncSatF32x4U : [0xfd, 0x102]: "i32x4.relaxed_trunc_sat_f32x4_u" | "i32x4.relaxed_trunc_f32x4_u",
|
||||
I32x4RelaxedTruncSatF64x2SZero : [0xfd, 0x103]: "i32x4.relaxed_trunc_sat_f64x2_s_zero" | "i32x4.relaxed_trunc_f64x2_s_zero",
|
||||
I32x4RelaxedTruncSatF64x2UZero : [0xfd, 0x104]: "i32x4.relaxed_trunc_sat_f64x2_u_zero" | "i32x4.relaxed_trunc_f64x2_u_zero",
|
||||
F32x4RelaxedFma : [0xfd, 0x105]: "f32x4.relaxed_fma",
|
||||
F32x4RelaxedFnma : [0xfd, 0x106]: "f32x4.relaxed_fnma",
|
||||
F64x2RelaxedFma : [0xfd, 0x107]: "f64x2.relaxed_fma",
|
||||
F64x2RelaxedFnma : [0xfd, 0x108]: "f64x2.relaxed_fnma",
|
||||
I32x4RelaxedTruncF32x4S : [0xfd, 0x101]: "i32x4.relaxed_trunc_f32x4_s",
|
||||
I32x4RelaxedTruncF32x4U : [0xfd, 0x102]: "i32x4.relaxed_trunc_f32x4_u",
|
||||
I32x4RelaxedTruncF64x2SZero : [0xfd, 0x103]: "i32x4.relaxed_trunc_f64x2_s_zero",
|
||||
I32x4RelaxedTruncF64x2UZero : [0xfd, 0x104]: "i32x4.relaxed_trunc_f64x2_u_zero",
|
||||
F32x4RelaxedMadd : [0xfd, 0x105]: "f32x4.relaxed_madd",
|
||||
F32x4RelaxedNmadd : [0xfd, 0x106]: "f32x4.relaxed_nmadd",
|
||||
F64x2RelaxedMadd : [0xfd, 0x107]: "f64x2.relaxed_madd",
|
||||
F64x2RelaxedNmadd : [0xfd, 0x108]: "f64x2.relaxed_nmadd",
|
||||
I8x16RelaxedLaneselect : [0xfd, 0x109]: "i8x16.relaxed_laneselect",
|
||||
I16x8RelaxedLaneselect : [0xfd, 0x10A]: "i16x8.relaxed_laneselect",
|
||||
I32x4RelaxedLaneselect : [0xfd, 0x10B]: "i32x4.relaxed_laneselect",
|
||||
|
@ -1162,9 +1162,8 @@ instructions! {
|
|||
F64x2RelaxedMin : [0xfd, 0x10F]: "f64x2.relaxed_min",
|
||||
F64x2RelaxedMax : [0xfd, 0x110]: "f64x2.relaxed_max",
|
||||
I16x8RelaxedQ15mulrS: [0xfd, 0x111]: "i16x8.relaxed_q15mulr_s",
|
||||
I16x8DotI8x16I7x16S: [0xfd, 0x112]: "i16x8.dot_i8x16_i7x16_s",
|
||||
I32x4DotI8x16I7x16AddS: [0xfd, 0x113]: "i32x4.dot_i8x16_i7x16_add_s",
|
||||
F32x4RelaxedDotBf16x8AddF32x4: [0xfd, 0x114]: "f32x4.relaxed_dot_bf16x8_add_f32x4",
|
||||
I16x8RelaxedDotI8x16I7x16S: [0xfd, 0x112]: "i16x8.relaxed_dot_i8x16_i7x16_s",
|
||||
I32x4RelaxedDotI8x16I7x16AddS: [0xfd, 0x113]: "i32x4.relaxed_dot_i8x16_i7x16_add_s",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ impl<'a> Parse<'a> for Table<'a> {
|
|||
} else if l.peek::<u32>() {
|
||||
TableKind::Normal {
|
||||
ty: parser.parse()?,
|
||||
init_expr: if parser.peek::<LParen>() {
|
||||
init_expr: if !parser.is_empty() {
|
||||
Some(parser.parse::<Expression>()?)
|
||||
} else {
|
||||
None
|
||||
|
|
Загрузка…
Ссылка в новой задаче