summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ir/cost.h6
-rw-r--r--src/ir/effects.h7
-rw-r--r--src/ir/module-utils.h4
-rw-r--r--src/literal.h2
-rw-r--r--src/passes/Print.cpp17
-rw-r--r--src/wasm-builder.h14
-rw-r--r--src/wasm-delegations-fields.h6
-rw-r--r--src/wasm-interpreter.h34
-rw-r--r--src/wasm.h8
-rw-r--r--src/wasm/wasm-binary.cpp7
-rw-r--r--src/wasm/wasm-s-parser.cpp13
-rw-r--r--src/wasm/wasm-stack.cpp7
-rw-r--r--src/wasm/wasm-validator.cpp13
-rw-r--r--src/wasm/wasm.cpp13
14 files changed, 106 insertions, 45 deletions
diff --git a/src/ir/cost.h b/src/ir/cost.h
index 1e383afca..268ac41b3 100644
--- a/src/ir/cost.h
+++ b/src/ir/cost.h
@@ -567,9 +567,11 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, Index> {
Index visitRttSub(RttSub* curr) { WASM_UNREACHABLE("TODO: GC"); }
Index visitStructNew(StructNew* curr) { WASM_UNREACHABLE("TODO: GC"); }
Index visitStructGet(StructGet* curr) {
- return 1 + nullCheckCost(curr->value) + visit(curr->value);
+ return 1 + nullCheckCost(curr->ref) + visit(curr->ref);
+ }
+ Index visitStructSet(StructSet* curr) {
+ return 1 + nullCheckCost(curr->ref) + visit(curr->ref) + visit(curr->value);
}
- Index visitStructSet(StructSet* curr) { WASM_UNREACHABLE("TODO: GC"); }
Index visitArrayNew(ArrayNew* curr) { WASM_UNREACHABLE("TODO: GC"); }
Index visitArrayGet(ArrayGet* curr) { WASM_UNREACHABLE("TODO: GC"); }
Index visitArraySet(ArraySet* curr) { WASM_UNREACHABLE("TODO: GC"); }
diff --git a/src/ir/effects.h b/src/ir/effects.h
index 80aa74cb6..d5b917d8b 100644
--- a/src/ir/effects.h
+++ b/src/ir/effects.h
@@ -563,12 +563,15 @@ private:
}
void visitStructGet(StructGet* curr) {
// traps when the arg is null
- if (curr->value->type.isNullable()) {
+ if (curr->ref->type.isNullable()) {
parent.implicitTrap = true;
}
}
void visitStructSet(StructSet* curr) {
- WASM_UNREACHABLE("TODO (gc): struct.set");
+ // traps when the arg is null
+ if (curr->ref->type.isNullable()) {
+ parent.implicitTrap = true;
+ }
}
void visitArrayNew(ArrayNew* curr) {
WASM_UNREACHABLE("TODO (gc): array.new");
diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h
index 64f04da31..2e93aa677 100644
--- a/src/ir/module-utils.h
+++ b/src/ir/module-utils.h
@@ -430,7 +430,9 @@ inline void collectHeapTypes(Module& wasm,
} else if (curr->is<RefNull>()) {
counts.maybeNote(curr->type);
} else if (auto* get = curr->dynCast<StructGet>()) {
- counts.maybeNote(get->value->type);
+ counts.maybeNote(get->ref->type);
+ } else if (auto* set = curr->dynCast<StructSet>()) {
+ counts.maybeNote(set->ref->type);
} else if (Properties::isControlFlowStructure(curr)) {
counts.maybeNote(curr->type);
if (curr->type.isTuple()) {
diff --git a/src/literal.h b/src/literal.h
index 12d3c6d07..72224613d 100644
--- a/src/literal.h
+++ b/src/literal.h
@@ -43,7 +43,7 @@ class Literal {
Name func;
// exnref package. `nullptr` indicates a `null` value.
std::unique_ptr<ExceptionPackage> exn;
- // A reference to GC data, either a Struct or an Array. For both of those
+ // A reference to GC data, either a Struct or an Array. For both of those
// we store the referred data as a Literals object (which is natural for an
// Array, and for a Struct, is just the fields in order). The type is used
// to indicate whether this is a Struct or an Array, and of what type.
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index ee7aa9ac7..d7691fe07 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -1685,7 +1685,7 @@ struct PrintExpressionContents
}
void visitStructGet(StructGet* curr) {
const auto& field =
- curr->value->type.getHeapType().getStruct().fields[curr->index];
+ curr->ref->type.getHeapType().getStruct().fields[curr->index];
if (field.type == Type::i32 && field.packedType != Field::not_packed) {
if (curr->signed_) {
printMedium(o, "struct.get_s ");
@@ -1695,13 +1695,15 @@ struct PrintExpressionContents
} else {
printMedium(o, "struct.get ");
}
- printHeapTypeName(o, curr->value->type.getHeapType());
+ printHeapTypeName(o, curr->ref->type.getHeapType());
o << ' ';
o << curr->index;
}
void visitStructSet(StructSet* curr) {
- printMedium(o, "struct.set");
- WASM_UNREACHABLE("TODO (gc): struct.set");
+ printMedium(o, "struct.set ");
+ printHeapTypeName(o, curr->ref->type.getHeapType());
+ o << ' ';
+ o << curr->index;
}
void visitArrayNew(ArrayNew* curr) {
WASM_UNREACHABLE("TODO (gc): array.new");
@@ -2372,13 +2374,16 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> {
o << '(';
PrintExpressionContents(currFunction, o).visit(curr);
incIndent();
- printFullLine(curr->value);
+ printFullLine(curr->ref);
decIndent();
}
void visitStructSet(StructSet* curr) {
o << '(';
PrintExpressionContents(currFunction, o).visit(curr);
- WASM_UNREACHABLE("TODO (gc): struct.set");
+ incIndent();
+ printFullLine(curr->ref);
+ printFullLine(curr->value);
+ decIndent();
}
void visitArrayNew(ArrayNew* curr) {
o << '(';
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index e3b12d23f..5bc238878 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -727,21 +727,21 @@ public:
ret->finalize();
return ret;
}
- StructGet* makeStructGet(Index index,
- Expression* value,
- Type type,
- bool signed_ = false) {
+ StructGet*
+ makeStructGet(Index index, Expression* ref, Type type, bool signed_ = false) {
auto* ret = wasm.allocator.alloc<StructGet>();
ret->index = index;
- ret->value = value;
+ ret->ref = ref;
ret->type = type;
ret->signed_ = signed_;
ret->finalize();
return ret;
}
- StructSet* makeStructSet() {
+ StructSet* makeStructSet(Index index, Expression* ref, Expression* value) {
auto* ret = wasm.allocator.alloc<StructSet>();
- WASM_UNREACHABLE("TODO (gc): struct.set");
+ ret->index = index;
+ ret->ref = ref;
+ ret->value = value;
ret->finalize();
return ret;
}
diff --git a/src/wasm-delegations-fields.h b/src/wasm-delegations-fields.h
index f3c5b9546..44ac20b89 100644
--- a/src/wasm-delegations-fields.h
+++ b/src/wasm-delegations-fields.h
@@ -596,14 +596,16 @@ switch (DELEGATE_ID) {
case Expression::Id::StructGetId: {
DELEGATE_START(StructGet);
DELEGATE_FIELD_INT(StructGet, index);
- DELEGATE_FIELD_CHILD(StructGet, value);
+ DELEGATE_FIELD_CHILD(StructGet, ref);
DELEGATE_FIELD_INT(Load, signed_);
DELEGATE_END(StructGet);
break;
}
case Expression::Id::StructSetId: {
DELEGATE_START(StructSet);
- WASM_UNREACHABLE("TODO (gc): struct.set");
+ DELEGATE_FIELD_INT(StructSet, index);
+ DELEGATE_FIELD_CHILD(StructSet, ref);
+ DELEGATE_FIELD_CHILD(StructSet, value);
DELEGATE_END(StructSet);
break;
}
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index b6e526544..a22bb6e54 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1402,11 +1402,11 @@ public:
}
Flow visitStructGet(StructGet* curr) {
NOTE_ENTER("StructGet");
- Flow flow = this->visit(curr->value);
- if (flow.breaking()) {
- return flow;
+ Flow ref = this->visit(curr->ref);
+ if (ref.breaking()) {
+ return ref;
}
- auto data = flow.getSingleValue().getGCData();
+ auto data = ref.getSingleValue().getGCData();
if (!data) {
trap("null ref");
}
@@ -1414,7 +1414,31 @@ public:
}
Flow visitStructSet(StructSet* curr) {
NOTE_ENTER("StructSet");
- WASM_UNREACHABLE("TODO (gc): struct.set");
+ Flow ref = this->visit(curr->ref);
+ if (ref.breaking()) {
+ return ref;
+ }
+ Flow value = this->visit(curr->value);
+ if (value.breaking()) {
+ return value;
+ }
+ auto data = ref.getSingleValue().getGCData();
+ 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;
+ return Flow();
}
Flow visitArrayNew(ArrayNew* curr) {
NOTE_ENTER("ArrayNew");
diff --git a/src/wasm.h b/src/wasm.h
index cc390573d..c1b5b4bdf 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -1353,7 +1353,7 @@ public:
StructGet(MixedArena& allocator) {}
Index index;
- Expression* value;
+ Expression* ref;
// Packed fields have a sign.
bool signed_ = false;
@@ -1364,7 +1364,11 @@ class StructSet : public SpecificExpression<Expression::StructSetId> {
public:
StructSet(MixedArena& allocator) {}
- void finalize() { WASM_UNREACHABLE("TODO (gc): struct.set"); }
+ Index index;
+ Expression* ref;
+ Expression* value;
+
+ void finalize();
};
class ArrayNew : public SpecificExpression<Expression::ArrayNewId> {
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 361faf631..e70dc4a29 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -5632,7 +5632,7 @@ bool WasmBinaryBuilder::maybeVisitStructGet(Expression*& out, uint32_t code) {
}
auto type = getHeapType();
curr->index = getU32LEB();
- curr->value = popNonVoidExpression();
+ curr->ref = popNonVoidExpression();
curr->finalize();
out = curr;
return true;
@@ -5643,7 +5643,10 @@ bool WasmBinaryBuilder::maybeVisitStructSet(Expression*& out, uint32_t code) {
return false;
}
auto* curr = allocator.alloc<StructSet>();
- WASM_UNREACHABLE("TODO (gc): struct.set");
+ auto type = getHeapType();
+ curr->index = getU32LEB();
+ curr->ref = popNonVoidExpression();
+ curr->value = popNonVoidExpression();
curr->finalize();
out = curr;
return true;
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 3e605429d..37592fcd5 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -2142,15 +2142,16 @@ Expression* SExpressionWasmBuilder::makeStructGet(Element& s, bool signed_) {
auto structType = parseHeapType(*s[1]);
auto index = getStructIndex(structType, *s[2]);
auto type = structType.getStruct().fields[index].type;
- auto value = parseExpression(*s[3]);
- return Builder(wasm).makeStructGet(index, value, type, signed_);
+ auto ref = parseExpression(*s[3]);
+ return Builder(wasm).makeStructGet(index, ref, type, signed_);
}
Expression* SExpressionWasmBuilder::makeStructSet(Element& s) {
- auto ret = allocator.alloc<StructSet>();
- WASM_UNREACHABLE("TODO (gc): struct.set");
- ret->finalize();
- return ret;
+ auto structType = parseHeapType(*s[1]);
+ auto index = getStructIndex(structType, *s[2]);
+ auto ref = parseExpression(*s[3]);
+ auto value = parseExpression(*s[4]);
+ return Builder(wasm).makeStructSet(index, ref, value);
}
Expression* SExpressionWasmBuilder::makeArrayNew(Element& s, bool default_) {
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index 4791c4a23..9d0d04b6d 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -1910,7 +1910,7 @@ void BinaryInstWriter::visitStructNew(StructNew* curr) {
}
void BinaryInstWriter::visitStructGet(StructGet* curr) {
- const auto& heapType = curr->value->type.getHeapType();
+ const auto& heapType = curr->ref->type.getHeapType();
const auto& field = heapType.getStruct().fields[curr->index];
int8_t op;
if (field.type != Type::i32 || field.packedType == Field::not_packed) {
@@ -1926,8 +1926,9 @@ void BinaryInstWriter::visitStructGet(StructGet* curr) {
}
void BinaryInstWriter::visitStructSet(StructSet* curr) {
- o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::StructSet);
- WASM_UNREACHABLE("TODO (gc): struct.set");
+ o << int8_t(BinaryConsts::GCPrefix) << int8_t(BinaryConsts::StructSet);
+ parent.writeHeapType(curr->ref->type.getHeapType());
+ o << U32LEB(curr->index);
}
void BinaryInstWriter::visitArrayNew(ArrayNew* curr) {
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 9a8644b28..b2e208d53 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -2231,8 +2231,8 @@ void FunctionValidator::visitStructGet(StructGet* curr) {
shouldBeTrue(getModule()->features.hasGC(),
curr,
"struct.get requires gc to be enabled");
- if (curr->value->type != Type::unreachable) {
- const auto& fields = curr->value->type.getHeapType().getStruct().fields;
+ if (curr->ref->type != Type::unreachable) {
+ const auto& fields = curr->ref->type.getHeapType().getStruct().fields;
shouldBeTrue(curr->index < fields.size(), curr, "bad struct.get field");
shouldBeEqual(curr->type,
fields[curr->index].type,
@@ -2245,7 +2245,14 @@ void FunctionValidator::visitStructSet(StructSet* curr) {
shouldBeTrue(getModule()->features.hasGC(),
curr,
"struct.set requires gc to be enabled");
- WASM_UNREACHABLE("TODO (gc): struct.set");
+ if (curr->ref->type != Type::unreachable) {
+ const auto& fields = curr->ref->type.getHeapType().getStruct().fields;
+ shouldBeTrue(curr->index < fields.size(), curr, "bad struct.get field");
+ shouldBeEqual(curr->value->type,
+ fields[curr->index].type,
+ curr,
+ "struct.set must have the proper type");
+ }
}
void FunctionValidator::visitArrayNew(ArrayNew* curr) {
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 20f3ec843..c15042721 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -1085,14 +1085,21 @@ void CallRef::finalize(Type type_) {
// TODO (gc): struct.new
void StructGet::finalize() {
- if (value->type == Type::unreachable) {
+ if (ref->type == Type::unreachable) {
type = Type::unreachable;
} else {
- type = value->type.getHeapType().getStruct().fields[index].type;
+ type = ref->type.getHeapType().getStruct().fields[index].type;
+ }
+}
+
+void StructSet::finalize() {
+ if (ref->type == Type::unreachable) {
+ type = Type::unreachable;
+ } else {
+ type = Type::none;
}
}
-// TODO (gc): struct.set
// TODO (gc): array.new
// TODO (gc): array.get
// TODO (gc): array.set