diff options
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()) |