diff options
Diffstat (limited to 'src/wasm')
-rw-r--r-- | src/wasm/literal.cpp | 120 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 651 | ||||
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 32 | ||||
-rw-r--r-- | src/wasm/wasm-io.cpp | 15 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 441 | ||||
-rw-r--r-- | src/wasm/wasm-type.cpp | 12 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 72 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 38 |
8 files changed, 916 insertions, 465 deletions
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index be92ae03d..3d7303e23 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -144,10 +144,12 @@ void Literal::getBits(uint8_t (&buf)[16]) const { } bool Literal::operator==(const Literal& other) const { - if (type != other.type) + if (type != other.type) { return false; - if (type == none) + } + if (type == none) { return true; + } uint8_t bits[16], other_bits[16]; getBits(bits); other.getBits(other_bits); @@ -238,8 +240,9 @@ void Literal::printDouble(std::ostream& o, double d) { void Literal::printVec128(std::ostream& o, const std::array<uint8_t, 16>& v) { o << std::hex; for (auto i = 0; i < 16; i += 4) { - if (i) + if (i) { o << " "; + } o << "0x" << std::setfill('0') << std::setw(8) << uint32_t(v[i] | (v[i + 1] << 8) | (v[i + 2] << 16) | (v[i + 3] << 24)); } @@ -276,26 +279,32 @@ std::ostream& operator<<(std::ostream& o, Literal literal) { } Literal Literal::countLeadingZeroes() const { - if (type == Type::i32) + if (type == Type::i32) { return Literal((int32_t)CountLeadingZeroes(i32)); - if (type == Type::i64) + } + if (type == Type::i64) { return Literal((int64_t)CountLeadingZeroes(i64)); + } WASM_UNREACHABLE(); } Literal Literal::countTrailingZeroes() const { - if (type == Type::i32) + if (type == Type::i32) { return Literal((int32_t)CountTrailingZeroes(i32)); - if (type == Type::i64) + } + if (type == Type::i64) { return Literal((int64_t)CountTrailingZeroes(i64)); + } WASM_UNREACHABLE(); } Literal Literal::popCount() const { - if (type == Type::i32) + if (type == Type::i32) { return Literal((int32_t)PopCount(i32)); - if (type == Type::i64) + } + if (type == Type::i64) { return Literal((int64_t)PopCount(i64)); + } WASM_UNREACHABLE(); } @@ -315,24 +324,29 @@ Literal Literal::extendToF64() const { } Literal Literal::extendS8() const { - if (type == Type::i32) + if (type == Type::i32) { return Literal(int32_t(int8_t(geti32() & 0xFF))); - if (type == Type::i64) + } + if (type == Type::i64) { return Literal(int64_t(int8_t(geti64() & 0xFF))); + } WASM_UNREACHABLE(); } Literal Literal::extendS16() const { - if (type == Type::i32) + if (type == Type::i32) { return Literal(int32_t(int16_t(geti32() & 0xFFFF))); - if (type == Type::i64) + } + if (type == Type::i64) { return Literal(int64_t(int16_t(geti64() & 0xFFFF))); + } WASM_UNREACHABLE(); } Literal Literal::extendS32() const { - if (type == Type::i64) + if (type == Type::i64) { return Literal(int64_t(int32_t(geti64() & 0xFFFFFFFF))); + } WASM_UNREACHABLE(); } @@ -342,34 +356,42 @@ Literal Literal::wrapToI32() const { } Literal Literal::convertSIToF32() const { - if (type == Type::i32) + if (type == Type::i32) { return Literal(float(i32)); - if (type == Type::i64) + } + if (type == Type::i64) { return Literal(float(i64)); + } WASM_UNREACHABLE(); } Literal Literal::convertUIToF32() const { - if (type == Type::i32) + if (type == Type::i32) { return Literal(float(uint32_t(i32))); - if (type == Type::i64) + } + if (type == Type::i64) { return Literal(float(uint64_t(i64))); + } WASM_UNREACHABLE(); } Literal Literal::convertSIToF64() const { - if (type == Type::i32) + if (type == Type::i32) { return Literal(double(i32)); - if (type == Type::i64) + } + if (type == Type::i64) { return Literal(double(i64)); + } WASM_UNREACHABLE(); } Literal Literal::convertUIToF64() const { - if (type == Type::i32) + if (type == Type::i32) { return Literal(double(uint32_t(i32))); - if (type == Type::i64) + } + if (type == Type::i64) { return Literal(double(uint64_t(i64))); + } WASM_UNREACHABLE(); } @@ -551,23 +573,29 @@ Literal Literal::sqrt() const { Literal Literal::demote() const { auto f64 = getf64(); - if (std::isnan(f64)) + if (std::isnan(f64)) { return Literal(float(f64)); - if (std::isinf(f64)) + } + if (std::isinf(f64)) { return Literal(float(f64)); + } // when close to the limit, but still truncatable to a valid value, do that // see // https://github.com/WebAssembly/sexpr-wasm-prototype/blob/2d375e8d502327e814d62a08f22da9d9b6b675dc/src/wasm-interpreter.c#L247 uint64_t bits = reinterpreti64(); - if (bits > 0x47efffffe0000000ULL && bits < 0x47effffff0000000ULL) + if (bits > 0x47efffffe0000000ULL && bits < 0x47effffff0000000ULL) { return Literal(std::numeric_limits<float>::max()); - if (bits > 0xc7efffffe0000000ULL && bits < 0xc7effffff0000000ULL) + } + if (bits > 0xc7efffffe0000000ULL && bits < 0xc7effffff0000000ULL) { return Literal(-std::numeric_limits<float>::max()); + } // when we must convert to infinity, do that - if (f64 < -std::numeric_limits<float>::max()) + if (f64 < -std::numeric_limits<float>::max()) { return Literal(-std::numeric_limits<float>::infinity()); - if (f64 > std::numeric_limits<float>::max()) + } + if (f64 > std::numeric_limits<float>::max()) { return Literal(std::numeric_limits<float>::infinity()); + } return Literal(float(getf64())); } @@ -1067,14 +1095,17 @@ Literal Literal::min(const Literal& other) const { switch (type) { case Type::f32: { auto l = getf32(), r = other.getf32(); - if (l == r && l == 0) + if (l == r && l == 0) { return Literal(std::signbit(l) ? l : r); + } auto result = std::min(l, r); bool lnan = std::isnan(l), rnan = std::isnan(r); - if (!std::isnan(result) && !lnan && !rnan) + if (!std::isnan(result) && !lnan && !rnan) { return Literal(result); - if (!lnan && !rnan) + } + if (!lnan && !rnan) { return Literal((int32_t)0x7fc00000).castToF32(); + } return Literal(lnan ? l : r) .castToI32() .or_(Literal(0xc00000)) @@ -1082,14 +1113,17 @@ Literal Literal::min(const Literal& other) const { } case Type::f64: { auto l = getf64(), r = other.getf64(); - if (l == r && l == 0) + if (l == r && l == 0) { return Literal(std::signbit(l) ? l : r); + } auto result = std::min(l, r); bool lnan = std::isnan(l), rnan = std::isnan(r); - if (!std::isnan(result) && !lnan && !rnan) + if (!std::isnan(result) && !lnan && !rnan) { return Literal(result); - if (!lnan && !rnan) + } + if (!lnan && !rnan) { return Literal((int64_t)0x7ff8000000000000LL).castToF64(); + } return Literal(lnan ? l : r) .castToI64() .or_(Literal(int64_t(0x8000000000000LL))) @@ -1104,14 +1138,17 @@ Literal Literal::max(const Literal& other) const { switch (type) { case Type::f32: { auto l = getf32(), r = other.getf32(); - if (l == r && l == 0) + if (l == r && l == 0) { return Literal(std::signbit(l) ? r : l); + } auto result = std::max(l, r); bool lnan = std::isnan(l), rnan = std::isnan(r); - if (!std::isnan(result) && !lnan && !rnan) + if (!std::isnan(result) && !lnan && !rnan) { return Literal(result); - if (!lnan && !rnan) + } + if (!lnan && !rnan) { return Literal((int32_t)0x7fc00000).castToF32(); + } return Literal(lnan ? l : r) .castToI32() .or_(Literal(0xc00000)) @@ -1119,14 +1156,17 @@ Literal Literal::max(const Literal& other) const { } case Type::f64: { auto l = getf64(), r = other.getf64(); - if (l == r && l == 0) + if (l == r && l == 0) { return Literal(std::signbit(l) ? r : l); + } auto result = std::max(l, r); bool lnan = std::isnan(l), rnan = std::isnan(r); - if (!std::isnan(result) && !lnan && !rnan) + if (!std::isnan(result) && !lnan && !rnan) { return Literal(result); - if (!lnan && !rnan) + } + if (!lnan && !rnan) { return Literal((int64_t)0x7ff8000000000000LL).castToF64(); + } return Literal(lnan ? l : r) .castToI64() .or_(Literal(int64_t(0x8000000000000LL))) diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 6369a79fa..81020cf75 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -63,12 +63,15 @@ void WasmBinaryWriter::write() { writeDataCount(); writeFunctions(); writeDataSegments(); - if (debugInfo) + if (debugInfo) { writeNames(); - if (sourceMap && !sourceMapUrl.empty()) + } + if (sourceMap && !sourceMapUrl.empty()) { writeSourceMapUrl(); - if (symbolMap.size() > 0) + } + if (symbolMap.size() > 0) { writeSymbolMap(); + } if (sourceMap) { writeSourceMapEpilog(); @@ -81,8 +84,9 @@ void WasmBinaryWriter::write() { } void WasmBinaryWriter::writeHeader() { - if (debug) + if (debug) { std::cerr << "== writeHeader" << std::endl; + } o << int32_t(BinaryConsts::Magic); // magic number \0asm o << int32_t(BinaryConsts::Version); } @@ -109,8 +113,9 @@ void WasmBinaryWriter::writeResizableLimits(Address initial, template<typename T> int32_t WasmBinaryWriter::startSection(T code) { o << U32LEB(code); - if (sourceMap) + if (sourceMap) { sourceMapLocationsSizeAtSectionStart = sourceMapLocations.size(); + } return writeU32LEBPlaceholder(); // section size to be filled in later } @@ -144,20 +149,24 @@ WasmBinaryWriter::startSubsection(BinaryConsts::UserSections::Subsection code) { void WasmBinaryWriter::finishSubsection(int32_t start) { finishSection(start); } void WasmBinaryWriter::writeStart() { - if (!wasm->start.is()) + if (!wasm->start.is()) { return; - if (debug) + } + if (debug) { std::cerr << "== writeStart" << std::endl; + } auto start = startSection(BinaryConsts::Section::Start); o << U32LEB(getFunctionIndex(wasm->start.str)); finishSection(start); } void WasmBinaryWriter::writeMemory() { - if (!wasm->memory.exists || wasm->memory.imported()) + if (!wasm->memory.exists || wasm->memory.imported()) { return; - if (debug) + } + if (debug) { std::cerr << "== writeMemory" << std::endl; + } auto start = startSection(BinaryConsts::Section::Memory); o << U32LEB(1); // Define 1 memory writeResizableLimits(wasm->memory.initial, @@ -168,15 +177,18 @@ void WasmBinaryWriter::writeMemory() { } void WasmBinaryWriter::writeTypes() { - if (wasm->functionTypes.size() == 0) + if (wasm->functionTypes.size() == 0) { return; - if (debug) + } + if (debug) { std::cerr << "== writeTypes" << std::endl; + } auto start = startSection(BinaryConsts::Section::Type); o << U32LEB(wasm->functionTypes.size()); for (auto& type : wasm->functionTypes) { - if (debug) + if (debug) { std::cerr << "write one" << std::endl; + } o << S32LEB(BinaryConsts::EncodedType::Func); o << U32LEB(type->params.size()); for (auto param : type->params) { @@ -195,18 +207,21 @@ void WasmBinaryWriter::writeTypes() { int32_t WasmBinaryWriter::getFunctionTypeIndex(Name type) { // TODO: optimize for (size_t i = 0; i < wasm->functionTypes.size(); i++) { - if (wasm->functionTypes[i]->name == type) + if (wasm->functionTypes[i]->name == type) { return i; + } } abort(); } void WasmBinaryWriter::writeImports() { auto num = importInfo->getNumImports(); - if (num == 0) + if (num == 0) { return; - if (debug) + } + if (debug) { std::cerr << "== writeImports" << std::endl; + } auto start = startSection(BinaryConsts::Section::Import); o << U32LEB(num); auto writeImportHeader = [&](Importable* import) { @@ -214,23 +229,26 @@ void WasmBinaryWriter::writeImports() { writeInlineString(import->base.str); }; ModuleUtils::iterImportedFunctions(*wasm, [&](Function* func) { - if (debug) + if (debug) { std::cerr << "write one function" << std::endl; + } writeImportHeader(func); o << U32LEB(int32_t(ExternalKind::Function)); o << U32LEB(getFunctionTypeIndex(func->type)); }); ModuleUtils::iterImportedGlobals(*wasm, [&](Global* global) { - if (debug) + if (debug) { std::cerr << "write one global" << std::endl; + } writeImportHeader(global); o << U32LEB(int32_t(ExternalKind::Global)); o << binaryType(global->type); o << U32LEB(global->mutable_); }); if (wasm->memory.imported()) { - if (debug) + if (debug) { std::cerr << "write one memory" << std::endl; + } writeImportHeader(&wasm->memory); o << U32LEB(int32_t(ExternalKind::Memory)); writeResizableLimits(wasm->memory.initial, @@ -239,8 +257,9 @@ void WasmBinaryWriter::writeImports() { wasm->memory.shared); } if (wasm->table.imported()) { - if (debug) + if (debug) { std::cerr << "write one table" << std::endl; + } writeImportHeader(&wasm->table); o << U32LEB(int32_t(ExternalKind::Table)); o << S32LEB(BinaryConsts::EncodedType::AnyFunc); @@ -253,15 +272,18 @@ void WasmBinaryWriter::writeImports() { } void WasmBinaryWriter::writeFunctionSignatures() { - if (importInfo->getNumDefinedFunctions() == 0) + if (importInfo->getNumDefinedFunctions() == 0) { return; - if (debug) + } + if (debug) { std::cerr << "== writeFunctionSignatures" << std::endl; + } auto start = startSection(BinaryConsts::Section::Function); o << U32LEB(importInfo->getNumDefinedFunctions()); ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) { - if (debug) + if (debug) { std::cerr << "write one" << std::endl; + } o << U32LEB(getFunctionTypeIndex(func->type)); }); finishSection(start); @@ -272,35 +294,42 @@ void WasmBinaryWriter::writeExpression(Expression* curr) { } void WasmBinaryWriter::writeFunctions() { - if (importInfo->getNumDefinedFunctions() == 0) + if (importInfo->getNumDefinedFunctions() == 0) { return; - if (debug) + } + if (debug) { std::cerr << "== writeFunctions" << std::endl; + } auto start = startSection(BinaryConsts::Section::Code); o << U32LEB(importInfo->getNumDefinedFunctions()); ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) { size_t sourceMapLocationsSizeAtFunctionStart = sourceMapLocations.size(); - if (debug) + if (debug) { std::cerr << "write one at" << o.size() << std::endl; + } size_t sizePos = writeU32LEBPlaceholder(); size_t start = o.size(); - if (debug) + if (debug) { std::cerr << "writing" << func->name << std::endl; + } // Emit Stack IR if present, and if we can if (func->stackIR && !sourceMap) { - if (debug) + if (debug) { std::cerr << "write Stack IR" << std::endl; + } StackIRFunctionStackWriter<WasmBinaryWriter>(func, *this, o, debug); } else { - if (debug) + if (debug) { std::cerr << "write Binaryen IR" << std::endl; + } FunctionStackWriter<WasmBinaryWriter>(func, *this, o, sourceMap, debug); } size_t size = o.size() - start; assert(size <= std::numeric_limits<uint32_t>::max()); - if (debug) + if (debug) { std::cerr << "body size: " << size << ", writing at " << sizePos << ", next starts at " << o.size() << std::endl; + } auto sizeFieldSize = o.writeAt(sizePos, U32LEB(size)); if (sizeFieldSize != MaxLEB32Bytes) { // we can save some room, nice @@ -323,16 +352,19 @@ void WasmBinaryWriter::writeFunctions() { } void WasmBinaryWriter::writeGlobals() { - if (importInfo->getNumDefinedGlobals() == 0) + if (importInfo->getNumDefinedGlobals() == 0) { return; - if (debug) + } + if (debug) { std::cerr << "== writeglobals" << std::endl; + } auto start = startSection(BinaryConsts::Section::Global); auto num = importInfo->getNumDefinedGlobals(); o << U32LEB(num); ModuleUtils::iterDefinedGlobals(*wasm, [&](Global* global) { - if (debug) + if (debug) { std::cerr << "write one" << std::endl; + } o << binaryType(global->type); o << U32LEB(global->mutable_); writeExpression(global->init); @@ -342,15 +374,18 @@ void WasmBinaryWriter::writeGlobals() { } void WasmBinaryWriter::writeExports() { - if (wasm->exports.size() == 0) + if (wasm->exports.size() == 0) { return; - if (debug) + } + if (debug) { std::cerr << "== writeexports" << std::endl; + } auto start = startSection(BinaryConsts::Section::Export); o << U32LEB(wasm->exports.size()); for (auto& curr : wasm->exports) { - if (debug) + if (debug) { std::cerr << "write one" << std::endl; + } writeInlineString(curr->name.str); o << U32LEB(int32_t(curr->kind)); switch (curr->kind) { @@ -383,8 +418,9 @@ void WasmBinaryWriter::writeDataCount() { } void WasmBinaryWriter::writeDataSegments() { - if (wasm->memory.segments.size() == 0) + if (wasm->memory.segments.size() == 0) { return; + } if (wasm->memory.segments.size() > WebLimitations::MaxDataSegments) { std::cerr << "Some VMs may not accept this binary because it has a large " << "number of data segments. Run the limit-segments pass to " @@ -418,10 +454,12 @@ uint32_t WasmBinaryWriter::getGlobalIndex(Name name) { } void WasmBinaryWriter::writeFunctionTableDeclaration() { - if (!wasm->table.exists || wasm->table.imported()) + if (!wasm->table.exists || wasm->table.imported()) { return; - if (debug) + } + if (debug) { std::cerr << "== writeFunctionTableDeclaration" << std::endl; + } auto start = startSection(BinaryConsts::Section::Table); o << U32LEB(1); // Declare 1 table. o << S32LEB(BinaryConsts::EncodedType::AnyFunc); @@ -436,8 +474,9 @@ void WasmBinaryWriter::writeTableElements() { if (!wasm->table.exists || wasm->table.segments.size() == 0) { return; } - if (debug) + if (debug) { std::cerr << "== writeTableElements" << std::endl; + } auto start = startSection(BinaryConsts::Section::Element); o << U32LEB(wasm->table.segments.size()); @@ -460,10 +499,12 @@ void WasmBinaryWriter::writeNames() { hasContents = true; getFunctionIndex(wasm->functions[0]->name); // generate mappedFunctions } - if (!hasContents) + if (!hasContents) { return; - if (debug) + } + if (debug) { std::cerr << "== writeNames" << std::endl; + } auto start = startSection(BinaryConsts::Section::User); writeInlineString(BinaryConsts::UserSections::Name); auto substart = @@ -484,8 +525,9 @@ void WasmBinaryWriter::writeNames() { } void WasmBinaryWriter::writeSourceMapUrl() { - if (debug) + if (debug) { std::cerr << "== writeSourceMapUrl" << std::endl; + } auto start = startSection(BinaryConsts::Section::User); writeInlineString(BinaryConsts::UserSections::SourceMapUrl); writeInlineString(sourceMapUrl.c_str()); @@ -509,8 +551,9 @@ void WasmBinaryWriter::initializeDebugInfo() { void WasmBinaryWriter::writeSourceMapProlog() { *sourceMap << "{\"version\":3,\"sources\":["; for (size_t i = 0; i < wasm->debugInfoFileNames.size(); i++) { - if (i > 0) + if (i > 0) { *sourceMap << ","; + } // TODO respect JSON string encoding, e.g. quotes and control chars. *sourceMap << "\"" << wasm->debugInfoFileNames[i] << "\""; } @@ -695,20 +738,23 @@ void WasmBinaryWriter::emitBuffer(const char* data, size_t size) { } void WasmBinaryWriter::emitString(const char* str) { - if (debug) + if (debug) { std::cerr << "emitString " << str << std::endl; + } emitBuffer(str, strlen(str) + 1); } void WasmBinaryWriter::finishUp() { - if (debug) + if (debug) { std::cerr << "finishUp" << std::endl; + } // finish buffers for (const auto& buffer : buffersToWrite) { - if (debug) + if (debug) { std::cerr << "writing buffer" << (int)buffer.data[0] << "," << (int)buffer.data[1] << " at " << o.size() << " and pointer is at " << buffer.pointerLocation << std::endl; + } o.writeAt(buffer.pointerLocation, (uint32_t)o.size()); for (size_t i = 0; i < buffer.size; i++) { o << (uint8_t)buffer.data[i]; @@ -727,8 +773,9 @@ void WasmBinaryBuilder::read() { while (more()) { uint32_t sectionCode = getU32LEB(); uint32_t payloadLen = getU32LEB(); - if (pos + payloadLen > input.size()) + if (pos + payloadLen > input.size()) { throwError("Section extends beyond end of input"); + } auto oldPos = pos; @@ -840,129 +887,154 @@ void WasmBinaryBuilder::readUserSection(size_t payloadLen) { } uint8_t WasmBinaryBuilder::getInt8() { - if (!more()) + if (!more()) { throwError("unexpected end of input"); - if (debug) + } + if (debug) { std::cerr << "getInt8: " << (int)(uint8_t)input[pos] << " (at " << pos << ")" << std::endl; + } return input[pos++]; } uint16_t WasmBinaryBuilder::getInt16() { - if (debug) + if (debug) { std::cerr << "<==" << std::endl; + } auto ret = uint16_t(getInt8()); ret |= uint16_t(getInt8()) << 8; - if (debug) + if (debug) { std::cerr << "getInt16: " << ret << "/0x" << std::hex << ret << std::dec << " ==>" << std::endl; + } return ret; } uint32_t WasmBinaryBuilder::getInt32() { - if (debug) + if (debug) { std::cerr << "<==" << std::endl; + } auto ret = uint32_t(getInt16()); ret |= uint32_t(getInt16()) << 16; - if (debug) + if (debug) { std::cerr << "getInt32: " << ret << "/0x" << std::hex << ret << std::dec << " ==>" << std::endl; + } return ret; } uint64_t WasmBinaryBuilder::getInt64() { - if (debug) + if (debug) { std::cerr << "<==" << std::endl; + } auto ret = uint64_t(getInt32()); ret |= uint64_t(getInt32()) << 32; - if (debug) + if (debug) { std::cerr << "getInt64: " << ret << "/0x" << std::hex << ret << std::dec << " ==>" << std::endl; + } return ret; } uint8_t WasmBinaryBuilder::getLaneIndex(size_t lanes) { - if (debug) + if (debug) { std::cerr << "<==" << std::endl; + } auto ret = getInt8(); - if (ret >= lanes) + if (ret >= lanes) { throwError("Illegal lane index"); - if (debug) + } + if (debug) { std::cerr << "getLaneIndex(" << lanes << "): " << ret << " ==>" << std::endl; + } return ret; } Literal WasmBinaryBuilder::getFloat32Literal() { - if (debug) + if (debug) { std::cerr << "<==" << std::endl; + } auto ret = Literal(getInt32()); ret = ret.castToF32(); - if (debug) + if (debug) { std::cerr << "getFloat32: " << ret << " ==>" << std::endl; + } return ret; } Literal WasmBinaryBuilder::getFloat64Literal() { - if (debug) + if (debug) { std::cerr << "<==" << std::endl; + } auto ret = Literal(getInt64()); ret = ret.castToF64(); - if (debug) + if (debug) { std::cerr << "getFloat64: " << ret << " ==>" << std::endl; + } return ret; } Literal WasmBinaryBuilder::getVec128Literal() { - if (debug) + if (debug) { std::cerr << "<==" << std::endl; + } std::array<uint8_t, 16> bytes; for (auto i = 0; i < 16; ++i) { bytes[i] = getInt8(); } auto ret = Literal(bytes.data()); - if (debug) + if (debug) { std::cerr << "getVec128: " << ret << " ==>" << std::endl; + } return ret; } uint32_t WasmBinaryBuilder::getU32LEB() { - if (debug) + if (debug) { std::cerr << "<==" << std::endl; + } U32LEB ret; ret.read([&]() { return getInt8(); }); - if (debug) + if (debug) { std::cerr << "getU32LEB: " << ret.value << " ==>" << std::endl; + } return ret.value; } uint64_t WasmBinaryBuilder::getU64LEB() { - if (debug) + if (debug) { std::cerr << "<==" << std::endl; + } U64LEB ret; ret.read([&]() { return getInt8(); }); - if (debug) + if (debug) { std::cerr << "getU64LEB: " << ret.value << " ==>" << std::endl; + } return ret.value; } int32_t WasmBinaryBuilder::getS32LEB() { - if (debug) + if (debug) { std::cerr << "<==" << std::endl; + } S32LEB ret; ret.read([&]() { return (int8_t)getInt8(); }); - if (debug) + if (debug) { std::cerr << "getS32LEB: " << ret.value << " ==>" << std::endl; + } return ret.value; } int64_t WasmBinaryBuilder::getS64LEB() { - if (debug) + if (debug) { std::cerr << "<==" << std::endl; + } S64LEB ret; ret.read([&]() { return (int8_t)getInt8(); }); - if (debug) + if (debug) { std::cerr << "getS64LEB: " << ret.value << " ==>" << std::endl; + } return ret.value; } @@ -996,8 +1068,9 @@ Type WasmBinaryBuilder::getConcreteType() { } Name WasmBinaryBuilder::getInlineString() { - if (debug) + if (debug) { std::cerr << "<==" << std::endl; + } auto len = getU32LEB(); std::string str; for (size_t i = 0; i < len; i++) { @@ -1009,61 +1082,71 @@ Name WasmBinaryBuilder::getInlineString() { } str = str + curr; } - if (debug) + if (debug) { std::cerr << "getInlineString: " << str << " ==>" << std::endl; + } return Name(str); } void WasmBinaryBuilder::verifyInt8(int8_t x) { int8_t y = getInt8(); - if (x != y) + if (x != y) { throwError("surprising value"); + } } void WasmBinaryBuilder::verifyInt16(int16_t x) { int16_t y = getInt16(); - if (x != y) + if (x != y) { throwError("surprising value"); + } } void WasmBinaryBuilder::verifyInt32(int32_t x) { int32_t y = getInt32(); - if (x != y) + if (x != y) { throwError("surprising value"); + } } void WasmBinaryBuilder::verifyInt64(int64_t x) { int64_t y = getInt64(); - if (x != y) + if (x != y) { throwError("surprising value"); + } } void WasmBinaryBuilder::ungetInt8() { assert(pos > 0); - if (debug) + if (debug) { std::cerr << "ungetInt8 (at " << pos << ")" << std::endl; + } pos--; } void WasmBinaryBuilder::readHeader() { - if (debug) + if (debug) { std::cerr << "== readHeader" << std::endl; + } verifyInt32(BinaryConsts::Magic); verifyInt32(BinaryConsts::Version); } void WasmBinaryBuilder::readStart() { - if (debug) + if (debug) { std::cerr << "== readStart" << std::endl; + } startIndex = getU32LEB(); } void WasmBinaryBuilder::readMemory() { - if (debug) + if (debug) { std::cerr << "== readMemory" << std::endl; + } auto numMemories = getU32LEB(); - if (!numMemories) + if (!numMemories) { return; + } if (numMemories != 1) { throwError("Must be exactly 1 memory"); } @@ -1078,22 +1161,26 @@ void WasmBinaryBuilder::readMemory() { } void WasmBinaryBuilder::readSignatures() { - if (debug) + if (debug) { std::cerr << "== readSignatures" << std::endl; + } size_t numTypes = getU32LEB(); - if (debug) + if (debug) { std::cerr << "num: " << numTypes << std::endl; + } for (size_t i = 0; i < numTypes; i++) { - if (debug) + if (debug) { std::cerr << "read one" << std::endl; + } auto curr = make_unique<FunctionType>(); auto form = getS32LEB(); if (form != BinaryConsts::EncodedType::Func) { throwError("bad signature form " + std::to_string(form)); } size_t numParams = getU32LEB(); - if (debug) + if (debug) { std::cerr << "num params: " << numParams << std::endl; + } for (size_t j = 0; j < numParams; j++) { curr->params.push_back(getConcreteType()); } @@ -1126,25 +1213,30 @@ void WasmBinaryBuilder::getResizableLimits(Address& initial, initial = getU32LEB(); bool hasMax = (flags & BinaryConsts::HasMaximum) != 0; bool isShared = (flags & BinaryConsts::IsShared) != 0; - if (isShared && !hasMax) + if (isShared && !hasMax) { throwError("shared memory must have max size"); + } shared = isShared; - if (hasMax) + if (hasMax) { max = getU32LEB(); - else + } else { max = defaultIfNoMax; + } } void WasmBinaryBuilder::readImports() { - if (debug) + if (debug) { std::cerr << "== readImports" << std::endl; + } size_t num = getU32LEB(); - if (debug) + if (debug) { std::cerr << "num: " << num << std::endl; + } Builder builder(wasm); for (size_t i = 0; i < num; i++) { - if (debug) + if (debug) { std::cerr << "read one" << std::endl; + } auto module = getInlineString(); auto base = getInlineString(); auto kind = (ExternalKind)getU32LEB(); @@ -1176,14 +1268,16 @@ void WasmBinaryBuilder::readImports() { wasm.table.name = Name(std::string("timport$") + std::to_string(i)); auto elementType = getS32LEB(); WASM_UNUSED(elementType); - if (elementType != BinaryConsts::EncodedType::AnyFunc) + if (elementType != BinaryConsts::EncodedType::AnyFunc) { throwError("Imported table type is not AnyFunc"); + } wasm.table.exists = true; bool is_shared; getResizableLimits( wasm.table.initial, wasm.table.max, is_shared, Table::kUnlimitedSize); - if (is_shared) + if (is_shared) { throwError("Tables may not be shared"); + } break; } case ExternalKind::Memory: { @@ -1228,14 +1322,17 @@ void WasmBinaryBuilder::requireFunctionContext(const char* error) { } void WasmBinaryBuilder::readFunctionSignatures() { - if (debug) + if (debug) { std::cerr << "== readFunctionSignatures" << std::endl; + } size_t num = getU32LEB(); - if (debug) + if (debug) { std::cerr << "num: " << num << std::endl; + } for (size_t i = 0; i < num; i++) { - if (debug) + if (debug) { std::cerr << "read one" << std::endl; + } auto index = getU32LEB(); if (index >= wasm.functionTypes.size()) { throwError("invalid function type index for function"); @@ -1245,15 +1342,17 @@ void WasmBinaryBuilder::readFunctionSignatures() { } void WasmBinaryBuilder::readFunctions() { - if (debug) + if (debug) { std::cerr << "== readFunctions" << std::endl; + } size_t total = getU32LEB(); if (total != functionTypes.size()) { throwError("invalid function section size, must equal types"); } for (size_t i = 0; i < total; i++) { - if (debug) + if (debug) { std::cerr << "read one at " << pos << std::endl; + } size_t size = getU32LEB(); if (size == 0) { throwError("empty function size"); @@ -1267,8 +1366,9 @@ void WasmBinaryBuilder::readFunctions() { readNextDebugLocation(); auto type = functionTypes[i]; - if (debug) + if (debug) { std::cerr << "reading " << i << std::endl; + } func->type = type->name; func->result = type->result; for (size_t j = 0; j < type->params.size(); j++) { @@ -1286,8 +1386,9 @@ void WasmBinaryBuilder::readFunctions() { std::swap(func->prologLocation, debugLocation); { // process the function body - if (debug) + if (debug) { std::cerr << "processing function: " << i << std::endl; + } nextLabel = 0; debugLocation.clear(); willBeIgnored = false; @@ -1312,20 +1413,24 @@ void WasmBinaryBuilder::readFunctions() { debugLocation.clear(); functions.push_back(func); } - if (debug) + if (debug) { std::cerr << " end function bodies" << std::endl; + } } void WasmBinaryBuilder::readExports() { - if (debug) + if (debug) { std::cerr << "== readExports" << std::endl; + } size_t num = getU32LEB(); - if (debug) + if (debug) { std::cerr << "num: " << num << std::endl; + } std::set<Name> names; for (size_t i = 0; i < num; i++) { - if (debug) + if (debug) { std::cerr << "read one" << std::endl; + } auto curr = new Export; curr->name = getInlineString(); if (names.count(curr->name) > 0) { @@ -1344,8 +1449,9 @@ static int32_t readBase64VLQ(std::istream& in) { uint32_t shift = 0; while (1) { auto ch = in.get(); - if (ch == EOF) + if (ch == EOF) { throw MapParseException("unexpected EOF in the middle of VLQ"); + } if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch < 'g')) { // last number digit uint32_t digit = ch < 'a' ? ch - 'A' : ch - 'a' + 26; @@ -1365,17 +1471,20 @@ static int32_t readBase64VLQ(std::istream& in) { } void WasmBinaryBuilder::readSourceMapHeader() { - if (!sourceMap) + if (!sourceMap) { return; + } auto skipWhitespace = [&]() { - while (sourceMap->peek() == ' ' || sourceMap->peek() == '\n') + while (sourceMap->peek() == ' ' || sourceMap->peek() == '\n') { sourceMap->get(); + } }; auto maybeReadChar = [&](char expected) { - if (sourceMap->peek() != expected) + if (sourceMap->peek() != expected) { return false; + } sourceMap->get(); return true; }; @@ -1394,13 +1503,15 @@ void WasmBinaryBuilder::readSourceMapHeader() { size_t pos; while (1) { int ch = sourceMap->get(); - if (ch == EOF) + if (ch == EOF) { return false; + } if (ch == '\"') { if (matching) { // we matched a terminating quote. - if (pos == len) + if (pos == len) { break; + } matching = false; } else { matching = true; @@ -1428,8 +1539,9 @@ void WasmBinaryBuilder::readSourceMapHeader() { if (ch == EOF) { throw MapParseException("unexpected EOF in the middle of string"); } - if (ch == '\"') + if (ch == '\"') { break; + } vec.push_back(ch); } } @@ -1473,8 +1585,9 @@ void WasmBinaryBuilder::readSourceMapHeader() { } void WasmBinaryBuilder::readNextDebugLocation() { - if (!sourceMap) + if (!sourceMap) { return; + } while (nextDebugLocation.first && nextDebugLocation.first <= pos) { if (nextDebugLocation.first < pos) { @@ -1523,18 +1636,22 @@ Expression* WasmBinaryBuilder::readExpression() { } void WasmBinaryBuilder::readGlobals() { - if (debug) + if (debug) { std::cerr << "== readGlobals" << std::endl; + } size_t num = getU32LEB(); - if (debug) + if (debug) { std::cerr << "num: " << num << std::endl; + } for (size_t i = 0; i < num; i++) { - if (debug) + if (debug) { std::cerr << "read one" << std::endl; + } auto type = getConcreteType(); auto mutable_ = getU32LEB(); - if (mutable_ & ~1) + if (mutable_ & ~1) { throwError("Global mutability must be 0 or 1"); + } auto* init = readExpression(); wasm.addGlobal( Builder::makeGlobal("global$" + std::to_string(i), @@ -1545,16 +1662,18 @@ void WasmBinaryBuilder::readGlobals() { } void WasmBinaryBuilder::processExpressions() { - if (debug) + if (debug) { std::cerr << "== processExpressions" << std::endl; + } unreachableInTheWasmSense = false; while (1) { Expression* curr; auto ret = readExpression(curr); if (!curr) { lastSeparator = ret; - if (debug) + if (debug) { std::cerr << "== processExpressions finished" << std::endl; + } return; } expressionStack.push_back(curr); @@ -1567,13 +1686,15 @@ void WasmBinaryBuilder::processExpressions() { if (pos == endOfFunction) { throwError("Reached function end without seeing End opcode"); } - if (!more()) + if (!more()) { throwError("unexpected end of input"); + } auto peek = input[pos]; if (peek == BinaryConsts::End || peek == BinaryConsts::Else) { - if (debug) + if (debug) { std::cerr << "== processExpressions finished with unreachable" << std::endl; + } readNextDebugLocation(); lastSeparator = BinaryConsts::ASTNodes(peek); pos++; @@ -1587,8 +1708,9 @@ void WasmBinaryBuilder::processExpressions() { } void WasmBinaryBuilder::skipUnreachableCode() { - if (debug) + if (debug) { std::cerr << "== skipUnreachableCode" << std::endl; + } // preserve the stack, and restore it. it contains the instruction that made // us unreachable, and we can ignore anything after it. things after it may // pop, we want to undo that @@ -1608,8 +1730,9 @@ void WasmBinaryBuilder::skipUnreachableCode() { Expression* curr; auto ret = readExpression(curr); if (!curr) { - if (debug) + if (debug) { std::cerr << "== skipUnreachableCode finished" << std::endl; + } lastSeparator = ret; unreachableInTheWasmSense = false; willBeIgnored = before; @@ -1621,15 +1744,17 @@ void WasmBinaryBuilder::skipUnreachableCode() { } Expression* WasmBinaryBuilder::popExpression() { - if (debug) + if (debug) { std::cerr << "== popExpression" << std::endl; + } if (expressionStack.empty()) { if (unreachableInTheWasmSense) { // in unreachable code, trying to pop past the polymorphic stack // area results in receiving unreachables - if (debug) + if (debug) { std::cerr << "== popping unreachable from polymorphic stack" << std::endl; + } return allocator.alloc<Unreachable>(); } throwError( @@ -1644,8 +1769,9 @@ Expression* WasmBinaryBuilder::popExpression() { Expression* WasmBinaryBuilder::popNonVoidExpression() { auto* ret = popExpression(); - if (ret->type != none) + if (ret->type != none) { return ret; + } // we found a void, so this is stacky code that we must handle carefully Builder builder(wasm); // add elements until we find a non-void @@ -1654,8 +1780,9 @@ Expression* WasmBinaryBuilder::popNonVoidExpression() { while (1) { auto* curr = popExpression(); expressions.push_back(curr); - if (curr->type != none) + if (curr->type != none) { break; + } } auto* block = builder.makeBlock(); while (!expressions.empty()) { @@ -1686,8 +1813,9 @@ Name WasmBinaryBuilder::getGlobalName(Index index) { ModuleUtils::iterImportedGlobals(wasm, add); ModuleUtils::iterDefinedGlobals(wasm, add); } - if (index == Index(-1)) + if (index == Index(-1)) { return Name("null"); // just a force-rebuild + } if (mappedGlobals.count(index) == 0) { throwError("bad global index"); } @@ -1755,15 +1883,17 @@ void WasmBinaryBuilder::processFunctions() { } void WasmBinaryBuilder::readDataCount() { - if (debug) + if (debug) { std::cerr << "== readDataCount" << std::endl; + } hasDataCount = true; dataCount = getU32LEB(); } void WasmBinaryBuilder::readDataSegments() { - if (debug) + if (debug) { std::cerr << "== readDataSegments" << std::endl; + } auto num = getU32LEB(); for (size_t i = 0; i < num; i++) { Memory::Segment curr; @@ -1792,34 +1922,42 @@ void WasmBinaryBuilder::readDataSegments() { } void WasmBinaryBuilder::readFunctionTableDeclaration() { - if (debug) + if (debug) { std::cerr << "== readFunctionTableDeclaration" << std::endl; + } auto numTables = getU32LEB(); - if (numTables != 1) + if (numTables != 1) { throwError("Only 1 table definition allowed in MVP"); - if (wasm.table.exists) + } + if (wasm.table.exists) { throwError("Table cannot be both imported and defined"); + } wasm.table.exists = true; auto elemType = getS32LEB(); - if (elemType != BinaryConsts::EncodedType::AnyFunc) + if (elemType != BinaryConsts::EncodedType::AnyFunc) { throwError("ElementType must be AnyFunc in MVP"); + } bool is_shared; getResizableLimits( wasm.table.initial, wasm.table.max, is_shared, Table::kUnlimitedSize); - if (is_shared) + if (is_shared) { throwError("Tables may not be shared"); + } } void WasmBinaryBuilder::readTableElements() { - if (debug) + if (debug) { std::cerr << "== readTableElements" << std::endl; + } auto numSegments = getU32LEB(); - if (numSegments >= Table::kMaxSize) + if (numSegments >= Table::kMaxSize) { throwError("Too many segments"); + } for (size_t i = 0; i < numSegments; i++) { auto tableIndex = getU32LEB(); - if (tableIndex != 0) + if (tableIndex != 0) { throwError("Table elements must refer to table 0 in MVP"); + } wasm.table.segments.emplace_back(readExpression()); auto& indexSegment = functionTable[i]; @@ -1868,8 +2006,9 @@ static void escapeName(Name& name) { } void WasmBinaryBuilder::readNames(size_t payloadLen) { - if (debug) + if (debug) { std::cerr << "== readNames" << std::endl; + } auto sectionPos = pos; while (pos < sectionPos + payloadLen) { auto nameType = getU32LEB(); @@ -1958,16 +2097,18 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { if (pos == endOfFunction) { throwError("Reached function end without seeing End opcode"); } - if (debug) + if (debug) { std::cerr << "zz recurse into " << ++depth << " at " << pos << std::endl; + } readNextDebugLocation(); std::set<Function::DebugLocation> currDebugLocation; if (debugLocation.size()) { currDebugLocation.insert(*debugLocation.begin()); } uint8_t code = getInt8(); - if (debug) + if (debug) { std::cerr << "readExpression seeing " << (int)code << std::endl; + } switch (code) { case BinaryConsts::Block: visitBlock((curr = allocator.alloc<Block>())->cast<Block>()); @@ -2028,76 +2169,103 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { break; case BinaryConsts::AtomicPrefix: { code = static_cast<uint8_t>(getU32LEB()); - if (maybeVisitLoad(curr, code, /*isAtomic=*/true)) + if (maybeVisitLoad(curr, code, /*isAtomic=*/true)) { break; - if (maybeVisitStore(curr, code, /*isAtomic=*/true)) + } + if (maybeVisitStore(curr, code, /*isAtomic=*/true)) { break; - if (maybeVisitAtomicRMW(curr, code)) + } + if (maybeVisitAtomicRMW(curr, code)) { break; - if (maybeVisitAtomicCmpxchg(curr, code)) + } + if (maybeVisitAtomicCmpxchg(curr, code)) { break; - if (maybeVisitAtomicWait(curr, code)) + } + if (maybeVisitAtomicWait(curr, code)) { break; - if (maybeVisitAtomicNotify(curr, code)) + } + if (maybeVisitAtomicNotify(curr, code)) { break; + } throwError("invalid code after atomic prefix: " + std::to_string(code)); break; } case BinaryConsts::MiscPrefix: { auto opcode = getU32LEB(); - if (maybeVisitTruncSat(curr, opcode)) + if (maybeVisitTruncSat(curr, opcode)) { break; - if (maybeVisitMemoryInit(curr, opcode)) + } + if (maybeVisitMemoryInit(curr, opcode)) { break; - if (maybeVisitDataDrop(curr, opcode)) + } + if (maybeVisitDataDrop(curr, opcode)) { break; - if (maybeVisitMemoryCopy(curr, opcode)) + } + if (maybeVisitMemoryCopy(curr, opcode)) { break; - if (maybeVisitMemoryFill(curr, opcode)) + } + if (maybeVisitMemoryFill(curr, opcode)) { break; + } throwError("invalid code after nontrapping float-to-int prefix: " + std::to_string(opcode)); break; } case BinaryConsts::SIMDPrefix: { auto opcode = getU32LEB(); - if (maybeVisitSIMDBinary(curr, opcode)) + if (maybeVisitSIMDBinary(curr, opcode)) { break; - if (maybeVisitSIMDUnary(curr, opcode)) + } + if (maybeVisitSIMDUnary(curr, opcode)) { break; - if (maybeVisitSIMDConst(curr, opcode)) + } + if (maybeVisitSIMDConst(curr, opcode)) { break; - if (maybeVisitSIMDLoad(curr, opcode)) + } + if (maybeVisitSIMDLoad(curr, opcode)) { break; - if (maybeVisitSIMDStore(curr, opcode)) + } + if (maybeVisitSIMDStore(curr, opcode)) { break; - if (maybeVisitSIMDExtract(curr, opcode)) + } + if (maybeVisitSIMDExtract(curr, opcode)) { break; - if (maybeVisitSIMDReplace(curr, opcode)) + } + if (maybeVisitSIMDReplace(curr, opcode)) { break; - if (maybeVisitSIMDShuffle(curr, opcode)) + } + if (maybeVisitSIMDShuffle(curr, opcode)) { break; - if (maybeVisitSIMDBitselect(curr, opcode)) + } + if (maybeVisitSIMDBitselect(curr, opcode)) { break; - if (maybeVisitSIMDShift(curr, opcode)) + } + if (maybeVisitSIMDShift(curr, opcode)) { break; + } throwError("invalid code after SIMD prefix: " + std::to_string(opcode)); break; } default: { // otherwise, the code is a subcode TODO: optimize - if (maybeVisitBinary(curr, code)) + if (maybeVisitBinary(curr, code)) { break; - if (maybeVisitUnary(curr, code)) + } + if (maybeVisitUnary(curr, code)) { break; - if (maybeVisitConst(curr, code)) + } + if (maybeVisitConst(curr, code)) { break; - if (maybeVisitLoad(curr, code, /*isAtomic=*/false)) + } + if (maybeVisitLoad(curr, code, /*isAtomic=*/false)) { break; - if (maybeVisitStore(curr, code, /*isAtomic=*/false)) + } + if (maybeVisitStore(curr, code, /*isAtomic=*/false)) { break; - if (maybeVisitHost(curr, code)) + } + if (maybeVisitHost(curr, code)) { break; + } throwError("bad node code " + std::to_string(code)); break; } @@ -2105,8 +2273,9 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { if (curr && currDebugLocation.size()) { currFunction->debugLocations[curr] = *currDebugLocation.begin(); } - if (debug) + if (debug) { std::cerr << "zz recurse from " << depth-- << " at " << pos << std::endl; + } return BinaryConsts::ASTNodes(code); } @@ -2153,8 +2322,9 @@ void WasmBinaryBuilder::pushBlockElements(Block* curr, } void WasmBinaryBuilder::visitBlock(Block* curr) { - if (debug) + if (debug) { std::cerr << "zz node: Block" << std::endl; + } // special-case Block and de-recurse nested blocks in their first position, as // that is a common pattern that can be very highly nested. std::vector<Block*> stack; @@ -2228,8 +2398,9 @@ Expression* WasmBinaryBuilder::getBlockOrSingleton(Type type) { } void WasmBinaryBuilder::visitIf(If* curr) { - if (debug) + if (debug) { std::cerr << "zz node: If" << std::endl; + } curr->type = getType(); curr->condition = popNonVoidExpression(); curr->ifTrue = getBlockOrSingleton(curr->type); @@ -2243,8 +2414,9 @@ void WasmBinaryBuilder::visitIf(If* curr) { } void WasmBinaryBuilder::visitLoop(Loop* curr) { - if (debug) + if (debug) { std::cerr << "zz node: Loop" << std::endl; + } curr->type = getType(); curr->name = getNextLabel(); breakStack.push_back({curr->name, 0}); @@ -2274,8 +2446,9 @@ void WasmBinaryBuilder::visitLoop(Loop* curr) { WasmBinaryBuilder::BreakTarget WasmBinaryBuilder::getBreakTarget(int32_t offset) { - if (debug) + if (debug) { std::cerr << "getBreakTarget " << offset << std::endl; + } if (breakStack.size() < 1 + size_t(offset)) { throwError("bad breakindex (low)"); } @@ -2283,9 +2456,10 @@ WasmBinaryBuilder::getBreakTarget(int32_t offset) { if (index >= breakStack.size()) { throwError("bad breakindex (high)"); } - if (debug) + if (debug) { std::cerr << "breaktarget " << breakStack[index].name << " arity " << breakStack[index].arity << std::endl; + } auto& ret = breakStack[index]; // if the break is in literally unreachable code, then we will not emit it // anyhow, so do not note that the target has breaks to it @@ -2296,39 +2470,47 @@ WasmBinaryBuilder::getBreakTarget(int32_t offset) { } void WasmBinaryBuilder::visitBreak(Break* curr, uint8_t code) { - if (debug) + if (debug) { std::cerr << "zz node: Break, code " << int32_t(code) << std::endl; + } BreakTarget target = getBreakTarget(getU32LEB()); curr->name = target.name; - if (code == BinaryConsts::BrIf) + if (code == BinaryConsts::BrIf) { curr->condition = popNonVoidExpression(); - if (target.arity) + } + if (target.arity) { curr->value = popNonVoidExpression(); + } curr->finalize(); } void WasmBinaryBuilder::visitSwitch(Switch* curr) { - if (debug) + if (debug) { std::cerr << "zz node: Switch" << std::endl; + } curr->condition = popNonVoidExpression(); auto numTargets = getU32LEB(); - if (debug) + if (debug) { std::cerr << "targets: " << numTargets << std::endl; + } for (size_t i = 0; i < numTargets; i++) { curr->targets.push_back(getBreakTarget(getU32LEB()).name); } auto defaultTarget = getBreakTarget(getU32LEB()); curr->default_ = defaultTarget.name; - if (debug) + if (debug) { std::cerr << "default: " << curr->default_ << std::endl; - if (defaultTarget.arity) + } + if (defaultTarget.arity) { curr->value = popNonVoidExpression(); + } curr->finalize(); } void WasmBinaryBuilder::visitCall(Call* curr) { - if (debug) + if (debug) { std::cerr << "zz node: Call" << std::endl; + } auto index = getU32LEB(); FunctionType* type; if (index < functionImports.size()) { @@ -2353,16 +2535,18 @@ void WasmBinaryBuilder::visitCall(Call* curr) { } void WasmBinaryBuilder::visitCallIndirect(CallIndirect* curr) { - if (debug) + if (debug) { std::cerr << "zz node: CallIndirect" << std::endl; + } auto index = getU32LEB(); if (index >= wasm.functionTypes.size()) { throwError("bad call_indirect function index"); } auto* fullType = wasm.functionTypes[index].get(); auto reserved = getU32LEB(); - if (reserved != 0) + if (reserved != 0) { throwError("Invalid flags field in call_indirect"); + } curr->fullType = fullType->name; auto num = fullType->params.size(); curr->operands.resize(num); @@ -2375,8 +2559,9 @@ void WasmBinaryBuilder::visitCallIndirect(CallIndirect* curr) { } void WasmBinaryBuilder::visitGetLocal(GetLocal* curr) { - if (debug) + if (debug) { std::cerr << "zz node: GetLocal " << pos << std::endl; + } requireFunctionContext("local.get"); curr->index = getU32LEB(); if (curr->index >= currFunction->getNumLocals()) { @@ -2387,8 +2572,9 @@ void WasmBinaryBuilder::visitGetLocal(GetLocal* curr) { } void WasmBinaryBuilder::visitSetLocal(SetLocal* curr, uint8_t code) { - if (debug) + if (debug) { std::cerr << "zz node: Set|TeeLocal" << std::endl; + } requireFunctionContext("local.set outside of function"); curr->index = getU32LEB(); if (curr->index >= currFunction->getNumLocals()) { @@ -2401,16 +2587,18 @@ void WasmBinaryBuilder::visitSetLocal(SetLocal* curr, uint8_t code) { } void WasmBinaryBuilder::visitGetGlobal(GetGlobal* curr) { - if (debug) + if (debug) { std::cerr << "zz node: GetGlobal " << pos << std::endl; + } auto index = getU32LEB(); curr->name = getGlobalName(index); curr->type = wasm.getGlobal(curr->name)->type; } void WasmBinaryBuilder::visitSetGlobal(SetGlobal* curr) { - if (debug) + if (debug) { std::cerr << "zz node: SetGlobal" << std::endl; + } auto index = getU32LEB(); curr->name = getGlobalName(index); curr->value = popNonVoidExpression(); @@ -2419,8 +2607,9 @@ void WasmBinaryBuilder::visitSetGlobal(SetGlobal* curr) { void WasmBinaryBuilder::readMemoryAccess(Address& alignment, Address& offset) { auto rawAlignment = getU32LEB(); - if (rawAlignment > 4) + if (rawAlignment > 4) { throwError("Alignment must be of a reasonable size"); + } alignment = Pow2(rawAlignment); offset = getU32LEB(); } @@ -2514,8 +2703,9 @@ bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out, default: return false; } - if (debug) + if (debug) { std::cerr << "zz node: Load" << std::endl; + } } else { switch (code) { case BinaryConsts::I32AtomicLoad8U: @@ -2557,8 +2747,9 @@ bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out, return false; } curr->signed_ = false; - if (debug) + if (debug) { std::cerr << "zz node: AtomicLoad" << std::endl; + } } curr->isAtomic = isAtomic; @@ -2666,8 +2857,9 @@ bool WasmBinaryBuilder::maybeVisitStore(Expression*& out, } curr->isAtomic = isAtomic; - if (debug) + if (debug) { std::cerr << "zz node: Store" << std::endl; + } readMemoryAccess(curr->align, curr->offset); curr->value = popNonVoidExpression(); curr->ptr = popNonVoidExpression(); @@ -2678,8 +2870,9 @@ bool WasmBinaryBuilder::maybeVisitStore(Expression*& out, bool WasmBinaryBuilder::maybeVisitAtomicRMW(Expression*& out, uint8_t code) { if (code < BinaryConsts::AtomicRMWOps_Begin || - code > BinaryConsts::AtomicRMWOps_End) + code > BinaryConsts::AtomicRMWOps_End) { return false; + } auto* curr = allocator.alloc<AtomicRMW>(); // Set curr to the given opcode, type and size. @@ -2725,12 +2918,14 @@ bool WasmBinaryBuilder::maybeVisitAtomicRMW(Expression*& out, uint8_t code) { #undef SET_FOR_OP #undef SET - if (debug) + if (debug) { std::cerr << "zz node: AtomicRMW" << std::endl; + } Address readAlign; readMemoryAccess(readAlign, curr->offset); - if (readAlign != curr->bytes) + if (readAlign != curr->bytes) { throwError("Align of AtomicRMW must match size"); + } curr->value = popNonVoidExpression(); curr->ptr = popNonVoidExpression(); curr->finalize(); @@ -2741,8 +2936,9 @@ bool WasmBinaryBuilder::maybeVisitAtomicRMW(Expression*& out, uint8_t code) { bool WasmBinaryBuilder::maybeVisitAtomicCmpxchg(Expression*& out, uint8_t code) { if (code < BinaryConsts::AtomicCmpxchgOps_Begin || - code > BinaryConsts::AtomicCmpxchgOps_End) + code > BinaryConsts::AtomicCmpxchgOps_End) { return false; + } auto* curr = allocator.alloc<AtomicCmpxchg>(); // Set curr to the given type and size. @@ -2776,12 +2972,14 @@ bool WasmBinaryBuilder::maybeVisitAtomicCmpxchg(Expression*& out, WASM_UNREACHABLE(); } - if (debug) + if (debug) { std::cerr << "zz node: AtomicCmpxchg" << std::endl; + } Address readAlign; readMemoryAccess(readAlign, curr->offset); - if (readAlign != curr->bytes) + if (readAlign != curr->bytes) { throwError("Align of AtomicCpxchg must match size"); + } curr->replacement = popNonVoidExpression(); curr->expected = popNonVoidExpression(); curr->ptr = popNonVoidExpression(); @@ -2791,8 +2989,10 @@ bool WasmBinaryBuilder::maybeVisitAtomicCmpxchg(Expression*& out, } bool WasmBinaryBuilder::maybeVisitAtomicWait(Expression*& out, uint8_t code) { - if (code < BinaryConsts::I32AtomicWait || code > BinaryConsts::I64AtomicWait) + if (code < BinaryConsts::I32AtomicWait || + code > BinaryConsts::I64AtomicWait) { return false; + } auto* curr = allocator.alloc<AtomicWait>(); switch (code) { @@ -2806,34 +3006,39 @@ bool WasmBinaryBuilder::maybeVisitAtomicWait(Expression*& out, uint8_t code) { WASM_UNREACHABLE(); } curr->type = i32; - if (debug) + if (debug) { std::cerr << "zz node: AtomicWait" << std::endl; + } curr->timeout = popNonVoidExpression(); curr->expected = popNonVoidExpression(); curr->ptr = popNonVoidExpression(); Address readAlign; readMemoryAccess(readAlign, curr->offset); - if (readAlign != getTypeSize(curr->expectedType)) + if (readAlign != getTypeSize(curr->expectedType)) { throwError("Align of AtomicWait must match size"); + } curr->finalize(); out = curr; return true; } bool WasmBinaryBuilder::maybeVisitAtomicNotify(Expression*& out, uint8_t code) { - if (code != BinaryConsts::AtomicNotify) + if (code != BinaryConsts::AtomicNotify) { return false; + } auto* curr = allocator.alloc<AtomicNotify>(); - if (debug) + if (debug) { std::cerr << "zz node: AtomicNotify" << std::endl; + } curr->type = i32; curr->notifyCount = popNonVoidExpression(); curr->ptr = popNonVoidExpression(); Address readAlign; readMemoryAccess(readAlign, curr->offset); - if (readAlign != getTypeSize(curr->type)) + if (readAlign != getTypeSize(curr->type)) { throwError("Align of AtomicNotify must match size"); + } curr->finalize(); out = curr; return true; @@ -2841,8 +3046,9 @@ bool WasmBinaryBuilder::maybeVisitAtomicNotify(Expression*& out, uint8_t code) { bool WasmBinaryBuilder::maybeVisitConst(Expression*& out, uint8_t code) { Const* curr; - if (debug) + if (debug) { std::cerr << "zz node: Const, code " << code << std::endl; + } switch (code) { case BinaryConsts::I32Const: curr = allocator.alloc<Const>(); @@ -3089,8 +3295,9 @@ bool WasmBinaryBuilder::maybeVisitUnary(Expression*& out, uint8_t code) { default: return false; } - if (debug) + if (debug) { std::cerr << "zz node: Unary" << std::endl; + } curr->value = popNonVoidExpression(); curr->finalize(); out = curr; @@ -3135,8 +3342,9 @@ bool WasmBinaryBuilder::maybeVisitTruncSat(Expression*& out, uint32_t code) { default: return false; } - if (debug) + if (debug) { std::cerr << "zz node: Unary (nontrapping float-to-int)" << std::endl; + } curr->value = popNonVoidExpression(); curr->finalize(); out = curr; @@ -3270,8 +3478,9 @@ bool WasmBinaryBuilder::maybeVisitBinary(Expression*& out, uint8_t code) { default: return false; } - if (debug) + if (debug) { std::cerr << "zz node: Binary" << std::endl; + } curr->right = popNonVoidExpression(); curr->left = popNonVoidExpression(); curr->finalize(); @@ -3592,8 +3801,9 @@ bool WasmBinaryBuilder::maybeVisitSIMDBinary(Expression*& out, uint32_t code) { default: return false; } - if (debug) + if (debug) { std::cerr << "zz node: Binary" << std::endl; + } curr->right = popNonVoidExpression(); curr->left = popNonVoidExpression(); curr->finalize(); @@ -3972,8 +4182,9 @@ bool WasmBinaryBuilder::maybeVisitSIMDShift(Expression*& out, uint32_t code) { } void WasmBinaryBuilder::visitSelect(Select* curr) { - if (debug) + if (debug) { std::cerr << "zz node: Select" << std::endl; + } curr->condition = popNonVoidExpression(); curr->ifFalse = popNonVoidExpression(); curr->ifTrue = popNonVoidExpression(); @@ -3981,8 +4192,9 @@ void WasmBinaryBuilder::visitSelect(Select* curr) { } void WasmBinaryBuilder::visitReturn(Return* curr) { - if (debug) + if (debug) { std::cerr << "zz node: Return" << std::endl; + } requireFunctionContext("return"); if (currFunction->result != none) { curr->value = popNonVoidExpression(); @@ -4008,29 +4220,34 @@ bool WasmBinaryBuilder::maybeVisitHost(Expression*& out, uint8_t code) { default: return false; } - if (debug) + if (debug) { std::cerr << "zz node: Host" << std::endl; + } auto reserved = getU32LEB(); - if (reserved != 0) + if (reserved != 0) { throwError("Invalid reserved field on grow_memory/current_memory"); + } curr->finalize(); out = curr; return true; } void WasmBinaryBuilder::visitNop(Nop* curr) { - if (debug) + if (debug) { std::cerr << "zz node: Nop" << std::endl; + } } void WasmBinaryBuilder::visitUnreachable(Unreachable* curr) { - if (debug) + if (debug) { std::cerr << "zz node: Unreachable" << std::endl; + } } void WasmBinaryBuilder::visitDrop(Drop* curr) { - if (debug) + if (debug) { std::cerr << "zz node: Drop" << std::endl; + } curr->value = popNonVoidExpression(); curr->finalize(); } diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index a6a84a974..453780720 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -86,8 +86,9 @@ Expression* EmscriptenGlueGenerator::generateLoadStackPointer() { /* type =*/i32); } Global* stackPointer = getStackPointerGlobal(); - if (!stackPointer) + if (!stackPointer) { Fatal() << "stack pointer global not found"; + } return builder.makeGetGlobal(stackPointer->name, i32); } @@ -103,8 +104,9 @@ EmscriptenGlueGenerator::generateStoreStackPointer(Expression* value) { /* type =*/i32); } Global* stackPointer = getStackPointerGlobal(); - if (!stackPointer) + if (!stackPointer) { Fatal() << "stack pointer global not found"; + } return builder.makeSetGlobal(stackPointer->name, value); } @@ -312,8 +314,9 @@ Function* EmscriptenGlueGenerator::generateMemoryGrowthFunction() { void EmscriptenGlueGenerator::generateStackInitialization(Address addr) { auto* stackPointer = getStackPointerGlobal(); assert(!stackPointer->imported()); - if (!stackPointer->init || !stackPointer->init->is<Const>()) + if (!stackPointer->init || !stackPointer->init->is<Const>()) { Fatal() << "stack pointer global is not assignable"; + } stackPointer->init->cast<Const>()->value = Literal(int32_t(addr)); } @@ -322,8 +325,9 @@ inline void exportFunction(Module& wasm, Name name, bool must_export) { assert(!must_export); return; } - if (wasm.getExportOrNull(name)) + if (wasm.getExportOrNull(name)) { return; // Already exported + } auto exp = new Export; exp->name = exp->value = name; exp->kind = ExternalKind::Function; @@ -350,8 +354,9 @@ void EmscriptenGlueGenerator::generateDynCallThunks() { std::vector<NameType> params; params.emplace_back("fptr", i32); // function pointer param int p = 0; - for (const auto& ty : funcType->params) + for (const auto& ty : funcType->params) { params.emplace_back(std::to_string(p++), ty); + } Function* f = builder.makeFunction(name, std::move(params), funcType->result, {}); Expression* fptr = builder.makeGetLocal(0, i32); @@ -373,8 +378,9 @@ struct RemoveStackPointer : public PostWalker<RemoveStackPointer> { void visitGetGlobal(GetGlobal* curr) { if (getModule()->getGlobalOrNull(curr->name) == stackPointer) { needStackSave = true; - if (!builder) + if (!builder) { builder = make_unique<Builder>(*getModule()); + } replaceCurrent(builder->makeCall(STACK_SAVE, {}, i32)); } } @@ -382,8 +388,9 @@ struct RemoveStackPointer : public PostWalker<RemoveStackPointer> { void visitSetGlobal(SetGlobal* curr) { if (getModule()->getGlobalOrNull(curr->name) == stackPointer) { needStackRestore = true; - if (!builder) + if (!builder) { builder = make_unique<Builder>(*getModule()); + } replaceCurrent(builder->makeCall(STACK_RESTORE, {curr->value}, none)); } } @@ -398,8 +405,9 @@ private: void EmscriptenGlueGenerator::replaceStackPointerGlobal() { Global* stackPointer = getStackPointerGlobal(); - if (!stackPointer) + if (!stackPointer) { return; + } // Replace all uses of stack pointer global RemoveStackPointer walker(stackPointer); @@ -796,8 +804,9 @@ struct FixInvokeFunctionNamesWalker } static Name fixEmEHSjLjNames(const Name& name, const std::string& sig) { - if (name == "emscripten_longjmp_jmpbuf") + if (name == "emscripten_longjmp_jmpbuf") { return "emscripten_longjmp"; + } return fixEmExceptionInvoke(name, sig); } @@ -840,10 +849,11 @@ template<class C> void printSet(std::ostream& o, C& c) { o << "["; bool first = true; for (auto& item : c) { - if (first) + if (first) { first = false; - else + } else { o << ","; + } o << '"' << item << '"'; } o << "]"; diff --git a/src/wasm/wasm-io.cpp b/src/wasm/wasm-io.cpp index 1bdb76d5f..90df2de12 100644 --- a/src/wasm/wasm-io.cpp +++ b/src/wasm/wasm-io.cpp @@ -37,8 +37,9 @@ static void readTextData(std::string& input, Module& wasm) { } void ModuleReader::readText(std::string filename, Module& wasm) { - if (debug) + if (debug) { std::cerr << "reading text from " << filename << "\n"; + } auto input(read_file<std::string>( filename, Flags::Text, debug ? Flags::Debug : Flags::Release)); readTextData(input, wasm); @@ -64,8 +65,9 @@ static void readBinaryData(std::vector<char>& input, void ModuleReader::readBinary(std::string filename, Module& wasm, std::string sourceMapFilename) { - if (debug) + if (debug) { std::cerr << "reading binary from " << filename << "\n"; + } auto input(read_file<std::vector<char>>( filename, Flags::Binary, debug ? Flags::Debug : Flags::Release)); readBinaryData(input, wasm, sourceMapFilename, debug); @@ -123,8 +125,9 @@ void ModuleWriter::writeText(Module& wasm, Output& output) { } void ModuleWriter::writeText(Module& wasm, std::string filename) { - if (debug) + if (debug) { std::cerr << "writing text to " << filename << "\n"; + } Output output(filename, Flags::Text, debug ? Flags::Debug : Flags::Release); writeText(wasm, output); } @@ -140,8 +143,9 @@ void ModuleWriter::writeBinary(Module& wasm, Output& output) { sourceMapStream->open(sourceMapFilename); writer.setSourceMap(sourceMapStream.get(), sourceMapUrl); } - if (symbolMap.size() > 0) + if (symbolMap.size() > 0) { writer.setSymbolMap(symbolMap); + } writer.write(); buffer.writeTo(output); if (sourceMapStream) { @@ -150,8 +154,9 @@ void ModuleWriter::writeBinary(Module& wasm, Output& output) { } void ModuleWriter::writeBinary(Module& wasm, std::string filename) { - if (debug) + if (debug) { std::cerr << "writing binary to " << filename << "\n"; + } Output output(filename, Flags::Binary, debug ? Flags::Debug : Flags::Release); writeBinary(wasm, output); } diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index bb498329f..cd9eb690a 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -37,12 +37,15 @@ using cashew::IString; namespace { int unhex(char c) { - if (c >= '0' && c <= '9') + if (c >= '0' && c <= '9') { return c - '0'; - if (c >= 'a' && c <= 'f') + } + if (c >= 'a' && c <= 'f') { return c - 'a' + 10; - if (c >= 'A' && c <= 'F') + } + if (c >= 'A' && c <= 'F') { return c - 'A' + 10; + } throw wasm::ParseException("invalid hexadecimal"); } } // namespace @@ -58,28 +61,33 @@ static Address getCheckedAddress(const Element* s, const char* errorText) { } Element::List& Element::list() { - if (!isList()) + if (!isList()) { throw ParseException("expected list", line, col); + } return list_; } Element* Element::operator[](unsigned i) { - if (!isList()) + if (!isList()) { throw ParseException("expected list", line, col); - if (i >= list().size()) + } + if (i >= list().size()) { throw ParseException("expected more elements in list", line, col); + } return list()[i]; } IString Element::str() const { - if (!isStr()) + if (!isStr()) { throw ParseException("expected string", line, col); + } return str_; } const char* Element::c_str() const { - if (!isStr()) + if (!isStr()) { throw ParseException("expected string", line, col); + } return str_.str; } @@ -102,8 +110,9 @@ Element::setMetadata(size_t line_, size_t col_, SourceLocation* startLoc_) { std::ostream& operator<<(std::ostream& o, Element& e) { if (e.isList_) { o << '('; - for (auto item : e.list_) + for (auto item : e.list_) { o << ' ' << *item; + } o << " )"; } else { o << e.str_.str; @@ -130,8 +139,9 @@ Element* SExpressionParser::parse() { Element* curr = allocator.alloc<Element>(); while (1) { skipWhitespace(); - if (input[0] == 0) + if (input[0] == 0) { break; + } if (input[0] == '(') { input++; stack.push_back(curr); @@ -156,29 +166,34 @@ Element* SExpressionParser::parse() { curr->list().push_back(parseString()); } } - if (stack.size() != 0) + if (stack.size() != 0) { throw ParseException("stack is not empty", curr->line, curr->col); + } return curr; } void SExpressionParser::parseDebugLocation() { // Extracting debug location (if valid) char* debugLoc = input + 3; // skipping ";;@" - while (debugLoc[0] && debugLoc[0] == ' ') + while (debugLoc[0] && debugLoc[0] == ' ') { debugLoc++; + } char* debugLocEnd = debugLoc; - while (debugLocEnd[0] && debugLocEnd[0] != '\n') + while (debugLocEnd[0] && debugLocEnd[0] != '\n') { debugLocEnd++; + } char* pos = debugLoc; - while (pos < debugLocEnd && pos[0] != ':') + while (pos < debugLocEnd && pos[0] != ':') { pos++; + } if (pos >= debugLocEnd) { return; // no line number } std::string name(debugLoc, pos); char* lineStart = ++pos; - while (pos < debugLocEnd && pos[0] != ':') + while (pos < debugLocEnd && pos[0] != ':') { pos++; + } std::string lineStr(lineStart, pos); if (pos >= debugLocEnd) { return; // no column number @@ -203,19 +218,22 @@ void SExpressionParser::skipWhitespace() { if (input[2] == '@') { parseDebugLocation(); } - while (input[0] && input[0] != '\n') + while (input[0] && input[0] != '\n') { input++; + } line++; - if (!input[0]) + if (!input[0]) { return; + } lineStart = ++input; } else if (input[0] == '(' && input[1] == ';') { // Skip nested block comments. input += 2; int depth = 1; while (1) { - if (!input[0]) + if (!input[0]) { return; + } if (input[0] == '(' && input[1] == ';') { input += 2; depth++; @@ -252,15 +270,18 @@ Element* SExpressionParser::parseString() { input++; std::string str; while (1) { - if (input[0] == 0) + if (input[0] == 0) { throw ParseException("unterminated string", line, start - lineStart); - if (input[0] == '"') + } + if (input[0] == '"') { break; + } if (input[0] == '\\') { str += input[0]; - if (input[1] == 0) + if (input[1] == 0) { throw ParseException( "unterminated string escape", line, start - lineStart); + } str += input[1]; input += 2; continue; @@ -274,10 +295,12 @@ Element* SExpressionParser::parseString() { ->setMetadata(line, start - lineStart, loc); } while (input[0] && !isspace(input[0]) && input[0] != ')' && input[0] != '(' && - input[0] != ';') + input[0] != ';') { input++; - if (start == input) + } + if (start == input) { throw ParseException("expected string", line, input - lineStart); + } char temp = input[0]; input[0] = 0; auto ret = allocator.alloc<Element>() @@ -291,12 +314,15 @@ SExpressionWasmBuilder::SExpressionWasmBuilder(Module& wasm, Element& module, Name* moduleName) : wasm(wasm), allocator(wasm.allocator) { - if (module.size() == 0) + if (module.size() == 0) { throw ParseException("empty toplevel, expected module"); - if (module[0]->str() != MODULE) + } + if (module[0]->str() != MODULE) { throw ParseException("toplevel does not start with module"); - if (module.size() == 1) + } + if (module.size() == 1) { return; + } Index i = 1; if (module[i]->dollared()) { if (moduleName) { @@ -338,55 +364,69 @@ SExpressionWasmBuilder::SExpressionWasmBuilder(Module& wasm, bool SExpressionWasmBuilder::isImport(Element& curr) { for (Index i = 0; i < curr.size(); i++) { auto& x = *curr[i]; - if (x.isList() && x.size() > 0 && x[0]->isStr() && x[0]->str() == IMPORT) + if (x.isList() && x.size() > 0 && x[0]->isStr() && x[0]->str() == IMPORT) { return true; + } } return false; } void SExpressionWasmBuilder::preParseImports(Element& curr) { IString id = curr[0]->str(); - if (id == IMPORT) + if (id == IMPORT) { parseImport(curr); + } if (isImport(curr)) { - if (id == FUNC) + if (id == FUNC) { parseFunction(curr, true /* preParseImport */); - else if (id == GLOBAL) + } else if (id == GLOBAL) { parseGlobal(curr, true /* preParseImport */); - else if (id == TABLE) + } else if (id == TABLE) { parseTable(curr, true /* preParseImport */); - else if (id == MEMORY) + } else if (id == MEMORY) { parseMemory(curr, true /* preParseImport */); - else + } else { throw ParseException( "fancy import we don't support yet", curr.line, curr.col); + } } } void SExpressionWasmBuilder::parseModuleElement(Element& curr) { - if (isImport(curr)) + if (isImport(curr)) { return; // already done + } IString id = curr[0]->str(); - if (id == START) + if (id == START) { return parseStart(curr); - if (id == FUNC) + } + if (id == FUNC) { return parseFunction(curr); - if (id == MEMORY) + } + if (id == MEMORY) { return parseMemory(curr); - if (id == DATA) + } + if (id == DATA) { return parseData(curr); - if (id == EXPORT) + } + if (id == EXPORT) { return parseExport(curr); - if (id == IMPORT) + } + if (id == IMPORT) { return; // already done - if (id == GLOBAL) + } + if (id == GLOBAL) { return parseGlobal(curr); - if (id == TABLE) + } + if (id == TABLE) { return parseTable(curr); - if (id == ELEM) + } + if (id == ELEM) { return parseElem(curr); - if (id == TYPE) + } + if (id == TYPE) { return; // already done + } std::cerr << "bad module element " << id.str << '\n'; throw ParseException("unknown module element", curr.line, curr.col); } @@ -397,8 +437,9 @@ Name SExpressionWasmBuilder::getFunctionName(Element& s) { } else { // index size_t offset = atoi(s.str().c_str()); - if (offset >= functionNames.size()) + if (offset >= functionNames.size()) { throw ParseException("unknown function in getFunctionName"); + } return functionNames[offset]; } } @@ -409,8 +450,9 @@ Name SExpressionWasmBuilder::getFunctionTypeName(Element& s) { } else { // index size_t offset = atoi(s.str().c_str()); - if (offset >= functionTypeNames.size()) + if (offset >= functionTypeNames.size()) { throw ParseException("unknown function type in getFunctionTypeName"); + } return functionTypeNames[offset]; } } @@ -421,18 +463,21 @@ Name SExpressionWasmBuilder::getGlobalName(Element& s) { } else { // index size_t offset = atoi(s.str().c_str()); - if (offset >= globalNames.size()) + if (offset >= globalNames.size()) { throw ParseException("unknown global in getGlobalName"); + } return globalNames[offset]; } } void SExpressionWasmBuilder::preParseFunctionType(Element& s) { IString id = s[0]->str(); - if (id == TYPE) + if (id == TYPE) { return parseType(s); - if (id != FUNC) + } + if (id != FUNC) { return; + } size_t i = 1; Name name, exportName; i = parseFunctionNames(s, name, exportName); @@ -449,13 +494,15 @@ void SExpressionWasmBuilder::preParseFunctionType(Element& s) { Element& curr = *s[i]; IString id = curr[0]->str(); if (id == RESULT) { - if (curr.size() > 2) + if (curr.size() > 2) { throw ParseException("invalid result arity", curr.line, curr.col); + } functionTypes[name] = stringToType(curr[1]->str()); } else if (id == TYPE) { Name typeName = getFunctionTypeName(*curr[1]); - if (!wasm.getFunctionTypeOrNull(typeName)) + if (!wasm.getFunctionTypeOrNull(typeName)) { throw ParseException("unknown function type", curr.line, curr.col); + } type = wasm.getFunctionType(typeName); functionTypes[name] = type->result; } else if (id == PARAM && curr.size() > 1) { @@ -487,8 +534,9 @@ void SExpressionWasmBuilder::preParseFunctionType(Element& s) { if (need) { functionType->name = Name::fromInt(wasm.functionTypes.size()); functionTypeNames.push_back(functionType->name); - if (wasm.getFunctionTypeOrNull(functionType->name)) + if (wasm.getFunctionTypeOrNull(functionType->name)) { throw ParseException("duplicate function type", s.line, s.col); + } wasm.addFunctionType(std::move(functionType)); } } @@ -547,8 +595,9 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) { ex->name = exportName; ex->value = name; ex->kind = ExternalKind::Function; - if (wasm.getExportOrNull(ex->name)) + if (wasm.getExportOrNull(ex->name)) { throw ParseException("duplicate export", s.line, s.col); + } wasm.addExport(ex.release()); } Expression* body = nullptr; @@ -604,14 +653,16 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) { currLocalTypes[name] = type; } } else if (id == RESULT) { - if (curr.size() > 2) + if (curr.size() > 2) { throw ParseException("invalid result arity", curr.line, curr.col); + } result = stringToType(curr[1]->str()); } else if (id == TYPE) { Name name = getFunctionTypeName(*curr[1]); type = name; - if (!wasm.getFunctionTypeOrNull(name)) + if (!wasm.getFunctionTypeOrNull(name)) { throw ParseException("unknown function type"); + } FunctionType* type = wasm.getFunctionType(name); result = type->result; for (size_t j = 0; j < type->params.size(); j++) { @@ -628,8 +679,9 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) { if (typeParams.size() > 0 && params.size() == 0) { params = typeParams; } - if (!currFunction) + if (!currFunction) { makeFunction(); + } Expression* ex = parseExpression(curr); if (!body) { body = ex; @@ -650,15 +702,18 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) { break; } } - if (!type.is()) + if (!type.is()) { throw ParseException("no function type [internal error?]", s.line, s.col); + } } if (importModule.is()) { // this is an import, actually - if (!importBase.size()) + if (!importBase.size()) { throw ParseException("module but no base for import"); - if (!preParseImport) + } + if (!preParseImport) { throw ParseException("!preParseImport in func"); + } auto im = make_unique<Function>(); im->name = name; im->module = importModule; @@ -666,17 +721,20 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) { im->type = type; FunctionTypeUtils::fillFunction(im.get(), wasm.getFunctionType(type)); functionTypes[name] = im->result; - if (wasm.getFunctionOrNull(im->name)) + if (wasm.getFunctionOrNull(im->name)) { throw ParseException("duplicate import", s.line, s.col); + } wasm.addFunction(im.release()); - if (currFunction) + if (currFunction) { throw ParseException("import module inside function dec"); + } currLocalTypes.clear(); nameMapper.clear(); return; } - if (preParseImport) + if (preParseImport) { throw ParseException("preParseImport in func"); + } if (brokeToAutoBlock) { ensureAutoBlock(); autoBlock->name = FAKE_RETURN; @@ -688,8 +746,9 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) { makeFunction(); body = allocator.alloc<Nop>(); } - if (currFunction->result != result) + if (currFunction->result != result) { throw ParseException("bad func declaration", s.line, s.col); + } currFunction->body = body; currFunction->type = type; if (s.startLoc) { @@ -698,8 +757,9 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) { if (s.endLoc) { currFunction->epilogLocation.insert(getDebugLocation(*s.endLoc)); } - if (wasm.getFunctionOrNull(currFunction->name)) + if (wasm.getFunctionOrNull(currFunction->name)) { throw ParseException("duplicate function", s.line, s.col); + } wasm.addFunction(currFunction.release()); currLocalTypes.clear(); nameMapper.clear(); @@ -709,16 +769,20 @@ Type SExpressionWasmBuilder::stringToType(const char* str, bool allowError, bool prefix) { if (str[0] == 'i') { - if (str[1] == '3' && str[2] == '2' && (prefix || str[3] == 0)) + if (str[1] == '3' && str[2] == '2' && (prefix || str[3] == 0)) { return i32; - if (str[1] == '6' && str[2] == '4' && (prefix || str[3] == 0)) + } + if (str[1] == '6' && str[2] == '4' && (prefix || str[3] == 0)) { return i64; + } } if (str[0] == 'f') { - if (str[1] == '3' && str[2] == '2' && (prefix || str[3] == 0)) + if (str[1] == '3' && str[2] == '2' && (prefix || str[3] == 0)) { return f32; - if (str[1] == '6' && str[2] == '4' && (prefix || str[3] == 0)) + } + if (str[1] == '6' && str[2] == '4' && (prefix || str[3] == 0)) { return f64; + } } if (str[0] == 'v') { if (str[1] == '1' && str[2] == '2' && str[3] == '8' && @@ -726,24 +790,31 @@ Type SExpressionWasmBuilder::stringToType(const char* str, return v128; } } - if (allowError) + if (allowError) { return none; + } throw ParseException("invalid wasm type"); } Type SExpressionWasmBuilder::stringToLaneType(const char* str) { - if (strcmp(str, "i8x16") == 0) + if (strcmp(str, "i8x16") == 0) { return i32; - if (strcmp(str, "i16x8") == 0) + } + if (strcmp(str, "i16x8") == 0) { return i32; - if (strcmp(str, "i32x4") == 0) + } + if (strcmp(str, "i32x4") == 0) { return i32; - if (strcmp(str, "i64x2") == 0) + } + if (strcmp(str, "i64x2") == 0) { return i64; - if (strcmp(str, "f32x4") == 0) + } + if (strcmp(str, "f32x4") == 0) { return f32; - if (strcmp(str, "f64x2") == 0) + } + if (strcmp(str, "f64x2") == 0) { return f64; + } return none; } @@ -831,18 +902,21 @@ Expression* SExpressionWasmBuilder::makeHost(Element& s, HostOp op) { } Index SExpressionWasmBuilder::getLocalIndex(Element& s) { - if (!currFunction) + if (!currFunction) { throw ParseException("local access in non-function scope", s.line, s.col); + } if (s.dollared()) { auto ret = s.str(); - if (currFunction->localIndices.count(ret) == 0) + if (currFunction->localIndices.count(ret) == 0) { throw ParseException("bad local name", s.line, s.col); + } return currFunction->getLocalIndex(ret); } // this is a numeric index Index ret = atoi(s.c_str()); - if (ret >= currFunction->getNumLocals()) + if (ret >= currFunction->getNumLocals()) { throw ParseException("bad local index", s.line, s.col); + } return ret; } @@ -886,16 +960,18 @@ Expression* SExpressionWasmBuilder::makeSetGlobal(Element& s) { auto ret = allocator.alloc<SetGlobal>(); ret->name = getGlobalName(*s[1]); if (wasm.getGlobalOrNull(ret->name) && - !wasm.getGlobalOrNull(ret->name)->mutable_) + !wasm.getGlobalOrNull(ret->name)->mutable_) { throw ParseException("global.set of immutable", s.line, s.col); + } ret->value = parseExpression(s[2]); ret->finalize(); return ret; } Expression* SExpressionWasmBuilder::makeBlock(Element& s) { - if (!currFunction) + if (!currFunction) { throw ParseException("block is unallowed outside of functions"); + } // special-case Block, because Block nesting (in their first element) can be // incredibly deep auto curr = allocator.alloc<Block>(); @@ -920,8 +996,9 @@ Expression* SExpressionWasmBuilder::makeBlock(Element& s) { curr->name = nameMapper.pushLabelName(sName); // block signature curr->type = parseOptionalResultType(s, i); - if (i >= s.size()) + if (i >= s.size()) { break; // empty block + } auto& first = *s[i]; if (first[0]->str() == BLOCK) { // recurse @@ -994,8 +1071,9 @@ static Literal makeLanes(Element& s, MixedArena& allocator, Type lane_t) { Expression* SExpressionWasmBuilder::makeConst(Element& s, Type type) { if (type != v128) { auto ret = parseConst(s[1]->str(), type, allocator); - if (!ret) + if (!ret) { throw ParseException("bad const"); + } return ret; } @@ -1044,14 +1122,15 @@ static uint8_t parseMemBytes(const char*& s, uint8_t fallback) { ret = 1; s++; } else if (s[0] == '1') { - if (s[1] != '6') + if (s[1] != '6') { throw ParseException("expected 16 for memop size"); + } ret = 2; s += 2; } else if (s[0] == '3') { - if (s[1] != '2') + if (s[1] != '2') { throw ParseException("expected 32 for memop size"); - ; + }; ret = 4; s += 2; } else { @@ -1070,26 +1149,31 @@ static size_t parseMemAttributes(Element& s, while (!s[i]->isList()) { const char* str = s[i]->c_str(); const char* eq = strchr(str, '='); - if (!eq) + if (!eq) { throw ParseException("missing = in memory attribute"); + } eq++; - if (*eq == 0) + if (*eq == 0) { throw ParseException("missing value in memory attribute", s.line, s.col); + } char* endptr; uint64_t value = strtoll(eq, &endptr, 10); if (*endptr != 0) { throw ParseException("bad memory attribute immediate", s.line, s.col); } if (str[0] == 'a') { - if (value > std::numeric_limits<uint32_t>::max()) + if (value > std::numeric_limits<uint32_t>::max()) { throw ParseException("bad align", s.line, s.col); + } *align = value; } else if (str[0] == 'o') { - if (value > std::numeric_limits<uint32_t>::max()) + if (value > std::numeric_limits<uint32_t>::max()) { throw ParseException("bad offset", s.line, s.col); + } *offset = value; - } else + } else { throw ParseException("bad memory attribute"); + } i++; } return i; @@ -1099,13 +1183,16 @@ static const char* findMemExtra(const Element& s, size_t skip, bool isAtomic) { auto* str = s.c_str(); auto size = strlen(str); auto* ret = strchr(str, '.'); - if (!ret) + if (!ret) { throw ParseException("missing '.' in memory access", s.line, s.col); + } ret += skip; - if (isAtomic) + if (isAtomic) { ret += 7; // after "type.atomic.load" - if (ret > str + size) + } + if (ret > str + size) { throw ParseException("memory access ends abruptly", s.line, s.col); + } return ret; } @@ -1143,11 +1230,13 @@ Expression* SExpressionWasmBuilder::makeAtomicRMWOrCmpxchg(Element& s, *s[0], 11 /* after "type.atomic.rmw" */, /* isAtomic = */ false); auto bytes = parseMemBytes(extra, getTypeSize(type)); extra = strchr(extra, '.'); // after the optional '_u' and before the opcode - if (!extra) + if (!extra) { throw ParseException("malformed atomic rmw instruction"); + } extra++; // after the '.' - if (!strncmp(extra, "cmpxchg", 7)) + if (!strncmp(extra, "cmpxchg", 7)) { return makeAtomicCmpxchg(s, type, bytes, extra); + } return makeAtomicRMW(s, type, bytes, extra); } @@ -1158,24 +1247,26 @@ Expression* SExpressionWasmBuilder::makeAtomicRMW(Element& s, auto ret = allocator.alloc<AtomicRMW>(); ret->type = type; ret->bytes = bytes; - if (!strncmp(extra, "add", 3)) + if (!strncmp(extra, "add", 3)) { ret->op = Add; - else if (!strncmp(extra, "and", 3)) + } else if (!strncmp(extra, "and", 3)) { ret->op = And; - else if (!strncmp(extra, "or", 2)) + } else if (!strncmp(extra, "or", 2)) { ret->op = Or; - else if (!strncmp(extra, "sub", 3)) + } else if (!strncmp(extra, "sub", 3)) { ret->op = Sub; - else if (!strncmp(extra, "xor", 3)) + } else if (!strncmp(extra, "xor", 3)) { ret->op = Xor; - else if (!strncmp(extra, "xchg", 4)) + } else if (!strncmp(extra, "xchg", 4)) { ret->op = Xchg; - else + } else { throw ParseException("bad atomic rmw operator"); + } Address align; size_t i = parseMemAttributes(s, &ret->offset, &align, ret->bytes); - if (align != ret->bytes) + if (align != ret->bytes) { throw ParseException("Align of Atomic RMW must match size"); + } ret->ptr = parseExpression(s[i]); ret->value = parseExpression(s[i + 1]); ret->finalize(); @@ -1191,8 +1282,9 @@ Expression* SExpressionWasmBuilder::makeAtomicCmpxchg(Element& s, ret->bytes = bytes; Address align; size_t i = parseMemAttributes(s, &ret->offset, &align, ret->bytes); - if (align != ret->bytes) + if (align != ret->bytes) { throw ParseException("Align of Atomic Cmpxchg must match size"); + } ret->ptr = parseExpression(s[i]); ret->expected = parseExpression(s[i + 1]); ret->replacement = parseExpression(s[i + 2]); @@ -1224,11 +1316,13 @@ static uint8_t parseLaneIndex(const Element* s, size_t lanes) { const char* str = s->c_str(); char* end; auto n = static_cast<unsigned long long>(strtoll(str, &end, 10)); - if (end == str || *end != '\0') + if (end == str || *end != '\0') { throw ParseException("Expected lane index"); - if (n > lanes) + } + if (n > lanes) { throw ParseException("lane index must be less than " + std::to_string(lanes)); + } return uint8_t(n); } @@ -1353,10 +1447,12 @@ Expression* SExpressionWasmBuilder::makeIf(Element& s) { Expression* SExpressionWasmBuilder::makeMaybeBlock(Element& s, size_t i, Type type) { Index stopAt = -1; - if (s.size() == i) + if (s.size() == i) { return allocator.alloc<Nop>(); - if (s.size() == i + 1) + } + if (s.size() == i + 1) { return parseExpression(s[i]); + } auto ret = allocator.alloc<Block>(); for (; i < s.size() && i < stopAt; i++) { ret->list.push_back(parseExpression(s[i])); @@ -1369,18 +1465,21 @@ SExpressionWasmBuilder::makeMaybeBlock(Element& s, size_t i, Type type) { } Type SExpressionWasmBuilder::parseOptionalResultType(Element& s, Index& i) { - if (s.size() == i) + if (s.size() == i) { return none; + } // TODO(sbc): Remove support for old result syntax (bare streing) once the // spec tests are updated. - if (s[i]->isStr()) + if (s[i]->isStr()) { return stringToType(s[i++]->str()); + } Element& params = *s[i]; IString id = params[0]->str(); - if (id != RESULT) + if (id != RESULT) { return none; + } i++; return stringToType(params[1]->str()); @@ -1414,8 +1513,9 @@ Expression* SExpressionWasmBuilder::makeCall(Element& s) { } Expression* SExpressionWasmBuilder::makeCallIndirect(Element& s) { - if (!wasm.table.exists) + if (!wasm.table.exists) { throw ParseException("no table"); + } auto ret = allocator.alloc<CallIndirect>(); Index i = 1; Element& typeElement = *s[i]; @@ -1423,8 +1523,9 @@ Expression* SExpressionWasmBuilder::makeCallIndirect(Element& s) { // type name given IString type = typeElement[1]->str(); auto* fullType = wasm.getFunctionTypeOrNull(type); - if (!fullType) + if (!fullType) { throw ParseException("invalid call_indirect type", s.line, s.col); + } ret->fullType = fullType->name; i++; } else { @@ -1465,8 +1566,9 @@ Name SExpressionWasmBuilder::getLabel(Element& s) { } catch (std::out_of_range&) { throw ParseException("out of range break offset"); } - if (offset > nameMapper.labelStack.size()) + if (offset > nameMapper.labelStack.size()) { throw ParseException("invalid label", s.line, s.col); + } if (offset == nameMapper.labelStack.size()) { // a break to the function's scope. this means we need an automatic block, // with a name @@ -1482,8 +1584,9 @@ Expression* SExpressionWasmBuilder::makeBreak(Element& s) { size_t i = 1; ret->name = getLabel(*s[i]); i++; - if (i == s.size()) + if (i == s.size()) { return ret; + } if (s[0]->str() == BR_IF) { if (i + 1 < s.size()) { ret->value = parseExpression(s[i]); @@ -1503,8 +1606,9 @@ Expression* SExpressionWasmBuilder::makeBreakTable(Element& s) { while (!s[i]->isList()) { ret->targets.push_back(getLabel(*s[i++])); } - if (ret->targets.size() == 0) + if (ret->targets.size() == 0) { throw ParseException("switch with no targets"); + } ret->default_ = ret->targets.back(); ret->targets.pop_back(); ret->condition = parseExpression(s[i++]); @@ -1533,8 +1637,9 @@ void SExpressionWasmBuilder::stringToBinary(const char* input, data.resize(originalSize + size); char* write = data.data() + originalSize; while (1) { - if (input[0] == 0) + if (input[0] == 0) { break; + } if (input[0] == '\\') { if (input[1] == '"') { *write++ = '"'; @@ -1578,15 +1683,17 @@ Index SExpressionWasmBuilder::parseMemoryLimits(Element& s, Index i) { return i; } uint64_t max = atoll(s[i++]->c_str()); - if (max > Memory::kMaxSize) + if (max > Memory::kMaxSize) { throw ParseException("total memory must be <= 4GB"); + } wasm.memory.max = max; return i; } void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) { - if (wasm.memory.exists) + if (wasm.memory.exists) { throw ParseException("too many memories"); + } wasm.memory.exists = true; wasm.memory.shared = false; Index i = 1; @@ -1601,8 +1708,9 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) { ex->name = inner[1]->str(); ex->value = wasm.memory.name; ex->kind = ExternalKind::Memory; - if (wasm.getExportOrNull(ex->name)) + if (wasm.getExportOrNull(ex->name)) { throw ParseException("duplicate export", s.line, s.col); + } wasm.addExport(ex.release()); i++; } else if (inner[0]->str() == IMPORT) { @@ -1614,8 +1722,9 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) { parseMemoryLimits(inner, 1); i++; } else { - if (!(inner.size() > 0 ? inner[0]->str() != IMPORT : true)) + if (!(inner.size() > 0 ? inner[0]->str() != IMPORT : true)) { throw ParseException("bad import ending"); + } // (memory (data ..)) format auto offset = allocator.alloc<Const>()->set(Literal(int32_t(0))); parseInnerData(*s[i], 1, offset, false); @@ -1623,8 +1732,9 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) { return; } } - if (!wasm.memory.shared) + if (!wasm.memory.shared) { i = parseMemoryLimits(s, i); + } // Parse memory initializers. while (i < s.size()) { @@ -1652,8 +1762,9 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) { } void SExpressionWasmBuilder::parseData(Element& s) { - if (!wasm.memory.exists) + if (!wasm.memory.exists) { throw ParseException("data but no memory"); + } bool isPassive = false; Expression* offset = nullptr; Index i = 1; @@ -1703,16 +1814,18 @@ void SExpressionWasmBuilder::parseExport(Element& s) { } else if (inner[0]->str() == GLOBAL) { ex->kind = ExternalKind::Global; if (wasm.getGlobalOrNull(ex->value) && - wasm.getGlobal(ex->value)->mutable_) + wasm.getGlobal(ex->value)->mutable_) { throw ParseException("cannot export a mutable global", s.line, s.col); + } } else { throw ParseException("invalid export"); } } else if (!s[2]->dollared() && !std::isdigit(s[2]->str()[0])) { ex->value = s[3]->str(); if (s[2]->str() == MEMORY) { - if (!wasm.memory.exists) + if (!wasm.memory.exists) { throw ParseException("memory exported but no memory"); + } ex->kind = ExternalKind::Memory; } else if (s[2]->str() == TABLE) { ex->kind = ExternalKind::Table; @@ -1726,8 +1839,9 @@ void SExpressionWasmBuilder::parseExport(Element& s) { ex->value = s[2]->str(); ex->kind = ExternalKind::Function; } - if (wasm.getExportOrNull(ex->name)) + if (wasm.getExportOrNull(ex->name)) { throw ParseException("duplicate export", s.line, s.col); + } wasm.addExport(ex.release()); } @@ -1741,13 +1855,15 @@ void SExpressionWasmBuilder::parseImport(Element& s) { kind = ExternalKind::Function; } else if ((*s[3])[0]->str() == MEMORY) { kind = ExternalKind::Memory; - if (wasm.memory.exists) + if (wasm.memory.exists) { throw ParseException("more than one memory"); + } wasm.memory.exists = true; } else if ((*s[3])[0]->str() == TABLE) { kind = ExternalKind::Table; - if (wasm.table.exists) + if (wasm.table.exists) { throw ParseException("more than one table"); + } wasm.table.exists = true; } else if ((*s[3])[0]->str() == GLOBAL) { kind = ExternalKind::Global; @@ -1793,11 +1909,13 @@ void SExpressionWasmBuilder::parseImport(Element& s) { kind = ExternalKind::Function; } auto module = s[i++]->str(); - if (!s[i]->isStr()) + if (!s[i]->isStr()) { throw ParseException("no name for import"); + } auto base = s[i++]->str(); - if (!module.size() || !base.size()) + if (!module.size() || !base.size()) { throw ParseException("imports must have module and base"); + } // parse internals Element& inner = newStyle ? *s[3] : s; Index j = newStyle ? newStyleInner : i; @@ -1814,16 +1932,18 @@ void SExpressionWasmBuilder::parseImport(Element& s) { type->result = stringToType(params[1]->str()); } else if (id == TYPE) { IString name = params[1]->str(); - if (!wasm.getFunctionTypeOrNull(name)) + if (!wasm.getFunctionTypeOrNull(name)) { throw ParseException("bad function type for import"); + } *type = *wasm.getFunctionType(name); } else { throw ParseException("bad import element"); } if (inner.size() > j + 1) { Element& result = *inner[j + 1]; - if (result[0]->str() != RESULT) + if (result[0]->str() != RESULT) { throw ParseException("expected result"); + } type->result = stringToType(result[1]->str()); } } @@ -1843,8 +1963,9 @@ void SExpressionWasmBuilder::parseImport(Element& s) { type = stringToType(inner[j]->str()); } else { auto& inner2 = *inner[j]; - if (inner2[0]->str() != MUT) + if (inner2[0]->str() != MUT) { throw ParseException("expected mut"); + } type = stringToType(inner2[1]->str()); mutable_ = true; } @@ -1874,8 +1995,9 @@ void SExpressionWasmBuilder::parseImport(Element& s) { wasm.memory.base = base; if (inner[j]->isList()) { auto& limits = *inner[j]; - if (!(limits[0]->isStr() && limits[0]->str() == "shared")) + if (!(limits[0]->isStr() && limits[0]->str() == "shared")) { throw ParseException("bad memory limit declaration"); + } wasm.memory.shared = true; parseMemoryLimits(limits, 1); } else { @@ -1905,8 +2027,9 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) { ex->name = inner[1]->str(); ex->value = global->name; ex->kind = ExternalKind::Global; - if (wasm.getExportOrNull(ex->name)) + if (wasm.getExportOrNull(ex->name)) { throw ParseException("duplicate export", s.line, s.col); + } wasm.addExport(ex.release()); exported = true; i++; @@ -1922,30 +2045,35 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) { break; } } - if (exported && mutable_) + if (exported && mutable_) { throw ParseException("cannot export a mutable global", s.line, s.col); + } if (type == none) { type = stringToType(s[i++]->str()); } if (importModule.is()) { // this is an import, actually - if (!importBase.size()) + if (!importBase.size()) { throw ParseException("module but no base for import"); - if (!preParseImport) + } + if (!preParseImport) { throw ParseException("!preParseImport in global"); + } auto im = make_unique<Global>(); im->name = global->name; im->module = importModule; im->base = importBase; im->type = type; im->mutable_ = mutable_; - if (wasm.getGlobalOrNull(im->name)) + if (wasm.getGlobalOrNull(im->name)) { throw ParseException("duplicate import", s.line, s.col); + } wasm.addGlobal(im.release()); return; } - if (preParseImport) + if (preParseImport) { throw ParseException("preParseImport in global"); + } global->type = type; if (i < s.size()) { global->init = parseExpression(s[i++]); @@ -1953,25 +2081,30 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) { throw ParseException("global without init", s.line, s.col); } global->mutable_ = mutable_; - if (i != s.size()) + if (i != s.size()) { throw ParseException("extra import elements"); - if (wasm.getGlobalOrNull(global->name)) + } + if (wasm.getGlobalOrNull(global->name)) { throw ParseException("duplicate import", s.line, s.col); + } wasm.addGlobal(global.release()); } void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) { - if (wasm.table.exists) + if (wasm.table.exists) { throw ParseException("more than one table"); + } wasm.table.exists = true; Index i = 1; - if (i == s.size()) + if (i == s.size()) { return; // empty table in old notation + } if (s[i]->dollared()) { wasm.table.name = s[i++]->str(); } - if (i == s.size()) + if (i == s.size()) { return; + } Name importModule, importBase; if (s[i]->isList()) { auto& inner = *s[i]; @@ -1980,13 +2113,15 @@ void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) { ex->name = inner[1]->str(); ex->value = wasm.table.name; ex->kind = ExternalKind::Table; - if (wasm.getExportOrNull(ex->name)) + if (wasm.getExportOrNull(ex->name)) { throw ParseException("duplicate export", s.line, s.col); + } wasm.addExport(ex.release()); i++; } else if (inner[0]->str() == IMPORT) { - if (!preParseImport) + if (!preParseImport) { throw ParseException("!preParseImport in table"); + } wasm.table.module = inner[1]->str(); wasm.table.base = inner[2]->str(); i++; @@ -1994,8 +2129,9 @@ void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) { throw ParseException("invalid table"); } } - if (i == s.size()) + if (i == s.size()) { return; + } if (!s[i]->dollared()) { if (s[i]->str() == FUNCREF) { // (table type (elem ..)) @@ -2044,8 +2180,9 @@ void SExpressionWasmBuilder::parseElem(Element& s) { void SExpressionWasmBuilder::parseInnerElem(Element& s, Index i, Expression* offset) { - if (!wasm.table.exists) + if (!wasm.table.exists) { throw ParseException("elem without table", s.line, s.col); + } if (!offset) { offset = allocator.alloc<Const>()->set(Literal(int32_t(0))); } @@ -2071,8 +2208,9 @@ void SExpressionWasmBuilder::parseType(Element& s) { type->params.push_back(stringToType(curr[j]->str())); } } else if (curr[0]->str() == RESULT) { - if (curr.size() > 2) + if (curr.size() > 2) { throw ParseException("invalid result arity", curr.line, curr.col); + } type->result = stringToType(curr[1]->str()); } } @@ -2080,8 +2218,9 @@ void SExpressionWasmBuilder::parseType(Element& s) { type->name = Name::fromInt(wasm.functionTypes.size()); } functionTypeNames.push_back(type->name); - if (wasm.getFunctionTypeOrNull(type->name)) + if (wasm.getFunctionTypeOrNull(type->name)) { throw ParseException("duplicate function type", s.line, s.col); + } wasm.addFunctionType(std::move(type)); } diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 78ad6f628..449dff4db 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -69,14 +69,18 @@ FeatureSet getFeatures(Type type) { } Type getType(unsigned size, bool float_) { - if (size < 4) + if (size < 4) { return Type::i32; - if (size == 4) + } + if (size == 4) { return float_ ? Type::f32 : Type::i32; - if (size == 8) + } + if (size == 8) { return float_ ? Type::f64 : Type::i64; - if (size == 16) + } + if (size == 16) { return Type::v128; + } WASM_UNREACHABLE(); } diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index ea8e92047..b84105c8d 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -66,8 +66,9 @@ struct ValidationInfo { std::ostringstream& getStream(Function* func) { std::unique_lock<std::mutex> lock(mutex); auto iter = outputs.find(func); - if (iter != outputs.end()) + if (iter != outputs.end()) { return *(iter->second.get()); + } auto& ret = outputs[func] = make_unique<std::ostringstream>(); return *ret.get(); } @@ -78,8 +79,9 @@ struct ValidationInfo { std::ostream& fail(S text, T curr, Function* func) { valid.store(false); auto& stream = getStream(func); - if (quiet) + if (quiet) { return stream; + } auto& ret = printFailureHeader(func); ret << text << ", on \n"; return printModuleComponent(curr, ret); @@ -87,8 +89,9 @@ struct ValidationInfo { std::ostream& printFailureHeader(Function* func) { auto& stream = getStream(func); - if (quiet) + if (quiet) { return stream; + } Colors::red(stream); if (func) { stream << "[wasm-validator error in function "; @@ -220,16 +223,18 @@ public: static void visitPreBlock(FunctionValidator* self, Expression** currp) { auto* curr = (*currp)->cast<Block>(); - if (curr->name.is()) + if (curr->name.is()) { self->breakInfos[curr->name]; + } } void visitBlock(Block* curr); static void visitPreLoop(FunctionValidator* self, Expression** currp) { auto* curr = (*currp)->cast<Loop>(); - if (curr->name.is()) + if (curr->name.is()) { self->breakInfos[curr->name]; + } } void visitLoop(Loop* curr); @@ -240,10 +245,12 @@ public: PostWalker<FunctionValidator>::scan(self, currp); auto* curr = *currp; - if (curr->is<Block>()) + if (curr->is<Block>()) { self->pushTask(visitPreBlock, currp); - if (curr->is<Loop>()) + } + if (curr->is<Loop>()) { self->pushTask(visitPreLoop, currp); + } } void noteBreak(Name name, Expression* value, Expression* curr); @@ -319,8 +326,9 @@ private: }; void FunctionValidator::noteLabelName(Name name) { - if (!name.is()) + if (!name.is()) { return; + } bool inserted; std::tie(std::ignore, inserted) = labelNames.insert(name); shouldBeTrue( @@ -520,8 +528,9 @@ void FunctionValidator::noteBreak(Name name, } auto iter = breakInfos.find(name); if (!shouldBeTrue( - iter != breakInfos.end(), curr, "all break targets must be valid")) + iter != breakInfos.end(), curr, "all break targets must be valid")) { return; + } auto& info = iter->second; if (!info.hasBeenSet()) { info = BreakInfo(valueType, arity); @@ -560,15 +569,18 @@ void FunctionValidator::visitSwitch(Switch* curr) { } void FunctionValidator::visitCall(Call* curr) { - if (!info.validateGlobally) + if (!info.validateGlobally) { return; + } auto* target = getModule()->getFunctionOrNull(curr->target); - if (!shouldBeTrue(!!target, curr, "call target must exist")) + if (!shouldBeTrue(!!target, curr, "call target must exist")) { return; + } if (!shouldBeTrue(curr->operands.size() == target->params.size(), curr, - "call param number must match")) + "call param number must match")) { return; + } for (size_t i = 0; i < curr->operands.size(); i++) { if (!shouldBeEqualOrFirstIsUnreachable(curr->operands[i]->type, target->params[i], @@ -581,17 +593,20 @@ void FunctionValidator::visitCall(Call* curr) { } void FunctionValidator::visitCallIndirect(CallIndirect* curr) { - if (!info.validateGlobally) + if (!info.validateGlobally) { return; + } auto* type = getModule()->getFunctionTypeOrNull(curr->fullType); - if (!shouldBeTrue(!!type, curr, "call_indirect type must exist")) + if (!shouldBeTrue(!!type, curr, "call_indirect type must exist")) { return; + } shouldBeEqualOrFirstIsUnreachable( curr->target->type, i32, curr, "indirect call target must be an i32"); if (!shouldBeTrue(curr->operands.size() == type->params.size(), curr, - "call param number must match")) + "call param number must match")) { return; + } for (size_t i = 0; i < curr->operands.size(); i++) { if (!shouldBeEqualOrFirstIsUnreachable(curr->operands[i]->type, type->params[i], @@ -639,16 +654,18 @@ void FunctionValidator::visitSetLocal(SetLocal* curr) { } void FunctionValidator::visitGetGlobal(GetGlobal* curr) { - if (!info.validateGlobally) + if (!info.validateGlobally) { return; + } shouldBeTrue(getModule()->getGlobalOrNull(curr->name), curr, "global.get name must be valid"); } void FunctionValidator::visitSetGlobal(SetGlobal* curr) { - if (!info.validateGlobally) + if (!info.validateGlobally) { return; + } auto* global = getModule()->getGlobalOrNull(curr->name); if (shouldBeTrue(global, curr, @@ -674,10 +691,11 @@ void FunctionValidator::visitLoad(Load* curr) { curr, "Atomic load should be i32 or i64"); } - if (curr->type == v128) + if (curr->type == v128) { shouldBeTrue(getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)"); + } shouldBeFalse(curr->isAtomic && !getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); @@ -704,10 +722,11 @@ void FunctionValidator::visitStore(Store* curr) { curr, "Atomic store should be i32 or i64"); } - if (curr->valueType == v128) + if (curr->valueType == v128) { shouldBeTrue(getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)"); + } shouldBeFalse(curr->isAtomic && !getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); @@ -1232,8 +1251,9 @@ void FunctionValidator::visitUnary(Unary* curr) { none, curr, "unaries must not receive a none as their input"); - if (curr->value->type == unreachable) + if (curr->value->type == unreachable) { return; // nothing to check + } switch (curr->op) { case ClzInt32: case CtzInt32: @@ -1542,11 +1562,13 @@ void FunctionValidator::visitFunction(Function* curr) { } static bool checkOffset(Expression* curr, Address add, Address max) { - if (curr->is<GetGlobal>()) + if (curr->is<GetGlobal>()) { return true; + } auto* c = curr->dynCast<Const>(); - if (!c) + if (!c) { return false; + } uint64_t raw = c->value.getInteger(); if (raw > std::numeric_limits<Address::address_t>::max()) { return false; @@ -1763,10 +1785,11 @@ static void validateMemory(Module& module, ValidationInfo& info) { info.shouldBeTrue(!curr.shared || curr.hasMax(), "memory", "shared memory must have max size"); - if (curr.shared) + if (curr.shared) { info.shouldBeTrue(module.features.hasAtomics(), "memory", "memory is shared, but atomics are disabled"); + } for (auto& segment : curr.segments) { Index size = segment.data.size(); if (segment.isPassive) { @@ -1781,8 +1804,9 @@ static void validateMemory(Module& module, ValidationInfo& info) { if (!info.shouldBeEqual(segment.offset->type, i32, segment.offset, - "segment offset should be i32")) + "segment offset should be i32")) { continue; + } info.shouldBeTrue(checkOffset(segment.offset, segment.data.size(), curr.initial * Memory::kPageSize), diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 22cce6e80..bf12c22d4 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -185,11 +185,13 @@ struct TypeSeeker : public PostWalker<TypeSeeker> { void visitSwitch(Switch* curr) { for (auto name : curr->targets) { - if (name == targetName) + if (name == targetName) { types.push_back(curr->value ? curr->value->type : none); + } } - if (curr->default_ == targetName) + if (curr->default_ == targetName) { types.push_back(curr->value ? curr->value->type : none); + } } void visitBlock(Block* curr) { @@ -243,15 +245,18 @@ static Type mergeTypes(std::vector<Type>& types) { static void handleUnreachable(Block* block, bool breakabilityKnown = false, bool hasBreak = false) { - if (block->type == unreachable) + if (block->type == unreachable) { return; // nothing to do - if (block->list.size() == 0) + } + if (block->list.size() == 0) { return; // nothing to do + } // if we are concrete, stop - even an unreachable child // won't change that (since we have a break with a value, // or the final child flows out a value) - if (isConcreteType(block->type)) + if (isConcreteType(block->type)) { return; + } // look for an unreachable child for (auto* child : block->list) { if (child->type == unreachable) { @@ -280,11 +285,13 @@ void Block::finalize() { // (return) // (i32.const 10) // ) - if (isConcreteType(type)) + if (isConcreteType(type)) { return; + } // if we are unreachable, we are done - if (type == unreachable) + if (type == unreachable) { return; + } // we may still be unreachable if we have an unreachable // child for (auto* child : list) { @@ -398,20 +405,24 @@ void CallIndirect::finalize() { } bool FunctionType::structuralComparison(FunctionType& b) { - if (result != b.result) + if (result != b.result) { return false; - if (params.size() != b.params.size()) + } + if (params.size() != b.params.size()) { return false; + } for (size_t i = 0; i < params.size(); i++) { - if (params[i] != b.params[i]) + if (params[i] != b.params[i]) { return false; + } } return true; } bool FunctionType::operator==(FunctionType& b) { - if (name != b.name) + if (name != b.name) { return false; + } return structuralComparison(b); } bool FunctionType::operator!=(FunctionType& b) { return !(*this == b); } @@ -419,10 +430,11 @@ bool FunctionType::operator!=(FunctionType& b) { return !(*this == b); } bool SetLocal::isTee() { return type != none; } void SetLocal::setTee(bool is) { - if (is) + if (is) { type = value->type; - else + } else { type = none; + } finalize(); // type may need to be unreachable } |