diff options
author | Jacob Gravelle <jgravelle@google.com> | 2018-01-22 12:50:36 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-22 12:50:36 -0800 |
commit | 02729a12e1735f629d3066b51c96a056f712b080 (patch) | |
tree | 353a495836776695d0f86f08b6292635c4dba101 /src | |
parent | b01f2bb237e086fe4ae852c6004297fa8f8b39c2 (diff) | |
download | binaryen-02729a12e1735f629d3066b51c96a056f712b080.tar.gz binaryen-02729a12e1735f629d3066b51c96a056f712b080.tar.bz2 binaryen-02729a12e1735f629d3066b51c96a056f712b080.zip |
First pass at LLD support for Emscripten (#1346)
* Skeleton of a beginning of o2wasm, WIP and probably not going to be used
* Get building post-cherry-pick
* ast->ir, remove commented out code, include a debug module print because linking
* Read linking section, print emscripten metadata json
* WasmBinaryWriter emits user sections on Module
* Remove debugging prints, everything that isn't needed to build metadata
* Rename o2wasm to lld-metadata
* lld-metadata support for outputting to file
* Use tables index instead of function index for initializer functions
* Add lld-emscripten tool to add emscripten-runtime functions to wasm modules (built with lld)
* Handle EM_ASM in lld-emscripten
* Add a list of functions to forcibly export (for initializer functions)
* Disable incorrect initializer function reading
* Add error printing when parsing .o files in lld-metadata
* Remove ';; METADATA: ' prefix from lld-metadata, output is now standalone json
* Support em_asm consts that aren't at the start of a segment
* Initial test framework for lld-metadata tool
* Add em_asm test
* Add support for WASM_INIT_FUNCS in the linking section
* Remove reloc section parsing because it's unused
* lld-emscripten can read and write text
* Add test harness for lld-emscripten
* Export all functions for now
* Add missing lld test output
* Add support for reading object files differently
Only difference so far is in importing mutable globals being an object
file representation for symbols, but invalid wasm.
* Update help strings
* Update linking tests for stackAlloc fix
* Rename lld-emscripten,lld-metadata to wasm-emscripten-finalize,wasm-link-metadata
* Add help text to header comments
* auto& instead of auto &
* Extract LinkType to abi/wasm-object.h
* Remove special handling for wasm object file reading, allow mutable globals
* Add braces around default switch case
* Fix flake8 errors
* Handle generating dyncall thunks for imports as well
* Use explicit bool for stackPointerGlobal
* Use glob patterns for lld file iteration
* Use __wasm_call_ctors for all initializer functions
Diffstat (limited to 'src')
-rw-r--r-- | src/abi/wasm-object.h | 40 | ||||
-rw-r--r-- | src/tools/s2wasm.cpp | 2 | ||||
-rw-r--r-- | src/tools/wasm-emscripten-finalize.cpp | 103 | ||||
-rw-r--r-- | src/tools/wasm-link-metadata.cpp | 118 | ||||
-rw-r--r-- | src/wasm-binary.h | 10 | ||||
-rw-r--r-- | src/wasm-emscripten.cpp | 139 | ||||
-rw-r--r-- | src/wasm-emscripten.h | 12 | ||||
-rw-r--r-- | src/wasm-io.h | 3 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 20 | ||||
-rw-r--r-- | src/wasm/wasm-io.cpp | 9 |
10 files changed, 395 insertions, 61 deletions
diff --git a/src/abi/wasm-object.h b/src/abi/wasm-object.h new file mode 100644 index 000000000..0ce814030 --- /dev/null +++ b/src/abi/wasm-object.h @@ -0,0 +1,40 @@ +/* + * Copyright 2018 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Contains definitions used for wasm object files. +// See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md +// + +#ifndef wasm_abi_wasm_object_h +#define wasm_abi_wasm_object_h + +namespace wasm { + +namespace ABI { + enum LinkType : unsigned { + WASM_STACK_POINTER = 0x1, + WASM_SYMBOL_INFO = 0x2, + WASM_DATA_SIZE = 0x3, + WASM_DATA_ALIGNMENT = 0x4, + WASM_SEGMENT_INFO = 0x5, + WASM_INIT_FUNCS = 0x6, + }; +} // namespace ABI + +} // namespace wasm + +#endif // wasm_abi_wasm_object_h diff --git a/src/tools/s2wasm.cpp b/src/tools/s2wasm.cpp index 6e7b2c05e..32af57dba 100644 --- a/src/tools/s2wasm.cpp +++ b/src/tools/s2wasm.cpp @@ -184,7 +184,7 @@ int main(int argc, const char *argv[]) { std::cerr << "Emscripten gluing..." << std::endl; WasmPrinter::printModule(&wasm, std::cerr); } - metadata = emscriptenGlue( + metadata = ";; METADATA: " + emscriptenGlue( wasm, allowMemoryGrowth, linker.getStackPointerAddress(), diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp new file mode 100644 index 000000000..87505748c --- /dev/null +++ b/src/tools/wasm-emscripten-finalize.cpp @@ -0,0 +1,103 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// wasm-emscripten-finalize console tool +// Performs Emscripten-specific transforms on .wasm files +// + +#include <exception> + +#include "ir/trapping.h" +#include "support/colors.h" +#include "support/command-line.h" +#include "support/file.h" +#include "wasm-binary.h" +#include "wasm-emscripten.h" +#include "wasm-io.h" +#include "wasm-linker.h" +#include "wasm-printing.h" +#include "wasm-validator.h" + +using namespace cashew; +using namespace wasm; + +int main(int argc, const char *argv[]) { + std::string infile; + std::string outfile; + bool emitBinary = true; + std::vector<Name> forcedExports; + Options options("wasm-emscripten-finalize", + "Performs Emscripten-specific transforms on .wasm files"); + options + .add("--output", "-o", "Output file", + Options::Arguments::One, + [&outfile](Options*, const std::string &argument) { + outfile = argument; + Colors::disable(); + }) + .add("--emit-text", "-S", "Emit text instead of binary for the output file", + Options::Arguments::Zero, + [&emitBinary](Options*, const std::string &) { + emitBinary = false; + }) + .add_positional("INFILE", Options::Arguments::One, + [&infile](Options *o, const std::string &argument) { + infile = argument; + }); + options.parse(argc, argv); + + if (infile == "") { + Fatal() << "Need to specify an infile\n"; + } + if (outfile == "" && emitBinary) { + Fatal() << "Need to specify an outfile, or use text output\n"; + } + + Module wasm; + ModuleReader reader; + reader.read(infile, wasm); + + if (options.debug) { + std::cerr << "Module before:\n"; + WasmPrinter::printModule(&wasm, std::cerr); + } + + EmscriptenGlueGenerator generator(wasm); + generator.generateRuntimeFunctions(); + generator.generateMemoryGrowthFunction(); + generator.generateDynCallThunks(); + generator.fixEmAsmConsts(); + + if (options.debug) { + std::cerr << "Module after:\n"; + WasmPrinter::printModule(&wasm, std::cerr); + } + + ModuleWriter writer; + // writer.setDebug(options.debug); + writer.setDebugInfo(true); + // writer.setDebugInfo(options.passOptions.debugInfo); + // writer.setSymbolMap(symbolMap); + writer.setBinary(emitBinary); + // if (emitBinary) { + // writer.setSourceMapFilename(sourceMapFilename); + // writer.setSourceMapUrl(sourceMapUrl); + // } + writer.write(wasm, outfile); + + return 0; +} diff --git a/src/tools/wasm-link-metadata.cpp b/src/tools/wasm-link-metadata.cpp new file mode 100644 index 000000000..1ca64880f --- /dev/null +++ b/src/tools/wasm-link-metadata.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// wasm-link-metadata console tool +// Reads wasm .o file and emits .json metadata +// + +#include <exception> + +#include "abi/wasm-object.h" +#include "ir/trapping.h" +#include "support/colors.h" +#include "support/command-line.h" +#include "support/file.h" +#include "wasm-binary.h" +#include "wasm-emscripten.h" +#include "wasm-io.h" +#include "wasm-linker.h" +#include "wasm-printing.h" +#include "wasm-validator.h" + +using namespace cashew; +using namespace wasm; + +void parseLinkingSection(std::vector<char> const& data, uint32_t &dataSize) { + unsigned idx = 0; + auto get = [&idx, &data](){ return data[idx++]; }; + auto readNext = [get](){ + U32LEB leb; + leb.read(get); + return leb.value; + }; + + while (idx < data.size()) { + ABI::LinkType type = static_cast<ABI::LinkType>(readNext()); + uint32_t size = readNext(); + uint32_t startIdx = idx; + + switch(type) { + case ABI::WASM_DATA_SIZE: { + dataSize = readNext(); + break; + } + default: { + break; + } + } + // Always go to the end of the subsection based on size, not contents. + idx = startIdx + size; + } +} + +int main(int argc, const char *argv[]) { + std::string infile; + std::string outfile; + Options options("wasm-link-metadata", + "Reads wasm .o file and emits .json metadata"); + options + .add("--output", "-o", "Output file", + Options::Arguments::One, + [&outfile](Options *o, const std::string &argument) { + outfile = argument; + Colors::disable(); + }) + .add_positional("INFILE", Options::Arguments::One, + [&infile](Options *o, const std::string &argument) { + infile = argument; + }); + options.parse(argc, argv); + + if (infile == "") { + Fatal() << "Need to specify an infile\n"; + } + + Module wasm; + try { + ModuleReader reader; + reader.readBinary(infile, wasm); + } catch (ParseException& p) { + p.dump(std::cerr); + Fatal() << "error in parsing wasm binary"; + } + + if (options.debug) { + WasmPrinter::printModule(&wasm, std::cerr); + } + + uint32_t dataSize = 0; + for (auto §ion : wasm.userSections) { + if (section.name == "linking") { + parseLinkingSection(section.data, dataSize); + } + } + + std::vector<Name> initializerFunctions; + initializerFunctions.push_back("__wasm_call_ctors"); + + EmscriptenGlueGenerator generator(wasm); + std::string metadata = generator.generateEmscriptenMetadata(dataSize, initializerFunctions); + Output output(outfile, Flags::Text, Flags::Release); + output << metadata; + + return 0; +} diff --git a/src/wasm-binary.h b/src/wasm-binary.h index e5bfd9f2d..7e932c305 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -724,6 +724,7 @@ public: void writeNames(); void writeSourceMapUrl(); void writeSymbolMap(); + void writeUserSections(); void writeSourceMapProlog(); void writeSourceMapEpilog(); @@ -814,7 +815,14 @@ class WasmBinaryBuilder { std::set<BinaryConsts::Section> seenSections; public: - WasmBinaryBuilder(Module& wasm, const std::vector<char>& input, bool debug) : wasm(wasm), allocator(wasm.allocator), input(input), debug(debug), sourceMap(nullptr), nextDebugLocation(0, { 0, 0, 0 }), useDebugLocation(false) {} + WasmBinaryBuilder(Module& wasm, const std::vector<char>& input, bool debug) + : wasm(wasm), + allocator(wasm.allocator), + input(input), + debug(debug), + sourceMap(nullptr), + nextDebugLocation(0, { 0, 0, 0 }), + useDebugLocation(false) {} void read(); void readUserSection(size_t payloadLen); diff --git a/src/wasm-emscripten.cpp b/src/wasm-emscripten.cpp index a07254061..60bf5cce3 100644 --- a/src/wasm-emscripten.cpp +++ b/src/wasm-emscripten.cpp @@ -40,28 +40,39 @@ void addExportedFunction(Module& wasm, Function* function) { wasm.addExport(export_); } -Load* EmscriptenGlueGenerator::generateLoadStackPointer() { - Load* load = builder.makeLoad( - /* bytes =*/ 4, - /* signed =*/ false, - /* offset =*/ stackPointerOffset, - /* align =*/ 4, - /* ptr =*/ builder.makeConst(Literal(0)), - /* type =*/ i32 - ); - return load; +Global* EmscriptenGlueGenerator::getStackPointerGlobal() { + // Assumption: first global is __stack_pointer + return wasm.globals[0].get(); } -Store* EmscriptenGlueGenerator::generateStoreStackPointer(Expression* value) { - Store* store = builder.makeStore( - /* bytes =*/ 4, - /* offset =*/ stackPointerOffset, - /* align =*/ 4, - /* ptr =*/ builder.makeConst(Literal(0)), - /* value =*/ value, - /* type =*/ i32 - ); - return store; +Expression* EmscriptenGlueGenerator::generateLoadStackPointer() { + if (!useStackPointerGlobal) { + return builder.makeLoad( + /* bytes =*/ 4, + /* signed =*/ false, + /* offset =*/ stackPointerOffset, + /* align =*/ 4, + /* ptr =*/ builder.makeConst(Literal(0)), + /* type =*/ i32 + ); + } + Global* stackPointer = getStackPointerGlobal(); + return builder.makeGetGlobal(stackPointer->name, i32); +} + +Expression* EmscriptenGlueGenerator::generateStoreStackPointer(Expression* value) { + if (!useStackPointerGlobal) { + return builder.makeStore( + /* bytes =*/ 4, + /* offset =*/ stackPointerOffset, + /* align =*/ 4, + /* ptr =*/ builder.makeConst(Literal(0)), + /* value =*/ value, + /* type =*/ i32 + ); + } + Global* stackPointer = getStackPointerGlobal(); + return builder.makeSetGlobal(stackPointer->name, value); } void EmscriptenGlueGenerator::generateStackSaveFunction() { @@ -82,7 +93,7 @@ void EmscriptenGlueGenerator::generateStackAllocFunction() { Function* function = builder.makeFunction( name, std::move(params), i32, { { "1", i32 } } ); - Load* loadStack = generateLoadStackPointer(); + Expression* loadStack = generateLoadStackPointer(); GetLocal* getSizeArg = builder.makeGetLocal(0, i32); Binary* sub = builder.makeBinary(SubInt32, loadStack, getSizeArg); const static uint32_t bitAlignment = 16; @@ -90,7 +101,7 @@ void EmscriptenGlueGenerator::generateStackAllocFunction() { Const* subConst = builder.makeConst(Literal(~bitMask)); Binary* maskedSub = builder.makeBinary(AndInt32, sub, subConst); SetLocal* teeStackLocal = builder.makeTeeLocal(1, maskedSub); - Store* storeStack = generateStoreStackPointer(teeStackLocal); + Expression* storeStack = generateStoreStackPointer(teeStackLocal); Block* block = builder.makeBlock(); block->list.push_back(storeStack); @@ -109,7 +120,7 @@ void EmscriptenGlueGenerator::generateStackRestoreFunction() { name, std::move(params), none, {} ); GetLocal* getArg = builder.makeGetLocal(0, i32); - Store* store = generateStoreStackPointer(getArg); + Expression* store = generateStoreStackPointer(getArg); function->body = store; @@ -147,21 +158,7 @@ static bool hasI64ResultOrParam(FunctionType* ft) { return false; } -void removeImportsWithSubstring(Module& module, Name name) { - std::vector<Name> toRemove; - for (auto& import : module.imports) { - if (import->name.hasSubstring(name)) { - toRemove.push_back(import->name); - } - } - for (auto importName : toRemove) { - module.removeImport(importName); - } -} - void EmscriptenGlueGenerator::generateDynCallThunks() { - removeImportsWithSubstring(wasm, EMSCRIPTEN_ASM_CONST); // we create _sig versions - std::unordered_set<std::string> sigs; Builder builder(wasm); std::vector<Name> tableSegmentData; @@ -172,7 +169,12 @@ void EmscriptenGlueGenerator::generateDynCallThunks() { if (indirectFunc == dummyFunction) { continue; } - std::string sig(getSig(wasm.getFunction(indirectFunc))); + std::string sig; + if (auto import = wasm.getImportOrNull(indirectFunc)) { + sig = getSig(wasm.getFunctionType(import->functionType)); + } else { + sig = getSig(wasm.getFunction(indirectFunc)); + } auto* funcType = ensureFunctionType(sig, &wasm); if (hasI64ResultOrParam(funcType)) continue; // Can't export i64s on the web. if (!sigs.insert(sig).second) continue; // Sig is already in the set @@ -196,7 +198,7 @@ void EmscriptenGlueGenerator::generateDynCallThunks() { struct AsmConstWalker : public PostWalker<AsmConstWalker> { Module& wasm; - std::unordered_map<Address, Address> segmentsByAddress; // address => segment index + std::vector<Address> segmentOffsets; // segment index => address offset std::map<std::string, std::set<std::string>> sigsForCode; std::map<std::string, Address> ids; @@ -206,7 +208,7 @@ struct AsmConstWalker : public PostWalker<AsmConstWalker> { for (unsigned i = 0; i < wasm.memory.segments.size(); ++i) { Const* addrConst = wasm.memory.segments[i].offset->cast<Const>(); auto address = addrConst->value.geti32(); - segmentsByAddress[address] = Address(i); + segmentOffsets.push_back(address); } } @@ -214,6 +216,7 @@ struct AsmConstWalker : public PostWalker<AsmConstWalker> { private: std::string codeForConstAddr(Const* addrConst); + const char* stringAtAddr(Address adddress); Literal idLiteralForCode(std::string code); std::string asmConstSig(std::string baseSig); Name nameForImportWithSig(std::string sig); @@ -222,7 +225,8 @@ private: }; void AsmConstWalker::visitCallImport(CallImport* curr) { - if (curr->target.hasSubstring(EMSCRIPTEN_ASM_CONST)) { + Import* import = wasm.getImport(curr->target); + if (import->base.hasSubstring(EMSCRIPTEN_ASM_CONST)) { auto arg = curr->operands[0]->cast<Const>(); auto code = codeForConstAddr(arg); arg->value = idLiteralForCode(code); @@ -241,13 +245,25 @@ void AsmConstWalker::visitCallImport(CallImport* curr) { std::string AsmConstWalker::codeForConstAddr(Const* addrConst) { auto address = addrConst->value.geti32(); - auto segmentIterator = segmentsByAddress.find(address); - if (segmentIterator == segmentsByAddress.end()) { - // If we can't find the segment corresponding with the address, then we omitted the segment and the address points to an empty string. + const char* str = stringAtAddr(address); + if (!str) { + // If we can't find the segment corresponding with the address, then we + // omitted the segment and the address points to an empty string. return escape(""); } - Address segmentIndex = segmentsByAddress[address]; - return escape(&wasm.memory.segments[segmentIndex].data[0]); + auto result = escape(str); + return result; +} + +const char* AsmConstWalker::stringAtAddr(Address address) { + for (unsigned i = 0; i < wasm.memory.segments.size(); ++i) { + Memory::Segment &segment = wasm.memory.segments[i]; + Address offset = segmentOffsets[i]; + if (address >= offset && address < offset + segment.data.size()) { + return &segment.data[address - offset]; + } + } + return nullptr; } std::string AsmConstWalker::escape(const char *input) { @@ -308,6 +324,31 @@ void AsmConstWalker::addImport(Name importName, std::string baseSig) { wasm.addImport(import); } +AsmConstWalker fixEmAsmConstsAndReturnWalker(Module& wasm) { + // Collect imports to remove + // This would find our generated functions if we ran it later + std::vector<Name> toRemove; + for (auto& import : wasm.imports) { + if (import->base.hasSubstring(EMSCRIPTEN_ASM_CONST)) { + toRemove.push_back(import->name); + } + } + + // Walk the module, generate _sig versions of EM_ASM functions + AsmConstWalker walker(wasm); + walker.walkModule(&wasm); + + // Remove the base functions that we didn't generate + for (auto importName : toRemove) { + wasm.removeImport(importName); + } + return walker; +} + +void EmscriptenGlueGenerator::fixEmAsmConsts() { + fixEmAsmConstsAndReturnWalker(wasm); +} + template<class C> void printSet(std::ostream& o, C& c) { o << "["; @@ -324,11 +365,9 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata( Address staticBump, std::vector<Name> const& initializerFunctions) { std::stringstream meta; - meta << ";; METADATA: { "; + meta << "{ "; - // find asmConst calls, and emit their metadata - AsmConstWalker walker(wasm); - walker.walkModule(&wasm); + AsmConstWalker walker = fixEmAsmConstsAndReturnWalker(wasm); // print meta << "\"asmConsts\": {"; diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h index 0a0f88574..1878e6531 100644 --- a/src/wasm-emscripten.h +++ b/src/wasm-emscripten.h @@ -29,7 +29,8 @@ public: EmscriptenGlueGenerator(Module& wasm, Address stackPointerOffset = Address(0)) : wasm(wasm), builder(wasm), - stackPointerOffset(stackPointerOffset) { } + stackPointerOffset(stackPointerOffset), + useStackPointerGlobal(stackPointerOffset == 0) { } void generateRuntimeFunctions(); Function* generateMemoryGrowthFunction(); @@ -41,13 +42,18 @@ public: std::string generateEmscriptenMetadata( Address staticBump, std::vector<Name> const& initializerFunctions); + // Replace placeholder emscripten_asm_const functions with *_signature versions. + void fixEmAsmConsts(); + private: Module& wasm; Builder builder; Address stackPointerOffset; + bool useStackPointerGlobal; - Load* generateLoadStackPointer(); - Store* generateStoreStackPointer(Expression* value); + Global* getStackPointerGlobal(); + Expression* generateLoadStackPointer(); + Expression* generateStoreStackPointer(Expression* value); void generateStackSaveFunction(); void generateStackAllocFunction(); void generateStackRestoreFunction(); diff --git a/src/wasm-io.h b/src/wasm-io.h index afdc4503c..17a722472 100644 --- a/src/wasm-io.h +++ b/src/wasm-io.h @@ -42,6 +42,9 @@ public: void readBinary(std::string filename, Module& wasm); // read text or binary, checking the contents for what it is void read(std::string filename, Module& wasm); + + // check whether a file is a wasm binary + bool isBinaryFile(std::string filename); }; class ModuleWriter : public ModuleIO { diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 514b489a9..44ce9a2d1 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -61,6 +61,9 @@ void WasmBinaryWriter::write() { if (sourceMap) { writeSourceMapEpilog(); } + + writeUserSections(); + finishUp(); } @@ -551,6 +554,17 @@ static void writeBase64VLQ(std::ostream& out, int32_t n) { } } +void WasmBinaryWriter::writeUserSections() { + for (auto& section : wasm->userSections) { + auto start = startSection(0); + writeInlineString(section.name.c_str()); + for (size_t i = 0; i < section.data.size(); i++) { + o << uint8_t(section.data[i]); + } + finishSection(start); + } +} + void WasmBinaryWriter::writeDebugLocation(size_t offset, const Function::DebugLocation& loc) { if (lastBytecodeOffset > 0) { *sourceMap << ","; @@ -1626,9 +1640,9 @@ void WasmBinaryBuilder::readImports() { case ExternalKind::Global: { curr->globalType = getWasmType(); auto globalMutable = getU32LEB(); - if (globalMutable) { - throw ParseException("imported globals cannot be mutable"); - } + // TODO: actually use the globalMutable flag. Currently mutable global + // imports is a future feature, to be implemented with thread support. + (void)globalMutable; break; } default: { diff --git a/src/wasm/wasm-io.cpp b/src/wasm/wasm-io.cpp index ebc9af8de..1f50d7140 100644 --- a/src/wasm/wasm-io.cpp +++ b/src/wasm/wasm-io.cpp @@ -46,15 +46,18 @@ void ModuleReader::readBinary(std::string filename, Module& wasm) { parser.read(); } -void ModuleReader::read(std::string filename, Module& wasm) { - // see if this is a wasm binary +bool ModuleReader::isBinaryFile(std::string filename) { std::ifstream infile; std::ios_base::openmode flags = std::ifstream::in | std::ifstream::binary; infile.open(filename, flags); char buffer[4] = { 1, 2, 3, 4 }; infile.read(buffer, 4); infile.close(); - if (buffer[0] == '\0' && buffer[1] == 'a' && buffer[2] == 's' && buffer[3] == 'm') { + return buffer[0] == '\0' && buffer[1] == 'a' && buffer[2] == 's' && buffer[3] == 'm'; +} + +void ModuleReader::read(std::string filename, Module& wasm) { + if (isBinaryFile(filename)) { readBinary(filename, wasm); } else { // default to text |