From ec0f05cb98d6a4e30375a7a6a78966d25fdb5d9c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 21 Sep 2023 12:28:23 -0700 Subject: Support i8/i16 mutable arrays as public types for string interop (#5814) Probably any array of non-reference data can be allowed to be public and sent out of the module, as it is just data. For now, however, just special case the i8 and i16 array types which are useful already for string interop. --- src/ir/module-utils.cpp | 5 +++++ src/wasm-type.h | 14 ++++++++++++++ src/wasm/wasm-type.cpp | 23 +++++++++++++++++++++++ src/wasm/wasm-validator.cpp | 6 +++++- 4 files changed, 47 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ir/module-utils.cpp b/src/ir/module-utils.cpp index 2b2f51323..ed147053b 100644 --- a/src/ir/module-utils.cpp +++ b/src/ir/module-utils.cpp @@ -506,6 +506,11 @@ InsertOrderedSet getPublicTypeSet(Module& wasm) { WASM_UNREACHABLE("unexpected export kind"); } + // Ignorable public types are public. + for (auto type : getIgnorablePublicTypes()) { + notePublic(type); + } + // Find all the other public types reachable from directly publicized types. std::vector workList(publicTypes.begin(), publicTypes.end()); while (workList.size()) { diff --git a/src/wasm-type.h b/src/wasm-type.h index 927e37845..d97bdeba3 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -661,6 +661,20 @@ struct TypeBuilder { void dump(); }; +// We consider certain specific types to always be public, to allow closed- +// world to operate even if they escape. Specifically, "plain old data" types +// like array of i8 and i16, which are used to represent strings, may cross +// the boundary in Web environments. +// +// These are "ignorable as public", because we do not error on them being +// public. That is, we +// +// 1. Consider them public, so that passes that do not operate on public types +// do not in fact operate on them, and +// 2. Are ok with them being public in the validator. +// +std::unordered_set getIgnorablePublicTypes(); + std::ostream& operator<<(std::ostream&, Type); std::ostream& operator<<(std::ostream&, Type::Printed); std::ostream& operator<<(std::ostream&, HeapType); diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index ba38231b6..4ce72582c 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -2580,6 +2580,29 @@ void TypeBuilder::dump() { } } +std::unordered_set getIgnorablePublicTypes() { + auto array8 = Array(Field(Field::i8, Mutable)); + auto array16 = Array(Field(Field::i16, Mutable)); + TypeBuilder builder(4); + // We handle final and non-final here, but should remove one of them + // eventually TODO + builder[0] = array8; + builder[0].setOpen(false); + builder[1] = array16; + builder[1].setOpen(false); + builder[2] = array8; + builder[2].setOpen(true); + builder[3] = array16; + builder[3].setOpen(true); + auto result = builder.build(); + assert(result); + std::unordered_set ret; + for (auto type : *result) { + ret.insert(type); + } + return ret; +} + } // namespace wasm namespace std { diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 2d00c4b67..3baaacb16 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -3726,8 +3726,12 @@ static void validateClosedWorldInterface(Module& module, ValidationInfo& info) { } } + // Ignorable public types are public, but we can ignore them for purposes of + // erroring here: It is always ok that they are public. + auto ignorable = getIgnorablePublicTypes(); + for (auto type : ModuleUtils::getPublicHeapTypes(module)) { - if (!publicFuncTypes.count(type)) { + if (!publicFuncTypes.count(type) && !ignorable.count(type)) { auto name = type.toString(); if (auto it = module.typeNames.find(type); it != module.typeNames.end()) { name = it->second.name.toString(); -- cgit v1.2.3