summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcheck.py6
-rw-r--r--src/asm2wasm.h61
-rw-r--r--src/asm_v_wasm.h22
-rw-r--r--src/asmjs/asm_v_wasm.cpp30
-rw-r--r--src/ast_utils.h10
-rw-r--r--src/binaryen-shell.cpp4
-rw-r--r--src/mixed_arena.h162
-rw-r--r--src/passes/MergeBlocks.cpp2
-rw-r--r--src/passes/Print.cpp3
-rw-r--r--src/passes/RemoveUnusedBrs.cpp2
-rw-r--r--src/s2wasm.h2
-rw-r--r--src/wasm-binary.h224
-rw-r--r--src/wasm-builder.h6
-rw-r--r--src/wasm-linker.cpp19
-rw-r--r--src/wasm-s-parser.h13
-rw-r--r--src/wasm.h155
-rw-r--r--src/wasm2asm.h54
17 files changed, 478 insertions, 297 deletions
diff --git a/check.py b/check.py
index 025fc60e9..d405cd287 100755
--- a/check.py
+++ b/check.py
@@ -212,19 +212,19 @@ def binary_format_check(wast, verify_final_result=True):
cmd = [os.path.join('bin', 'wasm-as'), wast, '-o', 'a.wasm']
print ' ', ' '.join(cmd)
if os.path.exists('a.wasm'): os.unlink('a.wasm')
- subprocess.check_call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ subprocess.check_call(cmd, stdout=subprocess.PIPE)
assert os.path.exists('a.wasm')
cmd = [os.path.join('bin', 'wasm-dis'), 'a.wasm', '-o', 'ab.wast']
print ' ', ' '.join(cmd)
if os.path.exists('ab.wast'): os.unlink('ab.wast')
- subprocess.check_call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ subprocess.check_call(cmd, stdout=subprocess.PIPE)
assert os.path.exists('ab.wast')
# make sure it is a valid wast
cmd = [os.path.join('bin', 'binaryen-shell'), 'ab.wast']
print ' ', ' '.join(cmd)
- subprocess.check_call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ subprocess.check_call(cmd, stdout=subprocess.PIPE)
if verify_final_result:
expected = open(wast + '.fromBinary').read()
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index c852885f8..1da59d2f2 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -216,41 +216,41 @@ private:
// function types. we fill in this information as we see
// uses, in the first pass
- std::map<IString, FunctionType> importedFunctionTypes;
+ std::map<IString, FunctionType*> importedFunctionTypes;
std::map<IString, std::vector<CallImport*>> importedFunctionCalls;
void noteImportedFunctionCall(Ref ast, WasmType resultType, AsmData *asmData, CallImport* call) {
assert(ast[0] == CALL && ast[1][0] == NAME);
IString importName = ast[1][1]->getIString();
- FunctionType type;
- type.name = IString((std::string("type$") + importName.str).c_str(), false); // TODO: make a list of such types
- type.result = resultType;
+ auto* type = allocator.alloc<FunctionType>();
+ type->name = IString((std::string("type$") + importName.str).c_str(), false); // TODO: make a list of such types
+ type->result = resultType;
Ref args = ast[2];
for (unsigned i = 0; i < args->size(); i++) {
- type.params.push_back(detectWasmType(args[i], asmData));
+ type->params.push_back(detectWasmType(args[i], asmData));
}
// if we already saw this signature, verify it's the same (or else handle that)
if (importedFunctionTypes.find(importName) != importedFunctionTypes.end()) {
- FunctionType& previous = importedFunctionTypes[importName];
+ FunctionType* previous = importedFunctionTypes[importName];
#if 0
std::cout << "compare " << importName.str << "\nfirst: ";
type.print(std::cout, 0);
std::cout << "\nsecond: ";
previous.print(std::cout, 0) << ".\n";
#endif
- if (type != previous) {
+ if (*type != *previous) {
// merge it in. we'll add on extra 0 parameters for ones not actually used, etc.
- for (size_t i = 0; i < type.params.size(); i++) {
- if (previous.params.size() > i) {
- if (previous.params[i] == none) {
- previous.params[i] = type.params[i]; // use a more concrete type
+ for (size_t i = 0; i < type->params.size(); i++) {
+ if (previous->params.size() > i) {
+ if (previous->params[i] == none) {
+ previous->params[i] = type->params[i]; // use a more concrete type
}
} else {
- previous.params.push_back(type.params[i]); // add a new param
+ previous->params.push_back(type->params[i]); // add a new param
}
}
- if (previous.result == none) {
- previous.result = type.result; // use a more concrete type
+ if (previous->result == none) {
+ previous->result = type->result; // use a more concrete type
}
}
} else {
@@ -262,7 +262,7 @@ private:
FunctionType* getFunctionType(Ref parent, ExpressionList& operands) {
// generate signature
WasmType result = !!parent ? detectWasmType(parent, nullptr) : none;
- return ensureFunctionType(getSig(result, operands), &wasm, allocator);
+ return ensureFunctionType(getSig(result, operands), &wasm);
}
public:
@@ -423,9 +423,9 @@ private:
if (base == ABS) {
assert(operands && operands->size() == 1);
WasmType type = (*operands)[0]->type;
- if (type == i32) return ensureFunctionType("ii", &wasm, allocator);
- if (type == f32) return ensureFunctionType("ff", &wasm, allocator);
- if (type == f64) return ensureFunctionType("dd", &wasm, allocator);
+ if (type == i32) return ensureFunctionType("ii", &wasm);
+ if (type == f32) return ensureFunctionType("ff", &wasm);
+ if (type == f64) return ensureFunctionType("dd", &wasm);
}
}
return nullptr;
@@ -699,7 +699,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
import->type = builtin;
continue;
}
- import->type = ensureFunctionType(getSig(&importedFunctionTypes[name]), &wasm, allocator);
+ import->type = ensureFunctionType(getSig(importedFunctionTypes[name]), &wasm);
} else if (import->module != ASM2WASM) { // special-case the special module
// never actually used
toErase.push_back(name);
@@ -716,9 +716,9 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
auto& list = pair.second;
auto type = importedFunctionTypes[name];
for (auto* call : list) {
- for (size_t i = call->operands.size(); i < type.params.size(); i++) {
+ for (size_t i = call->operands.size(); i < type->params.size(); i++) {
auto val = allocator.alloc<Const>();
- val->type = val->value.type = type.params[i];
+ val->type = val->value.type = type->params[i];
call->operands.push_back(val);
}
}
@@ -1021,7 +1021,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
import->name = F64_REM;
import->module = ASM2WASM;
import->base = F64_REM;
- import->type = ensureFunctionType("ddd", &wasm, allocator);
+ import->type = ensureFunctionType("ddd", &wasm);
wasm.addImport(import);
}
return call;
@@ -1059,7 +1059,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
import->name = DEBUGGER;
import->module = ASM2WASM;
import->base = DEBUGGER;
- import->type = ensureFunctionType("v", &wasm, allocator);
+ import->type = ensureFunctionType("v", &wasm);
wasm.addImport(import);
}
return call;
@@ -1172,7 +1172,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
import->name = F64_TO_INT;
import->module = ASM2WASM;
import->base = F64_TO_INT;
- import->type = ensureFunctionType("id", &wasm, allocator);
+ import->type = ensureFunctionType("id", &wasm);
wasm.addImport(import);
}
return ret;
@@ -1303,20 +1303,25 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
abort();
}
}
- Call* ret;
+ Expression* ret;
+ ExpressionList* operands;
if (wasm.checkImport(name)) {
Ref parent = astStackHelper.getParent();
WasmType type = !!parent ? detectWasmType(parent, &asmData) : none;
auto specific = allocator.alloc<CallImport>();
noteImportedFunctionCall(ast, type, &asmData, specific);
+ specific->target = name;
+ operands = &specific->operands;
ret = specific;
} else {
- ret = allocator.alloc<Call>();
+ auto specific = allocator.alloc<Call>();
+ specific->target = name;
+ operands = &specific->operands;
+ ret = specific;
}
- ret->target = name;
Ref args = ast[2];
for (unsigned i = 0; i < args->size(); i++) {
- ret->operands.push_back(process(args[i]));
+ operands->push_back(process(args[i]));
}
return ret;
}
diff --git a/src/asm_v_wasm.h b/src/asm_v_wasm.h
index 27acf3dcc..cfb4d44d5 100644
--- a/src/asm_v_wasm.h
+++ b/src/asm_v_wasm.h
@@ -33,15 +33,31 @@ std::string getSig(FunctionType *type);
std::string getSig(Function *func);
-std::string getSig(CallBase *call);
+template<typename CallBase>
+std::string getSig(CallBase *call) {
+ std::string ret;
+ ret += getSig(call->type);
+ for (auto operand : call->operands) {
+ ret += getSig(operand->type);
+ }
+ return ret;
+}
-std::string getSig(WasmType result, const ExpressionList& operands);
+template<typename ListType>
+std::string getSig(WasmType result, const ListType& operands) {
+ std::string ret;
+ ret += getSig(result);
+ for (auto operand : operands) {
+ ret += getSig(operand->type);
+ }
+ return ret;
+}
WasmType sigToWasmType(char sig);
FunctionType sigToFunctionType(std::string sig);
-FunctionType* ensureFunctionType(std::string sig, Module* wasm, MixedArena& allocator);
+FunctionType* ensureFunctionType(std::string sig, Module* wasm);
} // namespace wasm
diff --git a/src/asmjs/asm_v_wasm.cpp b/src/asmjs/asm_v_wasm.cpp
index 317a8b625..3e7e0241e 100644
--- a/src/asmjs/asm_v_wasm.cpp
+++ b/src/asmjs/asm_v_wasm.cpp
@@ -71,24 +71,6 @@ std::string getSig(Function *func) {
return ret;
}
-std::string getSig(CallBase *call) {
- std::string ret;
- ret += getSig(call->type);
- for (auto operand : call->operands) {
- ret += getSig(operand->type);
- }
- return ret;
-}
-
-std::string getSig(WasmType result, const ExpressionList& operands) {
- std::string ret;
- ret += getSig(result);
- for (auto operand : operands) {
- ret += getSig(operand->type);
- }
- return ret;
-}
-
WasmType sigToWasmType(char sig) {
switch (sig) {
case 'i': return i32;
@@ -100,22 +82,22 @@ WasmType sigToWasmType(char sig) {
}
}
-FunctionType sigToFunctionType(std::string sig) {
- FunctionType ret;
- ret.result = sigToWasmType(sig[0]);
+FunctionType* sigToFunctionType(std::string sig, MixedArena& allocator) {
+ auto ret = allocator.alloc<FunctionType>();
+ ret->result = sigToWasmType(sig[0]);
for (size_t i = 1; i < sig.size(); i++) {
- ret.params.push_back(sigToWasmType(sig[i]));
+ ret->params.push_back(sigToWasmType(sig[i]));
}
return ret;
}
-FunctionType* ensureFunctionType(std::string sig, Module* wasm, MixedArena& allocator) {
+FunctionType* ensureFunctionType(std::string sig, Module* wasm) {
cashew::IString name(("FUNCSIG$" + sig).c_str(), false);
if (wasm->checkFunctionType(name)) {
return wasm->getFunctionType(name);
}
// add new type
- auto type = allocator.alloc<FunctionType>();
+ auto type = wasm->allocator.alloc<FunctionType>();
type->name = name;
type->result = sigToWasmType(sig[0]);
for (size_t i = 1; i < sig.size(); i++) {
diff --git a/src/ast_utils.h b/src/ast_utils.h
index 66dbf039a..5b569435e 100644
--- a/src/ast_utils.h
+++ b/src/ast_utils.h
@@ -136,6 +136,16 @@ struct ExpressionManipulator {
static void nop(InputType* target) {
convert<InputType, Nop>(target);
}
+
+ // Convert a node that allocates
+ template<typename InputType, typename OutputType>
+ static OutputType* convert(InputType *input, MixedArena& allocator) {
+ assert(sizeof(OutputType) <= sizeof(InputType));
+ input->~InputType(); // arena-allocaed, so no destructor, but avoid UB.
+ OutputType* output = (OutputType*)(input);
+ new (output) OutputType(allocator);
+ return output;
+ }
};
struct ExpressionAnalyzer {
diff --git a/src/binaryen-shell.cpp b/src/binaryen-shell.cpp
index 12cda7a5d..4f2890969 100644
--- a/src/binaryen-shell.cpp
+++ b/src/binaryen-shell.cpp
@@ -34,10 +34,6 @@
using namespace cashew;
using namespace wasm;
-// Globals
-
-MixedArena globalAllocator;
-
//
// An invocation into a module
//
diff --git a/src/mixed_arena.h b/src/mixed_arena.h
index a89880953..930bf3c0e 100644
--- a/src/mixed_arena.h
+++ b/src/mixed_arena.h
@@ -58,7 +58,8 @@
struct MixedArena {
// fast bump allocation
std::vector<char*> chunks;
- int index; // in last chunk
+ size_t chunkSize = 32768;
+ size_t index; // in last chunk
// multithreaded allocation - each arena is valid on a specific thread.
// if we are on the wrong thread, we safely look in the linked
@@ -73,8 +74,7 @@ struct MixedArena {
next = nullptr;
}
- template<class T>
- T* alloc() {
+ void* allocSpace(size_t size) {
// the bump allocator data should not be modified by multiple threads at once.
if (std::this_thread::get_id() != threadId) {
// TODO use a fast double-checked locking pattern.
@@ -87,18 +87,27 @@ struct MixedArena {
curr->next = new MixedArena(); // will have our thread id
}
}
- return curr->alloc<T>();
+ return curr->allocSpace(size);
}
- const size_t CHUNK = 10000;
- size_t currSize = (sizeof(T) + 7) & (-8); // same alignment as malloc TODO optimize?
- assert(currSize < CHUNK);
- if (chunks.size() == 0 || index + currSize >= CHUNK) {
- chunks.push_back(new char[CHUNK]);
+ size = (size + 7) & (-8); // same alignment as malloc TODO optimize?
+ bool mustAllocate = false;
+ while (chunkSize <= size) {
+ chunkSize *= 2;
+ mustAllocate = true;
+ }
+ if (chunks.size() == 0 || index + size >= chunkSize || mustAllocate) {
+ chunks.push_back(new char[chunkSize]);
index = 0;
}
- T* ret = (T*)(chunks.back() + index);
- index += currSize;
- new (ret) T();
+ auto* ret = chunks.back() + index;
+ index += size;
+ return static_cast<void*>(ret);
+ }
+
+ template<class T>
+ T* alloc() {
+ auto* ret = static_cast<T*>(allocSpace(sizeof(T)));
+ new (ret) T(*this); // allocated objects receive the allocator, so they can allocate more later if necessary
return ret;
}
@@ -115,6 +124,133 @@ struct MixedArena {
}
};
-extern MixedArena globalAllocator;
+
+//
+// A vector that allocates in an arena.
+//
+// TODO: consider not saving the allocator, but requiring it be
+// passed in when needed, would make this (and thus Blocks etc.
+// smaller)
+//
+// TODO: specialize on the initial size of the array
+
+template <typename T>
+class ArenaVector {
+ MixedArena& allocator;
+ T* data = nullptr;
+ size_t usedElements = 0,
+ allocatedElements = 0;
+
+ void allocate(size_t size) {
+ allocatedElements = size;
+ data = static_cast<T*>(allocator.allocSpace(sizeof(T) * allocatedElements));
+ }
+
+ void reallocate(size_t size) {
+ T* old = data;
+ allocate(size);
+ for (size_t i = 0; i < usedElements; i++) {
+ data[i] = old[i];
+ }
+ }
+
+public:
+ ArenaVector(MixedArena& allocator) : allocator(allocator) {}
+
+ ArenaVector(ArenaVector<T>&& other) : allocator(other.allocator) {
+ *this = other;
+ }
+
+ T& operator[](size_t index) const {
+ assert(index < usedElements);
+ return data[index];
+ }
+
+ size_t size() const {
+ return usedElements;
+ }
+
+ void resize(size_t size) {
+ if (size > allocatedElements) {
+ reallocate(size);
+ }
+ // construct new elements
+ for (size_t i = usedElements; i < size; i++) {
+ new (data + i) T();
+ }
+ usedElements = size;
+ }
+
+ T& back() const {
+ assert(usedElements > 0);
+ return data[usedElements - 1];
+ }
+
+ T& pop_back() {
+ assert(usedElements > 0);
+ usedElements--;
+ return data[usedElements];
+ }
+
+ void push_back(T item) {
+ if (usedElements == allocatedElements) {
+ reallocate((allocatedElements + 1) * 2); // TODO: optimize
+ }
+ data[usedElements] = item;
+ usedElements++;
+ }
+
+ template<typename ListType>
+ void set(ListType& list) {
+ size_t size = list.size();
+ if (allocatedElements < size) {
+ allocate(size);
+ }
+ for (size_t i = 0; i < size; i++) {
+ data[i] = list[i];
+ }
+ usedElements = size;
+ }
+
+ void operator=(ArenaVector<T>& other) {
+ set(other);
+ }
+
+ void operator=(ArenaVector<T>&& other) {
+ data = other.data;
+ usedElements = other.usedElements;
+ allocatedElements = other.allocatedElements;
+ other.data = nullptr;
+ other.usedElements = other.allocatedElements = 0;
+ }
+
+ // iteration
+
+ struct Iterator {
+ const ArenaVector<T>* parent;
+ size_t index;
+
+ Iterator(const ArenaVector<T>* parent, size_t index) : parent(parent), index(index) {}
+
+ bool operator!=(const Iterator& other) const {
+ return index != other.index || parent != other.parent;
+ }
+
+ void operator++() {
+ index++;
+ }
+
+ T& operator*() {
+ return (*parent)[index];
+ }
+ };
+
+ Iterator begin() const {
+ return Iterator(this, 0);
+ }
+ Iterator end() const {
+ return Iterator(this, usedElements);
+ }
+};
#endif // wasm_mixed_arena_h
diff --git a/src/passes/MergeBlocks.cpp b/src/passes/MergeBlocks.cpp
index f3b85ab3d..d26817e18 100644
--- a/src/passes/MergeBlocks.cpp
+++ b/src/passes/MergeBlocks.cpp
@@ -34,7 +34,7 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks, Visitor<MergeBloc
Block* child = curr->list[i]->dynCast<Block>();
if (!child) continue;
if (child->name.is()) continue; // named blocks can have breaks to them (and certainly do, if we ran RemoveUnusedNames and RemoveUnusedBrs)
- ExpressionList merged;
+ ExpressionList merged(getModule()->allocator);
for (size_t j = 0; j < i; j++) {
merged.push_back(curr->list[j]);
}
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index bb89b2720..eb0a6d33b 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -186,7 +186,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
decIndent();
}
- void printCallBody(Call* curr) {
+ template<typename CallBase>
+ void printCallBody(CallBase* curr) {
o << curr->target;
if (curr->operands.size() > 0) {
incIndent();
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp
index 5c21908a8..570e14b38 100644
--- a/src/passes/RemoveUnusedBrs.cpp
+++ b/src/passes/RemoveUnusedBrs.cpp
@@ -82,7 +82,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R
if (!flow->value || self->valueCanFlow) {
if (!flow->value) {
// br => nop
- ExpressionManipulator::nop(flow);
+ ExpressionManipulator::nop<Break>(flow);
} else {
// br with value => value
*flows[i] = flow->value;
diff --git a/src/s2wasm.h b/src/s2wasm.h
index 94684facf..00e6b12a2 100644
--- a/src/s2wasm.h
+++ b/src/s2wasm.h
@@ -689,7 +689,7 @@ class S2WasmBuilder {
auto input = inputs.begin();
auto* target = *input;
std::vector<Expression*> operands(++input, inputs.end());
- auto* funcType = ensureFunctionType(getSig(type, operands), &wasm, allocator);
+ auto* funcType = ensureFunctionType(getSig(type, operands), &wasm);
assert(type == funcType->result);
auto* indirect = builder.makeCallIndirect(funcType, target, std::move(operands));
setOutput(indirect, assign);
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index ea57d5d3b..d13e1a526 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -451,7 +451,7 @@ class WasmBinaryWriter : public Visitor<WasmBinaryWriter, void> {
// we need function types for all our functions
for (auto* func : wasm->functions) {
if (func->type.isNull()) {
- func->type = ensureFunctionType(getSig(func), wasm, allocator)->name;
+ func->type = ensureFunctionType(getSig(func), wasm)->name;
}
}
}
@@ -1616,12 +1616,12 @@ public:
case BinaryConsts::Else: curr = nullptr; break;
default: {
// otherwise, the code is a subcode TODO: optimize
- if (maybeVisit<Binary>(curr, code)) break;
- if (maybeVisit<Unary>(curr, code)) break;
- if (maybeVisit<Const>(curr, code)) break;
- if (maybeVisit<Load>(curr, code)) break;
- if (maybeVisit<Store>(curr, code)) break;
- if (maybeVisit<Host>(curr, code)) break;
+ if (maybeVisitBinary(curr, code)) break;
+ if (maybeVisitUnary(curr, code)) break;
+ if (maybeVisitConst(curr, code)) break;
+ if (maybeVisitLoad(curr, code)) break;
+ if (maybeVisitStore(curr, code)) break;
+ if (maybeVisitHost(curr, code)) break;
std::cerr << "bad code 0x" << std::hex << (int)code << std::endl;
abort();
}
@@ -1630,18 +1630,6 @@ public:
return BinaryConsts::ASTNodes(code);
}
- template<typename T>
- bool maybeVisit(Expression*& curr, uint8_t code) {
- T temp;
- if (maybeVisitImpl(&temp, code)) {
- auto actual = allocator.alloc<T>();
- *actual = temp;
- curr = actual;
- return true;
- }
- return false;
- }
-
void visitBlock(Block *curr) {
if (debug) std::cerr << "zz node: Block" << std::endl;
// special-case Block and de-recurse nested blocks in their first position, as that is
@@ -1817,134 +1805,143 @@ public:
offset = getU32LEB();
}
- bool maybeVisitImpl(Load *curr, uint8_t code) {
+ bool maybeVisitLoad(Expression*& out, uint8_t code) {
+ Load* curr;
switch (code) {
- case BinaryConsts::I32LoadMem8S: curr->bytes = 1; curr->type = i32; curr->signed_ = true; break;
- case BinaryConsts::I32LoadMem8U: curr->bytes = 1; curr->type = i32; curr->signed_ = false; break;
- case BinaryConsts::I32LoadMem16S: curr->bytes = 2; curr->type = i32; curr->signed_ = true; break;
- case BinaryConsts::I32LoadMem16U: curr->bytes = 2; curr->type = i32; curr->signed_ = false; break;
- case BinaryConsts::I32LoadMem: curr->bytes = 4; curr->type = i32; break;
- case BinaryConsts::I64LoadMem8S: curr->bytes = 1; curr->type = i64; curr->signed_ = true; break;
- case BinaryConsts::I64LoadMem8U: curr->bytes = 1; curr->type = i64; curr->signed_ = false; break;
- case BinaryConsts::I64LoadMem16S: curr->bytes = 2; curr->type = i64; curr->signed_ = true; break;
- case BinaryConsts::I64LoadMem16U: curr->bytes = 2; curr->type = i64; curr->signed_ = false; break;
- case BinaryConsts::I64LoadMem32S: curr->bytes = 4; curr->type = i64; curr->signed_ = true; break;
- case BinaryConsts::I64LoadMem32U: curr->bytes = 4; curr->type = i64; curr->signed_ = false; break;
- case BinaryConsts::I64LoadMem: curr->bytes = 8; curr->type = i64; break;
- case BinaryConsts::F32LoadMem: curr->bytes = 4; curr->type = f32; break;
- case BinaryConsts::F64LoadMem: curr->bytes = 8; curr->type = f64; break;
+ case BinaryConsts::I32LoadMem8S: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i32; curr->signed_ = true; break;
+ case BinaryConsts::I32LoadMem8U: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i32; curr->signed_ = false; break;
+ case BinaryConsts::I32LoadMem16S: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i32; curr->signed_ = true; break;
+ case BinaryConsts::I32LoadMem16U: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i32; curr->signed_ = false; break;
+ case BinaryConsts::I32LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i32; break;
+ case BinaryConsts::I64LoadMem8S: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i64; curr->signed_ = true; break;
+ case BinaryConsts::I64LoadMem8U: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i64; curr->signed_ = false; break;
+ case BinaryConsts::I64LoadMem16S: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i64; curr->signed_ = true; break;
+ case BinaryConsts::I64LoadMem16U: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i64; curr->signed_ = false; break;
+ case BinaryConsts::I64LoadMem32S: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i64; curr->signed_ = true; break;
+ case BinaryConsts::I64LoadMem32U: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i64; curr->signed_ = false; break;
+ case BinaryConsts::I64LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 8; curr->type = i64; break;
+ case BinaryConsts::F32LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = f32; break;
+ case BinaryConsts::F64LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 8; curr->type = f64; break;
default: return false;
}
if (debug) std::cerr << "zz node: Load" << std::endl;
readMemoryAccess(curr->align, curr->bytes, curr->offset);
curr->ptr = popExpression();
+ out = curr;
return true;
}
- bool maybeVisitImpl(Store *curr, uint8_t code) {
+ bool maybeVisitStore(Expression*& out, uint8_t code) {
+ Store* curr;
switch (code) {
- case BinaryConsts::I32StoreMem8: curr->bytes = 1; curr->type = i32; break;
- case BinaryConsts::I32StoreMem16: curr->bytes = 2; curr->type = i32; break;
- case BinaryConsts::I32StoreMem: curr->bytes = 4; curr->type = i32; break;
- case BinaryConsts::I64StoreMem8: curr->bytes = 1; curr->type = i64; break;
- case BinaryConsts::I64StoreMem16: curr->bytes = 2; curr->type = i64; break;
- case BinaryConsts::I64StoreMem32: curr->bytes = 4; curr->type = i64; break;
- case BinaryConsts::I64StoreMem: curr->bytes = 8; curr->type = i64; break;
- case BinaryConsts::F32StoreMem: curr->bytes = 4; curr->type = f32; break;
- case BinaryConsts::F64StoreMem: curr->bytes = 8; curr->type = f64; break;
+ case BinaryConsts::I32StoreMem8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->type = i32; break;
+ case BinaryConsts::I32StoreMem16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->type = i32; break;
+ case BinaryConsts::I32StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->type = i32; break;
+ case BinaryConsts::I64StoreMem8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->type = i64; break;
+ case BinaryConsts::I64StoreMem16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->type = i64; break;
+ case BinaryConsts::I64StoreMem32: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->type = i64; break;
+ case BinaryConsts::I64StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->type = i64; break;
+ case BinaryConsts::F32StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->type = f32; break;
+ case BinaryConsts::F64StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->type = f64; break;
default: return false;
}
if (debug) std::cerr << "zz node: Store" << std::endl;
readMemoryAccess(curr->align, curr->bytes, curr->offset);
curr->value = popExpression();
curr->ptr = popExpression();
+ out = curr;
return true;
}
- bool maybeVisitImpl(Const *curr, uint8_t code) {
+ bool maybeVisitConst(Expression*& out, uint8_t code) {
+ Const* curr;
switch (code) {
- case BinaryConsts::I32Const: curr->value = Literal(getS32LEB()); break;
- case BinaryConsts::I64Const: curr->value = Literal(getS64LEB()); break;
- case BinaryConsts::F32Const: curr->value = Literal(getFloat32()); break;
- case BinaryConsts::F64Const: curr->value = Literal(getFloat64()); break;
+ case BinaryConsts::I32Const: curr = allocator.alloc<Const>(); curr->value = Literal(getS32LEB()); break;
+ case BinaryConsts::I64Const: curr = allocator.alloc<Const>(); curr->value = Literal(getS64LEB()); break;
+ case BinaryConsts::F32Const: curr = allocator.alloc<Const>(); curr->value = Literal(getFloat32()); break;
+ case BinaryConsts::F64Const: curr = allocator.alloc<Const>(); curr->value = Literal(getFloat64()); break;
default: return false;
}
curr->type = curr->value.type;
+ out = curr;
if (debug) std::cerr << "zz node: Const" << std::endl;
return true;
}
- bool maybeVisitImpl(Unary *curr, uint8_t code) {
+ bool maybeVisitUnary(Expression*& out, uint8_t code) {
+ Unary* curr;
switch (code) {
- case BinaryConsts::I32Clz: curr->op = Clz; curr->type = i32; break;
- case BinaryConsts::I64Clz: curr->op = Clz; curr->type = i64; break;
- case BinaryConsts::I32Ctz: curr->op = Ctz; curr->type = i32; break;
- case BinaryConsts::I64Ctz: curr->op = Ctz; curr->type = i64; break;
- case BinaryConsts::I32Popcnt: curr->op = Popcnt; curr->type = i32; break;
- case BinaryConsts::I64Popcnt: curr->op = Popcnt; curr->type = i64; break;
- case BinaryConsts::I32EqZ: curr->op = EqZ; curr->type = i32; break;
- case BinaryConsts::I64EqZ: curr->op = EqZ; curr->type = i64; break;
- case BinaryConsts::F32Neg: curr->op = Neg; curr->type = f32; break;
- case BinaryConsts::F64Neg: curr->op = Neg; curr->type = f64; break;
- case BinaryConsts::F32Abs: curr->op = Abs; curr->type = f32; break;
- case BinaryConsts::F64Abs: curr->op = Abs; curr->type = f64; break;
- case BinaryConsts::F32Ceil: curr->op = Ceil; curr->type = f32; break;
- case BinaryConsts::F64Ceil: curr->op = Ceil; curr->type = f64; break;
- case BinaryConsts::F32Floor: curr->op = Floor; curr->type = f32; break;
- case BinaryConsts::F64Floor: curr->op = Floor; curr->type = f64; break;
- case BinaryConsts::F32NearestInt: curr->op = Nearest; curr->type = f32; break;
- case BinaryConsts::F64NearestInt: curr->op = Nearest; curr->type = f64; break;
- case BinaryConsts::F32Sqrt: curr->op = Sqrt; curr->type = f32; break;
- case BinaryConsts::F64Sqrt: curr->op = Sqrt; curr->type = f64; break;
- case BinaryConsts::F32UConvertI32: curr->op = ConvertUInt32; curr->type = f32; break;
- case BinaryConsts::F64UConvertI32: curr->op = ConvertUInt32; curr->type = f64; break;
- case BinaryConsts::F32SConvertI32: curr->op = ConvertSInt32; curr->type = f32; break;
- case BinaryConsts::F64SConvertI32: curr->op = ConvertSInt32; curr->type = f64; break;
- case BinaryConsts::F32UConvertI64: curr->op = ConvertUInt64; curr->type = f32; break;
- case BinaryConsts::F64UConvertI64: curr->op = ConvertUInt64; curr->type = f64; break;
- case BinaryConsts::F32SConvertI64: curr->op = ConvertSInt64; curr->type = f32; break;
- case BinaryConsts::F64SConvertI64: curr->op = ConvertSInt64; curr->type = f64; break;
-
- case BinaryConsts::I64STruncI32: curr->op = ExtendSInt32; curr->type = i64; break;
- case BinaryConsts::I64UTruncI32: curr->op = ExtendUInt32; curr->type = i64; break;
- case BinaryConsts::I32ConvertI64: curr->op = WrapInt64; curr->type = i32; break;
-
- case BinaryConsts::I32UTruncF32: curr->op = TruncUFloat32; curr->type = i32; break;
- case BinaryConsts::I32UTruncF64: curr->op = TruncUFloat64; curr->type = i32; break;
- case BinaryConsts::I32STruncF32: curr->op = TruncSFloat32; curr->type = i32; break;
- case BinaryConsts::I32STruncF64: curr->op = TruncSFloat64; curr->type = i32; break;
- case BinaryConsts::I64UTruncF32: curr->op = TruncUFloat32; curr->type = i64; break;
- case BinaryConsts::I64UTruncF64: curr->op = TruncUFloat64; curr->type = i64; break;
- case BinaryConsts::I64STruncF32: curr->op = TruncSFloat32; curr->type = i64; break;
- case BinaryConsts::I64STruncF64: curr->op = TruncSFloat64; curr->type = i64; break;
-
- case BinaryConsts::F32Trunc: curr->op = Trunc; curr->type = f32; break;
- case BinaryConsts::F64Trunc: curr->op = Trunc; curr->type = f64; break;
-
- case BinaryConsts::F32ConvertF64: curr->op = DemoteFloat64; curr->type = f32; break;
- case BinaryConsts::F64ConvertF32: curr->op = PromoteFloat32; curr->type = f64; break;
- case BinaryConsts::F32ReinterpretI32: curr->op = ReinterpretFloat; curr->type = i32; break;
- case BinaryConsts::F64ReinterpretI64: curr->op = ReinterpretFloat; curr->type = i64; break;
- case BinaryConsts::I64ReinterpretF64: curr->op = ReinterpretInt; curr->type = f64; break;
- case BinaryConsts::I32ReinterpretF32: curr->op = ReinterpretInt; curr->type = f32; break;
+ case BinaryConsts::I32Clz: curr = allocator.alloc<Unary>(); curr->op = Clz; curr->type = i32; break;
+ case BinaryConsts::I64Clz: curr = allocator.alloc<Unary>(); curr->op = Clz; curr->type = i64; break;
+ case BinaryConsts::I32Ctz: curr = allocator.alloc<Unary>(); curr->op = Ctz; curr->type = i32; break;
+ case BinaryConsts::I64Ctz: curr = allocator.alloc<Unary>(); curr->op = Ctz; curr->type = i64; break;
+ case BinaryConsts::I32Popcnt: curr = allocator.alloc<Unary>(); curr->op = Popcnt; curr->type = i32; break;
+ case BinaryConsts::I64Popcnt: curr = allocator.alloc<Unary>(); curr->op = Popcnt; curr->type = i64; break;
+ case BinaryConsts::I32EqZ: curr = allocator.alloc<Unary>(); curr->op = EqZ; curr->type = i32; break;
+ case BinaryConsts::I64EqZ: curr = allocator.alloc<Unary>(); curr->op = EqZ; curr->type = i64; break;
+ case BinaryConsts::F32Neg: curr = allocator.alloc<Unary>(); curr->op = Neg; curr->type = f32; break;
+ case BinaryConsts::F64Neg: curr = allocator.alloc<Unary>(); curr->op = Neg; curr->type = f64; break;
+ case BinaryConsts::F32Abs: curr = allocator.alloc<Unary>(); curr->op = Abs; curr->type = f32; break;
+ case BinaryConsts::F64Abs: curr = allocator.alloc<Unary>(); curr->op = Abs; curr->type = f64; break;
+ case BinaryConsts::F32Ceil: curr = allocator.alloc<Unary>(); curr->op = Ceil; curr->type = f32; break;
+ case BinaryConsts::F64Ceil: curr = allocator.alloc<Unary>(); curr->op = Ceil; curr->type = f64; break;
+ case BinaryConsts::F32Floor: curr = allocator.alloc<Unary>(); curr->op = Floor; curr->type = f32; break;
+ case BinaryConsts::F64Floor: curr = allocator.alloc<Unary>(); curr->op = Floor; curr->type = f64; break;
+ case BinaryConsts::F32NearestInt: curr = allocator.alloc<Unary>(); curr->op = Nearest; curr->type = f32; break;
+ case BinaryConsts::F64NearestInt: curr = allocator.alloc<Unary>(); curr->op = Nearest; curr->type = f64; break;
+ case BinaryConsts::F32Sqrt: curr = allocator.alloc<Unary>(); curr->op = Sqrt; curr->type = f32; break;
+ case BinaryConsts::F64Sqrt: curr = allocator.alloc<Unary>(); curr->op = Sqrt; curr->type = f64; break;
+ case BinaryConsts::F32UConvertI32: curr = allocator.alloc<Unary>(); curr->op = ConvertUInt32; curr->type = f32; break;
+ case BinaryConsts::F64UConvertI32: curr = allocator.alloc<Unary>(); curr->op = ConvertUInt32; curr->type = f64; break;
+ case BinaryConsts::F32SConvertI32: curr = allocator.alloc<Unary>(); curr->op = ConvertSInt32; curr->type = f32; break;
+ case BinaryConsts::F64SConvertI32: curr = allocator.alloc<Unary>(); curr->op = ConvertSInt32; curr->type = f64; break;
+ case BinaryConsts::F32UConvertI64: curr = allocator.alloc<Unary>(); curr->op = ConvertUInt64; curr->type = f32; break;
+ case BinaryConsts::F64UConvertI64: curr = allocator.alloc<Unary>(); curr->op = ConvertUInt64; curr->type = f64; break;
+ case BinaryConsts::F32SConvertI64: curr = allocator.alloc<Unary>(); curr->op = ConvertSInt64; curr->type = f32; break;
+ case BinaryConsts::F64SConvertI64: curr = allocator.alloc<Unary>(); curr->op = ConvertSInt64; curr->type = f64; break;
+
+ case BinaryConsts::I64STruncI32: curr = allocator.alloc<Unary>(); curr->op = ExtendSInt32; curr->type = i64; break;
+ case BinaryConsts::I64UTruncI32: curr = allocator.alloc<Unary>(); curr->op = ExtendUInt32; curr->type = i64; break;
+ case BinaryConsts::I32ConvertI64: curr = allocator.alloc<Unary>(); curr->op = WrapInt64; curr->type = i32; break;
+
+ case BinaryConsts::I32UTruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat32; curr->type = i32; break;
+ case BinaryConsts::I32UTruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat64; curr->type = i32; break;
+ case BinaryConsts::I32STruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat32; curr->type = i32; break;
+ case BinaryConsts::I32STruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat64; curr->type = i32; break;
+ case BinaryConsts::I64UTruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat32; curr->type = i64; break;
+ case BinaryConsts::I64UTruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat64; curr->type = i64; break;
+ case BinaryConsts::I64STruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat32; curr->type = i64; break;
+ case BinaryConsts::I64STruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat64; curr->type = i64; break;
+
+ case BinaryConsts::F32Trunc: curr = allocator.alloc<Unary>(); curr->op = Trunc; curr->type = f32; break;
+ case BinaryConsts::F64Trunc: curr = allocator.alloc<Unary>(); curr->op = Trunc; curr->type = f64; break;
+
+ case BinaryConsts::F32ConvertF64: curr = allocator.alloc<Unary>(); curr->op = DemoteFloat64; curr->type = f32; break;
+ case BinaryConsts::F64ConvertF32: curr = allocator.alloc<Unary>(); curr->op = PromoteFloat32; curr->type = f64; break;
+ case BinaryConsts::F32ReinterpretI32: curr = allocator.alloc<Unary>(); curr->op = ReinterpretFloat; curr->type = i32; break;
+ case BinaryConsts::F64ReinterpretI64: curr = allocator.alloc<Unary>(); curr->op = ReinterpretFloat; curr->type = i64; break;
+ case BinaryConsts::I64ReinterpretF64: curr = allocator.alloc<Unary>(); curr->op = ReinterpretInt; curr->type = f64; break;
+ case BinaryConsts::I32ReinterpretF32: curr = allocator.alloc<Unary>(); curr->op = ReinterpretInt; curr->type = f32; break;
default: return false;
}
if (debug) std::cerr << "zz node: Unary" << std::endl;
curr->value = popExpression();
+ out = curr;
return true;
}
- bool maybeVisitImpl(Binary *curr, uint8_t code) {
+ bool maybeVisitBinary(Expression*& out, uint8_t code) {
+ Binary* curr;
#define TYPED_CODE(code) { \
- case BinaryConsts::I32##code: curr->op = code; curr->type = i32; break; \
- case BinaryConsts::I64##code: curr->op = code; curr->type = i64; break; \
- case BinaryConsts::F32##code: curr->op = code; curr->type = f32; break; \
- case BinaryConsts::F64##code: curr->op = code; curr->type = f64; break; \
+ case BinaryConsts::I32##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = i32; break; \
+ case BinaryConsts::I64##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = i64; break; \
+ case BinaryConsts::F32##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = f32; break; \
+ case BinaryConsts::F64##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = f64; break; \
}
#define INT_TYPED_CODE(code) { \
- case BinaryConsts::I32##code: curr->op = code; curr->type = i32; break; \
- case BinaryConsts::I64##code: curr->op = code; curr->type = i64; break; \
+ case BinaryConsts::I32##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = i32; break; \
+ case BinaryConsts::I64##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = i64; break; \
}
#define FLOAT_TYPED_CODE(code) { \
- case BinaryConsts::F32##code: curr->op = code; curr->type = f32; break; \
- case BinaryConsts::F64##code: curr->op = code; curr->type = f64; break; \
+ case BinaryConsts::F32##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = f32; break; \
+ case BinaryConsts::F64##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = f64; break; \
}
switch (code) {
TYPED_CODE(Add);
@@ -1986,6 +1983,7 @@ public:
curr->right = popExpression();
curr->left = popExpression();
curr->finalize();
+ out = curr;
return true;
#undef TYPED_CODE
#undef INT_TYPED_CODE
@@ -2006,14 +2004,17 @@ public:
curr->value = popExpression();
}
}
- bool maybeVisitImpl(Host *curr, uint8_t code) {
+ bool maybeVisitHost(Expression*& out, uint8_t code) {
+ Host* curr;
switch (code) {
case BinaryConsts::CurrentMemory: {
+ curr = allocator.alloc<Host>();
curr->op = CurrentMemory;
curr->type = i32;
break;
}
case BinaryConsts::GrowMemory: {
+ curr = allocator.alloc<Host>();
curr->op = GrowMemory;
curr->operands.resize(1);
curr->operands[0] = popExpression();
@@ -2023,6 +2024,7 @@ public:
}
if (debug) std::cerr << "zz node: Host" << std::endl;
curr->finalize();
+ out = curr;
return true;
}
void visitNop(Nop *curr) {
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 6e342771b..e25dafc60 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -91,7 +91,7 @@ public:
call->fullType = type;
call->type = type->result;
call->target = target;
- call->operands = args;
+ call->operands.set(args);
return call;
}
// FunctionType
@@ -162,11 +162,11 @@ public:
ret->value = value;
return ret;
}
- Host* makeHost(HostOp op, Name nameOperand, ExpressionList&& operands) {
+ Host* makeHost(HostOp op, Name nameOperand, std::vector<Expression*>&& operands) {
auto* ret = allocator.alloc<Host>();
ret->op = op;
ret->nameOperand = nameOperand;
- ret->operands = operands;
+ ret->operands.set(operands);
return ret;
}
// Unreachable
diff --git a/src/wasm-linker.cpp b/src/wasm-linker.cpp
index 7524f439a..8fc4f18c8 100644
--- a/src/wasm-linker.cpp
+++ b/src/wasm-linker.cpp
@@ -58,18 +58,19 @@ void Linker::layout() {
auto import = out.wasm.allocator.alloc<Import>();
import->name = import->base = target;
import->module = ENV;
- import->type = ensureFunctionType(getSig(*f.second.begin()), &out.wasm,
- out.wasm.allocator);
+ import->type = ensureFunctionType(getSig(*f.second.begin()), &out.wasm);
out.wasm.addImport(import);
}
// Change each call. The target is the same since it's still the name.
// Delete and re-allocate the Expression as CallImport to avoid undefined
// behavior.
for (auto* call : f.second) {
- Call callCopy = std::move(*call);
- CallImport* newCall = ExpressionManipulator::convert<Call, CallImport>(call);
- newCall->type = callCopy.type;
- newCall->operands = std::move(callCopy.operands);
+ auto type = call->type;
+ auto operands = std::move(call->operands);
+ auto target = call->target;
+ CallImport* newCall = ExpressionManipulator::convert<Call, CallImport>(call, out.wasm.allocator);
+ newCall->type = type;
+ newCall->operands = std::move(operands);
newCall->target = target;
}
}
@@ -181,7 +182,7 @@ void Linker::layout() {
// ensure an explicit function type for indirect call targets
for (auto& name : out.wasm.table.names) {
auto* func = out.wasm.getFunction(name);
- func->type = ensureFunctionType(getSig(func), &out.wasm, out.wasm.allocator)->name;
+ func->type = ensureFunctionType(getSig(func), &out.wasm)->name;
}
}
@@ -226,7 +227,7 @@ void Linker::emscriptenGlue(std::ostream& o) {
auto import = parent->out.wasm.allocator.alloc<Import>();
import->name = import->base = curr->target;
import->module = ENV;
- import->type = ensureFunctionType(getSig(curr), &parent->out.wasm, parent->out.wasm.allocator);
+ import->type = ensureFunctionType(getSig(curr), &parent->out.wasm);
parent->out.wasm.addImport(import);
}
}
@@ -290,7 +291,7 @@ void Linker::makeDynCallThunks() {
wasm::Builder wasmBuilder(out.wasm);
for (const auto& indirectFunc : out.wasm.table.names) {
std::string sig(getSig(out.wasm.getFunction(indirectFunc)));
- auto* funcType = ensureFunctionType(sig, &out.wasm, out.wasm.allocator);
+ auto* funcType = ensureFunctionType(sig, &out.wasm);
if (!sigs.insert(sig).second) continue; // Sig is already in the set
std::vector<NameType> params;
params.emplace_back("fptr", i32); // function pointer param
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index be3263312..e1a073b0b 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -61,6 +61,7 @@ class Element {
public:
Element() : isList_(true) {}
+ Element(MixedArena& allocator) : Element() {}
bool isList() { return isList_; }
bool isStr() { return !isList_; }
@@ -1131,30 +1132,30 @@ private:
im->module = s[i++]->str();
if (!s[i]->isStr()) onError();
im->base = s[i++]->str();
- FunctionType type;
+ FunctionType* type = allocator.alloc<FunctionType>();
if (s.size() > i) {
Element& params = *s[i];
IString id = params[0]->str();
if (id == PARAM) {
for (size_t i = 1; i < params.size(); i++) {
- type.params.push_back(stringToWasmType(params[i]->str()));
+ type->params.push_back(stringToWasmType(params[i]->str()));
}
} else if (id == RESULT) {
- type.result = stringToWasmType(params[1]->str());
+ type->result = stringToWasmType(params[1]->str());
} else if (id == TYPE) {
IString name = params[1]->str();
if (!wasm.checkFunctionType(name)) onError();
- type = *wasm.getFunctionType(name);
+ *type = *wasm.getFunctionType(name);
} else {
onError();
}
if (s.size() > i+1) {
Element& result = *s[i+1];
assert(result[0]->str() == RESULT);
- type.result = stringToWasmType(result[1]->str());
+ type->result = stringToWasmType(result[1]->str());
}
}
- im->type = ensureFunctionType(getSig(&type), &wasm, allocator);
+ im->type = ensureFunctionType(getSig(type), &wasm);
wasm.addImport(im);
}
diff --git a/src/wasm.h b/src/wasm.h
index ee2f27388..62b551433 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -723,9 +723,14 @@ enum HostOp {
// x->name = a;
// x->leftOperand = b;
// ..
-// which is less compact but less ambiguous. But hopefully we can do better,
-// suggestions for API improvements here are welcome.
+// which is less compact but less ambiguous. See wasm-builder.h for a more
+// friendly API for building nodes.
//
+// Most nodes have no need of internal allocation, and when arena-allocated
+// they drop the provided arena on the floor. You can create random instances
+// of those that are not in an arena without issue. However, the nodes that
+// have internal allocation will need an allocator provided to them in order
+// to be constructed.
class Expression {
public:
@@ -757,22 +762,21 @@ public:
WasmType type; // the type of the expression: its *output*, not necessarily its input(s)
- Expression() : _id(InvalidId), type(none) {}
Expression(Id id) : _id(id), type(none) {}
-
+
template<class T>
bool is() {
- return _id == T()._id;
+ return int(_id) == int(T::SpecificId);
}
template<class T>
T* dynCast() {
- return _id == T()._id ? (T*)this : nullptr;
+ return int(_id) == int(T::SpecificId) ? (T*)this : nullptr;
}
template<class T>
T* cast() {
- assert(_id == T()._id);
+ assert(int(_id) == int(T::SpecificId));
return (T*)this;
}
};
@@ -804,18 +808,27 @@ inline const char *getExpressionName(Expression *curr) {
}
}
-typedef std::vector<Expression*> ExpressionList; // TODO: optimize?
+typedef ArenaVector<Expression*> ExpressionList;
-class Nop : public Expression {
+template<Expression::Id SID>
+class SpecificExpression : public Expression {
public:
- Nop() : Expression(NopId) {}
+ enum {
+ SpecificId = SID // compile-time access to the type for the class
+ };
+
+ SpecificExpression() : Expression(SID) {}
};
-class Block : public Expression {
+class Nop : public SpecificExpression<Expression::NopId> {
public:
- Block() : Expression(BlockId) {
- type = none; // blocks by default do not return, but if their last statement does, they might
- }
+ Nop() {}
+ Nop(MixedArena& allocator) {}
+};
+
+class Block : public SpecificExpression<Expression::BlockId> {
+public:
+ Block(MixedArena& allocator) : list(allocator) {}
Name name;
ExpressionList list;
@@ -827,11 +840,10 @@ public:
}
};
-class If : public Expression {
+class If : public SpecificExpression<Expression::IfId> {
public:
- If() : Expression(IfId), ifFalse(nullptr) {
- type = none; // by default none; if-else can have one, though
- }
+ If() : ifFalse(nullptr) {}
+ If(MixedArena& allocator) : If() {}
Expression *condition, *ifTrue, *ifFalse;
@@ -842,9 +854,10 @@ public:
}
};
-class Loop : public Expression {
+class Loop : public SpecificExpression<Expression::LoopId> {
public:
- Loop() : Expression(LoopId) {}
+ Loop() {}
+ Loop(MixedArena& allocator) {}
Name out, in;
Expression *body;
@@ -854,9 +867,10 @@ public:
}
};
-class Break : public Expression {
+class Break : public SpecificExpression<Expression::BreakId> {
public:
- Break() : Expression(BreakId), value(nullptr), condition(nullptr) {
+ Break() : value(nullptr), condition(nullptr) {}
+ Break(MixedArena& allocator) : Break() {
type = unreachable;
}
@@ -865,9 +879,10 @@ public:
Expression *condition;
};
-class Switch : public Expression {
+class Switch : public SpecificExpression<Expression::SwitchId> {
public:
- Switch() : Expression(SwitchId), condition(nullptr), value(nullptr) {
+ Switch() : condition(nullptr), value(nullptr) {}
+ Switch(MixedArena& allocator) : Switch() {
type = unreachable;
}
@@ -877,34 +892,29 @@ public:
Expression *value;
};
-class CallBase : public Expression {
+class Call : public SpecificExpression<Expression::CallId> {
public:
- CallBase(Id which) : Expression(which) {}
+ Call(MixedArena& allocator) : operands(allocator) {}
ExpressionList operands;
+ Name target;
};
-class Call : public CallBase {
+class CallImport : public SpecificExpression<Expression::CallImportId> {
public:
- Call() : CallBase(CallId) {}
+ CallImport(MixedArena& allocator) : operands(allocator) {}
+ ExpressionList operands;
Name target;
};
-class CallImport : public Call {
-public:
- CallImport() {
- _id = CallImportId;
- }
-};
-
class FunctionType {
public:
Name name;
WasmType result;
- std::vector<WasmType> params;
+ ArenaVector<WasmType> params;
- FunctionType() : result(none) {}
+ FunctionType(MixedArena& allocator) : result(none), params(allocator) {}
bool operator==(FunctionType& b) {
if (name != b.name) return false; // XXX
@@ -920,32 +930,36 @@ public:
}
};
-class CallIndirect : public CallBase {
+class CallIndirect : public SpecificExpression<Expression::CallIndirectId> {
public:
- CallIndirect() : CallBase(CallIndirectId) {}
+ CallIndirect(MixedArena& allocator) : operands(allocator) {}
+ ExpressionList operands;
FunctionType *fullType;
Expression *target;
};
-class GetLocal : public Expression {
+class GetLocal : public SpecificExpression<Expression::GetLocalId> {
public:
- GetLocal() : Expression(GetLocalId) {}
+ GetLocal() {}
+ GetLocal(MixedArena& allocator) {}
Index index;
};
-class SetLocal : public Expression {
+class SetLocal : public SpecificExpression<Expression::SetLocalId> {
public:
- SetLocal() : Expression(SetLocalId) {}
+ SetLocal() {}
+ SetLocal(MixedArena& allocator) {}
Index index;
Expression *value;
};
-class Load : public Expression {
+class Load : public SpecificExpression<Expression::LoadId> {
public:
- Load() : Expression(LoadId) {}
+ Load() {}
+ Load(MixedArena& allocator) {}
uint32_t bytes;
bool signed_;
@@ -954,9 +968,10 @@ public:
Expression *ptr;
};
-class Store : public Expression {
+class Store : public SpecificExpression<Expression::StoreId> {
public:
- Store() : Expression(StoreId) {}
+ Store() {}
+ Store(MixedArena& allocator) {}
unsigned bytes;
uint32_t offset;
@@ -964,9 +979,10 @@ public:
Expression *ptr, *value;
};
-class Const : public Expression {
+class Const : public SpecificExpression<Expression::ConstId> {
public:
- Const() : Expression(ConstId) {}
+ Const() {}
+ Const(MixedArena& allocator) {}
Literal value;
@@ -977,9 +993,10 @@ public:
}
};
-class Unary : public Expression {
+class Unary : public SpecificExpression<Expression::UnaryId> {
public:
- Unary() : Expression(UnaryId) {}
+ Unary() {}
+ Unary(MixedArena& allocator) {}
UnaryOp op;
Expression *value;
@@ -989,9 +1006,10 @@ public:
// no finalize since some opcodes have more than one type, so user must set it anyhow
};
-class Binary : public Expression {
+class Binary : public SpecificExpression<Expression::BinaryId> {
public:
- Binary() : Expression(BinaryId) {}
+ Binary() {}
+ Binary(MixedArena& allocator) {}
BinaryOp op;
Expression *left, *right;
@@ -1011,9 +1029,10 @@ public:
}
};
-class Select : public Expression {
+class Select : public SpecificExpression<Expression::SelectId> {
public:
- Select() : Expression(SelectId) {}
+ Select() {}
+ Select(MixedArena& allocator) {}
Expression *ifTrue, *ifFalse, *condition;
@@ -1022,18 +1041,19 @@ public:
}
};
-class Return : public Expression {
+class Return : public SpecificExpression<Expression::ReturnId> {
public:
- Expression *value;
-
- Return() : Expression(ReturnId), value(nullptr) {
+ Return() : value(nullptr) {
type = unreachable;
}
+ Return(MixedArena& allocator) : Return() {}
+
+ Expression *value;
};
-class Host : public Expression {
+class Host : public SpecificExpression<Expression::HostId> {
public:
- Host() : Expression(HostId) {}
+ Host(MixedArena& allocator) : operands(allocator) {}
HostOp op;
Name nameOperand;
@@ -1054,9 +1074,10 @@ public:
}
};
-class Unreachable : public Expression {
+class Unreachable : public SpecificExpression<Expression::UnreachableId> {
public:
- Unreachable() : Expression(UnreachableId) {
+ Unreachable() {}
+ Unreachable(MixedArena& allocator) {
type = unreachable;
}
};
@@ -1076,7 +1097,7 @@ public:
std::vector<Name> localNames;
std::map<Name, Index> localIndices;
- Function() : result(none) {}
+ Function(MixedArena& allocator) : result(none) {}
size_t getNumParams() {
return params.size();
@@ -1126,14 +1147,16 @@ public:
class Import {
public:
+ Import(MixedArena& allocator) : type(nullptr) {}
+
Name name, module, base; // name = module.base
FunctionType* type;
-
- Import() : type(nullptr) {}
};
class Export {
public:
+ Export(MixedArena& allocator) {}
+
Name name; // exported name
Name value; // internal name
};
diff --git a/src/wasm2asm.h b/src/wasm2asm.h
index 1dbe4f09a..1c1dba6e1 100644
--- a/src/wasm2asm.h
+++ b/src/wasm2asm.h
@@ -103,6 +103,8 @@ void flattenAppend(Ref ast, Ref extra) {
class Wasm2AsmBuilder {
+ MixedArena allocator;
+
public:
Wasm2AsmBuilder(bool debug) : debug(debug), tableSize(-1) {}
@@ -423,7 +425,12 @@ void Wasm2AsmBuilder::scanFunctionBody(Expression* curr) {
}
}
void visitCallImport(CallImport *curr) {
- visitCall(curr);
+ for (auto item : curr->operands) {
+ if (parent->isStatement(item)) {
+ parent->setStatement(curr);
+ break;
+ }
+ }
}
void visitCallIndirect(CallIndirect *curr) {
if (parent->isStatement(curr->target)) {
@@ -487,6 +494,7 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
Wasm2AsmBuilder* parent;
IString result;
Function* func;
+ MixedArena allocator;
ExpressionProcessor(Wasm2AsmBuilder* parent, Function* func) : parent(parent), func(func) {}
// A scoped temporary variable.
@@ -635,7 +643,7 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
// we need an equivalent to an if here, so use that code
Break fakeBreak = *curr;
fakeBreak.condition = nullptr;
- If fakeIf;
+ If fakeIf(allocator);
fakeIf.condition = curr->condition;
fakeIf.ifTrue = &fakeBreak;
return visit(&fakeIf, result);
@@ -709,7 +717,7 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
return makeStatementizedCall(curr->operands, ValueBuilder::makeBlock(), theCall, result, curr->type);
}
Ref visitCallImport(CallImport *curr) {
- return visitCall(curr);
+ abort();
}
Ref visitCallIndirect(CallIndirect *curr) {
std::string stable = std::string("FUNCTION_TABLE_") + getSig(curr->fullType);
@@ -751,7 +759,7 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
Ref visitLoad(Load *curr) {
if (isStatement(curr)) {
ScopedTemp temp(i32, parent);
- GetLocal fakeLocal;
+ GetLocal fakeLocal(allocator);
fakeLocal.index = func->getLocalIndex(temp.getName());
Load fakeLoad = *curr;
fakeLoad.ptr = &fakeLocal;
@@ -762,11 +770,11 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
if (curr->align != 0 && curr->align < curr->bytes) {
// set the pointer to a local
ScopedTemp temp(i32, parent);
- SetLocal set;
+ SetLocal set(allocator);
set.index = func->getLocalIndex(temp.getName());
set.value = curr->ptr;
Ref ptrSet = visit(&set, NO_RESULT);
- GetLocal get;
+ GetLocal get(allocator);
get.index = func->getLocalIndex(temp.getName());
// fake loads
Load load = *curr;
@@ -814,9 +822,9 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
if (isStatement(curr)) {
ScopedTemp tempPtr(i32, parent);
ScopedTemp tempValue(curr->type, parent);
- GetLocal fakeLocalPtr;
+ GetLocal fakeLocalPtr(allocator);
fakeLocalPtr.index = func->getLocalIndex(tempPtr.getName());
- GetLocal fakeLocalValue;
+ GetLocal fakeLocalValue(allocator);
fakeLocalValue.index = func->getLocalIndex(tempValue.getName());
Store fakeStore = *curr;
fakeStore.ptr = &fakeLocalPtr;
@@ -829,19 +837,19 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
if (curr->align != 0 && curr->align < curr->bytes) {
// set the pointer to a local
ScopedTemp temp(i32, parent);
- SetLocal set;
+ SetLocal set(allocator);
set.index = func->getLocalIndex(temp.getName());
set.value = curr->ptr;
Ref ptrSet = visit(&set, NO_RESULT);
- GetLocal get;
+ GetLocal get(allocator);
get.index = func->getLocalIndex(temp.getName());
// set the value to a local
ScopedTemp tempValue(curr->value->type, parent);
- SetLocal setValue;
+ SetLocal setValue(allocator);
setValue.index = func->getLocalIndex(tempValue.getName());
setValue.value = curr->value;
Ref valueSet = visit(&setValue, NO_RESULT);
- GetLocal getValue;
+ GetLocal getValue(allocator);
getValue.index = func->getLocalIndex(tempValue.getName());
// fake stores
Store store = *curr;
@@ -850,19 +858,19 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
Ref rest;
switch (curr->type) {
case i32: {
- Const _255;
+ Const _255(allocator);
_255.value = Literal(int32_t(255));
_255.type = i32;
for (size_t i = 0; i < curr->bytes; i++) {
- Const shift;
+ Const shift(allocator);
shift.value = Literal(int32_t(8*i));
shift.type = i32;
- Binary shifted;
+ Binary shifted(allocator);
shifted.op = ShrU;
shifted.left = &getValue;
shifted.right = &shift;
shifted.type = i32;
- Binary anded;
+ Binary anded(allocator);
anded.op = And;
anded.left = i > 0 ? static_cast<Expression*>(&shifted) : static_cast<Expression*>(&getValue);
anded.right = &_255;
@@ -910,7 +918,7 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
case i32: return ValueBuilder::makeInt(curr->value.geti32());
case f32: {
Ref ret = ValueBuilder::makeCall(MATH_FROUND);
- Const fake;
+ Const fake(allocator);
fake.value = Literal(double(curr->value.getf32()));
fake.type = f64;
ret[2]->push_back(visitConst(&fake));
@@ -929,7 +937,7 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
Ref visitUnary(Unary *curr) {
if (isStatement(curr)) {
ScopedTemp temp(curr->value->type, parent);
- GetLocal fakeLocal;
+ GetLocal fakeLocal(allocator);
fakeLocal.index = func->getLocalIndex(temp.getName());
Unary fakeUnary = *curr;
fakeUnary.value = &fakeLocal;
@@ -977,10 +985,10 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
Ref visitBinary(Binary *curr) {
if (isStatement(curr)) {
ScopedTemp tempLeft(curr->left->type, parent);
- GetLocal fakeLocalLeft;
+ GetLocal fakeLocalLeft(allocator);
fakeLocalLeft.index = func->getLocalIndex(tempLeft.getName());
ScopedTemp tempRight(curr->right->type, parent);
- GetLocal fakeLocalRight;
+ GetLocal fakeLocalRight(allocator);
fakeLocalRight.index = func->getLocalIndex(tempRight.getName());
Binary fakeBinary = *curr;
fakeBinary.left = &fakeLocalLeft;
@@ -1050,13 +1058,13 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) {
Ref visitSelect(Select *curr) {
if (isStatement(curr)) {
ScopedTemp tempIfTrue(curr->ifTrue->type, parent);
- GetLocal fakeLocalIfTrue;
+ GetLocal fakeLocalIfTrue(allocator);
fakeLocalIfTrue.index = func->getLocalIndex(tempIfTrue.getName());
ScopedTemp tempIfFalse(curr->ifFalse->type, parent);
- GetLocal fakeLocalIfFalse;
+ GetLocal fakeLocalIfFalse(allocator);
fakeLocalIfFalse.index = func->getLocalIndex(tempIfFalse.getName());
ScopedTemp tempCondition(i32, parent);
- GetLocal fakeCondition;
+ GetLocal fakeCondition(allocator);
fakeCondition.index = func->getLocalIndex(tempCondition.getName());
Select fakeSelect = *curr;
fakeSelect.ifTrue = &fakeLocalIfTrue;