Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scripts/fuzz_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ def is_git_repo():
'shared-polymorphism.wast',
'shared-struct.wast',
'shared-array.wast',
'shared-i31.wast',
]


Expand Down
5 changes: 3 additions & 2 deletions scripts/gen-s-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,8 +572,9 @@
("resume", "makeResume()"),
("suspend", "makeSuspend()"),
# GC
("i31.new", "makeRefI31()"), # deprecated
("ref.i31", "makeRefI31()"),
("i31.new", "makeRefI31(Unshared)"), # deprecated
("ref.i31", "makeRefI31(Unshared)"),
("ref.i31_shared", "makeRefI31(Shared)"),
("i31.get_s", "makeI31Get(true)"),
("i31.get_u", "makeI31Get(false)"),
("ref.test", "makeRefTest()"),
Expand Down
23 changes: 17 additions & 6 deletions src/gen-s-parser.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1831,7 +1831,7 @@ switch (buf[0]) {
}
case 'n':
if (op == "i31.new"sv) {
CHECK_ERR(makeRefI31(ctx, pos, annotations));
CHECK_ERR(makeRefI31(ctx, pos, annotations, Unshared));
return Ok{};
}
goto parse_error;
Expand Down Expand Up @@ -4505,12 +4505,23 @@ switch (buf[0]) {
goto parse_error;
case 'i': {
switch (buf[5]) {
case '3':
if (op == "ref.i31"sv) {
CHECK_ERR(makeRefI31(ctx, pos, annotations));
return Ok{};
case '3': {
switch (buf[7]) {
case '\0':
if (op == "ref.i31"sv) {
CHECK_ERR(makeRefI31(ctx, pos, annotations, Unshared));
return Ok{};
}
goto parse_error;
case '_':
if (op == "ref.i31_shared"sv) {
CHECK_ERR(makeRefI31(ctx, pos, annotations, Shared));
return Ok{};
}
goto parse_error;
default: goto parse_error;
}
goto parse_error;
}
case 's':
if (op == "ref.is_null"sv) {
CHECK_ERR(makeRefIsNull(ctx, pos, annotations));
Expand Down
3 changes: 2 additions & 1 deletion src/ir/properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ inline Literal getLiteral(const Expression* curr) {
return Literal(r->func, r->type.getHeapType());
} else if (auto* i = curr->dynCast<RefI31>()) {
if (auto* c = i->value->dynCast<Const>()) {
return Literal::makeI31(c->value.geti32());
return Literal::makeI31(c->value.geti32(),
i->type.getHeapType().getShared());
}
} else if (auto* s = curr->dynCast<StringConst>()) {
return Literal(s->string.toString());
Expand Down
6 changes: 3 additions & 3 deletions src/literal.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ class Literal {
static Literal makeFunc(Name func, HeapType type) {
return Literal(func, type);
}
static Literal makeI31(int32_t value) {
auto lit = Literal(Type(HeapType::i31, NonNullable));
static Literal makeI31(int32_t value, Shareability share) {
auto lit = Literal(Type(HeapTypes::i31.getBasic(share), NonNullable));
lit.i32 = value | 0x80000000;
return lit;
}
Expand Down Expand Up @@ -281,7 +281,7 @@ class Literal {
return i32;
}
int32_t geti31(bool signed_ = true) const {
assert(type.getHeapType() == HeapType::i31);
assert(type.getHeapType().getBasic(Unshared) == HeapType::i31);
// Cast to unsigned for the left shift to avoid undefined behavior.
return signed_ ? int32_t((uint32_t(i32) << 1)) >> 1 : (i32 & 0x7fffffff);
}
Expand Down
11 changes: 8 additions & 3 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,10 @@ struct NullInstrParserCtx {
Result<> makeCallRef(Index, const std::vector<Annotation>&, HeapTypeT, bool) {
return Ok{};
}
Result<> makeRefI31(Index, const std::vector<Annotation>&) { return Ok{}; }
Result<>
makeRefI31(Index, const std::vector<Annotation>&, Shareability share) {
return Ok{};
}
Result<> makeI31Get(Index, const std::vector<Annotation>&, bool) {
return Ok{};
}
Expand Down Expand Up @@ -2363,8 +2366,10 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
return withLoc(pos, irBuilder.makeCallRef(type, isReturn));
}

Result<> makeRefI31(Index pos, const std::vector<Annotation>& annotations) {
return withLoc(pos, irBuilder.makeRefI31());
Result<> makeRefI31(Index pos,
const std::vector<Annotation>& annotations,
Shareability share) {
return withLoc(pos, irBuilder.makeRefI31(share));
}

Result<> makeI31Get(Index pos,
Expand Down
11 changes: 7 additions & 4 deletions src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ template<typename Ctx>
Result<>
makeCallRef(Ctx&, Index, const std::vector<Annotation>&, bool isReturn);
template<typename Ctx>
Result<> makeRefI31(Ctx&, Index, const std::vector<Annotation>&);
Result<>
makeRefI31(Ctx&, Index, const std::vector<Annotation>&, Shareability share);
template<typename Ctx>
Result<> makeI31Get(Ctx&, Index, const std::vector<Annotation>&, bool signed_);
template<typename Ctx>
Expand Down Expand Up @@ -2127,9 +2128,11 @@ Result<> makeCallRef(Ctx& ctx,
}

template<typename Ctx>
Result<>
makeRefI31(Ctx& ctx, Index pos, const std::vector<Annotation>& annotations) {
return ctx.makeRefI31(pos, annotations);
Result<> makeRefI31(Ctx& ctx,
Index pos,
const std::vector<Annotation>& annotations,
Shareability share) {
return ctx.makeRefI31(pos, annotations, share);
}

template<typename Ctx>
Expand Down
7 changes: 7 additions & 0 deletions src/parser/wast-parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,13 @@ Result<ExpectedResult> result(Lexer& in) {
return RefResult{HeapType::func};
}

if (in.takeSExprStart("ref.i31_shared")) {
if (!in.takeRParen()) {
return in.err("expected end of ref.i31_shared");
}
return RefResult{HeapTypes::i31.getBasic(Shared)};
}

return in.err("unrecognized result");
}

Expand Down
5 changes: 4 additions & 1 deletion src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2076,7 +2076,10 @@ struct PrintExpressionContents
o << std::max(curr->tuple->type.size(), size_t(2)) << " ";
o << curr->index;
}
void visitRefI31(RefI31* curr) { printMedium(o, "ref.i31"); }
void visitRefI31(RefI31* curr) {
printMedium(
o, curr->type.getHeapType().isShared() ? "ref.i31_shared" : "ref.i31");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you may need to guard here against curr->type being unreachable (when the i32 child is unreachable), in which case getHeapType errors.

}
void visitI31Get(I31Get* curr) {
printMedium(o, curr->signed_ ? "i31.get_s" : "i31.get_u");
}
Expand Down
1 change: 1 addition & 0 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,7 @@ enum ASTNodes {
RefI31 = 0x1c,
I31GetS = 0x1d,
I31GetU = 0x1e,
RefI31Shared = 0x1f,

// stringref opcodes

Expand Down
3 changes: 2 additions & 1 deletion src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -873,9 +873,10 @@ class Builder {
ret->finalize();
return ret;
}
RefI31* makeRefI31(Expression* value) {
RefI31* makeRefI31(Expression* value, Shareability share = Unshared) {
auto* ret = wasm.allocator.alloc<RefI31>();
ret->value = value;
ret->type = Type(HeapTypes::i31.getBasic(share), NonNullable);
ret->finalize();
return ret;
}
Expand Down
3 changes: 2 additions & 1 deletion src/wasm-interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -1426,7 +1426,8 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
}
const auto& value = flow.getSingleValue();
NOTE_EVAL1(value);
return Literal::makeI31(value.geti32());
return Literal::makeI31(value.geti32(),
curr->type.getHeapType().getShared());
}
Flow visitI31Get(I31Get* curr) {
NOTE_ENTER("I31Get");
Expand Down
2 changes: 1 addition & 1 deletion src/wasm-ir-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
[[nodiscard]] Result<> makeTupleMake(uint32_t arity);
[[nodiscard]] Result<> makeTupleExtract(uint32_t arity, uint32_t index);
[[nodiscard]] Result<> makeTupleDrop(uint32_t arity);
[[nodiscard]] Result<> makeRefI31();
[[nodiscard]] Result<> makeRefI31(Shareability share);
[[nodiscard]] Result<> makeI31Get(bool signed_);
[[nodiscard]] Result<> makeCallRef(HeapType type, bool isReturn);
[[nodiscard]] Result<> makeRefTest(Type type);
Expand Down
3 changes: 2 additions & 1 deletion src/wasm/literal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ Literal::Literal(Type type) : type(type) {
return;
}

if (type.isRef() && type.getHeapType() == HeapType::i31) {
if (type.isRef() && type.getHeapType().isBasic() &&
type.getHeapType().getBasic(Unshared) == HeapType::i31) {
assert(type.isNonNullable());
i32 = 0;
return;
Expand Down
18 changes: 12 additions & 6 deletions src/wasm/wasm-binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7244,13 +7244,19 @@ void WasmBinaryReader::visitCallRef(CallRef* curr) {
}

bool WasmBinaryReader::maybeVisitRefI31(Expression*& out, uint32_t code) {
if (code != BinaryConsts::RefI31) {
return false;
Shareability share;
switch (code) {
case BinaryConsts::RefI31:
share = Unshared;
break;
case BinaryConsts::RefI31Shared:
share = Shared;
break;
default:
return false;
}
auto* curr = allocator.alloc<RefI31>();
curr->value = popNonVoidExpression();
curr->finalize();
out = curr;
auto* value = popNonVoidExpression();
out = Builder(wasm).makeRefI31(value, share);
return true;
}

Expand Down
4 changes: 2 additions & 2 deletions src/wasm/wasm-ir-builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1605,10 +1605,10 @@ Result<> IRBuilder::makeTupleDrop(uint32_t arity) {
return Ok{};
}

Result<> IRBuilder::makeRefI31() {
Result<> IRBuilder::makeRefI31(Shareability share) {
RefI31 curr;
CHECK_ERR(visitRefI31(&curr));
push(builder.makeRefI31(curr.value));
push(builder.makeRefI31(curr.value, share));
return Ok{};
}

Expand Down
4 changes: 3 additions & 1 deletion src/wasm/wasm-stack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2114,7 +2114,9 @@ void BinaryInstWriter::visitTupleExtract(TupleExtract* curr) {
}

void BinaryInstWriter::visitRefI31(RefI31* curr) {
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RefI31);
o << int8_t(BinaryConsts::GCPrefix)
<< U32LEB(curr->type.getHeapType().isShared() ? BinaryConsts::RefI31Shared
: BinaryConsts::RefI31);
}

void BinaryInstWriter::visitI31Get(I31Get* curr) {
Expand Down
3 changes: 2 additions & 1 deletion src/wasm/wasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,8 @@ void RefI31::finalize() {
if (value->type == Type::unreachable) {
type = Type::unreachable;
} else {
type = Type(HeapType::i31, NonNullable);
assert(type.isRef() && type.getHeapType().isBasic() &&
type.getHeapType().getBasic(Unshared) == HeapType::i31);
}
}

Expand Down
37 changes: 37 additions & 0 deletions test/lit/basic/shared-i31.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.

;; RUN: wasm-opt %s -all -S -o - | filecheck %s
;; RUN: wasm-opt %s -all --roundtrip -S -o - | filecheck %s

(module
;; CHECK: (type $0 (func (param (ref null (shared i31))) (result i32)))

;; CHECK: (type $1 (func (param i32) (result (ref (shared i31)))))

;; CHECK: (func $make (type $1) (param $0 i32) (result (ref (shared i31)))
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $make (param i32) (result (ref (shared i31)))
(ref.i31_shared (local.get 0))
)

;; CHECK: (func $get_s (type $0) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (i31.get_s
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $get_s (param (ref null (shared i31))) (result i32)
(i31.get_s (local.get 0))
)

;; CHECK: (func $get_u (type $0) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $get_u (param (ref null (shared i31))) (result i32)
(i31.get_u (local.get 0))
)
)
Loading