summaryrefslogtreecommitdiff
path: root/src/wasm-interpreter.h
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2020-12-10 15:25:23 -0800
committerGitHub <noreply@github.com>2020-12-10 15:25:23 -0800
commitc93da3de39a4592abc6cddbed30b5c7074069a24 (patch)
tree265bcd421a97a21d58493f65eb29f252bf3a6001 /src/wasm-interpreter.h
parent57a9e77add02dc1d874fdbfee2c61cae8c0eefa1 (diff)
downloadbinaryen-c93da3de39a4592abc6cddbed30b5c7074069a24.tar.gz
binaryen-c93da3de39a4592abc6cddbed30b5c7074069a24.tar.bz2
binaryen-c93da3de39a4592abc6cddbed30b5c7074069a24.zip
[GC] Add Array operations (#3436)
array.new/get/set/len - pretty straightforward after structs and all the infrastructure for them. Also fixes validation of the unnecessary heapType param in the text and binary formats in structs as well as arrays. Fixes printing of packed types in type names, which emitted i32 for them. That broke when we emitted the same name for an array of i8 and i32 as in the new testing here. Also fix a bug in Field::operator< which was wrong for packed types; again, this was easy to notice with the new testing.
Diffstat (limited to 'src/wasm-interpreter.h')
-rw-r--r--src/wasm-interpreter.h111
1 files changed, 92 insertions, 19 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index bf02b7987..d701aaf15 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1403,8 +1403,7 @@ public:
return rtt;
}
const auto& fields = curr->rtt->type.getHeapType().getStruct().fields;
- Literals data;
- data.resize(fields.size());
+ Literals data(fields.size());
for (Index i = 0; i < fields.size(); i++) {
if (curr->isWithDefault()) {
data[i] = Literal::makeZero(fields[i].type);
@@ -1416,8 +1415,7 @@ public:
data[i] = value.getSingleValue();
}
}
- return Flow(
- Literal(std::shared_ptr<Literals>(new Literals(data)), curr->type));
+ return Flow(Literal(std::make_shared<Literals>(data), curr->type));
}
Flow visitStructGet(StructGet* curr) {
NOTE_ENTER("StructGet");
@@ -1445,40 +1443,115 @@ public:
if (!data) {
trap("null ref");
}
- // 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.
auto field = curr->ref->type.getHeapType().getStruct().fields[curr->index];
- auto setValue = value.getSingleValue();
- if (field.type == Type::i32) {
- if (field.packedType == Field::i8) {
- setValue = setValue.and_(Literal(int32_t(0xff)));
- } else if (field.packedType == Field::i16) {
- setValue = setValue.and_(Literal(int32_t(0xffff)));
- }
- }
- (*data)[curr->index] = setValue;
+ (*data)[curr->index] = getMaybePackedValue(value.getSingleValue(), field);
return Flow();
}
Flow visitArrayNew(ArrayNew* curr) {
NOTE_ENTER("ArrayNew");
- WASM_UNREACHABLE("TODO (gc): array.new");
+ auto rtt = this->visit(curr->rtt);
+ if (rtt.breaking()) {
+ return rtt;
+ }
+ auto size = this->visit(curr->size);
+ if (size.breaking()) {
+ return size;
+ }
+ const auto& element = curr->rtt->type.getHeapType().getArray().element;
+ Index num = size.getSingleValue().geti32();
+ Literals data(num);
+ if (curr->isWithDefault()) {
+ for (Index i = 0; i < num; i++) {
+ data[i] = Literal::makeZero(element.type);
+ }
+ } else {
+ auto init = this->visit(curr->init);
+ if (init.breaking()) {
+ return init;
+ }
+ auto value = init.getSingleValue();
+ for (Index i = 0; i < num; i++) {
+ data[i] = value;
+ }
+ }
+ return Flow(Literal(std::make_shared<Literals>(data), curr->type));
}
Flow visitArrayGet(ArrayGet* curr) {
NOTE_ENTER("ArrayGet");
- WASM_UNREACHABLE("TODO (gc): array.get");
+ Flow ref = this->visit(curr->ref);
+ if (ref.breaking()) {
+ return ref;
+ }
+ Flow index = this->visit(curr->index);
+ if (index.breaking()) {
+ return index;
+ }
+ auto data = ref.getSingleValue().getGCData();
+ if (!data) {
+ trap("null ref");
+ }
+ Index i = index.getSingleValue().geti32();
+ if (i >= data->size()) {
+ trap("array oob");
+ }
+ return (*data)[i];
}
Flow visitArraySet(ArraySet* curr) {
NOTE_ENTER("ArraySet");
- WASM_UNREACHABLE("TODO (gc): array.set");
+ Flow ref = this->visit(curr->ref);
+ if (ref.breaking()) {
+ return ref;
+ }
+ Flow index = this->visit(curr->index);
+ if (index.breaking()) {
+ return index;
+ }
+ Flow value = this->visit(curr->value);
+ if (value.breaking()) {
+ return value;
+ }
+ auto data = ref.getSingleValue().getGCData();
+ if (!data) {
+ trap("null ref");
+ }
+ Index i = index.getSingleValue().geti32();
+ if (i >= data->size()) {
+ trap("array oob");
+ }
+ auto field = curr->ref->type.getHeapType().getArray().element;
+ (*data)[i] = getMaybePackedValue(value.getSingleValue(), field);
+ return Flow();
}
Flow visitArrayLen(ArrayLen* curr) {
NOTE_ENTER("ArrayLen");
- WASM_UNREACHABLE("TODO (gc): array.len");
+ Flow ref = this->visit(curr->ref);
+ if (ref.breaking()) {
+ return ref;
+ }
+ auto data = ref.getSingleValue().getGCData();
+ if (!data) {
+ trap("null ref");
+ }
+ return Literal(int32_t(data->size()));
}
virtual void trap(const char* why) { WASM_UNREACHABLE("unimp"); }
virtual void throwException(Literal exn) { WASM_UNREACHABLE("unimp"); }
+
+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) {
+ if (field.type == Type::i32) {
+ if (field.packedType == Field::i8) {
+ value = value.and_(Literal(int32_t(0xff)));
+ } else if (field.packedType == Field::i16) {
+ value = value.and_(Literal(int32_t(0xffff)));
+ }
+ }
+ return value;
+ }
};
// Execute a suspected constant expression (precompute and C-API).