summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-binary.cpp
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2020-12-07 15:23:24 -0800
committerGitHub <noreply@github.com>2020-12-07 15:23:24 -0800
commit72a7881b42ebed6b2ef36e912a8f5937106e5824 (patch)
tree5a79bfdbac295b47163e20cf76d25af9d8475b56 /src/wasm/wasm-binary.cpp
parent295780928d576613ea47bcc55dafc54619086bc8 (diff)
downloadbinaryen-72a7881b42ebed6b2ef36e912a8f5937106e5824.tar.gz
binaryen-72a7881b42ebed6b2ef36e912a8f5937106e5824.tar.bz2
binaryen-72a7881b42ebed6b2ef36e912a8f5937106e5824.zip
[GC] Add struct.get instruction parsing and execution (#3429)
This is the first instruction that uses a GC Struct or Array, so it's where we start to actually need support in the interpreter for those values, which is added here. GC data is modeled as a gcData field on a Literal, which is just a Literals. That is, both a struct and an array are represented as an array of values. The type which is alongside would indicate if it's a struct or an array. Note that the data is referred to using a shared_ptr so it should "just work", but we'll only be able to really test that once we add struct.new and so can verify that references are by reference and not value, etc. As the first instruction to care about i8/16 types (which are only possible in a Struct or Array) this adds support for parsing and emitting them. This PR includes fuzz fixes for some minor things the fuzzer found, including some bad printing of not having ResultTypeName in necessary places (found by the text format roundtripping fuzzer).
Diffstat (limited to 'src/wasm/wasm-binary.cpp')
-rw-r--r--src/wasm/wasm-binary.cpp60
1 files changed, 39 insertions, 21 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 3aace6721..361faf631 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -1030,7 +1030,7 @@ void WasmBinaryWriter::writeType(Type type) {
void WasmBinaryWriter::writeHeapType(HeapType type) {
if (type.isSignature() || type.isStruct() || type.isArray()) {
- o << S32LEB(getTypeIndex(type));
+ o << S64LEB(getTypeIndex(type)); // TODO: Actually s33
return;
}
int ret = 0;
@@ -1058,11 +1058,21 @@ void WasmBinaryWriter::writeHeapType(HeapType type) {
case HeapType::ArrayKind:
WASM_UNREACHABLE("TODO: compound GC types");
}
- o << S32LEB(ret); // TODO: Actually encoded as s33
+ o << S64LEB(ret); // TODO: Actually s33
}
void WasmBinaryWriter::writeField(const Field& field) {
- writeType(field.type);
+ if (field.type == Type::i32 && field.packedType != Field::not_packed) {
+ if (field.packedType == Field::i8) {
+ o << S32LEB(BinaryConsts::EncodedType::i8);
+ } else if (field.packedType == Field::i16) {
+ o << S32LEB(BinaryConsts::EncodedType::i16);
+ } else {
+ WASM_UNREACHABLE("invalid packed type");
+ }
+ } else {
+ writeType(field.type);
+ }
o << U32LEB(field.mutable_);
}
@@ -1335,14 +1345,13 @@ uint64_t WasmBinaryBuilder::getUPtrLEB() {
return wasm.memory.is64() ? getU64LEB() : getU32LEB();
}
-Type WasmBinaryBuilder::getType() {
- int type = getS32LEB();
+Type WasmBinaryBuilder::getType(int initial) {
// Single value types are negative; signature indices are non-negative
- if (type >= 0) {
+ if (initial >= 0) {
// TODO: Handle block input types properly.
- return getSignatureByTypeIndex(type).results;
+ return getSignatureByTypeIndex(initial).results;
}
- switch (type) {
+ switch (initial) {
// None only used for block signatures. TODO: Separate out?
case BinaryConsts::EncodedType::Empty:
return Type::none;
@@ -1374,13 +1383,15 @@ Type WasmBinaryBuilder::getType() {
case BinaryConsts::EncodedType::i31ref:
return Type::i31ref;
default:
- throwError("invalid wasm type: " + std::to_string(type));
+ throwError("invalid wasm type: " + std::to_string(initial));
}
WASM_UNREACHABLE("unexpected type");
}
+Type WasmBinaryBuilder::getType() { return getType(getS32LEB()); }
+
HeapType WasmBinaryBuilder::getHeapType() {
- int type = getS32LEB(); // TODO: Actually encoded as s33
+ auto type = getS64LEB(); // TODO: Actually s33
// Single heap types are negative; heap type indices are non-negative
if (type >= 0) {
if (size_t(type) >= types.size()) {
@@ -1408,7 +1419,19 @@ HeapType WasmBinaryBuilder::getHeapType() {
}
Field WasmBinaryBuilder::getField() {
- auto type = getConcreteType();
+ // The value may be a general wasm type, or one of the types only possible in
+ // a field.
+ auto initial = getS32LEB();
+ if (initial == BinaryConsts::EncodedType::i8) {
+ auto mutable_ = getU32LEB();
+ return Field(Field::i8, mutable_);
+ }
+ if (initial == BinaryConsts::EncodedType::i16) {
+ auto mutable_ = getU32LEB();
+ return Field(Field::i16, mutable_);
+ }
+ // It's a regular wasm value.
+ auto type = getType(initial);
auto mutable_ = getU32LEB();
return Field(type, mutable_);
}
@@ -1466,12 +1489,6 @@ void WasmBinaryBuilder::verifyInt64(int64_t x) {
}
}
-void WasmBinaryBuilder::ungetInt8() {
- assert(pos > 0);
- BYN_TRACE("ungetInt8 (at " << pos << ")\n");
- pos--;
-}
-
void WasmBinaryBuilder::readHeader() {
BYN_TRACE("== readHeader\n");
verifyInt32(BinaryConsts::Magic);
@@ -5601,20 +5618,21 @@ bool WasmBinaryBuilder::maybeVisitStructGet(Expression*& out, uint32_t code) {
switch (code) {
case BinaryConsts::StructGet:
curr = allocator.alloc<StructGet>();
- // ...
break;
case BinaryConsts::StructGetS:
curr = allocator.alloc<StructGet>();
- // ...
+ curr->signed_ = true;
break;
case BinaryConsts::StructGetU:
curr = allocator.alloc<StructGet>();
- // ...
+ curr->signed_ = false;
break;
default:
return false;
}
- WASM_UNREACHABLE("TODO (gc): struct.get");
+ auto type = getHeapType();
+ curr->index = getU32LEB();
+ curr->value = popNonVoidExpression();
curr->finalize();
out = curr;
return true;