summaryrefslogtreecommitdiff
path: root/src/wasm-stack.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm-stack.h')
-rw-r--r--src/wasm-stack.h100
1 files changed, 55 insertions, 45 deletions
diff --git a/src/wasm-stack.h b/src/wasm-stack.h
index f4d116d77..64718b7b2 100644
--- a/src/wasm-stack.h
+++ b/src/wasm-stack.h
@@ -382,11 +382,33 @@ void BinaryenIRWriter<SubType>::visitCall(Call* curr) {
for (auto* operand : curr->operands) {
visit(operand);
}
- emit(curr);
- // TODO FIXME: this and similar can be removed
- if (curr->type == unreachable) {
+
+ // For non-control-flow value-returning instructions, if the type of an
+ // expression is unreachable, we emit an unreachable and don't emit the
+ // instruction itself. If we don't emit an unreachable, instructions that
+ // follow can have a validation failure in wasm binary format. For example:
+ // [unreachable] (f32.add
+ // [unreachable] (i32.eqz
+ // [unreachable] (unreachable)
+ // )
+ // ...
+ // )
+ // This is a valid prgram in binaryen IR, because the unreachable type
+ // propagates out of an expression, making both i32.eqz and f32.add
+ // unreachable. But in binary format, this becomes:
+ // unreachable
+ // i32.eqz
+ // f32.add ;; validation failure; it takes an i32!
+ // And here f32.add causes validation failure in wasm validation. So in this
+ // case we add an unreachable to prevent following instructions to consume
+ // the current value (here i32.eqz).
+ //
+ // The same applies for other expressions.
+ if (curr->type == unreachable && !curr->isReturn) {
emitUnreachable();
+ return;
}
+ emit(curr);
}
template<typename SubType>
@@ -395,10 +417,11 @@ void BinaryenIRWriter<SubType>::visitCallIndirect(CallIndirect* curr) {
visit(operand);
}
visit(curr->target);
- emit(curr);
- if (curr->type == unreachable) {
+ if (curr->type == unreachable && !curr->isReturn) {
emitUnreachable();
+ return;
}
+ emit(curr);
}
template<typename SubType>
@@ -409,10 +432,11 @@ void BinaryenIRWriter<SubType>::visitLocalGet(LocalGet* curr) {
template<typename SubType>
void BinaryenIRWriter<SubType>::visitLocalSet(LocalSet* curr) {
visit(curr->value);
- emit(curr);
- if (curr->type == unreachable) {
+ if (curr->isTee() && curr->type == unreachable) {
emitUnreachable();
+ return;
}
+ emit(curr);
}
template<typename SubType>
@@ -430,7 +454,6 @@ template<typename SubType>
void BinaryenIRWriter<SubType>::visitLoad(Load* curr) {
visit(curr->ptr);
if (curr->type == unreachable) {
- // don't even emit it; we don't know the right type
emitUnreachable();
return;
}
@@ -441,27 +464,14 @@ template<typename SubType>
void BinaryenIRWriter<SubType>::visitStore(Store* curr) {
visit(curr->ptr);
visit(curr->value);
- if (curr->type == unreachable) {
- // don't even emit it; we don't know the right type
- emitUnreachable();
- return;
- }
emit(curr);
}
template<typename SubType>
void BinaryenIRWriter<SubType>::visitAtomicRMW(AtomicRMW* curr) {
visit(curr->ptr);
- // stop if the rest isn't reachable anyhow
- if (curr->ptr->type == unreachable) {
- return;
- }
visit(curr->value);
- if (curr->value->type == unreachable) {
- return;
- }
if (curr->type == unreachable) {
- // don't even emit it; we don't know the right type
emitUnreachable();
return;
}
@@ -471,20 +481,9 @@ void BinaryenIRWriter<SubType>::visitAtomicRMW(AtomicRMW* curr) {
template<typename SubType>
void BinaryenIRWriter<SubType>::visitAtomicCmpxchg(AtomicCmpxchg* curr) {
visit(curr->ptr);
- // stop if the rest isn't reachable anyhow
- if (curr->ptr->type == unreachable) {
- return;
- }
visit(curr->expected);
- if (curr->expected->type == unreachable) {
- return;
- }
visit(curr->replacement);
- if (curr->replacement->type == unreachable) {
- return;
- }
if (curr->type == unreachable) {
- // don't even emit it; we don't know the right type
emitUnreachable();
return;
}
@@ -494,16 +493,10 @@ void BinaryenIRWriter<SubType>::visitAtomicCmpxchg(AtomicCmpxchg* curr) {
template<typename SubType>
void BinaryenIRWriter<SubType>::visitAtomicWait(AtomicWait* curr) {
visit(curr->ptr);
- // stop if the rest isn't reachable anyhow
- if (curr->ptr->type == unreachable) {
- return;
- }
visit(curr->expected);
- if (curr->expected->type == unreachable) {
- return;
- }
visit(curr->timeout);
- if (curr->timeout->type == unreachable) {
+ if (curr->type == unreachable) {
+ emitUnreachable();
return;
}
emit(curr);
@@ -512,12 +505,9 @@ void BinaryenIRWriter<SubType>::visitAtomicWait(AtomicWait* curr) {
template<typename SubType>
void BinaryenIRWriter<SubType>::visitAtomicNotify(AtomicNotify* curr) {
visit(curr->ptr);
- // stop if the rest isn't reachable anyhow
- if (curr->ptr->type == unreachable) {
- return;
- }
visit(curr->notifyCount);
- if (curr->notifyCount->type == unreachable) {
+ if (curr->type == unreachable) {
+ emitUnreachable();
return;
}
emit(curr);
@@ -526,6 +516,10 @@ void BinaryenIRWriter<SubType>::visitAtomicNotify(AtomicNotify* curr) {
template<typename SubType>
void BinaryenIRWriter<SubType>::visitSIMDExtract(SIMDExtract* curr) {
visit(curr->vec);
+ if (curr->type == unreachable) {
+ emitUnreachable();
+ return;
+ }
emit(curr);
}
@@ -533,6 +527,10 @@ template<typename SubType>
void BinaryenIRWriter<SubType>::visitSIMDReplace(SIMDReplace* curr) {
visit(curr->vec);
visit(curr->value);
+ if (curr->type == unreachable) {
+ emitUnreachable();
+ return;
+ }
emit(curr);
}
@@ -540,6 +538,10 @@ template<typename SubType>
void BinaryenIRWriter<SubType>::visitSIMDShuffle(SIMDShuffle* curr) {
visit(curr->left);
visit(curr->right);
+ if (curr->type == unreachable) {
+ emitUnreachable();
+ return;
+ }
emit(curr);
}
@@ -548,6 +550,10 @@ void BinaryenIRWriter<SubType>::visitSIMDBitselect(SIMDBitselect* curr) {
visit(curr->left);
visit(curr->right);
visit(curr->cond);
+ if (curr->type == unreachable) {
+ emitUnreachable();
+ return;
+ }
emit(curr);
}
@@ -555,6 +561,10 @@ template<typename SubType>
void BinaryenIRWriter<SubType>::visitSIMDShift(SIMDShift* curr) {
visit(curr->vec);
visit(curr->shift);
+ if (curr->type == unreachable) {
+ emitUnreachable();
+ return;
+ }
emit(curr);
}