summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/Print.cpp3
-rw-r--r--src/wasm-binary.h93
-rw-r--r--src/wasm.cpp2
3 files changed, 71 insertions, 27 deletions
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 363147b98..69dc447a8 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -162,6 +162,9 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
if (curr->name.is()) {
o << ' ' << curr->name;
}
+ if (isConcreteWasmType(curr->type)) {
+ o << ' ' << printWasmType(curr->type);
+ }
incIndent();
auto block = curr->body->dynCast<Block>();
if (!full && block && block->name.isNull()) {
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 3047d43b7..4a32360a4 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -257,7 +257,7 @@ enum ElementType {
};
namespace UserSections {
-extern const char* Names;
+extern const char* Name;
}
enum ASTNodes {
@@ -424,7 +424,7 @@ enum ASTNodes {
GetGlobal = 0x1a,
SetGlobal = 0x1b,
- Nop = 0x00,
+ Unreachable = 0x00,
Block = 0x01,
Loop = 0x02,
If = 0x03,
@@ -434,7 +434,7 @@ enum ASTNodes {
BrIf = 0x07,
TableSwitch = 0x08,
Return = 0x09,
- Unreachable = 0x0a,
+ Nop = 0x0a,
Drop = 0x0b,
End = 0x0f
};
@@ -451,6 +451,20 @@ enum TypeForms {
} // namespace BinaryConsts
+
+struct ArityChecker : public PostWalker<ArityChecker, Visitor<ArityChecker>> {
+ std::unordered_map<cashew::IString, bool> arities;
+
+ ArityChecker(Expression* function) {
+ walk(function);
+ }
+
+ void visitBreak(Break* curr) {
+ // Assume the module has already beeen type-checked, and that all breaks have matching arity.
+ if (curr->value) arities[curr->name] = true;
+ }
+};
+
inline int8_t binaryWasmType(WasmType type) {
switch (type) {
case none: return 0;
@@ -468,6 +482,8 @@ class WasmBinaryWriter : public Visitor<WasmBinaryWriter, void> {
bool debug;
bool debugInfo = true;
+ std::unordered_map<cashew::IString, bool> brTargetArities;
+
MixedArena allocator;
void prepare() {
@@ -701,6 +717,10 @@ public:
if (numLocalsByType[i64]) o << U32LEB(numLocalsByType[i64]) << binaryWasmType(i64);
if (numLocalsByType[f32]) o << U32LEB(numLocalsByType[f32]) << binaryWasmType(f32);
if (numLocalsByType[f64]) o << U32LEB(numLocalsByType[f64]) << binaryWasmType(f64);
+
+ ArityChecker ar(function->body);
+ brTargetArities = std::move(ar.arities);
+
writeExpression(function->body);
size_t size = o.size() - start;
assert(size <= std::numeric_limits<uint32_t>::max());
@@ -825,7 +845,7 @@ public:
if (wasm->functions.size() == 0) return;
if (debug) std::cerr << "== writeNames" << std::endl;
auto start = startSection(BinaryConsts::Section::User);
- writeInlineString("names");
+ writeInlineString(BinaryConsts::UserSections::Name);
o << U32LEB(wasm->functions.size());
for (auto& curr : wasm->functions) {
writeInlineString(curr->name.str);
@@ -898,6 +918,18 @@ public:
void visitBlock(Block *curr) {
if (debug) std::cerr << "zz node: Block" << std::endl;
o << int8_t(BinaryConsts::Block);
+
+ int arity = curr->type != none && curr->type != unreachable;
+ if (brTargetArities.count(curr->name)) {
+ if (curr->type == unreachable) {
+ arity = brTargetArities[curr->name];
+ } else {
+ assert((curr->type != none) == brTargetArities[curr->name]);
+ }
+ }
+ // For blocks with type unreachable but whose breaks have arity 1, encode i32 as their
+ // signature so that the decoder knows to pop a value for the breaks' values.
+ o << binaryWasmType(curr->type != unreachable ? curr->type : arity ? i32 : none);
breakStack.push_back(curr->name);
size_t i = 0;
for (auto* child : curr->list) {
@@ -924,6 +956,7 @@ public:
if (debug) std::cerr << "zz node: If" << std::endl;
recurse(curr->condition);
o << int8_t(BinaryConsts::If);
+ o << binaryWasmType(curr->type != unreachable ? curr->type : none);
breakStack.push_back(IMPOSSIBLE_CONTINUE); // the binary format requires this; we have a block if we need one; TODO: optimize
recursePossibleBlockContents(curr->ifTrue); // TODO: emit block contents directly, if possible
breakStack.pop_back();
@@ -938,6 +971,7 @@ public:
void visitLoop(Loop *curr) {
if (debug) std::cerr << "zz node: Loop" << std::endl;
o << int8_t(BinaryConsts::Loop);
+ o << binaryWasmType(curr->type != unreachable ? curr->type : none);
breakStack.push_back(curr->name);
recursePossibleBlockContents(curr->body);
breakStack.pop_back();
@@ -961,7 +995,7 @@ public:
}
if (curr->condition) recurse(curr->condition);
o << int8_t(curr->condition ? BinaryConsts::BrIf : BinaryConsts::Br)
- << U32LEB(curr->value ? 1 : 0) << U32LEB(getBreakIndex(curr->name));
+ << U32LEB(getBreakIndex(curr->name));
}
void visitSwitch(Switch *curr) {
if (debug) std::cerr << "zz node: Switch" << std::endl;
@@ -969,11 +1003,11 @@ public:
recurse(curr->value);
}
recurse(curr->condition);
- o << int8_t(BinaryConsts::TableSwitch) << U32LEB(curr->value ? 1 : 0) << U32LEB(curr->targets.size());
+ o << int8_t(BinaryConsts::TableSwitch) << U32LEB(curr->targets.size());
for (auto target : curr->targets) {
- o << uint32_t(getBreakIndex(target));
+ o << U32LEB(getBreakIndex(target));
}
- o << uint32_t(getBreakIndex(curr->default_));
+ o << U32LEB(getBreakIndex(curr->default_));
}
void visitCall(Call *curr) {
if (debug) std::cerr << "zz node: Call" << std::endl;
@@ -1340,7 +1374,7 @@ public:
bool readUserSection() {
Name sectionName = getInlineString();
- if (sectionName.equals(BinaryConsts::UserSections::Names)) {
+ if (sectionName.equals(BinaryConsts::UserSections::Name)) {
readNames();
return true;
}
@@ -1720,7 +1754,8 @@ public:
}
}
- std::vector<Name> breakStack;
+ struct BreakTarget { Name name; int arity;};
+ std::vector<BreakTarget> breakStack;
std::vector<Expression*> expressionStack;
@@ -1908,8 +1943,9 @@ public:
// a common pattern that can be very highly nested.
std::vector<Block*> stack;
while (1) {
+ curr->type = getWasmType();
curr->name = getNextLabel();
- breakStack.push_back(curr->name);
+ breakStack.push_back({curr->name, curr->type != none});
stack.push_back(curr);
if (getInt8() == BinaryConsts::Block) {
// a recursion
@@ -1960,9 +1996,9 @@ public:
return block;
}
- Expression* getBlock() {
+ Expression* getBlock(WasmType ty) {
Name label = getNextLabel();
- breakStack.push_back(label);
+ breakStack.push_back({label, ty != none && ty != unreachable});
auto* block = Builder(wasm).blockify(getMaybeBlock());
breakStack.pop_back();
block->cast<Block>()->name = label;
@@ -1971,48 +2007,53 @@ public:
void visitIf(If *curr) {
if (debug) std::cerr << "zz node: If" << std::endl;
+ curr->type = getWasmType();
curr->condition = popExpression();
- curr->ifTrue = getBlock();
+ curr->ifTrue = getBlock(curr->type);
if (lastSeparator == BinaryConsts::Else) {
- curr->ifFalse = getBlock();
+ curr->ifFalse = getBlock(curr->type);
curr->finalize();
}
assert(lastSeparator == BinaryConsts::End);
}
void visitLoop(Loop *curr) {
if (debug) std::cerr << "zz node: Loop" << std::endl;
+ curr->type = getWasmType();
curr->name = getNextLabel();
- breakStack.push_back(curr->name);
+ breakStack.push_back({curr->name, 0});
curr->body = getMaybeBlock();
breakStack.pop_back();
curr->finalize();
}
- Name getBreakName(int32_t offset) {
+ BreakTarget getBreakTarget(int32_t offset) {
+ if (debug) std::cerr << "getBreakTarget "<<offset<<std::endl;
assert(breakStack.size() - 1 - offset < breakStack.size());
+ if (debug) std::cerr <<"breaktarget "<< breakStack[breakStack.size() - 1 - offset].name<< " arity "<<breakStack[breakStack.size() - 1 - offset].arity<< std::endl;
return breakStack[breakStack.size() - 1 - offset];
}
void visitBreak(Break *curr, uint8_t code) {
if (debug) std::cerr << "zz node: Break" << std::endl;
- auto arity = getU32LEB();
- assert(arity == 0 || arity == 1);
- curr->name = getBreakName(getU32LEB());
+ BreakTarget target = getBreakTarget(getU32LEB());
+ curr->name = target.name;
if (code == BinaryConsts::BrIf) curr->condition = popExpression();
- if (arity == 1) curr->value = popExpression();
+ if (target.arity) curr->value = popExpression();
curr->finalize();
}
void visitSwitch(Switch *curr) {
if (debug) std::cerr << "zz node: Switch" << std::endl;
- auto arity = getU32LEB();
- assert(arity == 0 || arity == 1);
curr->condition = popExpression();
- if (arity == 1) curr->value = popExpression();
+
auto numTargets = getU32LEB();
+ if (debug) std::cerr << "targets: "<< numTargets<<std::endl;
for (size_t i = 0; i < numTargets; i++) {
- curr->targets.push_back(getBreakName(getInt32()));
+ curr->targets.push_back(getBreakTarget(getU32LEB()).name);
}
- curr->default_ = getBreakName(getInt32());
+ auto defaultTarget = getBreakTarget(getU32LEB());
+ curr->default_ = defaultTarget.name;
+ if (debug) std::cerr << "default: "<< curr->default_<<std::endl;
+ if (defaultTarget.arity) curr->value = popExpression();
}
template<typename T>
diff --git a/src/wasm.cpp b/src/wasm.cpp
index f43f4be1e..b5a4314de 100644
--- a/src/wasm.cpp
+++ b/src/wasm.cpp
@@ -27,7 +27,7 @@ Name WASM("wasm"),
namespace BinaryConsts {
namespace UserSections {
-const char* Names = "names";
+const char* Name = "name";
}
}