summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md3
-rw-r--r--src/binaryen-c.cpp8
-rw-r--r--src/binaryen-c.h3
-rw-r--r--src/ir/ReFinalize.cpp6
-rw-r--r--src/ir/module-utils.h78
-rw-r--r--src/js/binaryen.js-post.js4
-rw-r--r--src/passes/InstrumentLocals.cpp81
-rw-r--r--src/tools/fuzzing.h54
-rw-r--r--src/tools/tool-options.h2
-rw-r--r--src/wasm-binary.h86
-rw-r--r--src/wasm-builder.h14
-rw-r--r--src/wasm-features.h11
-rw-r--r--src/wasm.h1
-rw-r--r--src/wasm/wasm-binary.cpp145
-rw-r--r--src/wasm/wasm-s-parser.cpp5
-rw-r--r--src/wasm/wasm-stack.cpp18
-rw-r--r--src/wasm/wasm-type.cpp8
-rw-r--r--src/wasm/wasm-validator.cpp1
-rw-r--r--src/wasm/wasm.cpp8
-rw-r--r--test/binaryen.js/expressions.js5
-rw-r--r--test/binaryen.js/kitchen-sink.js4
-rw-r--r--test/binaryen.js/kitchen-sink.js.txt2
-rw-r--r--test/example/c-api-kitchen-sink.c18
-rw-r--r--test/example/c-api-kitchen-sink.txt2
-rw-r--r--test/passes/fuzz-exec_all-features.txt12
-rw-r--r--test/passes/fuzz-exec_all-features.wast6
-rw-r--r--test/passes/fuzz_metrics_noprint.bin.txt48
-rw-r--r--test/passes/instrument-locals_all-features.txt36
-rw-r--r--test/passes/strip-target-features_roundtrip_print-features_all-features.txt1
-rw-r--r--test/passes/translate-to-fuzz_all-features.txt1629
-rw-r--r--test/unit/test_features.py3
31 files changed, 1233 insertions, 1069 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9bfab9c04..1d6edfac3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,9 @@ full changeset diff at the end of each section.
Current Trunk
-------------
+- `RefFunc` C and JS API constructors (`BinaryenRefFunc` and `ref.func`
+ respectively) now take an extra `type` parameter, similar to `RefNull`. This
+ is necessary for typed function references support.
- JS API functions for atomic notify/wait instructions are renamed.
- `module.atomic.notify` -> `module.memory.atomic.notify`
- `module.i32.atomic.wait` -> `module.memory.atomic.wait32`
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 443549de9..7365a3863 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -1187,9 +1187,11 @@ BinaryenExpressionRef BinaryenRefIsNull(BinaryenModuleRef module,
Builder(*(Module*)module).makeRefIsNull((Expression*)value));
}
-BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,
- const char* func) {
- return static_cast<Expression*>(Builder(*(Module*)module).makeRefFunc(func));
+BinaryenExpressionRef
+BinaryenRefFunc(BinaryenModuleRef module, const char* func, BinaryenType type) {
+ Type type_(type);
+ return static_cast<Expression*>(
+ Builder(*(Module*)module).makeRefFunc(func, type_));
}
BinaryenExpressionRef BinaryenRefEq(BinaryenModuleRef module,
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index 45beb3657..c4517257a 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -792,7 +792,8 @@ BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module,
BINARYEN_API BinaryenExpressionRef
BinaryenRefIsNull(BinaryenModuleRef module, BinaryenExpressionRef value);
BINARYEN_API BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,
- const char* func);
+ const char* func,
+ BinaryenType type);
BINARYEN_API BinaryenExpressionRef BinaryenRefEq(BinaryenModuleRef module,
BinaryenExpressionRef left,
BinaryenExpressionRef right);
diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp
index 19fed54a7..448c1f30a 100644
--- a/src/ir/ReFinalize.cpp
+++ b/src/ir/ReFinalize.cpp
@@ -126,7 +126,11 @@ void ReFinalize::visitMemorySize(MemorySize* curr) { curr->finalize(); }
void ReFinalize::visitMemoryGrow(MemoryGrow* curr) { curr->finalize(); }
void ReFinalize::visitRefNull(RefNull* curr) { curr->finalize(); }
void ReFinalize::visitRefIsNull(RefIsNull* curr) { curr->finalize(); }
-void ReFinalize::visitRefFunc(RefFunc* curr) { curr->finalize(); }
+void ReFinalize::visitRefFunc(RefFunc* curr) {
+ // TODO: should we look up the function and update the type from there? This
+ // could handle a change to the function's type, but is also not really what
+ // this class has been meant to do.
+}
void ReFinalize::visitRefEq(RefEq* curr) { curr->finalize(); }
void ReFinalize::visitTry(Try* curr) { curr->finalize(); }
void ReFinalize::visitThrow(Throw* curr) { curr->finalize(); }
diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h
index a2d256073..c8776297c 100644
--- a/src/ir/module-utils.h
+++ b/src/ir/module-utils.h
@@ -414,16 +414,29 @@ collectSignatures(Module& wasm,
Counts& counts;
TypeCounter(Counts& counts) : counts(counts) {}
+
void visitExpression(Expression* curr) {
- if (auto* call = curr->dynCast<CallIndirect>()) {
+ if (curr->is<RefNull>()) {
+ maybeNote(curr->type);
+ } else if (auto* call = curr->dynCast<CallIndirect>()) {
counts[call->sig]++;
} else if (Properties::isControlFlowStructure(curr)) {
- // TODO: Allow control flow to have input types as well
+ maybeNote(curr->type);
if (curr->type.isTuple()) {
+ // TODO: Allow control flow to have input types as well
counts[Signature(Type::none, curr->type)]++;
}
}
}
+
+ void maybeNote(Type type) {
+ if (type.isRef()) {
+ auto heapType = type.getHeapType();
+ if (heapType.isSignature()) {
+ counts[heapType.getSignature()]++;
+ }
+ }
+ }
};
TypeCounter(counts).walk(func->body);
};
@@ -434,6 +447,14 @@ collectSignatures(Module& wasm,
Counts counts;
for (auto& curr : wasm.functions) {
counts[curr->sig]++;
+ for (auto type : curr->vars) {
+ if (type.isRef()) {
+ auto heapType = type.getHeapType();
+ if (heapType.isSignature()) {
+ counts[heapType.getSignature()]++;
+ }
+ }
+ }
}
for (auto& curr : wasm.events) {
counts[curr->sig]++;
@@ -444,10 +465,61 @@ collectSignatures(Module& wasm,
counts[innerPair.first] += innerPair.second;
}
}
+
+ // TODO: recursively traverse each reference type, which may have a child type
+ // this is itself a reference type.
+
+ // We must sort all the dependencies of a signature before it. For example,
+ // (func (param (ref (func)))) must appear after (func). To do that, find the
+ // depth of dependencies of each signature. For example, if A depends on B
+ // which depends on C, then A's depth is 2, B's is 1, and C's is 0 (assuming
+ // no other dependencies).
+ Counts depthOfDependencies;
+ std::unordered_map<Signature, std::unordered_set<Signature>> isDependencyOf;
+ // To calculate the depth of dependencies, we'll do a flow analysis, visiting
+ // each signature as we find out new things about it.
+ std::set<Signature> toVisit;
+ for (auto& pair : counts) {
+ auto sig = pair.first;
+ depthOfDependencies[sig] = 0;
+ toVisit.insert(sig);
+ for (Type type : {sig.params, sig.results}) {
+ for (auto element : type) {
+ if (element.isRef()) {
+ auto heapType = element.getHeapType();
+ if (heapType.isSignature()) {
+ isDependencyOf[heapType.getSignature()].insert(sig);
+ }
+ }
+ }
+ }
+ }
+ while (!toVisit.empty()) {
+ auto iter = toVisit.begin();
+ auto sig = *iter;
+ toVisit.erase(iter);
+ // Anything that depends on this has a depth of dependencies equal to this
+ // signature's, plus this signature itself.
+ auto newDepth = depthOfDependencies[sig] + 1;
+ if (newDepth > counts.size()) {
+ Fatal() << "Cyclic signatures detected, cannot sort them.";
+ }
+ for (auto& other : isDependencyOf[sig]) {
+ if (depthOfDependencies[other] < newDepth) {
+ // We found something new to propagate.
+ depthOfDependencies[other] = newDepth;
+ toVisit.insert(other);
+ }
+ }
+ }
+ // Sort by frequency and then simplicity, and also keeping every signature
+ // before things that depend on it.
std::vector<std::pair<Signature, size_t>> sorted(counts.begin(),
counts.end());
std::sort(sorted.begin(), sorted.end(), [&](auto a, auto b) {
- // order by frequency then simplicity
+ if (depthOfDependencies[a.first] != depthOfDependencies[b.first]) {
+ return depthOfDependencies[a.first] < depthOfDependencies[b.first];
+ }
if (a.second != b.second) {
return a.second > b.second;
}
diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js
index b78fdd996..9abe5e718 100644
--- a/src/js/binaryen.js-post.js
+++ b/src/js/binaryen.js-post.js
@@ -2112,8 +2112,8 @@ function wrapModule(module, self = {}) {
'is_null'(value) {
return Module['_BinaryenRefIsNull'](module, value);
},
- 'func'(func) {
- return preserveStack(() => Module['_BinaryenRefFunc'](module, strToStack(func)));
+ 'func'(func, type) {
+ return preserveStack(() => Module['_BinaryenRefFunc'](module, strToStack(func), type));
},
'eq'(left, right) {
return Module['_BinaryenRefEq'](module, left, right);
diff --git a/src/passes/InstrumentLocals.cpp b/src/passes/InstrumentLocals.cpp
index 81494463f..004bfba74 100644
--- a/src/passes/InstrumentLocals.cpp
+++ b/src/passes/InstrumentLocals.cpp
@@ -135,45 +135,48 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> {
Builder builder(*getModule());
Name import;
auto type = curr->value->type;
- if (type.isFunction()) {
- import = set_funcref;
- } else {
- TODO_SINGLE_COMPOUND(curr->value->type);
- switch (type.getBasic()) {
- case Type::i32:
- import = set_i32;
- break;
- case Type::i64:
- return; // TODO
- case Type::f32:
- import = set_f32;
- break;
- case Type::f64:
- import = set_f64;
- break;
- case Type::v128:
- import = set_v128;
- break;
- case Type::externref:
- import = set_externref;
- break;
- case Type::exnref:
- import = set_exnref;
- break;
- case Type::anyref:
- import = set_anyref;
- break;
- case Type::eqref:
- import = set_eqref;
- break;
- case Type::i31ref:
- import = set_i31ref;
- break;
- case Type::unreachable:
- return; // nothing to do here
- default:
- WASM_UNREACHABLE("unexpected type");
- }
+ if (type.isFunction() && type != Type::funcref) {
+ // FIXME: support typed function references
+ return;
+ }
+ TODO_SINGLE_COMPOUND(curr->value->type);
+ switch (type.getBasic()) {
+ case Type::i32:
+ import = set_i32;
+ break;
+ case Type::i64:
+ return; // TODO
+ case Type::f32:
+ import = set_f32;
+ break;
+ case Type::f64:
+ import = set_f64;
+ break;
+ case Type::v128:
+ import = set_v128;
+ break;
+ case Type::funcref:
+ import = set_funcref;
+ break;
+ case Type::externref:
+ import = set_externref;
+ break;
+ case Type::exnref:
+ import = set_exnref;
+ break;
+ case Type::anyref:
+ import = set_anyref;
+ break;
+ case Type::eqref:
+ import = set_eqref;
+ break;
+ case Type::i31ref:
+ import = set_i31ref;
+ break;
+ case Type::unreachable:
+ return; // nothing to do here
+ default:
+ WASM_UNREACHABLE("unexpected type");
}
curr->value = builder.makeCall(import,
{builder.makeConst(int32_t(id++)),
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h
index df7cf2226..1c1359586 100644
--- a/src/tools/fuzzing.h
+++ b/src/tools/fuzzing.h
@@ -321,6 +321,10 @@ private:
}
return Type(types);
}
+ if (type.isFunction() && type != Type::funcref) {
+ // TODO: specific typed function references types.
+ return type;
+ }
SmallVector<Type, 2> options;
options.push_back(type); // includes itself
TODO_SINGLE_COMPOUND(type);
@@ -653,6 +657,10 @@ private:
Index numVars = upToSquared(MAX_VARS);
for (Index i = 0; i < numVars; i++) {
auto type = getConcreteType();
+ if (type.isRef() && !type.isNullable()) {
+ // We can't use a nullable type as a var, which is null-initialized.
+ continue;
+ }
funcContext->typeLocals[type].push_back(params.size() +
func->vars.size());
func->vars.push_back(type);
@@ -1371,7 +1379,6 @@ private:
}
Expression* makeCall(Type type) {
- // seems ok, go on
int tries = TRIES;
bool isReturn;
while (tries-- > 0) {
@@ -1392,7 +1399,7 @@ private:
return builder.makeCall(target->name, args, type, isReturn);
}
// we failed to find something
- return make(type);
+ return makeTrivial(type);
}
Expression* makeCallIndirect(Type type) {
@@ -1418,7 +1425,7 @@ private:
i = 0;
}
if (i == start) {
- return make(type);
+ return makeTrivial(type);
}
}
// with high probability, make sure the type is valid otherwise, most are
@@ -2018,12 +2025,28 @@ private:
if (!wasm.functions.empty() && !oneIn(wasm.functions.size())) {
target = pick(wasm.functions).get();
}
- return builder.makeRefFunc(target->name);
+ auto type = Type(HeapType(target->sig), /* nullable = */ true);
+ return builder.makeRefFunc(target->name, type);
}
if (type == Type::i31ref) {
return builder.makeI31New(makeConst(Type::i32));
}
- return builder.makeRefNull(type);
+ if (oneIn(2) && type.isNullable()) {
+ return builder.makeRefNull(type);
+ }
+ // TODO: randomize the order
+ for (auto& func : wasm.functions) {
+ // FIXME: RefFunc type should be non-nullable, but we emit nullable
+ // types for now.
+ if (type == Type(HeapType(func->sig), /* nullable = */ true)) {
+ return builder.makeRefFunc(func->name, type);
+ }
+ }
+ // We failed to find a function, so create a null reference if we can.
+ if (type.isNullable()) {
+ return builder.makeRefNull(type);
+ }
+ WASM_UNREACHABLE("un-handleable non-nullable type");
}
if (type.isTuple()) {
std::vector<Expression*> operands;
@@ -2972,6 +2995,7 @@ private:
Type::anyref,
Type::eqref,
Type::i31ref));
+ // TODO: emit typed function references types
}
Type getSingleConcreteType() { return pick(getSingleConcreteTypes()); }
@@ -2997,12 +3021,24 @@ private:
Type getEqReferenceType() { return pick(getEqReferenceTypes()); }
+ Type getMVPType() {
+ return pick(items(FeatureOptions<Type>().add(
+ FeatureSet::MVP, Type::i32, Type::i64, Type::f32, Type::f64)));
+ }
+
Type getTupleType() {
std::vector<Type> elements;
- size_t numElements = 2 + upTo(MAX_TUPLE_SIZE - 1);
- elements.resize(numElements);
- for (size_t i = 0; i < numElements; ++i) {
- elements[i] = getSingleConcreteType();
+ size_t maxElements = 2 + upTo(MAX_TUPLE_SIZE - 1);
+ for (size_t i = 0; i < maxElements; ++i) {
+ auto type = getSingleConcreteType();
+ // Don't add a non-nullable type into a tuple, as currently we can't spill
+ // them into locals (that would require a "let").
+ if (!type.isNullable()) {
+ elements.push_back(type);
+ }
+ }
+ while (elements.size() < 2) {
+ elements.push_back(getMVPType());
}
return Type(elements);
}
diff --git a/src/tools/tool-options.h b/src/tools/tool-options.h
index 4b084e191..70ce4efc0 100644
--- a/src/tools/tool-options.h
+++ b/src/tools/tool-options.h
@@ -89,6 +89,8 @@ struct ToolOptions : public Options {
.addFeature(FeatureSet::Multivalue, "multivalue functions")
.addFeature(FeatureSet::GC, "garbage collection")
.addFeature(FeatureSet::Memory64, "memory64")
+ .addFeature(FeatureSet::TypedFunctionReferences,
+ "typed function references")
.add("--no-validation",
"-n",
"Disables validation, assumes inputs are correct",
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index ef3f9c9d1..0918151c5 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -346,6 +346,10 @@ enum EncodedType {
anyref = -0x12, // 0x6e
// comparable reference type
eqref = -0x13, // 0x6d
+ // nullable typed function reference type, with parameter
+ nullable = -0x14, // 0x6c
+ // non-nullable typed function reference type, with parameter
+ nonnullable = -0x15, // 0x6b
// integer reference type
i31ref = -0x16, // 0x6a
// exception reference type
@@ -386,6 +390,7 @@ extern const char* ReferenceTypesFeature;
extern const char* MultivalueFeature;
extern const char* GCFeature;
extern const char* Memory64Feature;
+extern const char* TypedFunctionReferencesFeature;
enum Subsection {
NameModule = 0,
@@ -1009,82 +1014,6 @@ enum FeaturePrefix {
} // namespace BinaryConsts
-inline S32LEB binaryType(Type type) {
- int ret = 0;
- TODO_SINGLE_COMPOUND(type);
- switch (type.getBasic()) {
- // None only used for block signatures. TODO: Separate out?
- case Type::none:
- ret = BinaryConsts::EncodedType::Empty;
- break;
- case Type::i32:
- ret = BinaryConsts::EncodedType::i32;
- break;
- case Type::i64:
- ret = BinaryConsts::EncodedType::i64;
- break;
- case Type::f32:
- ret = BinaryConsts::EncodedType::f32;
- break;
- case Type::f64:
- ret = BinaryConsts::EncodedType::f64;
- break;
- case Type::v128:
- ret = BinaryConsts::EncodedType::v128;
- break;
- case Type::funcref:
- ret = BinaryConsts::EncodedType::funcref;
- break;
- case Type::externref:
- ret = BinaryConsts::EncodedType::externref;
- break;
- case Type::exnref:
- ret = BinaryConsts::EncodedType::exnref;
- break;
- case Type::anyref:
- ret = BinaryConsts::EncodedType::anyref;
- break;
- case Type::eqref:
- ret = BinaryConsts::EncodedType::eqref;
- break;
- case Type::i31ref:
- ret = BinaryConsts::EncodedType::i31ref;
- break;
- case Type::unreachable:
- WASM_UNREACHABLE("unexpected type");
- }
- return S32LEB(ret);
-}
-
-inline S32LEB binaryHeapType(HeapType type) {
- int ret = 0;
- switch (type.kind) {
- case HeapType::FuncKind:
- ret = BinaryConsts::EncodedHeapType::func;
- break;
- case HeapType::ExternKind:
- ret = BinaryConsts::EncodedHeapType::extern_;
- break;
- case HeapType::ExnKind:
- ret = BinaryConsts::EncodedHeapType::exn;
- break;
- case HeapType::AnyKind:
- ret = BinaryConsts::EncodedHeapType::any;
- break;
- case HeapType::EqKind:
- ret = BinaryConsts::EncodedHeapType::eq;
- break;
- case HeapType::I31Kind:
- ret = BinaryConsts::EncodedHeapType::i31;
- break;
- case HeapType::SignatureKind:
- case HeapType::StructKind:
- case HeapType::ArrayKind:
- WASM_UNREACHABLE("TODO: compound GC types");
- }
- return S32LEB(ret); // TODO: Actually encoded as s33
-}
-
// Writes out wasm to the binary format
class WasmBinaryWriter {
@@ -1234,6 +1163,9 @@ public:
Module* getModule() { return wasm; }
+ void writeType(Type type);
+ void writeHeapType(HeapType type);
+
private:
Module* wasm;
BufferWithRandomAccess& o;
@@ -1342,6 +1274,8 @@ public:
std::vector<Signature> functionSignatures;
void readFunctionSignatures();
+ Signature getFunctionSignatureByIndex(Index index);
+
size_t nextLabel;
Name getNextLabel();
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index d3af93896..6800aa2ed 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -588,10 +588,10 @@ public:
ret->finalize();
return ret;
}
- RefFunc* makeRefFunc(Name func) {
+ RefFunc* makeRefFunc(Name func, Type type) {
auto* ret = wasm.allocator.alloc<RefFunc>();
ret->func = func;
- ret->finalize();
+ ret->finalize(type);
return ret;
}
RefEq* makeRefEq(Expression* left, Expression* right) {
@@ -769,8 +769,7 @@ public:
}
if (type.isFunction()) {
if (!value.isNull()) {
- // TODO: with typed function references we need to do more for the type
- return makeRefFunc(value.getFunc());
+ return makeRefFunc(value.getFunc(), type);
}
return makeRefNull(type);
}
@@ -951,7 +950,12 @@ public:
return makeConstantExpression(Literal::makeZeros(curr->type));
}
if (curr->type.isFunction()) {
- return ExpressionManipulator::refNull(curr, curr->type);
+ if (curr->type.isNullable()) {
+ return ExpressionManipulator::refNull(curr, curr->type);
+ } else {
+ // We can't do any better, keep the original.
+ return curr;
+ }
}
Literal value;
// TODO: reuse node conditionally when possible for literals
diff --git a/src/wasm-features.h b/src/wasm-features.h
index a2bb52971..d2e3f343f 100644
--- a/src/wasm-features.h
+++ b/src/wasm-features.h
@@ -38,7 +38,8 @@ struct FeatureSet {
Multivalue = 1 << 9,
GC = 1 << 10,
Memory64 = 1 << 11,
- All = (1 << 12) - 1
+ TypedFunctionReferences = 1 << 12,
+ All = (1 << 13) - 1
};
static std::string toString(Feature f) {
@@ -67,6 +68,8 @@ struct FeatureSet {
return "gc";
case Memory64:
return "memory64";
+ case TypedFunctionReferences:
+ return "typed-function-references";
default:
WASM_UNREACHABLE("unexpected feature");
}
@@ -92,6 +95,9 @@ struct FeatureSet {
bool hasMultivalue() const { return (features & Multivalue) != 0; }
bool hasGC() const { return (features & GC) != 0; }
bool hasMemory64() const { return (features & Memory64) != 0; }
+ bool hasTypedFunctionReferences() const {
+ return (features & TypedFunctionReferences) != 0;
+ }
bool hasAll() const { return (features & All) != 0; }
void makeMVP() { features = MVP; }
@@ -110,6 +116,9 @@ struct FeatureSet {
void setMultivalue(bool v = true) { set(Multivalue, v); }
void setGC(bool v = true) { set(GC, v); }
void setMemory64(bool v = true) { set(Memory64, v); }
+ void setTypedFunctionReferences(bool v = true) {
+ set(TypedFunctionReferences, v);
+ }
void setAll(bool v = true) { features = v ? All : MVP; }
void enable(const FeatureSet& other) { features |= other.features; }
diff --git a/src/wasm.h b/src/wasm.h
index 1204eee0f..e9fb4461b 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -1198,6 +1198,7 @@ public:
Name func;
void finalize();
+ void finalize(Type type_);
};
class RefEq : public SpecificExpression<Expression::RefEqId> {
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index b343c6caf..a96039bc2 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -221,7 +221,7 @@ void WasmBinaryWriter::writeTypes() {
for (auto& sigType : {sig.params, sig.results}) {
o << U32LEB(sigType.size());
for (const auto& type : sigType) {
- o << binaryType(type);
+ writeType(type);
}
}
}
@@ -250,7 +250,7 @@ void WasmBinaryWriter::writeImports() {
BYN_TRACE("write one global\n");
writeImportHeader(global);
o << U32LEB(int32_t(ExternalKind::Global));
- o << binaryType(global->type);
+ writeType(global->type);
o << U32LEB(global->mutable_);
});
ModuleUtils::iterImportedEvents(*wasm, [&](Event* event) {
@@ -389,7 +389,7 @@ void WasmBinaryWriter::writeGlobals() {
BYN_TRACE("write one\n");
size_t i = 0;
for (const auto& t : global->type) {
- o << binaryType(t);
+ writeType(t);
o << U32LEB(global->mutable_);
if (global->type.size() == 1) {
writeExpression(global->init);
@@ -492,7 +492,12 @@ uint32_t WasmBinaryWriter::getEventIndex(Name name) const {
uint32_t WasmBinaryWriter::getTypeIndex(Signature sig) const {
auto it = typeIndices.find(sig);
- assert(it != typeIndices.end());
+#ifndef NDEBUG
+ if (it == typeIndices.end()) {
+ std::cout << "Missing signature: " << sig << '\n';
+ assert(0);
+ }
+#endif
return it->second;
}
@@ -799,6 +804,8 @@ void WasmBinaryWriter::writeFeaturesSection() {
return BinaryConsts::UserSections::GCFeature;
case FeatureSet::Memory64:
return BinaryConsts::UserSections::Memory64Feature;
+ case FeatureSet::TypedFunctionReferences:
+ return BinaryConsts::UserSections::TypedFunctionReferencesFeature;
default:
WASM_UNREACHABLE("unexpected feature flag");
}
@@ -950,6 +957,100 @@ void WasmBinaryWriter::finishUp() {
}
}
+void WasmBinaryWriter::writeType(Type type) {
+ if (type.isRef()) {
+ auto heapType = type.getHeapType();
+ // TODO: fully handle non-signature reference types (GC), and in reading
+ if (heapType.isSignature()) {
+ if (type.isNullable()) {
+ o << S32LEB(BinaryConsts::EncodedType::nullable);
+ } else {
+ o << S32LEB(BinaryConsts::EncodedType::nonnullable);
+ }
+ writeHeapType(heapType);
+ return;
+ }
+ }
+ int ret = 0;
+ TODO_SINGLE_COMPOUND(type);
+ switch (type.getBasic()) {
+ // None only used for block signatures. TODO: Separate out?
+ case Type::none:
+ ret = BinaryConsts::EncodedType::Empty;
+ break;
+ case Type::i32:
+ ret = BinaryConsts::EncodedType::i32;
+ break;
+ case Type::i64:
+ ret = BinaryConsts::EncodedType::i64;
+ break;
+ case Type::f32:
+ ret = BinaryConsts::EncodedType::f32;
+ break;
+ case Type::f64:
+ ret = BinaryConsts::EncodedType::f64;
+ break;
+ case Type::v128:
+ ret = BinaryConsts::EncodedType::v128;
+ break;
+ case Type::funcref:
+ ret = BinaryConsts::EncodedType::funcref;
+ break;
+ case Type::externref:
+ ret = BinaryConsts::EncodedType::externref;
+ break;
+ case Type::exnref:
+ ret = BinaryConsts::EncodedType::exnref;
+ break;
+ case Type::anyref:
+ ret = BinaryConsts::EncodedType::anyref;
+ break;
+ case Type::eqref:
+ ret = BinaryConsts::EncodedType::eqref;
+ break;
+ case Type::i31ref:
+ ret = BinaryConsts::EncodedType::i31ref;
+ break;
+ default:
+ WASM_UNREACHABLE("unexpected type");
+ }
+ o << S32LEB(ret);
+}
+
+void WasmBinaryWriter::writeHeapType(HeapType type) {
+ if (type.isSignature()) {
+ auto sig = type.getSignature();
+ o << S32LEB(getTypeIndex(sig));
+ return;
+ }
+ int ret = 0;
+ switch (type.kind) {
+ case HeapType::FuncKind:
+ ret = BinaryConsts::EncodedHeapType::func;
+ break;
+ case HeapType::ExternKind:
+ ret = BinaryConsts::EncodedHeapType::extern_;
+ break;
+ case HeapType::ExnKind:
+ ret = BinaryConsts::EncodedHeapType::exn;
+ break;
+ case HeapType::AnyKind:
+ ret = BinaryConsts::EncodedHeapType::any;
+ break;
+ case HeapType::EqKind:
+ ret = BinaryConsts::EncodedHeapType::eq;
+ break;
+ case HeapType::I31Kind:
+ ret = BinaryConsts::EncodedHeapType::i31;
+ break;
+ case HeapType::SignatureKind:
+ case HeapType::StructKind:
+ case HeapType::ArrayKind:
+ WASM_UNREACHABLE("TODO: compound GC types");
+ }
+ o << S32LEB(ret); // TODO: Actually encoded as s33
+}
+
// reader
bool WasmBinaryBuilder::hasDWARFSections() {
@@ -1253,6 +1354,10 @@ Type WasmBinaryBuilder::getType() {
return Type::anyref;
case BinaryConsts::EncodedType::eqref:
return Type::eqref;
+ case BinaryConsts::EncodedType::nullable:
+ return Type(getHeapType(), /* nullable = */ true);
+ case BinaryConsts::EncodedType::nonnullable:
+ return Type(getHeapType(), /* nullable = */ false);
case BinaryConsts::EncodedType::i31ref:
return Type::i31ref;
default:
@@ -1581,6 +1686,18 @@ void WasmBinaryBuilder::readFunctionSignatures() {
}
}
+Signature WasmBinaryBuilder::getFunctionSignatureByIndex(Index index) {
+ Signature sig;
+ if (index < functionImports.size()) {
+ return functionImports[index]->sig;
+ }
+ Index adjustedIndex = index - functionImports.size();
+ if (adjustedIndex >= functionSignatures.size()) {
+ throwError("invalid function index");
+ }
+ return functionSignatures[adjustedIndex];
+}
+
void WasmBinaryBuilder::readFunctions() {
BYN_TRACE("== readFunctions\n");
size_t total = getU32LEB();
@@ -2471,6 +2588,9 @@ void WasmBinaryBuilder::readFeatures(size_t payloadLen) {
wasm.features.setGC();
} else if (name == BinaryConsts::UserSections::Memory64Feature) {
wasm.features.setMemory64();
+ } else if (name ==
+ BinaryConsts::UserSections::TypedFunctionReferencesFeature) {
+ wasm.features.setTypedFunctionReferences();
}
}
}
@@ -3042,17 +3162,7 @@ void WasmBinaryBuilder::visitSwitch(Switch* curr) {
void WasmBinaryBuilder::visitCall(Call* curr) {
BYN_TRACE("zz node: Call\n");
auto index = getU32LEB();
- Signature sig;
- if (index < functionImports.size()) {
- auto* import = functionImports[index];
- sig = import->sig;
- } else {
- Index adjustedIndex = index - functionImports.size();
- if (adjustedIndex >= functionSignatures.size()) {
- throwError("invalid call index");
- }
- sig = functionSignatures[adjustedIndex];
- }
+ auto sig = getFunctionSignatureByIndex(index);
auto num = sig.params.size();
curr->operands.resize(num);
for (size_t i = 0; i < num; i++) {
@@ -5169,7 +5279,10 @@ void WasmBinaryBuilder::visitRefFunc(RefFunc* curr) {
throwError("ref.func: invalid call index");
}
functionRefs[index].push_back(curr); // we don't know function names yet
- curr->finalize();
+ // To support typed function refs, we give the reference not just a general
+ // funcref, but a specific subtype with the actual signature.
+ curr->finalize(
+ Type(HeapType(getFunctionSignatureByIndex(index)), /* nullable = */ true));
}
void WasmBinaryBuilder::visitRefEq(RefEq* curr) {
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 0636836d7..6286ae090 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -1890,7 +1890,10 @@ Expression* SExpressionWasmBuilder::makeRefFunc(Element& s) {
auto func = getFunctionName(*s[1]);
auto ret = allocator.alloc<RefFunc>();
ret->func = func;
- ret->finalize();
+ // To support typed function refs, we give the reference not just a general
+ // funcref, but a specific subtype with the actual signature.
+ ret->finalize(
+ Type(HeapType(functionSignatures[func]), /* nullable = */ true));
return ret;
}
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index c8a4f7a90..021b05cb6 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -24,11 +24,11 @@ static Name IMPOSSIBLE_CONTINUE("impossible-continue");
void BinaryInstWriter::emitResultType(Type type) {
if (type == Type::unreachable) {
- o << binaryType(Type::none);
+ parent.writeType(Type::none);
} else if (type.isTuple()) {
o << S32LEB(parent.getTypeIndex(Signature(Type::none, type)));
} else {
- o << binaryType(type);
+ parent.writeType(type);
}
}
@@ -1756,8 +1756,8 @@ void BinaryInstWriter::visitSelect(Select* curr) {
if (curr->type.isRef()) {
o << int8_t(BinaryConsts::SelectWithType) << U32LEB(curr->type.size());
for (size_t i = 0; i < curr->type.size(); i++) {
- o << binaryType(curr->type != Type::unreachable ? curr->type
- : Type::none);
+ parent.writeType(curr->type != Type::unreachable ? curr->type
+ : Type::none);
}
} else {
o << int8_t(BinaryConsts::Select);
@@ -1779,8 +1779,8 @@ void BinaryInstWriter::visitMemoryGrow(MemoryGrow* curr) {
}
void BinaryInstWriter::visitRefNull(RefNull* curr) {
- o << int8_t(BinaryConsts::RefNull)
- << binaryHeapType(curr->type.getHeapType());
+ o << int8_t(BinaryConsts::RefNull);
+ parent.writeHeapType(curr->type.getHeapType());
}
void BinaryInstWriter::visitRefIsNull(RefIsNull* curr) {
@@ -1966,7 +1966,8 @@ void BinaryInstWriter::mapLocalsAndEmitHeader() {
o << U32LEB(func->getNumVars());
for (Index i = varStart; i < varEnd; i++) {
mappedLocals[std::make_pair(i, 0)] = i;
- o << U32LEB(1) << binaryType(func->getLocalType(i));
+ o << U32LEB(1);
+ parent.writeType(func->getLocalType(i));
}
return;
}
@@ -1995,7 +1996,8 @@ void BinaryInstWriter::mapLocalsAndEmitHeader() {
setScratchLocals();
o << U32LEB(numLocalsByType.size());
for (auto& typeCount : numLocalsByType) {
- o << U32LEB(typeCount.second) << binaryType(typeCount.first);
+ o << U32LEB(typeCount.second);
+ parent.writeType(typeCount.first);
}
}
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index dc4d50ef4..cf4404739 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -460,6 +460,14 @@ Type Type::reinterpret() const {
FeatureSet Type::getFeatures() const {
auto getSingleFeatures = [](Type t) -> FeatureSet {
+ if (t != Type::funcref && t.isFunction()) {
+ // Strictly speaking, typed function references require the typed function
+ // references feature, however, we use these types internally regardless
+ // of the presence of features (in particular, since during load of the
+ // wasm we don't know the features yet, so we apply the more refined
+ // types).
+ return FeatureSet::ReferenceTypes;
+ }
TODO_SINGLE_COMPOUND(t);
switch (t.getBasic()) {
case Type::v128:
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 809ca5a6a..78e123a90 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -2313,6 +2313,7 @@ void FunctionValidator::visitFunction(Function* curr) {
for (const auto& var : curr->vars) {
features |= var.getFeatures();
shouldBeTrue(var.isConcrete(), curr, "vars must be concretely typed");
+ // TODO: check for nullability
}
shouldBeTrue(features <= getModule()->features,
curr->name,
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index c7a187b43..6245a3575 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -47,6 +47,7 @@ const char* ReferenceTypesFeature = "reference-types";
const char* MultivalueFeature = "multivalue";
const char* GCFeature = "gc";
const char* Memory64Feature = "memory64";
+const char* TypedFunctionReferencesFeature = "typed-function-references";
} // namespace UserSections
} // namespace BinaryConsts
@@ -984,7 +985,12 @@ void RefIsNull::finalize() {
type = Type::i32;
}
-void RefFunc::finalize() { type = Type::funcref; }
+void RefFunc::finalize() {
+ // No-op. We assume that the full proper typed function type has been applied
+ // previously.
+}
+
+void RefFunc::finalize(Type type_) { type = type_; }
void RefEq::finalize() {
if (left->type == Type::unreachable || right->type == Type::unreachable) {
diff --git a/test/binaryen.js/expressions.js b/test/binaryen.js/expressions.js
index a340adcbe..61fc0a3ef 100644
--- a/test/binaryen.js/expressions.js
+++ b/test/binaryen.js/expressions.js
@@ -1378,7 +1378,7 @@ console.log("# RefFunc");
const module = new binaryen.Module();
var func = "a";
- const theRefFunc = binaryen.RefFunc(module.ref.func(func));
+ const theRefFunc = binaryen.RefFunc(module.ref.func(func, binaryen.funcref));
assert(theRefFunc instanceof binaryen.RefFunc);
assert(theRefFunc instanceof binaryen.Expression);
assert(theRefFunc.func === func);
@@ -1388,7 +1388,8 @@ console.log("# RefFunc");
assert(theRefFunc.func === func);
theRefFunc.type = binaryen.f64;
theRefFunc.finalize();
- assert(theRefFunc.type === binaryen.funcref);
+ // TODO The type is a subtype of funcref, but we can't check that in the JS
+ // API atm.
console.log(theRefFunc.toText());
assert(
diff --git a/test/binaryen.js/kitchen-sink.js b/test/binaryen.js/kitchen-sink.js
index 836b7ab17..703e8cb5a 100644
--- a/test/binaryen.js/kitchen-sink.js
+++ b/test/binaryen.js/kitchen-sink.js
@@ -539,8 +539,8 @@ function test_core() {
// Reference types
module.ref.is_null(module.ref.null(binaryen.externref)),
module.ref.is_null(module.ref.null(binaryen.funcref)),
- module.ref.is_null(module.ref.func("kitchen()sinker")),
- module.select(temp10, module.ref.null(binaryen.funcref), module.ref.func("kitchen()sinker"), binaryen.funcref),
+ module.ref.is_null(module.ref.func("kitchen()sinker", binaryen.funcref)),
+ module.select(temp10, module.ref.null(binaryen.funcref), module.ref.func("kitchen()sinker", binaryen.funcref), binaryen.funcref),
// GC
module.ref.eq(module.ref.null(binaryen.eqref), module.ref.null(binaryen.eqref)),
diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt
index 4990c0abd..980a6d8c1 100644
--- a/test/binaryen.js/kitchen-sink.js.txt
+++ b/test/binaryen.js/kitchen-sink.js.txt
@@ -41,7 +41,7 @@ Features.ReferenceTypes: 256
Features.Multivalue: 512
Features.GC: 1024
Features.Memory64: 2048
-Features.All: 4095
+Features.All: 8191
InvalidId: 0
BlockId: 1
IfId: 2
diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c
index 8a2f22e8d..25f8b1937 100644
--- a/test/example/c-api-kitchen-sink.c
+++ b/test/example/c-api-kitchen-sink.c
@@ -310,7 +310,8 @@ void test_core() {
temp15 = makeInt32(module, 110), temp16 = makeInt64(module, 111);
BinaryenExpressionRef externrefExpr = BinaryenRefNull(module, BinaryenTypeExternref());
BinaryenExpressionRef funcrefExpr = BinaryenRefNull(module, BinaryenTypeFuncref());
- funcrefExpr = BinaryenRefFunc(module, "kitchen()sinker");
+ funcrefExpr =
+ BinaryenRefFunc(module, "kitchen()sinker", BinaryenTypeFuncref());
BinaryenExpressionRef exnrefExpr = BinaryenRefNull(module, BinaryenTypeExnref());
BinaryenExpressionRef i31refExpr = BinaryenI31New(module, makeInt32(module, 1));
@@ -737,15 +738,16 @@ void test_core() {
BinaryenRefIsNull(module, externrefExpr),
BinaryenRefIsNull(module, funcrefExpr),
BinaryenRefIsNull(module, exnrefExpr),
- BinaryenSelect(module,
- temp10,
- BinaryenRefNull(module, BinaryenTypeFuncref()),
- BinaryenRefFunc(module, "kitchen()sinker"),
- BinaryenTypeFuncref()),
+ BinaryenSelect(
+ module,
+ temp10,
+ BinaryenRefNull(module, BinaryenTypeFuncref()),
+ BinaryenRefFunc(module, "kitchen()sinker", BinaryenTypeFuncref()),
+ BinaryenTypeFuncref()),
// GC
BinaryenRefEq(module,
- BinaryenRefNull(module, BinaryenTypeEqref()),
- BinaryenRefNull(module, BinaryenTypeEqref())),
+ BinaryenRefNull(module, BinaryenTypeEqref()),
+ BinaryenRefNull(module, BinaryenTypeEqref())),
// Exception handling
BinaryenTry(module, tryBody, catchBody),
// Atomics
diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt
index ab9548924..dbbb30eb6 100644
--- a/test/example/c-api-kitchen-sink.txt
+++ b/test/example/c-api-kitchen-sink.txt
@@ -25,7 +25,7 @@ BinaryenFeatureReferenceTypes: 256
BinaryenFeatureMultivalue: 512
BinaryenFeatureGC: 1024
BinaryenFeatureMemory64: 2048
-BinaryenFeatureAll: 4095
+BinaryenFeatureAll: 8191
(f32.neg
(f32.const -33.61199951171875)
)
diff --git a/test/passes/fuzz-exec_all-features.txt b/test/passes/fuzz-exec_all-features.txt
index cbdcf4fdb..22e342fc1 100644
--- a/test/passes/fuzz-exec_all-features.txt
+++ b/test/passes/fuzz-exec_all-features.txt
@@ -207,3 +207,15 @@
)
[fuzz-exec] calling rmw-reads-modifies-and-writes-asymmetrical
[LoggingExternalInterface logging 214]
+[fuzz-exec] calling func
+[fuzz-exec] note result: func => funcref(func)
+(module
+ (type $none_=>_funcref (func (result funcref)))
+ (export "func" (func $func))
+ (func $func (result funcref)
+ (ref.func $func)
+ )
+)
+[fuzz-exec] calling func
+[fuzz-exec] note result: func => funcref(func)
+[fuzz-exec] comparing func
diff --git a/test/passes/fuzz-exec_all-features.wast b/test/passes/fuzz-exec_all-features.wast
index 4e5c926a5..960990a33 100644
--- a/test/passes/fuzz-exec_all-features.wast
+++ b/test/passes/fuzz-exec_all-features.wast
@@ -121,3 +121,9 @@
)
)
)
+(module
+ (export "func" (func $func))
+ (func $func (result funcref)
+ (ref.func $func)
+ )
+)
diff --git a/test/passes/fuzz_metrics_noprint.bin.txt b/test/passes/fuzz_metrics_noprint.bin.txt
index ad654067f..9e9b6f4f8 100644
--- a/test/passes/fuzz_metrics_noprint.bin.txt
+++ b/test/passes/fuzz_metrics_noprint.bin.txt
@@ -1,30 +1,30 @@
total
[events] : 0
- [exports] : 35
- [funcs] : 47
+ [exports] : 51
+ [funcs] : 67
[globals] : 7
[imports] : 4
[memory-data] : 4
- [table-data] : 16
- [total] : 6048
- [vars] : 137
- binary : 458
- block : 871
- break : 230
- call : 240
- call_indirect : 52
- const : 1081
- drop : 40
- global.get : 480
- global.set : 204
- if : 356
- load : 108
- local.get : 527
- local.set : 351
- loop : 155
- nop : 120
- return : 233
- select : 51
- store : 58
- unary : 432
+ [table-data] : 18
+ [total] : 4870
+ [vars] : 236
+ binary : 368
+ block : 699
+ break : 191
+ call : 300
+ call_indirect : 39
+ const : 847
+ drop : 91
+ global.get : 403
+ global.set : 171
+ if : 260
+ load : 85
+ local.get : 374
+ local.set : 251
+ loop : 111
+ nop : 86
+ return : 187
+ select : 30
+ store : 36
+ unary : 340
unreachable : 1
diff --git a/test/passes/instrument-locals_all-features.txt b/test/passes/instrument-locals_all-features.txt
index 03a5743e5..d027f54a0 100644
--- a/test/passes/instrument-locals_all-features.txt
+++ b/test/passes/instrument-locals_all-features.txt
@@ -157,18 +157,14 @@
)
)
(local.set $F
- (call $set_funcref
- (i32.const 15)
- (i32.const 4)
- (ref.func $test)
- )
+ (ref.func $test)
)
(local.set $X
(call $set_externref
- (i32.const 17)
+ (i32.const 16)
(i32.const 5)
(call $get_externref
- (i32.const 16)
+ (i32.const 15)
(i32.const 5)
(local.get $X)
)
@@ -176,10 +172,10 @@
)
(local.set $E
(call $set_exnref
- (i32.const 19)
+ (i32.const 18)
(i32.const 6)
(call $get_exnref
- (i32.const 18)
+ (i32.const 17)
(i32.const 6)
(local.get $E)
)
@@ -187,7 +183,7 @@
)
(local.set $x
(call $set_i32
- (i32.const 20)
+ (i32.const 19)
(i32.const 0)
(i32.const 11)
)
@@ -197,24 +193,24 @@
)
(local.set $z
(call $set_f32
- (i32.const 21)
+ (i32.const 20)
(i32.const 2)
(f32.const 33.209999084472656)
)
)
(local.set $w
(call $set_f64
- (i32.const 22)
+ (i32.const 21)
(i32.const 3)
(f64.const 44.321)
)
)
(local.set $F
(call $set_funcref
- (i32.const 24)
+ (i32.const 23)
(i32.const 4)
(call $get_funcref
- (i32.const 23)
+ (i32.const 22)
(i32.const 4)
(local.get $F)
)
@@ -222,10 +218,10 @@
)
(local.set $X
(call $set_externref
- (i32.const 26)
+ (i32.const 25)
(i32.const 5)
(call $get_externref
- (i32.const 25)
+ (i32.const 24)
(i32.const 5)
(local.get $X)
)
@@ -233,10 +229,10 @@
)
(local.set $E
(call $set_exnref
- (i32.const 28)
+ (i32.const 27)
(i32.const 6)
(call $get_exnref
- (i32.const 27)
+ (i32.const 26)
(i32.const 6)
(local.get $E)
)
@@ -274,14 +270,14 @@
)
(drop
(call $get_v128
- (i32.const 29)
+ (i32.const 28)
(i32.const 7)
(local.get $S)
)
)
(local.set $S
(call $set_v128
- (i32.const 30)
+ (i32.const 29)
(i32.const 7)
(v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003)
)
diff --git a/test/passes/strip-target-features_roundtrip_print-features_all-features.txt b/test/passes/strip-target-features_roundtrip_print-features_all-features.txt
index 18cee797f..96cb9b785 100644
--- a/test/passes/strip-target-features_roundtrip_print-features_all-features.txt
+++ b/test/passes/strip-target-features_roundtrip_print-features_all-features.txt
@@ -10,6 +10,7 @@
--enable-multivalue
--enable-gc
--enable-memory64
+--enable-typed-function-references
(module
(type $none_=>_v128_externref (func (result v128 externref)))
(func $foo (result v128 externref)
diff --git a/test/passes/translate-to-fuzz_all-features.txt b/test/passes/translate-to-fuzz_all-features.txt
index 6614e2009..055f80e00 100644
--- a/test/passes/translate-to-fuzz_all-features.txt
+++ b/test/passes/translate-to-fuzz_all-features.txt
@@ -2,23 +2,12 @@
(type $none_=>_none (func))
(type $i32_=>_none (func (param i32)))
(type $i64_=>_none (func (param i64)))
+ (type $i64_i32_=>_none (func (param i64 i32)))
(type $f32_=>_none (func (param f32)))
(type $f64_=>_none (func (param f64)))
(type $v128_=>_none (func (param v128)))
- (type $funcref_=>_none (func (param funcref)))
(type $exnref_=>_none (func (param exnref)))
(type $none_=>_i32 (func (result i32)))
- (type $anyref_anyref_externref_eqref_v128_=>_i64 (func (param anyref anyref externref eqref v128) (result i64)))
- (type $eqref_externref_exnref_v128_exnref_=>_i64 (func (param eqref externref exnref v128 exnref) (result i64)))
- (type $exnref_=>_f32 (func (param exnref) (result f32)))
- (type $exnref_i64_funcref_f64_f64_=>_f32 (func (param exnref i64 funcref f64 f64) (result f32)))
- (type $none_=>_funcref_f32_exnref_exnref (func (result funcref f32 exnref exnref)))
- (type $funcref_funcref_=>_funcref_f32_exnref_exnref (func (param funcref funcref) (result funcref f32 exnref exnref)))
- (type $none_=>_externref (func (result externref)))
- (type $i31ref_v128_=>_exnref (func (param i31ref v128) (result exnref)))
- (type $funcref_v128_=>_eqref (func (param funcref v128) (result eqref)))
- (type $anyref_=>_eqref (func (param anyref) (result eqref)))
- (type $i31ref_externref_v128_f32_f32_=>_eqref (func (param i31ref externref v128 f32 f32) (result eqref)))
(import "fuzzing-support" "log-i32" (func $log-i32 (param i32)))
(import "fuzzing-support" "log-i64" (func $log-i64 (param i64)))
(import "fuzzing-support" "log-f32" (func $log-f32 (param f32)))
@@ -27,37 +16,16 @@
(import "fuzzing-support" "log-exnref" (func $log-exnref (param exnref)))
(memory $0 (shared 16 17))
(data (i32.const 0) "N\0fN\f5\f9\b1\ff\fa\eb\e5\fe\a7\ec\fb\fc\f4\a6\e4\ea\f0\ae\e3")
- (table $0 17 funcref)
- (elem (i32.const 0) $func_1 $func_1 $func_1 $func_5 $func_5 $func_6 $func_6 $func_6 $func_6 $func_6 $func_6 $func_6 $func_6 $func_6 $func_6 $func_8 $func_9)
+ (table $0 0 funcref)
(global $global$ (mut eqref) (ref.null eq))
- (global $global$_0 (mut i32) (i32.const 470177031))
- (global $global$_1 (mut f64) (f64.const 2147483647))
- (global $global$_2 (mut (eqref f32 eqref funcref funcref i64)) (tuple.make
- (ref.null eq)
- (f32.const -2147483648)
- (ref.null eq)
- (ref.null func)
- (ref.null func)
- (i64.const -32)
- ))
- (global $global$_3 (mut f32) (f32.const -32769))
+ (global $global$_0 (mut externref) (ref.null extern))
+ (global $global$_1 (mut v128) (v128.const i32x4 0xfffffff9 0x06071c48 0x3f800000 0xc3800ae1))
+ (global $global$_2 (mut eqref) (ref.null eq))
+ (global $global$_3 (mut f64) (f64.const 0))
(global $hangLimit (mut i32) (i32.const 10))
+ (event $event$ (attr 0) (param i64 i32))
(export "hashMemory" (func $hashMemory))
(export "memory" (memory $0))
- (export "func" (func $func))
- (export "func_invoker" (func $func_invoker))
- (export "func_1_invoker" (func $func_1_invoker))
- (export "func_2" (func $func_2))
- (export "func_2_invoker" (func $func_2_invoker))
- (export "func_3" (func $func_3))
- (export "func_3_invoker" (func $func_3_invoker))
- (export "func_4_invoker" (func $func_4_invoker))
- (export "func_5" (func $func_5))
- (export "func_5_invoker" (func $func_5_invoker))
- (export "func_6" (func $func_6))
- (export "func_6_invoker" (func $func_6_invoker))
- (export "func_7" (func $func_7))
- (export "func_8" (func $func_8))
(export "hangLimitInitializer" (func $hangLimitInitializer))
(func $hashMemory (result i32)
(local $0 i32)
@@ -67,7 +35,7 @@
(global.get $hangLimit)
)
(return
- (i32.const 69)
+ (i32.const 235407412)
)
)
(global.set $hangLimit
@@ -82,18 +50,7 @@
(i32.const 5381)
)
(local.set $0
- (i32.xor
- (i32.add
- (i32.shl
- (local.get $0)
- (i32.const 5)
- )
- (local.get $0)
- )
- (i32.load8_u
- (i32.const 0)
- )
- )
+ (i32.const 1140933654)
)
(local.set $0
(i32.xor
@@ -102,109 +59,58 @@
(local.get $0)
(i32.const 5)
)
- (local.get $0)
+ (i32.const -127)
)
(i32.load8_u offset=1
(i32.const 0)
)
)
)
- (local.set $0
- (i32.xor
- (i32.add
- (i32.shl
- (local.get $0)
- (i32.const 5)
- )
- (local.get $0)
- )
- (i32.load8_u offset=2
- (i32.const 0)
- )
- )
- )
- (local.set $0
- (i32.xor
- (i32.add
- (i32.shl
- (local.get $0)
- (i32.const 5)
- )
- (local.get $0)
- )
- (i32.load8_u offset=3
- (i32.const 0)
- )
- )
- )
- (local.set $0
- (i32.xor
- (i32.add
- (i32.shl
- (local.get $0)
- (i32.const 5)
- )
- (local.get $0)
- )
- (i32.load8_u offset=4
- (i32.const 0)
- )
- )
- )
- (local.set $0
- (i32.xor
- (i32.add
- (i32.shl
- (local.get $0)
- (i32.const 5)
- )
- (local.get $0)
- )
- (i32.load8_u offset=5
- (i32.const 0)
- )
+ (f32.store offset=1 align=1
+ (i32.and
+ (i32.const -127)
+ (i32.const 15)
)
+ (f32.const -8)
)
- (local.set $0
- (i32.xor
- (i32.add
- (i32.shl
- (local.get $0)
- (i32.const 5)
- )
- (local.get $0)
- )
- (i32.load8_u offset=6
- (i32.const 0)
+ (if
+ (i32.eqz
+ (ref.is_null
+ (ref.null exn)
)
)
- )
- (local.set $0
- (i32.xor
- (i32.add
- (i32.shl
- (local.get $0)
- (i32.const 5)
+ (block $label$1
+ (nop)
+ (br_if $label$1
+ (loop $label$2 (result i32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const 980647737)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$3 (result i32)
+ (i32.const -1)
+ )
)
- (local.get $0)
- )
- (i32.load8_u offset=7
- (i32.const 0)
)
)
- )
- (local.set $0
- (i32.xor
- (i32.add
- (i32.shl
- (local.get $0)
- (i32.const 5)
- )
- (local.get $0)
- )
- (i32.load8_u offset=8
- (i32.const 0)
+ (block $label$4
+ (block $label$5
+ (nop)
+ (nop)
)
+ (nop)
)
)
(local.set $0
@@ -214,54 +120,231 @@
(local.get $0)
(i32.const 5)
)
- (local.get $0)
+ (i32.const 175316752)
)
- (i32.load8_u offset=9
+ (i32.load8_u offset=4
(i32.const 0)
)
)
)
- (local.set $0
+ (local.tee $0
(i32.xor
(i32.add
- (i32.shl
- (local.get $0)
- (i32.const 5)
+ (if
+ (i32.eqz
+ (i32.const 128)
+ )
+ (block $label$6
+ (i32.store8 offset=4
+ (i32.and
+ (loop $label$7 (result i32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const -2147483647)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$8 (result i32)
+ (loop $label$9
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const 262143)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block
+ (block $label$10
+ (nop)
+ (nop)
+ )
+ (br_if $label$9
+ (block
+ (i32.wrap_i64
+ (i64.trunc_f32_u
+ (block $label$11
+ (br_if $label$9
+ (i32.eqz
+ (br_if $label$8
+ (select
+ (i32.const 1162693199)
+ (i32.const 5909)
+ (i32.const 17989)
+ )
+ (i32.const 236914958)
+ )
+ )
+ )
+ (br $label$7)
+ )
+ )
+ )
+ (drop
+ (i32.eqz
+ (i32.const 1548964443)
+ )
+ )
+ )
+ )
+ (v128.store offset=22
+ (i32.and
+ (i32.const 307712331)
+ (i32.const 15)
+ )
+ (loop $label$12 (result v128)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const -13)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block (result v128)
+ (br_if $label$7
+ (i32.eqz
+ (i32.const 24)
+ )
+ )
+ (br_if $label$12
+ (i32.const -118)
+ )
+ (i8x16.gt_u
+ (i16x8.splat
+ (loop $label$13 (result i32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const -14)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block (result i32)
+ (nop)
+ (br_if $label$13
+ (i32.eqz
+ (i32.trunc_f32_u
+ (f32.const 1099511627776)
+ )
+ )
+ )
+ (f32.le
+ (f32.const 4398046511104)
+ (f32.const 320406528)
+ )
+ )
+ )
+ )
+ (loop $label$14 (result v128)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const 386596886)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$15 (result v128)
+ (br_if $label$12
+ (f32.eq
+ (f32.const -2147483648)
+ (f32.const 555950656)
+ )
+ )
+ (v128.const i32x4 0x80000000 0xffffff81 0x00008000 0x6e026f15)
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ (i32.const 0)
+ )
+ )
+ (i32.const 15)
+ )
+ (i31.get_s
+ (block $label$16 (result i31ref)
+ (nop)
+ (i31.new
+ (i32.const -256)
+ )
+ )
+ )
+ )
+ (return
+ (i32.const -9)
+ )
+ )
+ (block $label$17
+ (return
+ (i32.const 2376257)
+ )
+ )
)
(local.get $0)
)
- (i32.load8_u offset=10
+ (i32.load8_u offset=5
(i32.const 0)
)
)
)
(local.set $0
- (i32.xor
- (i32.add
- (i32.shl
- (local.get $0)
- (i32.const 5)
- )
- (local.get $0)
- )
- (i32.load8_u offset=11
- (i32.const 0)
+ (tuple.extract 0
+ (tuple.make
+ (i32.const 262145)
+ (i32.const 110)
)
)
)
(local.set $0
- (i32.xor
- (i32.add
- (i32.shl
- (local.get $0)
- (i32.const 5)
- )
- (local.get $0)
- )
- (i32.load8_u offset=12
- (i32.const 0)
- )
- )
+ (call $hashMemory)
)
(local.set $0
(i32.xor
@@ -272,7 +355,7 @@
)
(local.get $0)
)
- (i32.load8_u offset=13
+ (i32.load8_u offset=6
(i32.const 0)
)
)
@@ -284,380 +367,283 @@
(local.get $0)
(i32.const 5)
)
- (local.get $0)
- )
- (i32.load8_u offset=14
- (i32.const 0)
- )
- )
- )
- (local.set $0
- (i32.xor
- (i32.add
- (i32.shl
- (local.get $0)
- (i32.const 5)
+ (i32.xor
+ (i32.add
+ (i32.shl
+ (local.get $0)
+ (i32.const 5)
+ )
+ (local.get $0)
+ )
+ (i32.load8_u offset=8
+ (i32.const 0)
+ )
)
- (local.get $0)
)
- (i32.load8_u offset=15
+ (i32.load8_u offset=9
(i32.const 0)
)
)
)
- (local.get $0)
- )
- )
- (func $func (param $0 i31ref) (param $1 v128) (result exnref)
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (ref.null exn)
- )
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
- )
- )
- )
- (ref.null exn)
- )
- (func $func_invoker
- (drop
- (call $func
- (i31.new
- (i32.const 1633240409)
- )
- (v128.const i32x4 0xcf800000 0x4c816020 0x3e1a1a1a 0x00000000)
- )
- )
- )
- (func $func_0 (param $0 anyref) (param $1 anyref) (param $2 externref) (param $3 eqref) (param $4 v128) (result i64)
- (local $5 eqref)
- (local $6 (funcref externref i32 f64 f32 i64))
- (local $7 (f32 funcref eqref i32 i31ref i32))
- (local $8 v128)
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (i64.const 2147483647)
- )
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
- )
- )
- )
- (block $label$0 (result i64)
- (nop)
- (br_if $label$0
- (tuple.extract 1
- (tuple.make
- (f64.const -255)
- (i64.const -127)
- (ref.null func)
- )
- )
- (i32.const -24)
- )
- )
- )
- (func $func_1 (param $0 i31ref) (param $1 externref) (param $2 v128) (param $3 f32) (param $4 f32) (result eqref)
- (local $5 v128)
- (local $6 (exnref externref i64 i32 f64 funcref))
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (ref.null eq)
- )
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
- )
- )
- )
- (ref.null eq)
- )
- (func $func_1_invoker
- (drop
- (call $func_1
- (i31.new
- (i32.const 16777216)
- )
- (ref.null extern)
- (v128.const i32x4 0x5d455846 0xcf800000 0x42aa0000 0x46b2a800)
- (f32.const -17592186044416)
- (f32.const -4294967296)
- )
- )
- (call $log-i32
- (call $hashMemory)
- )
- (drop
- (call $func_1
- (i31.new
- (i32.const 73)
- )
- (ref.null extern)
- (v128.const i32x4 0xffff8001 0xffffffff 0x184c764c 0x10105676)
- (f32.const -9223372036854775808)
- (f32.const 129)
- )
- )
- (call $log-i32
- (call $hashMemory)
- )
- (drop
- (call $func_1
- (i31.new
- (i32.const -4096)
- )
- (ref.null extern)
- (v128.const i32x4 0x00000000 0x00000020 0x00000001 0xffc00000)
- (f32.const -nan:0x7fffbd)
- (f32.const -255.8040008544922)
- )
- )
- (call $log-i32
- (call $hashMemory)
- )
- (drop
- (call $func_1
- (i31.new
- (i32.const 1936946035)
- )
- (ref.null extern)
- (v128.const i32x4 0xff010001 0x4e07ffff 0x00060002 0xff00001f)
- (f32.const 6918)
- (f32.const 4.921484278772694e-25)
- )
- )
- (call $log-i32
- (call $hashMemory)
- )
- )
- (func $func_2 (param $0 funcref)
- (local $1 exnref)
- (local $2 (f64 externref f32 f32 v128 eqref))
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return)
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
- )
- )
- )
- (block $label$0
- (f32.store offset=3 align=2
- (i32.and
- (i32.const 15)
- (i32.const 15)
- )
- (f32.const 66)
- )
- (return)
- )
- )
- (func $func_2_invoker
- (call $func_2
- (ref.null func)
- )
- )
- (func $func_3 (param $0 exnref) (result f32)
- (local $1 i31ref)
- (local $2 i31ref)
- (local $3 (i32 externref f64 i32))
- (local $4 externref)
- (local $5 (f32 funcref))
- (local $6 i31ref)
- (local $7 i31ref)
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (f32.const -nan:0x7fffa6)
- )
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
- )
- )
- )
- (block $label$0
- (loop $label$1
- (block
- (if
+ (block $label$23
+ (if
+ (if (result i32)
(i32.eqz
- (global.get $hangLimit)
- )
- (return
- (f32.const 0.4049999713897705)
- )
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
- )
- )
- )
- (block
- (block $label$2
- (i32.store offset=4 align=1
- (i32.and
- (block $label$32 (result i32)
- (block $label$33
- (nop)
- (if
- (i32.eqz
- (i32.const -1)
- )
- (nop)
- (nop)
- )
- )
- (loop $label$34 (result i32)
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
+ (i32.const 218235656)
+ )
+ (block $label$24
+ (global.set $global$_3
+ (f64.add
+ (f64.mul
+ (loop $label$25 (result f64)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const 56235029)
+ )
)
- (return
- (f32.const 1048576)
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
)
)
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
+ (block (result f64)
+ (br_if $label$23
+ (block $label$26
+ (br $label$23)
+ )
)
+ (br_if $label$25
+ (i31.get_s
+ (i31.new
+ (i32.const -256)
+ )
+ )
+ )
+ (global.get $global$_3)
)
)
- (call $hashMemory)
+ (f64.const 0.878)
+ )
+ (block $label$27
+ (nop)
+ (br $label$23)
)
- )
- (i32.const 15)
- )
- (i32.load8_u offset=22
- (i32.and
- (i32.const -14)
- (i32.const 15)
)
)
+ (br $label$23)
)
- (nop)
- )
- (br_if $label$1
- (i32.const 33554431)
- )
- (br_if $label$1
- (i32.const 134217729)
- )
- )
- )
- (if
- (i32.eqz
- (i32.const -65535)
- )
- (block $label$4
- (global.set $global$_1
- (block $label$23
- (nop)
- (return
- (f32.const -4503599627370496)
- )
+ (select
+ (call $hashMemory)
+ (i32.const -2147483647)
+ (i32.const 5909)
)
)
- (call $log-i32
- (call $hashMemory)
- )
- )
- (loop $label$6
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (f32.const 2147483648)
+ (nop)
+ (block $label$32
+ (loop $label$33
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const 15)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
)
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
+ (block $label$34
+ (br_if $label$23
+ (i32.const 16911115)
+ )
+ (block $label$35
+ (atomic.fence)
+ (atomic.fence)
+ )
)
)
+ (atomic.fence)
+ (atomic.fence)
)
- (if
- (i32.eqz
- (i16x8.extract_lane_s 7
- (v128.const i32x4 0x1c5e4449 0x4644c000 0xcf800000 0x477fd300)
- )
- )
- (if
- (i32.const -127)
- (block $label$7
- (memory.copy
- (i32.const 32768)
- (i32.and
- (i32.const 32768)
- (i32.const 15)
+ )
+ (atomic.fence)
+ )
+ (local.set $0
+ (i32.xor
+ (memory.atomic.notify offset=4
+ (loop $label$36 (result i32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const 65512)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
)
- (global.get $global$_0)
)
- (nop)
)
- (block $label$8
- (call $log-i32
- (call $hashMemory)
+ (block (result i32)
+ (if
+ (ref.is_null
+ (block $label$37
+ (nop)
+ (br $label$36)
+ )
+ )
+ (nop)
+ (nop)
)
- (i32.atomic.store8 offset=4
- (i32.and
- (i32.const -70)
- (i32.const 15)
+ (br_if $label$36
+ (i32.eqz
+ (block $label$38 (result i32)
+ (loop $label$39
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const 67108864)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block
+ (br_if $label$39
+ (i32.eqz
+ (i32.const -58)
+ )
+ )
+ (br_if $label$39
+ (loop $label$40
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const 29)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$41
+ (if
+ (i32.const 65534)
+ (block $label$42
+ (nop)
+ (br_if $label$39
+ (i32.eqz
+ (i32.const -61)
+ )
+ )
+ )
+ (block $label$43
+ (nop)
+ (drop
+ (ref.null exn)
+ )
+ )
+ )
+ (br $label$40)
+ )
+ )
+ )
+ (f32.store offset=3 align=2
+ (i32.and
+ (select
+ (i32.const 42)
+ (loop $label$44 (result i32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const -9)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (i16x8.extract_lane_s 2
+ (v128.const i32x4 0x05030804 0x1e070503 0x80000001 0xffffffff)
+ )
+ )
+ (memory.atomic.notify offset=22
+ (i32.and
+ (i32.atomic.load offset=22
+ (i32.and
+ (i32.const 1499338050)
+ (i32.const 15)
+ )
+ )
+ (i32.const 15)
+ )
+ (i32.const -2)
+ )
+ )
+ (i32.const 15)
+ )
+ (f32.const -9223372036854775808)
+ )
+ )
+ )
+ (i32.const -2147483648)
+ )
)
- (i32.const 3342)
+ )
+ (select
+ (i32.const -127)
+ (i32.const 8)
+ (i32.const -255)
)
)
)
- (block $label$9
- (global.set $global$_0
- (i32.const 0)
- )
- (loop $label$14
+ (i32.const 608321884)
+ )
+ (i32.and
+ (i32.const 72)
+ (i64.eqz
+ (loop $label$45 (result i64)
(block
(if
(i32.eqz
(global.get $hangLimit)
)
(return
- (f32.const -0)
+ (i32.const 2131838335)
)
)
(global.set $hangLimit
@@ -667,371 +653,326 @@
)
)
)
- (block
- (block $label$15
+ (block (result i64)
+ (block $label$46
(nop)
- (f64.store offset=4
- (i32.and
- (i16x8.extract_lane_s 3
- (v128.const i32x4 0x06143637 0x1df25a02 0x00304800 0x713ecf76)
- )
- (i32.const 15)
- )
- (global.get $global$_1)
- )
)
- (br_if $label$14
- (i31.get_s
- (local.get $1)
- )
- )
- (call $log-f64
- (f64.div
- (f64.load offset=2 align=2
- (i32.and
- (i32.const -1)
- (i32.const 15)
- )
- )
- (f64.load offset=2 align=2
- (i32.and
- (call $hashMemory)
- (i32.const 15)
+ (br_if $label$45
+ (i32.eqz
+ (block $label$47
+ (br_if $label$45
+ (i32.eqz
+ (i32.rem_s
+ (if (result i32)
+ (i32.rem_u
+ (i32.atomic.load16_u offset=2
+ (i32.and
+ (if (result i32)
+ (i32.eqz
+ (loop $label$48 (result i32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const 55645307)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block (result i32)
+ (br_if $label$48
+ (i32.eqz
+ (i32.const 4374)
+ )
+ )
+ (br_if $label$48
+ (i32.const 791226157)
+ )
+ (if (result i32)
+ (i32.eqz
+ (i32.const 270077278)
+ )
+ (i32.const -1)
+ (i32.const 96)
+ )
+ )
+ )
+ )
+ (block $label$49
+ (nop)
+ (br $label$45)
+ )
+ (block $label$50 (result i32)
+ (loop $label$51
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const 44)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block
+ (nop)
+ (br_if $label$51
+ (i32.eqz
+ (i32.const 65507)
+ )
+ )
+ (br_if $label$51
+ (i32.const 1413679622)
+ )
+ )
+ )
+ (f64.eq
+ (f64.const -4095.596)
+ (f64.const -54)
+ )
+ )
+ )
+ (i32.const 15)
+ )
+ )
+ (i32.const 262143)
+ )
+ (i8x16.extract_lane_u 7
+ (select
+ (global.get $global$_1)
+ (i32x4.lt_u
+ (i32x4.gt_u
+ (v128.const i32x4 0xffff0002 0x0000ffa0 0x000000ff 0xff800000)
+ (v128.const i32x4 0x00000001 0xffffffb7 0x585f5c5d 0xe0000001)
+ )
+ (global.get $global$_1)
+ )
+ (i31.get_s
+ (i31.new
+ (i32.const 1431912225)
+ )
+ )
+ )
+ )
+ (block $label$52
+ (if
+ (i32.eqz
+ (memory.atomic.notify offset=4
+ (i8x16.extract_lane_s 6
+ (v128.const i32x4 0x0000040a 0x00000000 0x51080d5a 0x05040f53)
+ )
+ (i32.atomic.rmw8.cmpxchg_u offset=22
+ (i32.and
+ (if (result i32)
+ (i32.const 35)
+ (block $label$53
+ (br $label$45)
+ )
+ (i32.const 2147483647)
+ )
+ (i32.const 15)
+ )
+ (i32.const 47)
+ (i32.const 118818079)
+ )
+ )
+ )
+ (block $label$54
+ (drop
+ (ref.null exn)
+ )
+ (nop)
+ )
+ (block $label$55
+ (data.drop 0)
+ (nop)
+ )
+ )
+ (br $label$45)
+ )
+ )
+ (call $hashMemory)
+ )
+ )
)
+ (br $label$45)
)
)
)
+ (i64.const 5064094673136993862)
)
)
)
)
)
)
- (return
- (f32.const 4095.84912109375)
- )
- )
- )
- (func $func_3_invoker
- (drop
- (call $func_3
- (ref.null exn)
- )
- )
- (drop
- (call $func_3
- (ref.null exn)
- )
- )
- (drop
- (call $func_3
- (ref.null exn)
- )
- )
- )
- (func $func_4 (param $0 funcref) (param $1 funcref) (result funcref f32 exnref exnref)
- (local $2 f64)
- (local $3 externref)
- (local $4 f32)
- (local $5 (funcref eqref anyref i32 exnref))
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (tuple.make
- (ref.null func)
- (f32.const 4294967296)
- (ref.null exn)
- (ref.null exn)
- )
- )
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
- )
- )
- )
- (tuple.make
- (local.get $0)
- (f32.const 2147483648)
- (ref.null exn)
- (ref.null exn)
- )
- )
- (func $func_4_invoker
- (drop
- (call $func_4
- (ref.null func)
- (ref.null func)
- )
- )
- (drop
- (call $func_4
- (ref.null func)
- (ref.null func)
- )
- )
- (call $log-i32
- (call $hashMemory)
- )
- (drop
- (call $func_4
- (ref.null func)
- (ref.null func)
- )
- )
- (drop
- (call $func_4
- (ref.null func)
- (ref.null func)
- )
- )
- (call $log-i32
- (call $hashMemory)
- )
- )
- (func $func_5 (param $0 anyref) (result eqref)
- (local $1 (anyref anyref i32 f64 exnref f64))
- (local $2 f64)
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (ref.null eq)
- )
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
- )
- )
- )
- (return
- (ref.null eq)
- )
- )
- (func $func_5_invoker
- (drop
- (call $func_5
- (ref.null any)
- )
- )
- (call $log-i32
- (call $hashMemory)
- )
- (drop
- (call $func_5
- (ref.null any)
- )
- )
- (call $log-i32
- (call $hashMemory)
- )
- )
- (func $func_6 (param $0 funcref) (param $1 v128) (result eqref)
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (ref.null eq)
- )
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
- )
- )
- )
- (block $label$0
- (block $label$1
- (if
- (i32.const 0)
- (block $label$2
- (nop)
- (nop)
- )
- (block $label$3
- (nop)
- (i32.atomic.store8 offset=3
- (i32.const 826952521)
- (i31.get_u
- (i31.new
- (i32.const 2147483647)
- )
- )
+ (local.set $0
+ (i32.xor
+ (i32.add
+ (i32.shl
+ (local.get $0)
+ (i32.const 5)
)
- )
- )
- (block $label$4
- (call $log-i32
- (call $hashMemory)
- )
- (local.set $0
(local.get $0)
)
- )
- )
- (return
- (ref.null eq)
- )
- )
- )
- (func $func_6_invoker
- (drop
- (call $func_6
- (ref.null func)
- (v128.const i32x4 0x0e165b0c 0x5b120b08 0x005353f8 0x41d00000)
- )
- )
- )
- (func $func_7 (param $0 exnref) (param $1 i64) (param $2 funcref) (param $3 f64) (param $4 f64) (result f32)
- (local $5 funcref)
- (local $6 (f64 f64 f64))
- (local $7 exnref)
- (local $8 f64)
- (local $9 eqref)
- (local $10 i64)
- (local $11 v128)
- (local $12 i32)
- (local $13 (i31ref v128 f32 i64 exnref))
- (local $14 anyref)
- (local $15 (externref eqref externref externref eqref))
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (f32.const 43)
- )
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
- )
- )
- )
- (select
- (loop $label$0 (result f32)
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (f32.const 18446744073709551615)
- )
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
- )
+ (i32.shl
+ (local.get $0)
+ (i32.const 5)
)
)
- (f32.const -nan:0x7fffeb)
)
- (f32.const 18526)
- (i32.const -50)
- )
- )
- (func $func_8 (result externref)
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (ref.null extern)
- )
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
- )
- )
- )
- (block $label$0 (result externref)
- (call $log-i32
- (call $hashMemory)
- )
- (ref.null extern)
- )
- )
- (func $func_9 (param $0 eqref) (param $1 externref) (param $2 exnref) (param $3 v128) (param $4 exnref) (result i64)
- (local $5 f32)
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (i64.const -18014398509481983)
- )
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
- )
- )
- )
- (loop $label$0 (result i64)
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (i64.const 7709)
+ (nop)
+ (local.set $0
+ (i32.xor
+ (i32.add
+ (i32.const 5)
+ (local.get $0)
)
- )
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
+ (i32.load8_u offset=14
+ (i32.const 0)
)
)
)
- (block $label$1 (result i64)
- (br_if $label$0
- (i32.const 707800420)
- )
- (loop $label$2 (result i64)
- (block
- (if
- (i32.eqz
- (global.get $hangLimit)
- )
- (return
- (i64.const 2305843009213693952)
+ (block $label$56
+ (drop
+ (memory.atomic.notify offset=2
+ (i32.and
+ (f64.ne
+ (f64.const -1797693134862315708145274e284)
+ (select
+ (global.get $global$_3)
+ (if (result f64)
+ (i32.eqz
+ (i32.const -2147483647)
+ )
+ (f64.trunc
+ (f64.div
+ (if (result f64)
+ (i32.eqz
+ (i32.atomic.rmw8.xor_u offset=22
+ (i32.const 488975911)
+ (select
+ (i32.const -16383)
+ (if (result i32)
+ (i32.eqz
+ (loop $label$57 (result i32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const 386995985)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block (result i32)
+ (nop)
+ (br_if $label$57
+ (i32.const 453384208)
+ )
+ (i32.const -2147483648)
+ )
+ )
+ )
+ (i32.const 7753)
+ (block $label$58
+ (nop)
+ (br $label$56)
+ )
+ )
+ (i32.const 0)
+ )
+ )
+ )
+ (block $label$59 (result f64)
+ (nop)
+ (global.get $global$_3)
+ )
+ (block $label$60
+ (nop)
+ (br $label$56)
+ )
+ )
+ (tuple.extract 1
+ (loop $label$61
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const -8)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$62
+ (br $label$56)
+ )
+ )
+ )
+ )
+ )
+ (block $label$63 (result f64)
+ (nop)
+ (f64.load offset=4
+ (i32.and
+ (call $hashMemory)
+ (i32.const 15)
+ )
+ )
+ )
+ )
+ (ref.is_null
+ (ref.null eq)
+ )
+ )
)
+ (i32.const 15)
)
- (global.set $hangLimit
- (i32.sub
- (global.get $hangLimit)
- (i32.const 1)
+ (i32.const 235020035)
+ )
+ )
+ (i64.atomic.store32 offset=22
+ (i32.and
+ (memory.atomic.notify offset=22
+ (i32.and
+ (i32.const 255)
+ (i32.const 15)
)
+ (i32.const -255)
)
+ (i32.const 15)
)
- (block $label$3 (result i64)
- (data.drop 0)
- (i64.const -116)
- )
+ (i64.const 33554432)
)
)
+ (local.get $0)
)
)
(func $hangLimitInitializer
diff --git a/test/unit/test_features.py b/test/unit/test_features.py
index a44d58bbd..889b149b1 100644
--- a/test/unit/test_features.py
+++ b/test/unit/test_features.py
@@ -408,5 +408,6 @@ class TargetFeaturesSectionTest(utils.BinaryenTestCase):
'--enable-reference-types',
'--enable-multivalue',
'--enable-gc',
- '--enable-memory64'
+ '--enable-memory64',
+ '--enable-typed-function-references',
], p2.stdout.splitlines())