diff --git a/scripts/test/shared.py b/scripts/test/shared.py index 72a026fb595..b4f8208c678 100644 --- a/scripts/test/shared.py +++ b/scripts/test/shared.py @@ -396,7 +396,6 @@ def get_tests(test_dir, extensions=[], recursive=False): 'elem.wast', ] SPEC_TESTSUITE_PROPOSALS_TO_SKIP = [ - 'custom-page-sizes', 'wide-arithmetic', ] diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index efbf69d3de3..207c2a5ea57 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -502,6 +502,9 @@ BinaryenFeatures BinaryenFeatureCallIndirectOverlong(void) { BinaryenFeatures BinaryenFeatureRelaxedAtomics(void) { return static_cast(FeatureSet::RelaxedAtomics); } +BinaryenFeatures BinaryenFeatureCustomPageSizes(void) { + return static_cast(FeatureSet::CustomPageSizes); +} BinaryenFeatures BinaryenFeatureAll(void) { return static_cast(FeatureSet::All); } diff --git a/src/binaryen-c.h b/src/binaryen-c.h index 806574f744e..0c1a27df3a0 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -244,6 +244,7 @@ BINARYEN_API BinaryenFeatures BinaryenFeatureFP16(void); BINARYEN_API BinaryenFeatures BinaryenFeatureBulkMemoryOpt(void); BINARYEN_API BinaryenFeatures BinaryenFeatureCallIndirectOverlong(void); BINARYEN_API BinaryenFeatures BinaryenFeatureRelaxedAtomics(void); +BINARYEN_API BinaryenFeatures BinaryenFeatureCustomPageSizes(void); BINARYEN_API BinaryenFeatures BinaryenFeatureAll(void); // Modules diff --git a/src/ir/memory-utils.cpp b/src/ir/memory-utils.cpp index 5d377dc4bda..4bd629e2cbc 100644 --- a/src/ir/memory-utils.cpp +++ b/src/ir/memory-utils.cpp @@ -22,7 +22,8 @@ namespace wasm::MemoryUtils { bool isSubType(const Memory& a, const Memory& b) { return a.shared == b.shared && a.addressType == b.addressType && - a.initial >= b.initial && a.max <= b.max; + a.initial >= b.initial && a.max <= b.max && + a.pageSizeLog2 == b.pageSizeLog2; } bool flatten(Module& wasm) { diff --git a/src/ir/module-utils.cpp b/src/ir/module-utils.cpp index cc13101b717..8653e86f8b6 100644 --- a/src/ir/module-utils.cpp +++ b/src/ir/module-utils.cpp @@ -173,6 +173,7 @@ Memory* copyMemory(const Memory* memory, Module& out) { ret->hasExplicitName = memory->hasExplicitName; ret->initial = memory->initial; ret->max = memory->max; + ret->pageSizeLog2 = memory->pageSizeLog2; ret->shared = memory->shared; ret->addressType = memory->addressType; ret->module = memory->module; diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 0541b171f22..365df6ce4d5 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -191,6 +191,7 @@ function initializeConstants() { 'BulkMemoryOpt', 'CallIndirectOverlong', 'RelaxedAtomics', + 'CustomPageSizes', 'All' ].forEach(name => { Module['Features'][name] = Module['_BinaryenFeature' + name](); diff --git a/src/parser/context-decls.cpp b/src/parser/context-decls.cpp index f02ec30dd66..a98e3334a33 100644 --- a/src/parser/context-decls.cpp +++ b/src/parser/context-decls.cpp @@ -144,6 +144,7 @@ Result ParseDeclsCtx::addMemoryDecl(Index pos, m->initial = type.limits.initial; m->max = type.limits.max ? *type.limits.max : Memory::kUnlimitedSize; m->shared = type.shared; + m->pageSizeLog2 = type.pageSizeLog2; if (name) { // TODO: if the existing memory is not explicitly named, fix its name // and continue. diff --git a/src/parser/contexts.h b/src/parser/contexts.h index 3978afff45d..9fbb63607ff 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -49,6 +49,7 @@ struct Limits { struct MemType { Type addressType; Limits limits; + uint8_t pageSizeLog2; bool shared; }; @@ -173,8 +174,6 @@ struct NullTypeParserCtx { DataStringT makeDataString() { return Ok{}; } void appendDataString(DataStringT&, std::string_view) {} - MemTypeT makeMemType(Type, LimitsT, bool) { return Ok{}; } - BlockTypeT getBlockTypeFromResult(size_t results) { return Ok{}; } Result<> getBlockTypeFromTypeUse(Index, TypeUseT) { return Ok{}; } @@ -351,9 +350,8 @@ template struct TypeParserCtx { void appendDataString(DataStringT&, std::string_view) {} Result makeLimits(uint64_t, std::optional) { return Ok{}; } - LimitsT getLimitsFromData(DataStringT) { return Ok{}; } - MemTypeT makeMemType(Type, LimitsT, bool) { return Ok{}; } + MemTypeT makeMemType(Type, LimitsT, bool, uint8_t) { return Ok{}; } HeapType getBlockTypeFromResult(const std::vector results) { assert(results.size() == 1); @@ -1072,13 +1070,18 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx { data.insert(data.end(), str.begin(), str.end()); } - Limits getLimitsFromData(const std::vector& data) { - uint64_t size = (data.size() + Memory::kPageSize - 1) / Memory::kPageSize; + Limits getLimitsFromData(const std::vector& data, + uint8_t pageSizeLog2) { + uint64_t size = + (data.size() + (1 << pageSizeLog2) - 1) / (1 << pageSizeLog2); return {size, size}; } - MemType makeMemType(Type addressType, Limits limits, bool shared) { - return {addressType, limits, shared}; + MemType makeMemType(Type addressType, + Limits limits, + bool shared, + uint8_t pageSizeLog2) { + return {addressType, limits, pageSizeLog2, shared}; } Result @@ -1447,8 +1450,8 @@ struct ParseModuleTypesCtx : TypeParserCtx, Type makeTableType(Type addressType, LimitsT, Type type) { return type; } - LimitsT getLimitsFromData(DataStringT) { return Ok{}; } - MemTypeT makeMemType(Type, LimitsT, bool) { return Ok{}; } + LimitsT getLimitsFromData(DataStringT, uint8_t) { return Ok{}; } + MemTypeT makeMemType(Type, LimitsT, bool, uint8_t) { return Ok{}; } Result<> addFunc(Name name, const std::vector&, diff --git a/src/parser/parsers.h b/src/parser/parsers.h index d606563f1c1..ea911c0bd41 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -20,6 +20,7 @@ #include "common.h" #include "contexts.h" #include "lexer.h" +#include "wasm.h" #include "wat-parser-internal.h" namespace wasm::WATParser { @@ -825,7 +826,34 @@ template Result limits64(Ctx& ctx) { return ctx.makeLimits(uint64_t(*n), m); } -// memtype ::= (limits32 | 'i32' limits32 | 'i64' limit64) shared? +// mempagesize? ::= ('(' 'pagesize' u64 ')') ? +template MaybeResult mempagesize(Ctx& ctx) { + if (!ctx.in.takeSExprStart("pagesize"sv)) { + return {}; // No pagesize specified + } + auto pageSize = ctx.in.takeU64(); + if (!pageSize) { + return ctx.in.err("expected page size"); + } + + if (!Bits::isPowerOf2(*pageSize)) { + return ctx.in.err("page size must be a power of two"); + } + + if (!ctx.in.takeRParen()) { + return ctx.in.err("expected end of mempagesize"); + } + + uint8_t pageSizeLog2 = (uint8_t)Bits::ceilLog2(*pageSize); + + if (pageSizeLog2 != 0 && pageSizeLog2 != Memory::kDefaultPageSizeLog2) { + return ctx.in.err("memory page size can only be 1 or 64 KiB"); + } + + return pageSizeLog2; +} + +// memtype ::= (limits32 | 'i32' limits32 | 'i64' limit64) shared? mempagesize? // note: the index type 'i32' or 'i64' is already parsed to simplify parsing of // memory abbreviations. template Result memtype(Ctx& ctx) { @@ -847,7 +875,11 @@ Result memtypeContinued(Ctx& ctx, Type addressType) { if (ctx.in.takeKeyword("shared"sv)) { shared = true; } - return ctx.makeMemType(addressType, *limits, shared); + MaybeResult mempageSize = mempagesize(ctx); + CHECK_ERR(mempageSize); + const uint8_t pageSizeLog2 = + mempageSize ? *mempageSize : Memory::kDefaultPageSizeLog2; + return ctx.makeMemType(addressType, *limits, shared, pageSizeLog2); } // memorder ::= 'seqcst' | 'acqrel' @@ -3558,6 +3590,8 @@ template MaybeResult<> memory(Ctx& ctx) { std::optional mtype; std::optional data; + MaybeResult mempageSize = mempagesize(ctx); + CHECK_ERR(mempageSize); if (ctx.in.takeSExprStart("data"sv)) { if (import) { return ctx.in.err("imported memories cannot have inline data"); @@ -3567,9 +3601,17 @@ template MaybeResult<> memory(Ctx& ctx) { if (!ctx.in.takeRParen()) { return ctx.in.err("expected end of inline data"); } - mtype = - ctx.makeMemType(addressType, ctx.getLimitsFromData(*datastr), false); + const uint8_t pageSizeLog2 = + mempageSize.getPtr() ? *mempageSize : Memory::kDefaultPageSizeLog2; + mtype = ctx.makeMemType(addressType, + ctx.getLimitsFromData(*datastr, pageSizeLog2), + false, + pageSizeLog2); data = *datastr; + } else if (mempageSize) { + // If we have a memory page size not within a memtype expression, we expect + // a memory abbreviation. + return ctx.in.err("expected data segment in memory abbreviation"); } else { auto type = memtypeContinued(ctx, addressType); CHECK_ERR(type); diff --git a/src/passes/LLVMMemoryCopyFillLowering.cpp b/src/passes/LLVMMemoryCopyFillLowering.cpp index a2b29227c51..9ccf2934a5a 100644 --- a/src/passes/LLVMMemoryCopyFillLowering.cpp +++ b/src/passes/LLVMMemoryCopyFillLowering.cpp @@ -117,14 +117,17 @@ struct LLVMMemoryCopyFillLowering void createMemoryCopyFunc(Module* module) { Builder b(*module); Index dst = 0, src = 1, size = 2, start = 3, end = 4, step = 5, i = 6; - Name memory = module->memories.front()->name; + Name memoryName = module->memories.front()->name; + Address::address32_t pageSizeLog2 = module->memories.front()->pageSizeLog2; Block* body = b.makeBlock(); // end = memory size in bytes - body->list.push_back( - b.makeLocalSet(end, - b.makeBinary(BinaryOp::MulInt32, - b.makeMemorySize(memory), - b.makeConst(Memory::kPageSize)))); + body->list.push_back(b.makeLocalSet( + end, + pageSizeLog2 == 0 + ? static_cast(b.makeMemorySize(memoryName)) + : static_cast(b.makeBinary(BinaryOp::ShlInt32, + b.makeMemorySize(memoryName), + b.makeConst(pageSizeLog2))))); // if dst + size > memsize or src + size > memsize, then trap. body->list.push_back(b.makeIf( b.makeBinary(BinaryOp::OrInt32, @@ -187,9 +190,9 @@ struct LLVMMemoryCopyFillLowering b.makeLocalGet(src, Type::i32), b.makeLocalGet(i, Type::i32)), Type::i32, - memory), + memoryName), Type::i32, - memory), + memoryName), // i += step b.makeLocalSet(i, b.makeBinary(BinaryOp::AddInt32, @@ -203,19 +206,23 @@ struct LLVMMemoryCopyFillLowering void createMemoryFillFunc(Module* module) { Builder b(*module); Index dst = 0, val = 1, size = 2; - Name memory = module->memories.front()->name; + Name memoryName = module->memories.front()->name; + Address::address32_t pageSizeLog2 = module->memories.front()->pageSizeLog2; Block* body = b.makeBlock(); // if dst + size > memsize in bytes, then trap. - body->list.push_back( - b.makeIf(b.makeBinary(BinaryOp::GtUInt32, - b.makeBinary(BinaryOp::AddInt32, - b.makeLocalGet(dst, Type::i32), - b.makeLocalGet(size, Type::i32)), - b.makeBinary(BinaryOp::MulInt32, - b.makeMemorySize(memory), - b.makeConst(Memory::kPageSize))), - b.makeUnreachable())); + body->list.push_back(b.makeIf( + b.makeBinary( + BinaryOp::GtUInt32, + b.makeBinary(BinaryOp::AddInt32, + b.makeLocalGet(dst, Type::i32), + b.makeLocalGet(size, Type::i32)), + pageSizeLog2 == 0 + ? static_cast(b.makeMemorySize(memoryName)) + : static_cast(b.makeBinary(BinaryOp::ShlInt32, + b.makeMemorySize(memoryName), + b.makeConst(pageSizeLog2)))), + b.makeUnreachable())); body->list.push_back(b.makeBlock( "out", @@ -241,7 +248,7 @@ struct LLVMMemoryCopyFillLowering b.makeLocalGet(size, Type::i32)), b.makeLocalGet(val, Type::i32), Type::i32, - memory), + memoryName), b.makeBreak("copy", nullptr)})))); module->getFunction(memFillFuncName)->body = body; } diff --git a/src/passes/Memory64Lowering.cpp b/src/passes/Memory64Lowering.cpp index 1506c016eea..76777df50d3 100644 --- a/src/passes/Memory64Lowering.cpp +++ b/src/passes/Memory64Lowering.cpp @@ -293,8 +293,8 @@ struct Memory64Lowering : public WalkerPass> { for (auto& memory : module->memories) { if (memory->is64()) { memory->addressType = Type::i32; - if (memory->hasMax() && memory->max > Memory::kMaxSize32) { - memory->max = Memory::kMaxSize32; + if (memory->hasMax() && memory->max > memory->maxSize32()) { + memory->max = memory->maxSize32(); } } } diff --git a/src/passes/MemoryPacking.cpp b/src/passes/MemoryPacking.cpp index b9acb32f92e..23cbeb58567 100644 --- a/src/passes/MemoryPacking.cpp +++ b/src/passes/MemoryPacking.cpp @@ -315,7 +315,7 @@ void MemoryPacking::calculateRanges(Module* module, // Check if we can rule out a trap by it being in bounds. if (auto* c = segment->offset->dynCast()) { auto* memory = module->getMemory(segment->memory); - auto memorySize = memory->initial * Memory::kPageSize; + auto memorySize = memory->initial << memory->pageSizeLog2; Index start = c->value.getUnsigned(); Index size = segment->data.size(); Index end; diff --git a/src/passes/MultiMemoryLowering.cpp b/src/passes/MultiMemoryLowering.cpp index 9397f6cad44..c22a5db82d7 100644 --- a/src/passes/MultiMemoryLowering.cpp +++ b/src/passes/MultiMemoryLowering.cpp @@ -43,6 +43,7 @@ #include "ir/abstract.h" #include "ir/module-utils.h" #include "ir/names.h" +#include "support/utilities.h" #include "wasm-builder.h" #include #include @@ -435,6 +436,7 @@ struct MultiMemoryLowering : public Pass { : Builder::MemoryInfo::Memory64; isShared = getFirstMemory().shared; isImported = getFirstMemory().imported(); + uint8_t const pageSizeLog2 = getFirstMemory().pageSizeLog2; for (auto& memory : wasm->memories) { // We are assuming that each memory is configured the same as the first // and assert if any of the memories does not match this configuration @@ -445,6 +447,11 @@ struct MultiMemoryLowering : public Pass { if (memory->name != getFirstMemory().name && memory->imported()) { Fatal() << "MultiMemoryLowering: only the first memory can be imported"; } + // TODO: handle memory with different page sizes. + if (memory->pageSizeLog2 != pageSizeLog2) { + Fatal() + << "MultiMemoryLowering: all memories must have the same page size"; + } // Calculating the total initial and max page size for the combined memory // by totaling the initial and max page sizes for the memories in the @@ -456,8 +463,8 @@ struct MultiMemoryLowering : public Pass { } // Ensuring valid initial and max page sizes that do not exceed the number // of pages addressable by the pointerType - Address maxSize = - pointerType == Type::i32 ? Memory::kMaxSize32 : Memory::kMaxSize64; + Address maxSize = pointerType == Type::i32 ? getFirstMemory().maxSize32() + : getFirstMemory().maxSize64(); if (totalMaxPages > maxSize || totalMaxPages == 0) { totalMaxPages = Memory::kUnlimitedSize; } @@ -504,7 +511,7 @@ struct MultiMemoryLowering : public Pass { Name name = Names::getValidGlobalName( *wasm, memory->name.toString() + "_byte_offset"); offsetGlobalNames.push_back(std::move(name)); - addGlobal(name, offsetRunningTotal * Memory::kPageSize); + addGlobal(name, offsetRunningTotal << memory->pageSizeLog2); } offsetRunningTotal += memory->initial; } @@ -553,13 +560,17 @@ struct MultiMemoryLowering : public Pass { auto function = Builder::makeFunction( functionName, Signature(pointerType, pointerType), {}); function->setLocalName(0, "page_delta"); - auto pageSizeConst = [&]() { - return builder.makeConst(Literal(Memory::kPageSize)); + auto currPageSizeLog2 = wasm->memories[memIdx]->pageSizeLog2; + auto makeMulPageSize = [&](Expression* pageCountExpr) -> Expression* { + if (currPageSizeLog2 == 0) { + return pageCountExpr; + } + return builder.makeBinary(Abstract::getBinary(pointerType, Abstract::Shl), + pageCountExpr, + builder.makeConst(Literal(currPageSizeLog2))); }; - auto getOffsetDelta = [&]() { - return builder.makeBinary(Abstract::getBinary(pointerType, Abstract::Mul), - builder.makeLocalGet(0, pointerType), - pageSizeConst()); + auto getOffsetDelta = [&]() -> Expression* { + return makeMulPageSize(builder.makeLocalGet(0, pointerType)); }; auto getMoveSource = [&](Name global) { return builder.makeGlobalGet(global, pointerType); @@ -609,9 +620,7 @@ struct MultiMemoryLowering : public Pass { // size builder.makeBinary( Abstract::getBinary(pointerType, Abstract::Sub), - builder.makeBinary(Abstract::getBinary(pointerType, Abstract::Mul), - builder.makeLocalGet(sizeLocal, pointerType), - pageSizeConst()), + makeMulPageSize(builder.makeLocalGet(sizeLocal, pointerType)), getMoveSource(offsetGlobalName)), combinedMemory, combinedMemory)); @@ -645,12 +654,13 @@ struct MultiMemoryLowering : public Pass { auto function = Builder::makeFunction( functionName, Signature(Type::none, pointerType), {}); Expression* functionBody; + auto currPageSizeLog2 = wasm->memories[memIdx]->pageSizeLog2; auto pageSizeConst = [&]() { - return builder.makeConst(Literal(Memory::kPageSize)); + return builder.makeConst(Literal(currPageSizeLog2)); }; auto getOffsetInPageUnits = [&](Name global) { return builder.makeBinary( - Abstract::getBinary(pointerType, Abstract::DivU), + Abstract::getBinary(pointerType, Abstract::ShrU), builder.makeGlobalGet(global, pointerType), pageSizeConst()); }; diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index d92a412dbbd..4878b95fffb 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -3468,6 +3468,11 @@ void PrintSExpression::printMemoryHeader(Memory* curr) { if (curr->shared) { printMedium(o, " shared"); } + if (curr->pageSizeLog2 != Memory::kDefaultPageSizeLog2) { + o << " ("; + printMedium(o, "pagesize") << ' ' << (1 << (curr->pageSizeLog2)); + o << ')'; + } o << ")"; } diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp index 64f56744624..a87414c85ac 100644 --- a/src/passes/RemoveUnusedModuleElements.cpp +++ b/src/passes/RemoveUnusedModuleElements.cpp @@ -842,7 +842,7 @@ struct RemoveUnusedModuleElements : public Pass { segment->data.size(), segment->offset, memory, - memory->initial * Memory::kPageSize); + memory->initial << memory->pageSizeLog2); } }); ModuleUtils::iterActiveElementSegments( diff --git a/src/shell-interface.h b/src/shell-interface.h index 615000a7fba..9a16499f4e3 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -111,7 +111,7 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface { void init(Module& wasm, ModuleRunner& instance) override { ModuleUtils::iterDefinedMemories(wasm, [&](wasm::Memory* memory) { auto shellMemory = Memory(); - shellMemory.resize(memory->initial * wasm::Memory::kPageSize); + shellMemory.resize(memory->initial << memory->pageSizeLog2); memories[memory->name] = shellMemory; }); } diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index aa16e2b7833..06cb14ee8bb 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -839,9 +839,10 @@ void TranslateToFuzzReader::finalizeMemory() { // annoying in the fuzzer). Address ONE_GB = 1024 * 1024 * 1024; if (maxOffset <= ONE_GB) { - memory->initial = std::max( - memory->initial, - Address((maxOffset + Memory::kPageSize - 1) / Memory::kPageSize)); + memory->initial = + std::max(memory->initial, + Address((maxOffset + (1 << memory->pageSizeLog2) - 1) / + (1 << memory->pageSizeLog2))); } } memory->initial = std::max(memory->initial, fuzzParams->USABLE_MEMORY); @@ -855,7 +856,7 @@ void TranslateToFuzzReader::finalizeMemory() { // maximum larger than the initial. // TODO: scan the wasm for grow instructions? memory->max = - std::min(Address(memory->initial + 1), Address(Memory::kMaxSize32)); + std::min(Address(memory->initial + 1), Address(memory->maxSize32())); } if (!preserveImportsAndExports) { diff --git a/src/tools/tool-options.h b/src/tools/tool-options.h index 298fb5db349..164ae38564d 100644 --- a/src/tools/tool-options.h +++ b/src/tools/tool-options.h @@ -110,6 +110,7 @@ struct ToolOptions : public Options { "custom descriptors (RTTs) and exact references") .addFeature(FeatureSet::RelaxedAtomics, "acquire/release atomic memory operations") + .addFeature(FeatureSet::CustomPageSizes, "custom page sizes") .add("--enable-typed-function-references", "", "Deprecated compatibility flag", diff --git a/src/tools/wasm-split/instrumenter.cpp b/src/tools/wasm-split/instrumenter.cpp index 92861a8729a..56fa67373e3 100644 --- a/src/tools/wasm-split/instrumenter.cpp +++ b/src/tools/wasm-split/instrumenter.cpp @@ -81,7 +81,10 @@ void Instrumenter::addSecondaryMemory(size_t numFuncs) { secondaryMemory = Names::getValidMemoryName(*wasm, config.secondaryMemoryName); // Create a memory with enough pages to write into - size_t pages = (numFuncs + Memory::kPageSize - 1) / Memory::kPageSize; + // The memory uses the default page size to avoid issues in case custom page + // sizes are not supported. + size_t pages = + (numFuncs + Memory::kDefaultPageSize - 1) / Memory::kDefaultPageSize; auto mem = Builder::makeMemory(secondaryMemory, pages, pages, true); mem->module = config.importNamespace; mem->base = config.secondaryMemoryName; @@ -184,15 +187,20 @@ void Instrumenter::addProfileExport(size_t numFuncs) { const size_t profileSize = 8 + 4 * numFuncs; // 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()) { + size_t pages = + (profileSize + Memory::kDefaultPageSize - 1) / Memory::kDefaultPageSize; 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; + } else { + size_t pages = (profileSize + (1 << wasm->memories[0]->pageSizeLog2) - 1) / + (1 << wasm->memories[0]->pageSizeLog2); + if (wasm->memories[0]->initial < pages) { + wasm->memories[0]->initial = pages; + if (wasm->memories[0]->max < pages) { + wasm->memories[0]->max = pages; + } } } diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 3bd3199b67a..b6bdeac62f4 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -22,6 +22,7 @@ #define wasm_wasm_binary_h #include +#include #include #include @@ -461,6 +462,7 @@ extern const char* BulkMemoryOptFeature; extern const char* CallIndirectOverlongFeature; extern const char* CustomDescriptorsFeature; extern const char* RelaxedAtomicsFeature; +extern const char* CustomPageSizesFeature; enum Subsection { NameModule = 0, @@ -1264,7 +1266,12 @@ enum MemoryAccess { NaturalAlignment = 0 }; -enum MemoryFlags { HasMaximum = 1 << 0, IsShared = 1 << 1, Is64 = 1 << 2 }; +enum MemoryFlags { + HasMaximum = 1 << 0, + IsShared = 1 << 1, + Is64 = 1 << 2, + HasCustomPageSize = 1 << 3 +}; enum FeaturePrefix { FeatureUsed = '+', FeatureDisallowed = '-' }; @@ -1380,6 +1387,12 @@ class WasmBinaryWriter { int32_t writeU32LEBPlaceholder(); void writeResizableLimits( Address initial, Address maximum, bool hasMaximum, bool shared, bool is64); + void writeMemoryResizableLimits(Address initial, + Address maximum, + bool hasMaximum, + bool shared, + bool is64, + uint8_t pageSizeLog2); template int32_t startSection(T code); void finishSection(int32_t start); int32_t startSubsection(BinaryConsts::CustomSections::Subsection code); @@ -1635,6 +1648,7 @@ class WasmBinaryReader { Address& max, bool& shared, Type& addressType, + uint8_t& pageSizeLog2, Address defaultIfNoMax); void readImports(); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index cd73babb6ca..dc144d3af42 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -130,15 +130,18 @@ class Builder { return seg; } - static std::unique_ptr makeMemory(Name name, - Address initial = 0, - Address max = Memory::kMaxSize32, - bool shared = false, - Type addressType = Type::i32) { + static std::unique_ptr + makeMemory(Name name, + Address initial = 0, + Address max = Memory::kDefaultMaxSize32, + bool shared = false, + uint8_t pageSizeLog2 = Memory::kDefaultPageSizeLog2, + Type addressType = Type::i32) { auto memory = std::make_unique(); memory->name = name; memory->initial = initial; memory->max = max; + memory->pageSizeLog2 = pageSizeLog2; memory->shared = shared; memory->addressType = addressType; return memory; diff --git a/src/wasm-features.h b/src/wasm-features.h index 7f4b0a451af..adfa1e1a30b 100644 --- a/src/wasm-features.h +++ b/src/wasm-features.h @@ -56,11 +56,12 @@ struct FeatureSet { CallIndirectOverlong = 1 << 20, CustomDescriptors = 1 << 21, RelaxedAtomics = 1 << 22, + CustomPageSizes = 1 << 23, MVP = None, // Keep in sync with llvm default features: // https://github.com/llvm/llvm-project/blob/c7576cb89d6c95f03968076e902d3adfd1996577/clang/lib/Basic/Targets/WebAssembly.cpp#L150-L153 Default = SignExt | MutableGlobals, - All = (1 << 23) - 1, + All = (1 << 24) - 1, }; static std::string toString(Feature f) { @@ -111,6 +112,8 @@ struct FeatureSet { return "custom-descriptors"; case RelaxedAtomics: return "relaxed-atomics"; + case CustomPageSizes: + return "custom-page-sizes"; case MVP: case Default: case All: @@ -172,6 +175,7 @@ struct FeatureSet { return (features & CustomDescriptors) != 0; } bool hasRelaxedAtomics() const { return (features & RelaxedAtomics) != 0; } + bool hasCustomPageSizes() const { return (features & CustomPageSizes) != 0; } bool hasAll() const { return (features & All) != 0; } void set(FeatureSet f, bool v = true) { diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 20578e03089..ab1d32069f5 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3208,13 +3208,13 @@ class ModuleRunnerBase : public ExpressionRunner { // (This is separate from the constructor so that it does not occur // synchronously, which makes some code patterns harder to write.) void instantiate(bool validateImports_ = false) { - // initialize the rest of the external interface - externalInterface->init(wasm, *self()); - if (validateImports_) { validateImports(); } + // initialize the rest of the external interface + externalInterface->init(wasm, *self()); + initializeGlobals(); initializeTables(); initializeTags(); @@ -3647,6 +3647,10 @@ class ModuleRunnerBase : public ExpressionRunner { iter->second = size; } + Address::address64_t getMemoryPageSize(Name memory) { + return wasm.getMemory(memory)->pageSize(); + } + public: class FunctionScope { public: @@ -4017,10 +4021,12 @@ class ModuleRunnerBase : public ExpressionRunner { VISIT(flow, curr->ptr) auto info = getMemoryInstanceInfo(curr->memory); auto memorySize = info.instance->getMemorySize(info.name); - auto addr = - info.instance->getFinalAddress(curr, flow.getSingleValue(), memorySize); + auto memoryPageSize = info.instance->getMemoryPageSize(info.name); + auto addr = info.instance->getFinalAddress( + curr, flow.getSingleValue(), memorySize, memoryPageSize); if (curr->isAtomic()) { - info.instance->checkAtomicAddress(addr, curr->bytes, memorySize); + info.instance->checkAtomicAddress( + addr, curr->bytes, memorySize, memoryPageSize); } auto ret = info.interface()->load(curr, addr, info.name); return ret; @@ -4030,10 +4036,12 @@ class ModuleRunnerBase : public ExpressionRunner { VISIT(value, curr->value) auto info = getMemoryInstanceInfo(curr->memory); auto memorySize = info.instance->getMemorySize(info.name); - auto addr = - info.instance->getFinalAddress(curr, ptr.getSingleValue(), memorySize); + auto memoryPageSize = info.instance->getMemoryPageSize(info.name); + auto addr = info.instance->getFinalAddress( + curr, ptr.getSingleValue(), memorySize, memoryPageSize); if (curr->isAtomic()) { - info.instance->checkAtomicAddress(addr, curr->bytes, memorySize); + info.instance->checkAtomicAddress( + addr, curr->bytes, memorySize, memoryPageSize); } info.interface()->store(curr, addr, value.getSingleValue(), info.name); return Flow(); @@ -4044,10 +4052,16 @@ class ModuleRunnerBase : public ExpressionRunner { VISIT(value, curr->value) auto info = getMemoryInstanceInfo(curr->memory); auto memorySize = info.instance->getMemorySize(info.name); - auto addr = - info.instance->getFinalAddress(curr, ptr.getSingleValue(), memorySize); - auto loaded = info.instance->doAtomicLoad( - addr, curr->bytes, curr->type, info.name, memorySize, curr->order); + auto memoryPageSize = info.instance->getMemoryPageSize(info.name); + auto addr = info.instance->getFinalAddress( + curr, ptr.getSingleValue(), memorySize, memoryPageSize); + auto loaded = info.instance->doAtomicLoad(addr, + curr->bytes, + curr->type, + info.name, + memorySize, + memoryPageSize, + curr->order); auto computed = value.getSingleValue(); switch (curr->op) { case RMWAdd: @@ -4069,7 +4083,7 @@ class ModuleRunnerBase : public ExpressionRunner { break; } info.instance->doAtomicStore( - addr, curr->bytes, computed, info.name, memorySize); + addr, curr->bytes, computed, info.name, memorySize, memoryPageSize); return loaded; } Flow visitAtomicCmpxchg(AtomicCmpxchg* curr) { @@ -4078,14 +4092,24 @@ class ModuleRunnerBase : public ExpressionRunner { VISIT(replacement, curr->replacement) auto info = getMemoryInstanceInfo(curr->memory); auto memorySize = info.instance->getMemorySize(info.name); - auto addr = - info.instance->getFinalAddress(curr, ptr.getSingleValue(), memorySize); + auto memoryPageSize = info.instance->getMemoryPageSize(info.name); + auto addr = info.instance->getFinalAddress( + curr, ptr.getSingleValue(), memorySize, memoryPageSize); expected = Flow(wrapToSmallerSize(expected.getSingleValue(), curr->bytes)); - auto loaded = info.instance->doAtomicLoad( - addr, curr->bytes, curr->type, info.name, memorySize, curr->order); + auto loaded = info.instance->doAtomicLoad(addr, + curr->bytes, + curr->type, + info.name, + memorySize, + memoryPageSize, + curr->order); if (loaded == expected.getSingleValue()) { - info.instance->doAtomicStore( - addr, curr->bytes, replacement.getSingleValue(), info.name, memorySize); + info.instance->doAtomicStore(addr, + curr->bytes, + replacement.getSingleValue(), + info.name, + memorySize, + memoryPageSize); } return loaded; } @@ -4096,13 +4120,15 @@ class ModuleRunnerBase : public ExpressionRunner { auto bytes = curr->expectedType.getByteSize(); auto info = getMemoryInstanceInfo(curr->memory); auto memorySize = info.instance->getMemorySize(info.name); + auto memoryPageSize = info.instance->getMemoryPageSize(info.name); auto addr = info.instance->getFinalAddress( - curr, ptr.getSingleValue(), bytes, memorySize); + curr, ptr.getSingleValue(), bytes, memorySize, memoryPageSize); auto loaded = info.instance->doAtomicLoad(addr, bytes, curr->expectedType, info.name, memorySize, + memoryPageSize, MemoryOrder::SeqCst); if (loaded != expected.getSingleValue()) { return Literal(int32_t(1)); // not equal @@ -4122,10 +4148,11 @@ class ModuleRunnerBase : public ExpressionRunner { VISIT(count, curr->notifyCount) auto info = getMemoryInstanceInfo(curr->memory); auto memorySize = info.instance->getMemorySize(info.name); - auto addr = - info.instance->getFinalAddress(curr, ptr.getSingleValue(), 4, memorySize); + auto memoryPageSize = info.instance->getMemoryPageSize(info.name); + auto addr = info.instance->getFinalAddress( + curr, ptr.getSingleValue(), 4, memorySize, memoryPageSize); // Just check TODO actual threads support - info.instance->checkAtomicAddress(addr, 4, memorySize); + info.instance->checkAtomicAddress(addr, 4, memorySize, memoryPageSize); return Literal(int32_t(0)); // none woken up } Flow visitSIMDLoad(SIMDLoad* curr) { @@ -4207,12 +4234,13 @@ class ModuleRunnerBase : public ExpressionRunner { WASM_UNREACHABLE("invalid op"); }; auto memorySize = info.instance->getMemorySize(info.name); + auto memoryPageSize = info.instance->getMemoryPageSize(info.name); auto addressType = curr->ptr->type; auto fillLanes = [&](auto lanes, size_t laneBytes) { for (auto& lane : lanes) { auto ptr = Literal::makeFromInt64(src, addressType); - lane = loadLane( - info.instance->getFinalAddress(curr, ptr, laneBytes, memorySize)); + lane = loadLane(info.instance->getFinalAddress( + curr, ptr, laneBytes, memorySize, memoryPageSize)); src = ptr.add(Literal::makeFromInt32(laneBytes, addressType)).getUnsigned(); } @@ -4243,8 +4271,12 @@ class ModuleRunnerBase : public ExpressionRunner { VISIT(flow, curr->ptr) auto info = getMemoryInstanceInfo(curr->memory); auto memorySize = info.instance->getMemorySize(info.name); - Address src = info.instance->getFinalAddress( - curr, flow.getSingleValue(), curr->getMemBytes(), memorySize); + auto memoryPageSize = info.instance->getMemoryPageSize(info.name); + Address src = info.instance->getFinalAddress(curr, + flow.getSingleValue(), + curr->getMemBytes(), + memorySize, + memoryPageSize); auto zero = Literal::makeZero(curr->op == Load32ZeroVec128 ? Type::i32 : Type::i64); if (curr->op == Load32ZeroVec128) { @@ -4260,8 +4292,12 @@ class ModuleRunnerBase : public ExpressionRunner { VISIT(vecFlow, curr->vec) auto info = getMemoryInstanceInfo(curr->memory); auto memorySize = info.instance->getMemorySize(info.name); - Address addr = info.instance->getFinalAddress( - curr, ptrFlow.getSingleValue(), curr->getMemBytes(), memorySize); + auto memoryPageSize = info.instance->getMemoryPageSize(info.name); + Address addr = info.instance->getFinalAddress(curr, + ptrFlow.getSingleValue(), + curr->getMemBytes(), + memorySize, + memoryPageSize); Literal vec = vecFlow.getSingleValue(); switch (curr->op) { case Load8LaneVec128: @@ -4329,7 +4365,7 @@ class ModuleRunnerBase : public ExpressionRunner { VISIT(flow, curr->delta) auto info = getMemoryInstanceInfo(curr->memory); auto memorySize = info.instance->getMemorySize(info.name); - auto* memory = info.instance->wasm.getMemory(info.name); + Memory* memory = info.instance->wasm.getMemory(info.name); auto addressType = memory->addressType; auto fail = Literal::makeFromInt64(-1, addressType); Flow ret = Literal::makeFromInt64(memorySize, addressType); @@ -4337,7 +4373,8 @@ class ModuleRunnerBase : public ExpressionRunner { uint64_t maxAddr = addressType == Type::i32 ? std::numeric_limits::max() : std::numeric_limits::max(); - if (delta > maxAddr / Memory::kPageSize) { + Address::address64_t pageSizeLog2 = memory->pageSizeLog2; + if (delta > (maxAddr >> pageSizeLog2)) { // Impossible to grow this much. return fail; } @@ -4349,9 +4386,8 @@ class ModuleRunnerBase : public ExpressionRunner { if (newSize > memory->max) { return fail; } - if (!info.interface()->growMemory(info.name, - memorySize * Memory::kPageSize, - newSize * Memory::kPageSize)) { + if (!info.interface()->growMemory( + info.name, (memorySize << pageSizeLog2), (newSize << pageSizeLog2))) { // We failed to grow the memory in practice, even though it was valid // to try to do so. return fail; @@ -4379,15 +4415,16 @@ class ModuleRunnerBase : public ExpressionRunner { } auto info = getMemoryInstanceInfo(curr->memory); auto memorySize = info.instance->getMemorySize(info.name); - if (destVal + sizeVal > memorySize * Memory::kPageSize) { + auto memoryPageSize = info.instance->getMemoryPageSize(info.name); + if (destVal + sizeVal > (memorySize * memoryPageSize)) { trap("out of bounds memory access in memory.init"); } for (size_t i = 0; i < sizeVal; ++i) { Literal addr(destVal + i); - info.interface()->store8( - info.instance->getFinalAddressWithoutOffset(addr, 1, memorySize), - segment->data[offsetVal + i], - info.name); + info.interface()->store8(info.instance->getFinalAddressWithoutOffset( + addr, 1, memorySize, memoryPageSize), + segment->data[offsetVal + i], + info.name); } return {}; } @@ -4406,9 +4443,13 @@ class ModuleRunnerBase : public ExpressionRunner { auto destInfo = getMemoryInstanceInfo(curr->destMemory); auto sourceInfo = getMemoryInstanceInfo(curr->sourceMemory); auto destMemorySize = destInfo.instance->getMemorySize(destInfo.name); + auto const destMemoryPageSize = + destInfo.instance->getMemoryPageSize(destInfo.name); auto sourceMemorySize = sourceInfo.instance->getMemorySize(sourceInfo.name); - if (sourceVal + sizeVal > sourceMemorySize * Memory::kPageSize || - destVal + sizeVal > destMemorySize * Memory::kPageSize || + auto const sourceMemoryPageSize = + sourceInfo.instance->getMemoryPageSize(sourceInfo.name); + if (sourceVal + sizeVal > (sourceMemorySize * sourceMemoryPageSize) || + destVal + sizeVal > (destMemorySize * destMemoryPageSize) || // FIXME: better/cheaper way to detect wrapping? sourceVal + sizeVal < sourceVal || sourceVal + sizeVal < sizeVal || destVal + sizeVal < destVal || destVal + sizeVal < sizeVal) { @@ -4427,10 +4468,10 @@ class ModuleRunnerBase : public ExpressionRunner { for (int64_t i = start; i != end; i += step) { destInfo.interface()->store8( destInfo.instance->getFinalAddressWithoutOffset( - Literal(destVal + i), 1, destMemorySize), + Literal(destVal + i), 1, destMemorySize, destMemoryPageSize), sourceInfo.interface()->load8s( sourceInfo.instance->getFinalAddressWithoutOffset( - Literal(sourceVal + i), 1, sourceMemorySize), + Literal(sourceVal + i), 1, sourceMemorySize, sourceMemoryPageSize), sourceInfo.name), destInfo.name); } @@ -4445,18 +4486,20 @@ class ModuleRunnerBase : public ExpressionRunner { auto info = getMemoryInstanceInfo(curr->memory); auto memorySize = info.instance->getMemorySize(info.name); + auto const memoryPageSize = info.instance->getMemoryPageSize(info.name); // FIXME: cheaper wrapping detection? - if (destVal > memorySize * Memory::kPageSize || - sizeVal > memorySize * Memory::kPageSize || - destVal + sizeVal > memorySize * Memory::kPageSize) { + if (destVal > memorySize * memoryPageSize || + sizeVal > memorySize * memoryPageSize || + destVal + sizeVal > memorySize * memoryPageSize) { trap("out of bounds memory access in memory.fill"); } uint8_t val(value.getSingleValue().geti32()); for (size_t i = 0; i < sizeVal; ++i) { - info.interface()->store8(info.instance->getFinalAddressWithoutOffset( - Literal(destVal + i), 1, memorySize), - val, - info.name); + info.interface()->store8( + info.instance->getFinalAddressWithoutOffset( + Literal(destVal + i), 1, memorySize, memoryPageSize), + val, + info.name); } return {}; } @@ -5144,37 +5187,51 @@ class ModuleRunnerBase : public ExpressionRunner { } template - Address - getFinalAddress(LS* curr, Literal ptr, Index bytes, Address memorySize) { - Address memorySizeBytes = memorySize * Memory::kPageSize; + Address getFinalAddress(LS* curr, + Literal ptr, + Index bytes, + Address memorySize, + Address::address64_t memoryPageSize) { + Address memorySizeBytes = memorySize * memoryPageSize; uint64_t addr = ptr.type == Type::i32 ? ptr.geti32() : ptr.geti64(); trapIfGt(curr->offset, memorySizeBytes, "offset > memory"); trapIfGt(addr, memorySizeBytes - curr->offset, "final > memory"); addr += curr->offset; trapIfGt(bytes, memorySizeBytes, "bytes > memory"); - checkLoadAddress(addr, bytes, memorySize); + checkLoadAddress(addr, bytes, memorySize, memoryPageSize); return addr; } template - Address getFinalAddress(LS* curr, Literal ptr, Address memorySize) { - return getFinalAddress(curr, ptr, curr->bytes, memorySize); + Address getFinalAddress(LS* curr, + Literal ptr, + Address memorySize, + Address::address64_t memoryPageSize) { + return getFinalAddress(curr, ptr, curr->bytes, memorySize, memoryPageSize); } - Address - getFinalAddressWithoutOffset(Literal ptr, Index bytes, Address memorySize) { + Address getFinalAddressWithoutOffset(Literal ptr, + Index bytes, + Address memorySize, + Address::address64_t memoryPageSize) { uint64_t addr = ptr.type == Type::i32 ? ptr.geti32() : ptr.geti64(); - checkLoadAddress(addr, bytes, memorySize); + checkLoadAddress(addr, bytes, memorySize, memoryPageSize); return addr; } - void checkLoadAddress(Address addr, Index bytes, Address memorySize) { - Address memorySizeBytes = memorySize * Memory::kPageSize; + void checkLoadAddress(Address addr, + Index bytes, + Address memorySize, + Address::address64_t memoryPageSize) { + Address memorySizeBytes = memorySize * memoryPageSize; trapIfGt(addr, memorySizeBytes - bytes, "highest > memory"); } - void checkAtomicAddress(Address addr, Index bytes, Address memorySize) { - checkLoadAddress(addr, bytes, memorySize); + void checkAtomicAddress(Address addr, + Index bytes, + Address memorySize, + Address::address64_t memoryPageSize) { + checkLoadAddress(addr, bytes, memorySize, memoryPageSize); // Unaligned atomics trap. if (bytes > 1) { if (addr & (bytes - 1)) { @@ -5188,11 +5245,12 @@ class ModuleRunnerBase : public ExpressionRunner { Type type, Name memoryName, Address memorySize, + Address::address64_t memoryPageSize, MemoryOrder order) { if (order == MemoryOrder::Unordered) { Fatal() << "Expected a non-unordered MemoryOrder in doAtomicLoad"; } - checkAtomicAddress(addr, bytes, memorySize); + checkAtomicAddress(addr, bytes, memorySize, memoryPageSize); Const ptr; ptr.value = Literal(int32_t(addr)); ptr.type = Type::i32; @@ -5213,8 +5271,9 @@ class ModuleRunnerBase : public ExpressionRunner { Index bytes, Literal toStore, Name memoryName, - Address memorySize) { - checkAtomicAddress(addr, bytes, memorySize); + Address memorySize, + Address::address64_t memoryPageSize) { + checkAtomicAddress(addr, bytes, memorySize, memoryPageSize); Const ptr; ptr.value = Literal(int32_t(addr)); ptr.type = Type::i32; diff --git a/src/wasm.h b/src/wasm.h index e74d6532ac2..1bc83bc7ccc 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -27,9 +27,12 @@ #include #include #include +#include #include +#include #include #include +#include #include #include @@ -2467,28 +2470,35 @@ class DataSegment : public Named { class Memory : public Importable { public: - static const Address::address32_t kPageSize = 64 * 1024; static const Address::address64_t kUnlimitedSize = Address::address64_t(-1); - // In wasm32, the maximum memory size is limited by a 32-bit pointer: 4GB - static const Address::address32_t kMaxSize32 = - (uint64_t(4) * 1024 * 1024 * 1024) / kPageSize; - // in wasm64, the maximum number of pages - static const Address::address64_t kMaxSize64 = 1ull << (64 - 16); + + static const uint8_t kDefaultPageSizeLog2 = 16; + + static const Address::address32_t kDefaultPageSize = 1 + << kDefaultPageSizeLog2; + + static const Address::address32_t kDefaultMaxSize32 = + 1 << (32 - kDefaultPageSizeLog2); Address initial = 0; // sizes are in pages - Address max = kMaxSize32; + Address max = kDefaultMaxSize32; + + uint8_t pageSizeLog2 = kDefaultPageSizeLog2; bool shared = false; Type addressType = Type::i32; bool hasMax() { return max != kUnlimitedSize; } bool is64() { return addressType == Type::i64; } - void clear() { - name = ""; - initial = 0; - max = kMaxSize32; - shared = false; - addressType = Type::i32; + Address::address64_t maxSize32() const { return 1ull << (32 - pageSizeLog2); } + Address::address64_t maxSize64() const { + if (pageSizeLog2 == 0) { + return std::numeric_limits::max(); + } + return 1ull << (64 - pageSizeLog2); + } + Address::address64_t pageSize() const { + return 1ull << static_cast(pageSizeLog2); } }; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 85768b55fbc..e01001d3582 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -16,6 +16,7 @@ #include #include +#include #include "ir/module-utils.h" #include "ir/names.h" @@ -127,6 +128,35 @@ void WasmBinaryWriter::writeResizableLimits( } } +void WasmBinaryWriter::writeMemoryResizableLimits(Address initial, + Address maximum, + bool hasMaximum, + bool shared, + bool is64, + uint8_t pageSizeLog2) { + uint32_t flags = (hasMaximum ? (uint32_t)BinaryConsts::HasMaximum : 0U) | + (shared ? (uint32_t)BinaryConsts::IsShared : 0U) | + (is64 ? (uint32_t)BinaryConsts::Is64 : 0U) | + (pageSizeLog2 != Memory::kDefaultPageSizeLog2 + ? (uint32_t)BinaryConsts::HasCustomPageSize + : 0U); + o << U32LEB(flags); + if (is64) { + o << U64LEB(initial); + if (hasMaximum) { + o << U64LEB(maximum); + } + } else { + o << U32LEB(initial); + if (hasMaximum) { + o << U32LEB(maximum); + } + } + if (pageSizeLog2 != Memory::kDefaultPageSizeLog2) { + o << U32LEB(pageSizeLog2); + } +} + template int32_t WasmBinaryWriter::startSection(T code) { o << uint8_t(code); if (sourceMap) { @@ -205,11 +235,12 @@ void WasmBinaryWriter::writeMemories() { auto num = importInfo->getNumDefinedMemories(); o << U32LEB(num); ModuleUtils::iterDefinedMemories(*wasm, [&](Memory* memory) { - writeResizableLimits(memory->initial, - memory->max, - memory->hasMax(), - memory->shared, - memory->is64()); + writeMemoryResizableLimits(memory->initial, + memory->max, + memory->hasMax(), + memory->shared, + memory->is64(), + memory->pageSizeLog2); }); finishSection(start); } @@ -350,11 +381,12 @@ void WasmBinaryWriter::writeImports() { ModuleUtils::iterImportedMemories(*wasm, [&](Memory* memory) { writeImportHeader(memory); o << U32LEB(int32_t(ExternalKind::Memory)); - writeResizableLimits(memory->initial, - memory->max, - memory->hasMax(), - memory->shared, - memory->is64()); + writeMemoryResizableLimits(memory->initial, + memory->max, + memory->hasMax(), + memory->shared, + memory->is64(), + memory->pageSizeLog2); }); ModuleUtils::iterImportedTables(*wasm, [&](Table* table) { writeImportHeader(table); @@ -1457,6 +1489,8 @@ void WasmBinaryWriter::writeFeaturesSection() { return BinaryConsts::CustomSections::CustomDescriptorsFeature; case FeatureSet::RelaxedAtomics: return BinaryConsts::CustomSections::RelaxedAtomicsFeature; + case FeatureSet::CustomPageSizes: + return BinaryConsts::CustomSections::CustomPageSizesFeature; case FeatureSet::None: case FeatureSet::Default: case FeatureSet::All: @@ -2606,6 +2640,7 @@ void WasmBinaryReader::readMemories() { memory->max, memory->shared, memory->addressType, + memory->pageSizeLog2, Memory::kUnlimitedSize); wasm.addMemory(std::move(memory)); } @@ -2910,11 +2945,13 @@ void WasmBinaryReader::getResizableLimits(Address& initial, Address& max, bool& shared, Type& addressType, + uint8_t& pageSizeLog2, Address defaultIfNoMax) { auto flags = getU32LEB(); bool hasMax = (flags & BinaryConsts::HasMaximum) != 0; bool isShared = (flags & BinaryConsts::IsShared) != 0; bool is64 = (flags & BinaryConsts::Is64) != 0; + bool hasCustomPageSize = (flags & BinaryConsts::HasCustomPageSize) != 0; initial = is64 ? getU64LEB() : getU32LEB(); if (isShared && !hasMax) { throwError("shared memory must have max size"); @@ -2926,6 +2963,14 @@ void WasmBinaryReader::getResizableLimits(Address& initial, } else { max = defaultIfNoMax; } + if (hasCustomPageSize) { + auto readPageSizeLog2 = getU32LEB(); + if (readPageSizeLog2 != 0 && + readPageSizeLog2 != Memory::kDefaultPageSizeLog2) { + throwError("Memory page size is only allowed to be 1 or 64 KiB"); + } + pageSizeLog2 = (uint8_t)readPageSizeLog2; + } } void WasmBinaryReader::readImports() { @@ -2975,16 +3020,20 @@ void WasmBinaryReader::readImports() { table->module = module; table->base = base; table->type = getType(); - bool is_shared; + uint8_t page_size = 0xff; getResizableLimits(table->initial, table->max, is_shared, table->addressType, + page_size, Table::kUnlimitedSize); if (is_shared) { throwError("Tables may not be shared"); } + if (page_size != 0xff) { + throwError("Tables may not have a custom page size"); + } wasm.addTable(std::move(table)); break; } @@ -3002,6 +3051,7 @@ void WasmBinaryReader::readImports() { memory->max, memory->shared, memory->addressType, + memory->pageSizeLog2, Memory::kUnlimitedSize); wasm.addMemory(std::move(memory)); break; @@ -4973,14 +5023,19 @@ void WasmBinaryReader::readTableDeclarations() { auto table = Builder::makeTable(name, elemType); table->hasExplicitName = isExplicit; bool is_shared; + uint8_t pageSize = 0xff; getResizableLimits(table->initial, table->max, is_shared, table->addressType, + pageSize, Table::kUnlimitedSize); if (is_shared) { throwError("Tables may not be shared"); } + if (pageSize != 0xff) { + throwError("Tables may not specify a custom page size"); + } wasm.addTable(std::move(table)); } } @@ -5353,6 +5408,8 @@ void WasmBinaryReader::readFeatures(size_t sectionPos, size_t payloadLen) { feature = FeatureSet::CustomDescriptors; } else if (name == BinaryConsts::CustomSections::RelaxedAtomicsFeature) { feature = FeatureSet::RelaxedAtomics; + } else if (name == BinaryConsts::CustomSections::CustomPageSizesFeature) { + feature = FeatureSet::CustomPageSizes; } else { // Silently ignore unknown features (this may be and old binaryen running // on a new wasm). diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 5b1f0c7f4ed..03136f40028 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include #include @@ -4605,11 +4606,20 @@ static void validateMemories(Module& module, ValidationInfo& info) { info.shouldBeTrue(module.features.hasMemory64(), "memory", "64-bit memories require memory64 [--enable-memory64]"); + // TODO: The custom pages sizes proposals do not mention a verification + // method when the memory64 proposal is active simultaneously; the current + // implementation is based on spectest. + info.shouldBeTrue(memory->initial <= memory->maxSize64(), + "memory", + "initial memory must be <= 16EB"); + info.shouldBeTrue(!memory->hasMax() || memory->max <= memory->maxSize64(), + "memory", + "max memory must be <= 16EB, or unlimited"); } else { - info.shouldBeTrue(memory->initial <= Memory::kMaxSize32, + info.shouldBeTrue(memory->initial <= memory->maxSize32(), "memory", "initial memory must be <= 4GB"); - info.shouldBeTrue(!memory->hasMax() || memory->max <= Memory::kMaxSize32, + info.shouldBeTrue(!memory->hasMax() || memory->max <= memory->maxSize32(), "memory", "max memory must be <= 4GB, or unlimited"); } @@ -4621,6 +4631,18 @@ static void validateMemories(Module& module, ValidationInfo& info) { "memory", "shared memory requires threads [--enable-threads]"); } + + if (memory->pageSizeLog2 != Memory::kDefaultPageSizeLog2) { + info.shouldBeTrue( + module.features.hasCustomPageSizes(), + "memory", + "custom page sizes not enabled [--enable-custom-page-sizes]"); + info.shouldBeEqual( + Address(memory->pageSizeLog2), + Address(0), + "memory", + "custom page size must be 1 Byte or 65536 Bytes (64KiB)"); + } } } diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 4e901c152de..b51c32d4d71 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -62,6 +62,7 @@ const char* BulkMemoryOptFeature = "bulk-memory-opt"; const char* CallIndirectOverlongFeature = "call-indirect-overlong"; const char* CustomDescriptorsFeature = "custom-descriptors"; const char* RelaxedAtomicsFeature = "relaxed-atomics"; +const char* CustomPageSizesFeature = "custom-page-sizes"; } // namespace BinaryConsts::CustomSections diff --git a/src/wasm2js.h b/src/wasm2js.h index b92a7f851e5..5d35c31bc25 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -476,13 +476,13 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) { } else { Ref theVar = ValueBuilder::makeVar(); asmFunc[3]->push_back(theVar); - ValueBuilder::appendToVar( - theVar, - BUFFER, - ValueBuilder::makeNew(ValueBuilder::makeCall( - ValueBuilder::makeName("ArrayBuffer"), - ValueBuilder::makeInt(Address::address32_t( - wasm->memories[0]->initial.addr * Memory::kPageSize))))); + ValueBuilder::appendToVar(theVar, + BUFFER, + ValueBuilder::makeNew(ValueBuilder::makeCall( + ValueBuilder::makeName("ArrayBuffer"), + ValueBuilder::makeInt(Address::address32_t( + wasm->memories[0]->initial.addr + << wasm->memories[0]->pageSizeLog2))))); } } @@ -2486,13 +2486,12 @@ Ref Wasm2JSBuilder::processExpression(Expression* curr, void Wasm2JSBuilder::addMemoryFuncs(Ref ast, Module* wasm) { Ref memorySizeFunc = ValueBuilder::makeFunction(WASM_MEMORY_SIZE); - memorySizeFunc[3]->push_back(ValueBuilder::makeReturn( - makeJsCoercion(ValueBuilder::makeBinary( - ValueBuilder::makeDot(ValueBuilder::makeName(BUFFER), - IString("byteLength")), - DIV, - ValueBuilder::makeInt(Memory::kPageSize)), - JsType::JS_INT))); + memorySizeFunc[3]->push_back( + ValueBuilder::makeReturn(ValueBuilder::makeBinary( + ValueBuilder::makeDot(ValueBuilder::makeName(BUFFER), + IString("byteLength")), + RSHIFT, + ValueBuilder::makeInt(wasm->memories[0]->pageSizeLog2)))); ast->push_back(memorySizeFunc); if (!wasm->memories.empty() && @@ -2537,9 +2536,10 @@ void Wasm2JSBuilder::addMemoryGrowFunc(Ref ast, Module* wasm) { LT, ValueBuilder::makeName(IString("newPages"))), IString("&&"), - ValueBuilder::makeBinary(ValueBuilder::makeName(IString("newPages")), - LT, - ValueBuilder::makeInt(Memory::kMaxSize32))), + ValueBuilder::makeBinary( + ValueBuilder::makeName(IString("newPages")), + LT, + ValueBuilder::makeNum(wasm->memories[0]->maxSize32()))), block, NULL)); @@ -2550,9 +2550,10 @@ void Wasm2JSBuilder::addMemoryGrowFunc(Ref ast, Module* wasm) { IString("newBuffer"), ValueBuilder::makeNew(ValueBuilder::makeCall( ARRAY_BUFFER, - ValueBuilder::makeCall(MATH_IMUL, - ValueBuilder::makeName(IString("newPages")), - ValueBuilder::makeInt(Memory::kPageSize))))); + ValueBuilder::makeBinary( + ValueBuilder::makeName(IString("newPages")), + LSHIFT, + ValueBuilder::makeInt(wasm->memories[0]->pageSizeLog2))))); Ref newHEAP8 = ValueBuilder::makeVar(); ValueBuilder::appendToBlock(block, newHEAP8); @@ -2744,7 +2745,8 @@ void Wasm2JSGlue::emitPostES6() { // can be used for conversions, so make sure there's at least one page. if (!wasm.memories.empty() && wasm.memories[0]->imported()) { out << "var mem" << moduleName.str << " = new ArrayBuffer(" - << wasm.memories[0]->initial.addr * Memory::kPageSize << ");\n"; + << (wasm.memories[0]->initial.addr << wasm.memories[0]->pageSizeLog2) + << ");\n"; } // Actually invoke the `asmFunc` generated function, passing in all global diff --git a/test/binaryen.js/kitchen-sink.js b/test/binaryen.js/kitchen-sink.js index 673a470607d..68e0670f325 100644 --- a/test/binaryen.js/kitchen-sink.js +++ b/test/binaryen.js/kitchen-sink.js @@ -101,6 +101,7 @@ function test_features() { console.log("Features.Strings: " + binaryen.Features.Strings); console.log("Features.MultiMemory: " + binaryen.Features.MultiMemory); console.log("Features.RelaxedAtomics: " + binaryen.Features.RelaxedAtomics); + console.log("Features.CustomPageSizes: " + binaryen.Features.CustomPageSizes); console.log("Features.All: " + binaryen.Features.All); } diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt index c5ea5bded75..6bf9ae959f8 100644 --- a/test/binaryen.js/kitchen-sink.js.txt +++ b/test/binaryen.js/kitchen-sink.js.txt @@ -34,7 +34,8 @@ Features.ExtendedConst: 8192 Features.Strings: 16384 Features.MultiMemory: 32768 Features.RelaxedAtomics: 4194304 -Features.All: 8388607 +Features.CustomPageSizes: 8388608 +Features.All: 16777215 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 2499ffff646..1ae179ca265 100644 --- a/test/example/c-api-kitchen-sink.c +++ b/test/example/c-api-kitchen-sink.c @@ -376,6 +376,8 @@ void test_features() { printf("BinaryenFeatureStrings: %d\n", BinaryenFeatureStrings()); printf("BinaryenFeatureRelaxedAtomics: %d\n", BinaryenFeatureRelaxedAtomics()); + printf("BinaryenFeatureCustomPageSizes: %d\n", + BinaryenFeatureCustomPageSizes()); printf("BinaryenFeatureAll: %d\n", BinaryenFeatureAll()); } diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt index 4d68abcddd5..ed09c2b418c 100644 --- a/test/example/c-api-kitchen-sink.txt +++ b/test/example/c-api-kitchen-sink.txt @@ -48,7 +48,8 @@ BinaryenFeatureRelaxedSIMD: 4096 BinaryenFeatureExtendedConst: 8192 BinaryenFeatureStrings: 16384 BinaryenFeatureRelaxedAtomics: 4194304 -BinaryenFeatureAll: 8388607 +BinaryenFeatureCustomPageSizes: 8388608 +BinaryenFeatureAll: 16777215 (f32.neg (f32.const -33.61199951171875) ) diff --git a/test/lit/help/wasm-as.test b/test/lit/help/wasm-as.test index d9f1c51544b..9a59856cbac 100644 --- a/test/lit/help/wasm-as.test +++ b/test/lit/help/wasm-as.test @@ -140,6 +140,10 @@ ;; CHECK-NEXT: --disable-relaxed-atomics Disable acquire/release atomic memory ;; CHECK-NEXT: operations ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-custom-page-sizes Enable custom page sizes +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-custom-page-sizes Disable custom page sizes +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-ctor-eval.test b/test/lit/help/wasm-ctor-eval.test index 3ecda78f368..c6a36b5fce9 100644 --- a/test/lit/help/wasm-ctor-eval.test +++ b/test/lit/help/wasm-ctor-eval.test @@ -147,6 +147,10 @@ ;; CHECK-NEXT: --disable-relaxed-atomics Disable acquire/release atomic memory ;; CHECK-NEXT: operations ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-custom-page-sizes Enable custom page sizes +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-custom-page-sizes Disable custom page sizes +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-dis.test b/test/lit/help/wasm-dis.test index 4105874814a..d15ebace641 100644 --- a/test/lit/help/wasm-dis.test +++ b/test/lit/help/wasm-dis.test @@ -133,6 +133,10 @@ ;; CHECK-NEXT: --disable-relaxed-atomics Disable acquire/release atomic memory ;; CHECK-NEXT: operations ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-custom-page-sizes Enable custom page sizes +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-custom-page-sizes Disable custom page sizes +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-emscripten-finalize.test b/test/lit/help/wasm-emscripten-finalize.test index 0c94205267c..1200667793b 100644 --- a/test/lit/help/wasm-emscripten-finalize.test +++ b/test/lit/help/wasm-emscripten-finalize.test @@ -175,6 +175,10 @@ ;; CHECK-NEXT: --disable-relaxed-atomics Disable acquire/release atomic memory ;; CHECK-NEXT: operations ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-custom-page-sizes Enable custom page sizes +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-custom-page-sizes Disable custom page sizes +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-merge.test b/test/lit/help/wasm-merge.test index f6837860017..0e2dab535c4 100644 --- a/test/lit/help/wasm-merge.test +++ b/test/lit/help/wasm-merge.test @@ -163,6 +163,10 @@ ;; CHECK-NEXT: --disable-relaxed-atomics Disable acquire/release atomic memory ;; CHECK-NEXT: operations ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-custom-page-sizes Enable custom page sizes +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-custom-page-sizes Disable custom page sizes +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-metadce.test b/test/lit/help/wasm-metadce.test index b566afd8471..a556ca5bf9a 100644 --- a/test/lit/help/wasm-metadce.test +++ b/test/lit/help/wasm-metadce.test @@ -798,6 +798,10 @@ ;; CHECK-NEXT: --disable-relaxed-atomics Disable acquire/release atomic ;; CHECK-NEXT: memory operations ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-custom-page-sizes Enable custom page sizes +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-custom-page-sizes Disable custom page sizes +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-opt.test b/test/lit/help/wasm-opt.test index eff3724891c..58d7221086d 100644 --- a/test/lit/help/wasm-opt.test +++ b/test/lit/help/wasm-opt.test @@ -830,6 +830,10 @@ ;; CHECK-NEXT: --disable-relaxed-atomics Disable acquire/release atomic ;; CHECK-NEXT: memory operations ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-custom-page-sizes Enable custom page sizes +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-custom-page-sizes Disable custom page sizes +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-reduce.test b/test/lit/help/wasm-reduce.test index 12d258bed49..ad014fa0530 100644 --- a/test/lit/help/wasm-reduce.test +++ b/test/lit/help/wasm-reduce.test @@ -223,6 +223,10 @@ ;; CHECK-NEXT: --disable-relaxed-atomics Disable acquire/release atomic memory ;; CHECK-NEXT: operations ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-custom-page-sizes Enable custom page sizes +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-custom-page-sizes Disable custom page sizes +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-split.test b/test/lit/help/wasm-split.test index 102add9dfd7..30b651521b3 100644 --- a/test/lit/help/wasm-split.test +++ b/test/lit/help/wasm-split.test @@ -281,6 +281,10 @@ ;; CHECK-NEXT: --disable-relaxed-atomics Disable acquire/release atomic memory ;; CHECK-NEXT: operations ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-custom-page-sizes Enable custom page sizes +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-custom-page-sizes Disable custom page sizes +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm2js.test b/test/lit/help/wasm2js.test index cd55ac22235..2a67bc1dee2 100644 --- a/test/lit/help/wasm2js.test +++ b/test/lit/help/wasm2js.test @@ -762,6 +762,10 @@ ;; CHECK-NEXT: --disable-relaxed-atomics Disable acquire/release atomic ;; CHECK-NEXT: memory operations ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-custom-page-sizes Enable custom page sizes +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-custom-page-sizes Disable custom page sizes +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/passes/memory-copy-fill-lowering.wast b/test/lit/passes/memory-copy-fill-lowering.wast index 990c2fa30de..adc19e7e732 100644 --- a/test/lit/passes/memory-copy-fill-lowering.wast +++ b/test/lit/passes/memory-copy-fill-lowering.wast @@ -37,9 +37,9 @@ ;; CHECK-NEXT: (local $step i32) ;; CHECK-NEXT: (local $i i32) ;; CHECK-NEXT: (local.set $end -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (memory.size) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if @@ -135,9 +135,9 @@ ;; CHECK-NEXT: (local.get $dst) ;; CHECK-NEXT: (local.get $size) ;; CHECK-NEXT: ) -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (memory.size) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then diff --git a/test/lit/passes/multi-memory-lowering.wast b/test/lit/passes/multi-memory-lowering.wast index 9b7f5363503..b46b97ee721 100644 --- a/test/lit/passes/multi-memory-lowering.wast +++ b/test/lit/passes/multi-memory-lowering.wast @@ -839,9 +839,9 @@ ;; CHECK: (func $memory1_size (result i32) ;; CHECK-NEXT: (return -;; CHECK-NEXT: (i32.div_u +;; CHECK-NEXT: (i32.shr_u ;; CHECK-NEXT: (global.get $memory2_byte_offset) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -849,13 +849,13 @@ ;; CHECK: (func $memory2_size (result i32) ;; CHECK-NEXT: (return ;; CHECK-NEXT: (i32.sub -;; CHECK-NEXT: (i32.div_u +;; CHECK-NEXT: (i32.shr_u ;; CHECK-NEXT: (global.get $memory3_byte_offset) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) -;; CHECK-NEXT: (i32.div_u +;; CHECK-NEXT: (i32.shr_u ;; CHECK-NEXT: (global.get $memory2_byte_offset) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -865,9 +865,9 @@ ;; CHECK-NEXT: (return ;; CHECK-NEXT: (i32.sub ;; CHECK-NEXT: (memory.size) -;; CHECK-NEXT: (i32.div_u +;; CHECK-NEXT: (i32.shr_u ;; CHECK-NEXT: (global.get $memory3_byte_offset) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -898,16 +898,16 @@ ;; CHECK-NEXT: (memory.copy ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (global.get $memory2_byte_offset) -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $page_delta) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $memory2_byte_offset) ;; CHECK-NEXT: (i32.sub -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $memory_size) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $memory2_byte_offset) ;; CHECK-NEXT: ) @@ -915,18 +915,18 @@ ;; CHECK-NEXT: (global.set $memory2_byte_offset ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (global.get $memory2_byte_offset) -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $page_delta) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.set $memory3_byte_offset ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (global.get $memory3_byte_offset) -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $page_delta) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -958,16 +958,16 @@ ;; CHECK-NEXT: (memory.copy ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (global.get $memory3_byte_offset) -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $page_delta) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $memory3_byte_offset) ;; CHECK-NEXT: (i32.sub -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $memory_size) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $memory3_byte_offset) ;; CHECK-NEXT: ) @@ -975,9 +975,9 @@ ;; CHECK-NEXT: (global.set $memory3_byte_offset ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (global.get $memory3_byte_offset) -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $page_delta) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1007,9 +1007,9 @@ ;; BOUNDS: (func $memory1_size (result i32) ;; BOUNDS-NEXT: (return -;; BOUNDS-NEXT: (i32.div_u +;; BOUNDS-NEXT: (i32.shr_u ;; BOUNDS-NEXT: (global.get $memory2_byte_offset) -;; BOUNDS-NEXT: (i32.const 65536) +;; BOUNDS-NEXT: (i32.const 16) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) @@ -1017,13 +1017,13 @@ ;; BOUNDS: (func $memory2_size (result i32) ;; BOUNDS-NEXT: (return ;; BOUNDS-NEXT: (i32.sub -;; BOUNDS-NEXT: (i32.div_u +;; BOUNDS-NEXT: (i32.shr_u ;; BOUNDS-NEXT: (global.get $memory3_byte_offset) -;; BOUNDS-NEXT: (i32.const 65536) +;; BOUNDS-NEXT: (i32.const 16) ;; BOUNDS-NEXT: ) -;; BOUNDS-NEXT: (i32.div_u +;; BOUNDS-NEXT: (i32.shr_u ;; BOUNDS-NEXT: (global.get $memory2_byte_offset) -;; BOUNDS-NEXT: (i32.const 65536) +;; BOUNDS-NEXT: (i32.const 16) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) @@ -1033,9 +1033,9 @@ ;; BOUNDS-NEXT: (return ;; BOUNDS-NEXT: (i32.sub ;; BOUNDS-NEXT: (memory.size) -;; BOUNDS-NEXT: (i32.div_u +;; BOUNDS-NEXT: (i32.shr_u ;; BOUNDS-NEXT: (global.get $memory3_byte_offset) -;; BOUNDS-NEXT: (i32.const 65536) +;; BOUNDS-NEXT: (i32.const 16) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) @@ -1066,16 +1066,16 @@ ;; BOUNDS-NEXT: (memory.copy ;; BOUNDS-NEXT: (i32.add ;; BOUNDS-NEXT: (global.get $memory2_byte_offset) -;; BOUNDS-NEXT: (i32.mul +;; BOUNDS-NEXT: (i32.shl ;; BOUNDS-NEXT: (local.get $page_delta) -;; BOUNDS-NEXT: (i32.const 65536) +;; BOUNDS-NEXT: (i32.const 16) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: (global.get $memory2_byte_offset) ;; BOUNDS-NEXT: (i32.sub -;; BOUNDS-NEXT: (i32.mul +;; BOUNDS-NEXT: (i32.shl ;; BOUNDS-NEXT: (local.get $memory_size) -;; BOUNDS-NEXT: (i32.const 65536) +;; BOUNDS-NEXT: (i32.const 16) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: (global.get $memory2_byte_offset) ;; BOUNDS-NEXT: ) @@ -1083,18 +1083,18 @@ ;; BOUNDS-NEXT: (global.set $memory2_byte_offset ;; BOUNDS-NEXT: (i32.add ;; BOUNDS-NEXT: (global.get $memory2_byte_offset) -;; BOUNDS-NEXT: (i32.mul +;; BOUNDS-NEXT: (i32.shl ;; BOUNDS-NEXT: (local.get $page_delta) -;; BOUNDS-NEXT: (i32.const 65536) +;; BOUNDS-NEXT: (i32.const 16) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: (global.set $memory3_byte_offset ;; BOUNDS-NEXT: (i32.add ;; BOUNDS-NEXT: (global.get $memory3_byte_offset) -;; BOUNDS-NEXT: (i32.mul +;; BOUNDS-NEXT: (i32.shl ;; BOUNDS-NEXT: (local.get $page_delta) -;; BOUNDS-NEXT: (i32.const 65536) +;; BOUNDS-NEXT: (i32.const 16) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) @@ -1126,16 +1126,16 @@ ;; BOUNDS-NEXT: (memory.copy ;; BOUNDS-NEXT: (i32.add ;; BOUNDS-NEXT: (global.get $memory3_byte_offset) -;; BOUNDS-NEXT: (i32.mul +;; BOUNDS-NEXT: (i32.shl ;; BOUNDS-NEXT: (local.get $page_delta) -;; BOUNDS-NEXT: (i32.const 65536) +;; BOUNDS-NEXT: (i32.const 16) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: (global.get $memory3_byte_offset) ;; BOUNDS-NEXT: (i32.sub -;; BOUNDS-NEXT: (i32.mul +;; BOUNDS-NEXT: (i32.shl ;; BOUNDS-NEXT: (local.get $memory_size) -;; BOUNDS-NEXT: (i32.const 65536) +;; BOUNDS-NEXT: (i32.const 16) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: (global.get $memory3_byte_offset) ;; BOUNDS-NEXT: ) @@ -1143,9 +1143,9 @@ ;; BOUNDS-NEXT: (global.set $memory3_byte_offset ;; BOUNDS-NEXT: (i32.add ;; BOUNDS-NEXT: (global.get $memory3_byte_offset) -;; BOUNDS-NEXT: (i32.mul +;; BOUNDS-NEXT: (i32.shl ;; BOUNDS-NEXT: (local.get $page_delta) -;; BOUNDS-NEXT: (i32.const 65536) +;; BOUNDS-NEXT: (i32.const 16) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) ;; BOUNDS-NEXT: ) diff --git a/test/lit/wasm-split/multi-memory-lowering-export.wast b/test/lit/wasm-split/multi-memory-lowering-export.wast index 152aaf72310..4411ba78e39 100644 --- a/test/lit/wasm-split/multi-memory-lowering-export.wast +++ b/test/lit/wasm-split/multi-memory-lowering-export.wast @@ -20,9 +20,9 @@ ;; CHECK: (func $memory1_size (type $0) (result i32) ;; CHECK-NEXT: (return -;; CHECK-NEXT: (i32.div_u +;; CHECK-NEXT: (i32.shr_u ;; CHECK-NEXT: (global.get $memory2_byte_offset) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -31,9 +31,9 @@ ;; CHECK-NEXT: (return ;; CHECK-NEXT: (i32.sub ;; CHECK-NEXT: (memory.size) -;; CHECK-NEXT: (i32.div_u +;; CHECK-NEXT: (i32.shr_u ;; CHECK-NEXT: (global.get $memory2_byte_offset) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -64,16 +64,16 @@ ;; CHECK-NEXT: (memory.copy ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (global.get $memory2_byte_offset) -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $page_delta) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $memory2_byte_offset) ;; CHECK-NEXT: (i32.sub -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $memory_size) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $memory2_byte_offset) ;; CHECK-NEXT: ) @@ -81,9 +81,9 @@ ;; CHECK-NEXT: (global.set $memory2_byte_offset ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (global.get $memory2_byte_offset) -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $page_delta) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/wasm-split/multi-memory-lowering-import.wast b/test/lit/wasm-split/multi-memory-lowering-import.wast index 37ccfa16cb1..f8d505d89fc 100644 --- a/test/lit/wasm-split/multi-memory-lowering-import.wast +++ b/test/lit/wasm-split/multi-memory-lowering-import.wast @@ -17,9 +17,9 @@ ;; CHECK: (func $memory1_size (type $0) (result i32) ;; CHECK-NEXT: (return -;; CHECK-NEXT: (i32.div_u +;; CHECK-NEXT: (i32.shr_u ;; CHECK-NEXT: (global.get $memory2_byte_offset) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -28,9 +28,9 @@ ;; CHECK-NEXT: (return ;; CHECK-NEXT: (i32.sub ;; CHECK-NEXT: (memory.size) -;; CHECK-NEXT: (i32.div_u +;; CHECK-NEXT: (i32.shr_u ;; CHECK-NEXT: (global.get $memory2_byte_offset) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -61,16 +61,16 @@ ;; CHECK-NEXT: (memory.copy ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (global.get $memory2_byte_offset) -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $page_delta) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $memory2_byte_offset) ;; CHECK-NEXT: (i32.sub -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $memory_size) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $memory2_byte_offset) ;; CHECK-NEXT: ) @@ -78,9 +78,9 @@ ;; CHECK-NEXT: (global.set $memory2_byte_offset ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (global.get $memory2_byte_offset) -;; CHECK-NEXT: (i32.mul +;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $page_delta) -;; CHECK-NEXT: (i32.const 65536) +;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) 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 4d80eb6bb81..ce3e9222f7b 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 @@ -21,6 +21,7 @@ --enable-call-indirect-overlong --enable-custom-descriptors --enable-relaxed-atomics +--enable-custom-page-sizes (module (type $0 (func (result v128 externref))) (func $foo (type $0) (result v128 externref) diff --git a/test/unit/test_features.py b/test/unit/test_features.py index d44435811fc..35b65199a11 100644 --- a/test/unit/test_features.py +++ b/test/unit/test_features.py @@ -456,4 +456,5 @@ def test_emit_all_features(self): '--enable-call-indirect-overlong', '--enable-custom-descriptors', '--enable-relaxed-atomics', + '--enable-custom-page-sizes', ], p2.stdout.splitlines()) diff --git a/test/wasm2js/atomics_32.2asm.js b/test/wasm2js/atomics_32.2asm.js index a97bf17ed26..03ac931053b 100644 --- a/test/wasm2js/atomics_32.2asm.js +++ b/test/wasm2js/atomics_32.2asm.js @@ -143,7 +143,7 @@ function asmFunc(imports) { bufferView = HEAPU8; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { diff --git a/test/wasm2js/atomics_32.2asm.js.opt b/test/wasm2js/atomics_32.2asm.js.opt index deb8ce56186..04da6fac687 100644 --- a/test/wasm2js/atomics_32.2asm.js.opt +++ b/test/wasm2js/atomics_32.2asm.js.opt @@ -139,7 +139,7 @@ function asmFunc(imports) { bufferView = HEAPU8; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { diff --git a/test/wasm2js/bulk-memory.2asm.js b/test/wasm2js/bulk-memory.2asm.js index 4f25b9bd8ba..b1a25080bf6 100644 --- a/test/wasm2js/bulk-memory.2asm.js +++ b/test/wasm2js/bulk-memory.2asm.js @@ -61,7 +61,7 @@ function asmFunc(imports) { bufferView = HEAPU8; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -69,7 +69,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); @@ -162,7 +162,7 @@ function asmFunc(imports) { bufferView = HEAPU8; initActiveSegments(imports); function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { @@ -239,7 +239,7 @@ function asmFunc(imports) { bufferView = HEAPU8; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -247,7 +247,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); @@ -351,7 +351,7 @@ function asmFunc(imports) { bufferView = HEAPU8; initActiveSegments(imports); function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -359,7 +359,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/bulk-memory.2asm.js.opt b/test/wasm2js/bulk-memory.2asm.js.opt index 50ddecee8b2..be6ac9d195a 100644 --- a/test/wasm2js/bulk-memory.2asm.js.opt +++ b/test/wasm2js/bulk-memory.2asm.js.opt @@ -61,7 +61,7 @@ function asmFunc(imports) { bufferView = HEAPU8; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -69,7 +69,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); @@ -162,7 +162,7 @@ function asmFunc(imports) { bufferView = HEAPU8; initActiveSegments(imports); function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { @@ -239,7 +239,7 @@ function asmFunc(imports) { bufferView = HEAPU8; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -247,7 +247,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); @@ -304,7 +304,7 @@ function asmFunc(imports) { } function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -312,7 +312,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/deterministic.2asm.js b/test/wasm2js/deterministic.2asm.js index 33cb04a846e..e4c12bc8f78 100644 --- a/test/wasm2js/deterministic.2asm.js +++ b/test/wasm2js/deterministic.2asm.js @@ -34,7 +34,7 @@ function asmFunc(imports) { bufferView = HEAPU8; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { diff --git a/test/wasm2js/deterministic.2asm.js.opt b/test/wasm2js/deterministic.2asm.js.opt index 12ebdd8599d..2c25650a716 100644 --- a/test/wasm2js/deterministic.2asm.js.opt +++ b/test/wasm2js/deterministic.2asm.js.opt @@ -33,7 +33,7 @@ function asmFunc(imports) { bufferView = HEAPU8; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { diff --git a/test/wasm2js/dynamicLibrary.2asm.js b/test/wasm2js/dynamicLibrary.2asm.js index bb6f4dcaff6..cc4103f0774 100644 --- a/test/wasm2js/dynamicLibrary.2asm.js +++ b/test/wasm2js/dynamicLibrary.2asm.js @@ -77,7 +77,7 @@ function asmFunc(imports) { FUNCTION_TABLE[import$tableBase + 0] = foo; FUNCTION_TABLE[import$tableBase + 1] = bar; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { diff --git a/test/wasm2js/dynamicLibrary.2asm.js.opt b/test/wasm2js/dynamicLibrary.2asm.js.opt index 543f755f37d..d0c8c7b2900 100644 --- a/test/wasm2js/dynamicLibrary.2asm.js.opt +++ b/test/wasm2js/dynamicLibrary.2asm.js.opt @@ -69,7 +69,7 @@ function asmFunc(imports) { FUNCTION_TABLE[import$tableBase + 0] = foo; FUNCTION_TABLE[import$tableBase + 1] = foo; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { diff --git a/test/wasm2js/emscripten-grow-no.2asm.js b/test/wasm2js/emscripten-grow-no.2asm.js index 79963d6624c..e633392e300 100644 --- a/test/wasm2js/emscripten-grow-no.2asm.js +++ b/test/wasm2js/emscripten-grow-no.2asm.js @@ -52,7 +52,7 @@ function asmFunc(imports) { bufferView = HEAPU8; initActiveSegments(imports); function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { diff --git a/test/wasm2js/emscripten-grow-no.2asm.js.opt b/test/wasm2js/emscripten-grow-no.2asm.js.opt index 79963d6624c..e633392e300 100644 --- a/test/wasm2js/emscripten-grow-no.2asm.js.opt +++ b/test/wasm2js/emscripten-grow-no.2asm.js.opt @@ -52,7 +52,7 @@ function asmFunc(imports) { bufferView = HEAPU8; initActiveSegments(imports); function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { diff --git a/test/wasm2js/emscripten-grow-yes.2asm.js b/test/wasm2js/emscripten-grow-yes.2asm.js index 6ab56747baf..7df826d54ba 100644 --- a/test/wasm2js/emscripten-grow-yes.2asm.js +++ b/test/wasm2js/emscripten-grow-yes.2asm.js @@ -57,7 +57,7 @@ function asmFunc(imports) { bufferView = HEAPU8; initActiveSegments(imports); function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -65,7 +65,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/emscripten-grow-yes.2asm.js.opt b/test/wasm2js/emscripten-grow-yes.2asm.js.opt index 6ab56747baf..7df826d54ba 100644 --- a/test/wasm2js/emscripten-grow-yes.2asm.js.opt +++ b/test/wasm2js/emscripten-grow-yes.2asm.js.opt @@ -57,7 +57,7 @@ function asmFunc(imports) { bufferView = HEAPU8; initActiveSegments(imports); function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -65,7 +65,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/emscripten.2asm.js b/test/wasm2js/emscripten.2asm.js index 24a556b25d7..acf66476190 100644 --- a/test/wasm2js/emscripten.2asm.js +++ b/test/wasm2js/emscripten.2asm.js @@ -218,7 +218,7 @@ function asmFunc(imports) { FUNCTION_TABLE[2] = bar; FUNCTION_TABLE[3] = tabled; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { diff --git a/test/wasm2js/emscripten.2asm.js.opt b/test/wasm2js/emscripten.2asm.js.opt index caef2389639..749a7edaef3 100644 --- a/test/wasm2js/emscripten.2asm.js.opt +++ b/test/wasm2js/emscripten.2asm.js.opt @@ -212,7 +212,7 @@ function asmFunc(imports) { FUNCTION_TABLE[2] = bar; FUNCTION_TABLE[3] = internal; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { diff --git a/test/wasm2js/endianness.2asm.js b/test/wasm2js/endianness.2asm.js index 5e29d67c345..e9f0c8c9396 100644 --- a/test/wasm2js/endianness.2asm.js +++ b/test/wasm2js/endianness.2asm.js @@ -652,7 +652,7 @@ function asmFunc(imports) { bufferView = HEAPU8; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -660,7 +660,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/grow-memory-tricky.2asm.js b/test/wasm2js/grow-memory-tricky.2asm.js index 0dc0e1ee110..d75a80c5df5 100644 --- a/test/wasm2js/grow-memory-tricky.2asm.js +++ b/test/wasm2js/grow-memory-tricky.2asm.js @@ -36,7 +36,7 @@ function asmFunc(imports) { } function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -44,7 +44,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/grow-memory-tricky.2asm.js.opt b/test/wasm2js/grow-memory-tricky.2asm.js.opt index d02bfcaa656..abc0b7ef835 100644 --- a/test/wasm2js/grow-memory-tricky.2asm.js.opt +++ b/test/wasm2js/grow-memory-tricky.2asm.js.opt @@ -26,7 +26,7 @@ function asmFunc(imports) { } function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -34,7 +34,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/grow_memory.2asm.js b/test/wasm2js/grow_memory.2asm.js index 83a9b998de3..47cb08ca085 100644 --- a/test/wasm2js/grow_memory.2asm.js +++ b/test/wasm2js/grow_memory.2asm.js @@ -29,7 +29,7 @@ function asmFunc(imports) { } function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -37,7 +37,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/left-to-right.2asm.js b/test/wasm2js/left-to-right.2asm.js index 6553cbc11d5..63bc9225796 100644 --- a/test/wasm2js/left-to-right.2asm.js +++ b/test/wasm2js/left-to-right.2asm.js @@ -2083,7 +2083,7 @@ function asmFunc(imports) { bufferView = HEAPU8; var FUNCTION_TABLE = [i32_t0, i32_t1, i64_t0, i64_t1, f32_t0, f32_t1, f64_t0, f64_t1]; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -2091,7 +2091,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/minified-memory.2asm.js b/test/wasm2js/minified-memory.2asm.js index 1d3e8c942f8..d2aded1bfdb 100644 --- a/test/wasm2js/minified-memory.2asm.js +++ b/test/wasm2js/minified-memory.2asm.js @@ -27,7 +27,7 @@ function asmFunc(imports) { } function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -35,7 +35,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/minified-memory.2asm.js.opt b/test/wasm2js/minified-memory.2asm.js.opt index 6d1dfa47d7f..a7c31ca6858 100644 --- a/test/wasm2js/minified-memory.2asm.js.opt +++ b/test/wasm2js/minified-memory.2asm.js.opt @@ -27,7 +27,7 @@ function asmFunc(imports) { } function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -35,7 +35,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/reinterpret_scratch.2asm.js b/test/wasm2js/reinterpret_scratch.2asm.js index 547206072a9..22969331eae 100644 --- a/test/wasm2js/reinterpret_scratch.2asm.js +++ b/test/wasm2js/reinterpret_scratch.2asm.js @@ -50,7 +50,7 @@ function asmFunc(imports) { bufferView = HEAPU8; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { diff --git a/test/wasm2js/reinterpret_scratch.2asm.js.opt b/test/wasm2js/reinterpret_scratch.2asm.js.opt index bc077cdce1f..63901569ec6 100644 --- a/test/wasm2js/reinterpret_scratch.2asm.js.opt +++ b/test/wasm2js/reinterpret_scratch.2asm.js.opt @@ -45,7 +45,7 @@ function asmFunc(imports) { bufferView = HEAPU8; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { diff --git a/test/wasm2js/start_func.2asm.js b/test/wasm2js/start_func.2asm.js index 0ca4c66dfb8..2eb744f319a 100644 --- a/test/wasm2js/start_func.2asm.js +++ b/test/wasm2js/start_func.2asm.js @@ -25,7 +25,7 @@ function asmFunc(imports) { foo(); function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -33,7 +33,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/start_func.2asm.js.opt b/test/wasm2js/start_func.2asm.js.opt index 6a002727208..3b7e05608fa 100644 --- a/test/wasm2js/start_func.2asm.js.opt +++ b/test/wasm2js/start_func.2asm.js.opt @@ -25,7 +25,7 @@ function asmFunc(imports) { foo(); function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -33,7 +33,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/traps.2asm.js b/test/wasm2js/traps.2asm.js index f7a469ebe2c..54f62705314 100644 --- a/test/wasm2js/traps.2asm.js +++ b/test/wasm2js/traps.2asm.js @@ -1660,7 +1660,7 @@ function asmFunc(imports) { } function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } function __wasm_memory_grow(pagesToAdd) { @@ -1668,7 +1668,7 @@ function asmFunc(imports) { var oldPages = __wasm_memory_size() | 0; var newPages = oldPages + pagesToAdd | 0; if ((oldPages < newPages) && (newPages < 65536)) { - var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536)); + var newBuffer = new ArrayBuffer(newPages << 16); var newHEAP8 = new Int8Array(newBuffer); newHEAP8.set(HEAP8); HEAP8 = new Int8Array(newBuffer); diff --git a/test/wasm2js/unaligned.2asm.js b/test/wasm2js/unaligned.2asm.js index bf33c2d789a..d7f03e1b471 100644 --- a/test/wasm2js/unaligned.2asm.js +++ b/test/wasm2js/unaligned.2asm.js @@ -160,7 +160,7 @@ function asmFunc(imports) { bufferView = HEAPU8; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return { diff --git a/test/wasm2js/unaligned.2asm.js.opt b/test/wasm2js/unaligned.2asm.js.opt index 552868ded2b..ad5f96a4971 100644 --- a/test/wasm2js/unaligned.2asm.js.opt +++ b/test/wasm2js/unaligned.2asm.js.opt @@ -109,7 +109,7 @@ function asmFunc(imports) { bufferView = HEAPU8; function __wasm_memory_size() { - return buffer.byteLength / 65536 | 0; + return buffer.byteLength >> 16; } return {