summaryrefslogtreecommitdiff
path: root/src/wasm-binary.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm-binary.h')
-rw-r--r--src/wasm-binary.h86
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;