diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/cost.h | 6 | ||||
-rw-r--r-- | src/ir/effects.h | 7 | ||||
-rw-r--r-- | src/ir/module-utils.h | 4 | ||||
-rw-r--r-- | src/literal.h | 2 | ||||
-rw-r--r-- | src/passes/Print.cpp | 17 | ||||
-rw-r--r-- | src/wasm-builder.h | 14 | ||||
-rw-r--r-- | src/wasm-delegations-fields.h | 6 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 34 | ||||
-rw-r--r-- | src/wasm.h | 8 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 7 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 13 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 7 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 13 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 13 |
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 |