impl multi-memories wasm-split
diff --git a/src/ir/names.h b/src/ir/names.h index af6ca15..db45ef4 100644 --- a/src/ir/names.h +++ b/src/ir/names.h
@@ -83,6 +83,10 @@ return getValidName( root, [&](Name test) { return !module.getElementSegmentOrNull(test); }); } +inline Name getValidMemoryName(Module& module, Name root) { + return getValidName(root, + [&](Name test) { return !module.getMemoryOrNull(test); }); +} class MinifiedNameGenerator { size_t state = 0;
diff --git a/src/tools/wasm-split/instrumenter.cpp b/src/tools/wasm-split/instrumenter.cpp index 50da9d0..538cd43 100644 --- a/src/tools/wasm-split/instrumenter.cpp +++ b/src/tools/wasm-split/instrumenter.cpp
@@ -28,19 +28,27 @@ void Instrumenter::run(PassRunner* runner, Module* wasm) { this->runner = runner; this->wasm = wasm; - addGlobals(); + size_t numFuncs = 0; + ModuleUtils::iterDefinedFunctions(*wasm, [&](Function*) { ++numFuncs; }); + + // Calculate the size of the profile: + // 8 bytes module hash + + // 4 bytes for the timestamp for each function + const size_t profileSize = 8 + 4 * numFuncs; + addGlobals(numFuncs); + addMemory(profileSize); instrumentFuncs(); - addProfileExport(); + addProfileExport(numFuncs, profileSize); } -void Instrumenter::addGlobals() { +void Instrumenter::addGlobals(size_t numFuncs) { if (options.storageKind != WasmSplitOptions::StorageKind::InGlobals) { // Don't need globals return; } // Create fresh global names (over-reserves, but that's ok) counterGlobal = Names::getValidGlobalName(*wasm, "monotonic_counter"); - functionGlobals.reserve(wasm->functions.size()); + functionGlobals.reserve(numFuncs); ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) { functionGlobals.push_back(Names::getValidGlobalName( *wasm, std::string(func->name.c_str()) + "_timestamp")); @@ -62,6 +70,13 @@ } } +void Instrumenter::addMemory(size_t profileSize) { + instrumentMemory = Names::getValidMemoryName(*wasm, "split_instrumenter"); + // Create a memory with enough pages to write into + size_t pages = (profileSize + Memory::kPageSize - 1) / Memory::kPageSize; + wasm->addMemory(Builder::makeMemory(instrumentMemory, pages, pages)); +} + void Instrumenter::instrumentFuncs() { // Inject code at the beginning of each function to advance the monotonic // counter and set the function's timestamp if it hasn't already been set. @@ -108,7 +123,6 @@ } // (i32.atomic.store8 offset=funcidx (i32.const 0) (i32.const 1)) Index funcIdx = 0; - assert(!wasm->memories.empty()); ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) { func->body = builder.makeSequence( builder.makeAtomicStore(1, @@ -116,7 +130,7 @@ builder.makeConstPtr(0, Type::i32), builder.makeConst(uint32_t(1)), Type::i32, - wasm->memories[0]->name), + instrumentMemory), func->body, func->body->type); ++funcIdx; @@ -141,7 +155,7 @@ // otherwise. Functions with smaller non-zero timestamps were called earlier in // the instrumented run than funtions with larger timestamps. -void Instrumenter::addProfileExport() { +void Instrumenter::addProfileExport(size_t numFuncs, size_t profileSize) { // Create and export a function to dump the profile into a given memory // buffer. The function takes the available address and buffer size as // arguments and returns the total size of the profile. It only actually @@ -153,13 +167,6 @@ writeProfile->setLocalName(0, "addr"); writeProfile->setLocalName(1, "size"); - size_t numFuncs = 0; - ModuleUtils::iterDefinedFunctions(*wasm, [&](Function*) { ++numFuncs; }); - - // Calculate the size of the profile: - // 8 bytes module hash + - // 4 bytes for the timestamp for each function - const size_t profileSize = 8 + 4 * numFuncs; // Create the function body Builder builder(*wasm); @@ -170,22 +177,10 @@ return builder.makeConst(int32_t(profileSize)); }; - // Also make sure there is a memory with enough pages to write into - size_t pages = (profileSize + Memory::kPageSize - 1) / Memory::kPageSize; - if (wasm->memories.empty()) { - wasm->addMemory(Builder::makeMemory("0")); - wasm->memories[0]->initial = pages; - wasm->memories[0]->max = pages; - } else if (wasm->memories[0]->initial < pages) { - wasm->memories[0]->initial = pages; - if (wasm->memories[0]->max < pages) { - wasm->memories[0]->max = pages; - } - } // Write the hash followed by all the time stamps Expression* writeData = builder.makeStore( - 8, 0, 1, getAddr(), hashConst(), Type::i64, wasm->memories[0]->name); + 8, 0, 1, getAddr(), hashConst(), Type::i64, instrumentMemory); uint32_t offset = 8; switch (options.storageKind) { @@ -199,7 +194,7 @@ getAddr(), builder.makeGlobalGet(global, Type::i32), Type::i32, - wasm->memories[0]->name)); + instrumentMemory)); offset += 4; } break; @@ -249,9 +244,9 @@ builder.makeBinary( MulInt32, getFuncIdx(), builder.makeConst(uint32_t(4)))), builder.makeAtomicLoad( - 1, 0, getFuncIdx(), Type::i32, wasm->memories[0]->name), + 1, 0, getFuncIdx(), Type::i32, instrumentMemory), Type::i32, - wasm->memories[0]->name), + instrumentMemory), builder.makeLocalSet( funcIdxVar, builder.makeBinary( @@ -271,11 +266,13 @@ wasm->addExport( Builder::makeExport(options.profileExport, name, ExternalKind::Function)); - // Export the memory if it is not already exported or imported. + // Export the main memory, assumed to be at idx 0, if it is not already exported or imported. if (!wasm->memories[0]->imported()) { bool memoryExported = false; + const char* memoryName = wasm->memories[0]->name.c_str(); for (auto& ex : wasm->exports) { - if (ex->kind == ExternalKind::Memory) { + const char* exportValue = ex->value.c_str(); + if (ex->kind == ExternalKind::Memory && strncmp(exportValue, memoryName, strlen(memoryName) == 0)) { memoryExported = true; break; }
diff --git a/src/tools/wasm-split/instrumenter.h b/src/tools/wasm-split/instrumenter.h index 7de5a91..1913d12 100644 --- a/src/tools/wasm-split/instrumenter.h +++ b/src/tools/wasm-split/instrumenter.h
@@ -36,14 +36,16 @@ Name counterGlobal; std::vector<Name> functionGlobals; - Instrumenter(const WasmSplitOptions& options, uint64_t moduleHash); + Name instrumentMemory; + Instrumenter(const WasmSplitOptions& options, uint64_t moduleHash); void run(PassRunner* runner, Module* wasm) override; private: - void addGlobals(); + void addGlobals(size_t numFuncs); + void addMemory(size_t profileSize); void instrumentFuncs(); - void addProfileExport(); + void addProfileExport(size_t numFuncs, size_t profileSize); }; } // namespace wasm