From 83ae39af1f8ffe67856b16f7ee13de066169b48f Mon Sep 17 00:00:00 2001 From: Thomas Lively <7121787+tlively@users.noreply.github.com> Date: Wed, 9 Jun 2021 22:54:56 -0400 Subject: Store signatures as HeapTypes when parsing binaries (#3929) When parsing func.ref instructions, we need to get the HeapType corresponding to the referenced function's signature. Since constructing HeapTypes from Signatures can be expensive under equirecursive typing, keep track of the original function signature HeapTypes directly during parsing rather than storing them as Signatures. --- src/wasm/wasm-binary.cpp | 53 +++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 21 deletions(-) (limited to 'src/wasm/wasm-binary.cpp') diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 35bc468b1..84834352b 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -1987,6 +1987,7 @@ void WasmBinaryBuilder::readImports() { case ExternalKind::Function: { Name name(std::string("fimport$") + std::to_string(functionCounter++)); auto index = getU32LEB(); + functionTypes.push_back(getTypeByIndex(index)); auto curr = builder.makeFunction(name, getSignatureByTypeIndex(index), {}); curr->module = module; @@ -2084,28 +2085,37 @@ void WasmBinaryBuilder::readFunctionSignatures() { for (size_t i = 0; i < num; i++) { BYN_TRACE("read one\n"); auto index = getU32LEB(); - functionSignatures.push_back(getSignatureByTypeIndex(index)); + functionTypes.push_back(getTypeByIndex(index)); + // Check that the type is a signature. + getSignatureByTypeIndex(index); } } -Signature WasmBinaryBuilder::getSignatureByFunctionIndex(Index index) { - Signature sig; - if (index < functionImports.size()) { - return functionImports[index]->sig; +HeapType WasmBinaryBuilder::getTypeByIndex(Index index) { + if (index >= types.size()) { + throwError("invalid type index " + std::to_string(index) + " / " + + std::to_string(types.size())); } - Index adjustedIndex = index - functionImports.size(); - if (adjustedIndex >= functionSignatures.size()) { + return types[index]; +} + +HeapType WasmBinaryBuilder::getTypeByFunctionIndex(Index index) { + if (index >= functionTypes.size()) { throwError("invalid function index"); } - return functionSignatures[adjustedIndex]; + return functionTypes[index]; } Signature WasmBinaryBuilder::getSignatureByTypeIndex(Index index) { - if (index >= types.size()) { - throwError("invalid type index " + std::to_string(index) + " / " + - std::to_string(types.size())); + auto heapType = getTypeByIndex(index); + if (!heapType.isSignature()) { + throwError("invalid signature type " + heapType.toString()); } - auto heapType = types[index]; + return heapType.getSignature(); +} + +Signature WasmBinaryBuilder::getSignatureByFunctionIndex(Index index) { + auto heapType = getTypeByFunctionIndex(index); if (!heapType.isSignature()) { throwError("invalid signature type " + heapType.toString()); } @@ -2115,7 +2125,7 @@ Signature WasmBinaryBuilder::getSignatureByTypeIndex(Index index) { void WasmBinaryBuilder::readFunctions() { BYN_TRACE("== readFunctions\n"); size_t total = getU32LEB(); - if (total != functionSignatures.size()) { + if (total != functionTypes.size() - functionImports.size()) { throwError("invalid function section size, must equal types"); } for (size_t i = 0; i < total; i++) { @@ -2129,7 +2139,7 @@ void WasmBinaryBuilder::readFunctions() { auto* func = new Function; func->name = Name::fromInt(i); - func->sig = functionSignatures[i]; + func->sig = getSignatureByFunctionIndex(functionImports.size() + i); currFunction = func; if (DWARF) { @@ -2860,7 +2870,7 @@ void WasmBinaryBuilder::readElementSegments() { } else { for (Index j = 0; j < size; j++) { Index index = getU32LEB(); - auto sig = getSignatureByFunctionIndex(index); + auto sig = getTypeByFunctionIndex(index); // Use a placeholder name for now auto* refFunc = Builder(wasm).makeRefFunc(Name::fromInt(index), sig); functionRefs[index].push_back(refFunc); @@ -6043,14 +6053,15 @@ void WasmBinaryBuilder::visitRefIs(RefIs* curr, uint8_t code) { void WasmBinaryBuilder::visitRefFunc(RefFunc* curr) { BYN_TRACE("zz node: RefFunc\n"); Index index = getU32LEB(); - if (index >= functionImports.size() + functionSignatures.size()) { - throwError("ref.func: invalid call index"); - } - functionRefs[index].push_back(curr); // we don't know function names yet + // We don't know function names yet, so record this use to be updated later. + // Note that we do not need to check that 'index' is in bounds, as that will + // be verified in the next line. (Also, note that functionRefs[index] may + // write to an odd place in the functionRefs map if index is invalid, but that + // is harmless.) + functionRefs[index].push_back(curr); // 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(getSignatureByFunctionIndex(index)), NonNullable)); + curr->finalize(Type(getTypeByFunctionIndex(index), NonNullable)); } void WasmBinaryBuilder::visitRefEq(RefEq* curr) { -- cgit v1.2.3