diff options
Diffstat (limited to 'src/wasm-binary.h')
-rw-r--r-- | src/wasm-binary.h | 86 |
1 files changed, 72 insertions, 14 deletions
diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 76a9b62be..d923b9ecb 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -30,13 +30,40 @@ namespace wasm { struct LEB128 { - int32_t value; - LEB128(int32_t value) : value(value) {} + uint32_t value; + + LEB128(uint32_t value) : value(value) {} + + void write(std::vector<uint8_t>* out) { + uint32_t temp = value; + do { + uint8_t byte = value & 127; + temp >>= 7; + if (temp) { + byte = byte | 128; + } + out.push_back(byte); + } while (temp); + } + + void read(std::function<uint8_t ()> get) { + value = 0; + uint32_t shift = 0; + while (1) { + uint8_t byte = get(); + value |= ((byte & 127) << shift); + if (byte & 128) break; + shift += 7; + } + } }; +// // We mostly stream into a buffer as we create the binary format, however, -// sometimes we need to backtrack and write to a location behind us. -class BufferWithRandomAccess : public std::vector<unsigned char> { +// sometimes we need to backtrack and write to a location behind us - wasm +// is optimized for reading, not writing. +// +class BufferWithRandomAccess : public std::vector<uint8_t> { public: BufferWithRandomAccess& operator<<(int8_t x) { push_back(x); @@ -66,8 +93,7 @@ public: return *this; } BufferWithRandomAccess& operator<<(LEB128 x) { - // XXX TODO - magic + x.write(this); return *this; } @@ -285,6 +311,7 @@ public: writeDataSegments(); writeFunctionTable(); writeEnd(); + finishUp(); } writeMemory() { @@ -367,10 +394,10 @@ public: } o << getFunctionTypeIndex(type); o << int8_t(FunctionEntry::Named | - (FunctionEntry::Import * !!import) | - (FunctionEntry::Locals * (function && function->locals.size() > 0) | - (FunctionEntry::Export) * (wasm.exportsMap[name].count(name) > 0))); - // TODO: name. how can we do an offset? into what section? and how do we know it now? + (FunctionEntry::Import * !!import) | + (FunctionEntry::Locals * (function && function->locals.size() > 0) | + (FunctionEntry::Export) * (wasm.exportsMap[name].count(name) > 0))); + emitString(Name.str); if (function && function->locals.size() > 0) { mapLocals(function); o << uint16_t(numLocalsByType[i32]) @@ -389,10 +416,10 @@ public: writeDataSegments() { o << Section::DataSegments << LEB128(wasm.memory.segments.size()); for (auto& segment : wasm.memory.segments) { - o << int32_t(segment.offset) - << int32_t(XXX) // TODO: where/when do we emit this? - << int32_t(segment.size) - << int8_t(1); // load at program start + o << int32_t(segment.offset); + emitBuffer(segment.data, segment.size); + o << int32_t(segment.size); + o << int8_t(1); // load at program start } } @@ -418,6 +445,37 @@ public: o << Section::End; } + // helpers + + struct Buffer { + const char* data; + size_t size; + size_t pointerLocation; + Buffer(const char* data, size_t size, size_t pointerLocation) : data(data), size(size), pointerLocation(pointerLocation) {} + }; + + std::vector<Buffer> buffersToWrite; + + void emitBuffer(const char* data, size_t size) { + assert(size > 0); + buffersToWrite.emplace_back(data, size, o.size()); + o << uint32_t(0); // placeholder + } + + void emitString(const char *str) { + emitBuffer(str, strlen(str) + 1); + } + + void finishUp() { + // finish buffers + for (auto& buffer : buffersToWrite) { + o.writeAt(buffer.pointerLocation, (uint32_t)o.size()); + for (size_t i = 0; i < buffer.size; i++) { + o << buffer.data[i]; + } + } + } + // AST writing via visitors std::vector<Name> breakStack; |