diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/Precompute.cpp | 11 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 40 |
2 files changed, 38 insertions, 13 deletions
diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp index bf5924720..355af7ed0 100644 --- a/src/passes/Precompute.cpp +++ b/src/passes/Precompute.cpp @@ -168,11 +168,6 @@ struct Precompute if (curr->type.isVector()) { return; } - // Don't try to precompute a reference. We can't replace it with a constant - // expression, as that would make a copy of it by value. - if (curr->type.isRef()) { - return; - } // try to evaluate this into a const Flow flow = precomputeExpression(curr); if (flow.getType().hasVector()) { @@ -228,6 +223,12 @@ private: // Precompute an expression, returning a flow, which may be a constant // (that we can replace the expression with if replaceExpression is set). Flow precomputeExpression(Expression* curr, bool replaceExpression = true) { + // Don't try to precompute a reference. We can't replace it with a constant + // expression, as that would make a copy of it by value. + // TODO: do so when safe + if (curr->type.isRef()) { + return Flow(NONCONSTANT_FLOW); + } try { return PrecomputingExpressionRunner( getModule(), getValues, replaceExpression) diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index d701aaf15..e4c20082e 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1427,7 +1427,8 @@ public: if (!data) { trap("null ref"); } - return (*data)[curr->index]; + auto field = curr->ref->type.getHeapType().getStruct().fields[curr->index]; + return extendForPacking((*data)[curr->index], field, curr->signed_); } Flow visitStructSet(StructSet* curr) { NOTE_ENTER("StructSet"); @@ -1444,7 +1445,7 @@ public: trap("null ref"); } auto field = curr->ref->type.getHeapType().getStruct().fields[curr->index]; - (*data)[curr->index] = getMaybePackedValue(value.getSingleValue(), field); + (*data)[curr->index] = truncateForPacking(value.getSingleValue(), field); return Flow(); } Flow visitArrayNew(ArrayNew* curr) { @@ -1494,7 +1495,8 @@ public: if (i >= data->size()) { trap("array oob"); } - return (*data)[i]; + auto field = curr->ref->type.getHeapType().getArray().element; + return extendForPacking((*data)[i], field, curr->signed_); } Flow visitArraySet(ArraySet* curr) { NOTE_ENTER("ArraySet"); @@ -1519,7 +1521,7 @@ public: trap("array oob"); } auto field = curr->ref->type.getHeapType().getArray().element; - (*data)[i] = getMaybePackedValue(value.getSingleValue(), field); + (*data)[i] = truncateForPacking(value.getSingleValue(), field); return Flow(); } Flow visitArrayLen(ArrayLen* curr) { @@ -1541,13 +1543,35 @@ public: private: // Truncate the value if we need to. The storage is just a list of Literals, - // so we can't just write the value like we would to a C struct field. - Literal getMaybePackedValue(Literal value, const Field& field) { + // so we can't just write the value like we would to a C struct field and + // expect it to truncate for us. Instead, we truncate so the stored value is + // proper for the type. + Literal truncateForPacking(Literal value, const Field& field) { + if (field.type == Type::i32) { + int32_t c = value.geti32(); + if (field.packedType == Field::i8) { + value = Literal(c & 0xff); + } else if (field.packedType == Field::i16) { + value = Literal(c & 0xffff); + } + } + return value; + } + + Literal extendForPacking(Literal value, const Field& field, bool signed_) { if (field.type == Type::i32) { + int32_t c = value.geti32(); if (field.packedType == Field::i8) { - value = value.and_(Literal(int32_t(0xff))); + // The stored value should already be truncated. + assert(c == (c & 0xff)); + if (signed_) { + value = Literal((c << 24) >> 24); + } } else if (field.packedType == Field::i16) { - value = value.and_(Literal(int32_t(0xffff))); + assert(c == (c & 0xffff)); + if (signed_) { + value = Literal((c << 16) >> 16); + } } } return value; |