Skip to content

Commit 5234c80

Browse files
author
Zoltan Herczeg
committed
Implement full reference support for call_ref, ref_null and variables
Support named references for globals, locals Support named references for call_ref, ref_null Improve type comparison
1 parent 9ee3f00 commit 5234c80

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+915
-406
lines changed

include/wabt/binary-reader-logging.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
181181
Result OnCatchExpr(Index tag_index) override;
182182
Result OnCatchAllExpr() override;
183183
Result OnCallIndirectExpr(Index sig_index, Index table_index) override;
184-
Result OnCallRefExpr() override;
184+
Result OnCallRefExpr(Type sig_type) override;
185185
Result OnCompareExpr(Opcode opcode) override;
186186
Result OnConvertExpr(Opcode opcode) override;
187187
Result OnDelegateExpr(Index depth) override;

include/wabt/binary-reader-nop.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ class BinaryReaderNop : public BinaryReaderDelegate {
250250
Result OnCallIndirectExpr(Index sig_index, Index table_index) override {
251251
return Result::Ok;
252252
}
253-
Result OnCallRefExpr() override { return Result::Ok; }
253+
Result OnCallRefExpr(Type sig_type) override { return Result::Ok; }
254254
Result OnCatchExpr(Index tag_index) override { return Result::Ok; }
255255
Result OnCatchAllExpr() override { return Result::Ok; }
256256
Result OnCompareExpr(Opcode opcode) override { return Result::Ok; }

include/wabt/binary-reader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ class BinaryReaderDelegate {
255255
Index default_target_depth) = 0;
256256
virtual Result OnCallExpr(Index func_index) = 0;
257257
virtual Result OnCallIndirectExpr(Index sig_index, Index table_index) = 0;
258-
virtual Result OnCallRefExpr() = 0;
258+
virtual Result OnCallRefExpr(Type sig_type) = 0;
259259
virtual Result OnCatchExpr(Index tag_index) = 0;
260260
virtual Result OnCatchAllExpr() = 0;
261261
virtual Result OnCompareExpr(Opcode opcode) = 0;

include/wabt/ir.h

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,41 @@ namespace wabt {
3636

3737
struct Module;
3838

39-
enum class VarType {
39+
enum class VarType : uint16_t {
4040
Index,
4141
Name,
4242
};
4343

4444
struct Var {
45+
// Var can represent variables or types.
46+
47+
// Represent a variable:
48+
// has_opt_type() is false
49+
// Only used by wast-parser
50+
51+
// Represent a type:
52+
// has_opt_type() is true, is_index() is true
53+
// type can be get by to_type()
54+
// Binary reader only constructs this variant
55+
56+
// Represent both a variable and a type:
57+
// has_opt_type() is true, is_name() is true
58+
// A reference, which index is unknown
59+
// Only used by wast-parser
60+
4561
explicit Var();
4662
explicit Var(Index index, const Location& loc);
4763
explicit Var(std::string_view name, const Location& loc);
64+
explicit Var(Type type, const Location& loc);
4865
Var(Var&&);
4966
Var(const Var&);
5067
Var& operator=(const Var&);
5168
Var& operator=(Var&&);
5269
~Var();
5370

54-
VarType type() const { return type_; }
5571
bool is_index() const { return type_ == VarType::Index; }
5672
bool is_name() const { return type_ == VarType::Name; }
73+
bool has_opt_type() const { return opt_type_ < 0; }
5774

5875
Index index() const {
5976
assert(is_index());
@@ -63,17 +80,25 @@ struct Var {
6380
assert(is_name());
6481
return name_;
6582
}
83+
Type::Enum opt_type() const {
84+
assert(has_opt_type());
85+
return static_cast<Type::Enum>(opt_type_);
86+
}
6687

6788
void set_index(Index);
6889
void set_name(std::string&&);
6990
void set_name(std::string_view);
91+
void set_opt_type(Type::Enum);
92+
Type to_type() const;
7093

7194
Location loc;
7295

7396
private:
7497
void Destroy();
7598

7699
VarType type_;
100+
// Can be set to Type::Enum types, 0 represent no optional type.
101+
int16_t opt_type_;
77102
union {
78103
Index index_;
79104
std::string name_;
@@ -259,8 +284,8 @@ struct FuncSignature {
259284
// So to use this type we need to translate its name into
260285
// a proper index from the module type section.
261286
// This is the mapping from parameter/result index to its name.
262-
std::unordered_map<uint32_t, std::string> param_type_names;
263-
std::unordered_map<uint32_t, std::string> result_type_names;
287+
std::unordered_map<uint32_t, Var> param_type_names;
288+
std::unordered_map<uint32_t, Var> result_type_names;
264289

265290
Index GetNumParams() const { return param_types.size(); }
266291
Index GetNumResults() const { return result_types.size(); }
@@ -544,10 +569,10 @@ using MemoryCopyExpr = MemoryBinaryExpr<ExprType::MemoryCopy>;
544569
template <ExprType TypeEnum>
545570
class RefTypeExpr : public ExprMixin<TypeEnum> {
546571
public:
547-
RefTypeExpr(Type type, const Location& loc = Location())
572+
RefTypeExpr(Var type, const Location& loc = Location())
548573
: ExprMixin<TypeEnum>(loc), type(type) {}
549574

550-
Type type;
575+
Var type;
551576
};
552577

553578
using RefNullExpr = RefTypeExpr<ExprType::RefNull>;
@@ -734,9 +759,7 @@ class CallRefExpr : public ExprMixin<ExprType::CallRef> {
734759
explicit CallRefExpr(const Location& loc = Location())
735760
: ExprMixin<ExprType::CallRef>(loc) {}
736761

737-
// This field is setup only during Validate phase,
738-
// so keep that in mind when you use it.
739-
Var function_type_index;
762+
Var sig_type;
740763
};
741764

742765
template <ExprType TypeEnum>
@@ -924,6 +947,8 @@ struct Func {
924947

925948
std::string name;
926949
FuncDeclaration decl;
950+
// Contains references with unknown indicies.
951+
TypeVector local_type_list;
927952
LocalTypes local_types;
928953
BindingHash bindings;
929954
ExprList exprs;
@@ -941,7 +966,7 @@ struct Global {
941966
explicit Global(std::string_view name) : name(name) {}
942967

943968
std::string name;
944-
Type type = Type::Void;
969+
Var type;
945970
bool mutable_ = false;
946971
ExprList init_expr;
947972
};

include/wabt/leb128.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ void WriteS32Leb128(Stream* stream, T value, const char* desc) {
6363
size_t ReadU32Leb128(const uint8_t* p, const uint8_t* end, uint32_t* out_value);
6464
size_t ReadU64Leb128(const uint8_t* p, const uint8_t* end, uint64_t* out_value);
6565
size_t ReadS32Leb128(const uint8_t* p, const uint8_t* end, uint32_t* out_value);
66+
size_t ReadS33Leb128(const uint8_t* p, const uint8_t* end, uint64_t* out_value);
6667
size_t ReadS64Leb128(const uint8_t* p, const uint8_t* end, uint64_t* out_value);
6768

6869
} // namespace wabt

include/wabt/shared-validator.h

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct ValidateOptions {
4343
class SharedValidator {
4444
public:
4545
WABT_DISALLOW_COPY_AND_ASSIGN(SharedValidator);
46+
using FuncType = TypeChecker::FuncType;
4647
SharedValidator(Errors*, const ValidateOptions& options);
4748

4849
// TODO: Move into SharedValidator?
@@ -140,7 +141,7 @@ class SharedValidator {
140141
Result EndBrTable(const Location&);
141142
Result OnCall(const Location&, Var func_var);
142143
Result OnCallIndirect(const Location&, Var sig_var, Var table_var);
143-
Result OnCallRef(const Location&, Index* function_type_index);
144+
Result OnCallRef(const Location&, Var function_type_var);
144145
Result OnCatch(const Location&, Var tag_var, bool is_catch_all);
145146
Result OnCompare(const Location&, Opcode);
146147
Result OnConst(const Location&, Type);
@@ -177,7 +178,7 @@ class SharedValidator {
177178
Result OnNop(const Location&);
178179
Result OnRefFunc(const Location&, Var func_var);
179180
Result OnRefIsNull(const Location&);
180-
Result OnRefNull(const Location&, Type type);
181+
Result OnRefNull(const Location&, Var func_type_var);
181182
Result OnRethrow(const Location&, Var depth);
182183
Result OnReturnCall(const Location&, Var func_var);
183184
Result OnReturnCallIndirect(const Location&, Var sig_var, Var table_var);
@@ -220,18 +221,6 @@ class SharedValidator {
220221
Result OnUnreachable(const Location&);
221222

222223
private:
223-
struct FuncType {
224-
FuncType() = default;
225-
FuncType(const TypeVector& params,
226-
const TypeVector& results,
227-
Index type_index)
228-
: params(params), results(results), type_index(type_index) {}
229-
230-
TypeVector params;
231-
TypeVector results;
232-
Index type_index;
233-
};
234-
235224
struct StructType {
236225
StructType() = default;
237226
StructType(const TypeMutVector& fields) : fields(fields) {}

include/wabt/token.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ WABT_TOKEN(Module, "module")
5555
WABT_TOKEN(Mut, "mut")
5656
WABT_TOKEN(NanArithmetic, "nan:arithmetic")
5757
WABT_TOKEN(NanCanonical, "nan:canonical")
58+
WABT_TOKEN(Null, "null")
5859
WABT_TOKEN(Offset, "offset")
5960
WABT_TOKEN(Output, "output")
6061
WABT_TOKEN(PageSize, "pagesize")

include/wabt/type-checker.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <functional>
2121
#include <type_traits>
2222
#include <vector>
23+
#include <map>
2324

2425
#include "wabt/common.h"
2526
#include "wabt/feature.h"
@@ -31,6 +32,18 @@ class TypeChecker {
3132
public:
3233
using ErrorCallback = std::function<void(const char* msg)>;
3334

35+
struct FuncType {
36+
FuncType() = default;
37+
FuncType(const TypeVector& params,
38+
const TypeVector& results,
39+
Index type_index)
40+
: params(params), results(results), type_index(type_index) {}
41+
42+
TypeVector params;
43+
TypeVector results;
44+
Index type_index;
45+
};
46+
3447
struct Label {
3548
Label(LabelType,
3649
const TypeVector& param_types,
@@ -48,7 +61,8 @@ class TypeChecker {
4861
bool unreachable;
4962
};
5063

51-
explicit TypeChecker(const Features& features) : features_(features) {}
64+
explicit TypeChecker(const Features& features, std::map<Index, FuncType>& func_types)
65+
: features_(features), func_types_(func_types) {}
5266

5367
void set_error_callback(const ErrorCallback& error_callback) {
5468
error_callback_ = error_callback;
@@ -80,7 +94,7 @@ class TypeChecker {
8094
Result OnCallIndirect(const TypeVector& param_types,
8195
const TypeVector& result_types,
8296
const Limits& table_limits);
83-
Result OnIndexedFuncRef(Index* out_index);
97+
Result OnCallRef(Type);
8498
Result OnReturnCall(const TypeVector& param_types,
8599
const TypeVector& result_types);
86100
Result OnReturnCallIndirect(const TypeVector& param_types,
@@ -141,7 +155,7 @@ class TypeChecker {
141155
Result BeginInitExpr(Type type);
142156
Result EndInitExpr();
143157

144-
static Result CheckType(Type actual, Type expected);
158+
Result CheckType(Type actual, Type expected);
145159

146160
private:
147161
void WABT_PRINTF_FORMAT(2, 3) PrintError(const char* fmt, ...);
@@ -210,6 +224,7 @@ class TypeChecker {
210224
// to represent "any".
211225
TypeVector* br_table_sig_ = nullptr;
212226
Features features_;
227+
std::map<Index, FuncType>& func_types_;
213228
};
214229

215230
} // namespace wabt

include/wabt/type.h

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ class Type {
4646
FuncRef = -0x10, // 0x70
4747
ExternRef = -0x11, // 0x6f
4848
Reference = -0x15, // 0x6b
49+
Ref = -0x1c, // 0x64
50+
RefNull = -0x1d, // 0x63
4951
Func = -0x20, // 0x60
5052
Struct = -0x21, // 0x5f
5153
Array = -0x22, // 0x5e
@@ -58,25 +60,52 @@ class Type {
5860
I32U = 7, // Not actually specified, but used internally with load/store
5961
};
6062

63+
// Used by FuncRef / ExternRef
64+
enum GenericReferenceType : uint32_t {
65+
ReferenceOrNull = kInvalidIndex,
66+
ReferenceNonNull = kInvalidIndex - 1,
67+
};
68+
6169
Type() = default; // Provided so Type can be member of a union.
6270
Type(int32_t code)
6371
: enum_(static_cast<Enum>(code)), type_index_(kInvalidIndex) {}
6472
Type(Enum e) : enum_(e), type_index_(kInvalidIndex) {}
6573
Type(Enum e, Index type_index) : enum_(e), type_index_(type_index) {
66-
assert(e == Enum::Reference);
74+
assert(e == Enum::FuncRef || e == Enum::ExternRef ||
75+
e == Enum::Reference || e == Enum::Ref ||
76+
e == Enum::RefNull || type_index == kInvalidIndex);
6777
}
6878
constexpr operator Enum() const { return enum_; }
6979

80+
bool IsNullableRef() const {
81+
return enum_ == Type::Reference || enum_ == Type::ExnRef ||
82+
enum_ == Type::RefNull ||
83+
((enum_ == Type::ExternRef || enum_ == Type::FuncRef) && type_index_ == ReferenceOrNull);
84+
}
85+
7086
bool IsRef() const {
7187
return enum_ == Type::ExternRef || enum_ == Type::FuncRef ||
72-
enum_ == Type::Reference || enum_ == Type::ExnRef;
88+
enum_ == Type::Reference || enum_ == Type::ExnRef ||
89+
enum_ == Type::RefNull || enum_ == Type::Ref;
7390
}
7491

75-
bool IsReferenceWithIndex() const { return enum_ == Type::Reference; }
92+
bool IsReferenceWithIndex() const {
93+
return enum_ == Type::Reference || enum_ == Type::Ref ||
94+
enum_ == Type::RefNull;
95+
}
7696

77-
bool IsNullableRef() const {
78-
// Currently all reftypes are nullable
79-
return IsRef();
97+
bool IsGenericRef() const {
98+
return enum_ == Type::ExternRef || enum_ == Type::FuncRef;
99+
}
100+
101+
bool IsNullableGenericRef() const {
102+
assert(enum_ == Type::ExternRef || enum_ == Type::FuncRef);
103+
return type_index_ == ReferenceOrNull;
104+
}
105+
106+
// The == comparison only compares the enum_ member.
107+
bool IsSame(const Type& rhs) const {
108+
return enum_ == rhs.enum_ && type_index_ == rhs.type_index_;
80109
}
81110

82111
std::string GetName() const {
@@ -89,13 +118,18 @@ class Type {
89118
case Type::I8: return "i8";
90119
case Type::I16: return "i16";
91120
case Type::ExnRef: return "exnref";
92-
case Type::FuncRef: return "funcref";
93121
case Type::Func: return "func";
94122
case Type::Void: return "void";
95123
case Type::Any: return "any";
96-
case Type::ExternRef: return "externref";
124+
case Type::FuncRef:
125+
return type_index_ == ReferenceOrNull ? "funcref" : "(ref func)";
126+
case Type::ExternRef:
127+
return type_index_ == ReferenceOrNull ? "externref" : "(ref extern)";
97128
case Type::Reference:
129+
case Type::Ref:
98130
return StringPrintf("(ref %d)", type_index_);
131+
case Type::RefNull:
132+
return StringPrintf("(ref null %d)", type_index_);
99133
default:
100134
return StringPrintf("<type_index[%d]>", enum_);
101135
}
@@ -132,7 +166,7 @@ class Type {
132166
}
133167

134168
Index GetReferenceIndex() const {
135-
assert(enum_ == Enum::Reference);
169+
assert(IsReferenceWithIndex());
136170
return type_index_;
137171
}
138172

@@ -151,6 +185,8 @@ class Type {
151185
case Type::ExnRef:
152186
case Type::ExternRef:
153187
case Type::Reference:
188+
case Type::Ref:
189+
case Type::RefNull:
154190
return TypeVector(this, this + 1);
155191

156192
default:

0 commit comments

Comments
 (0)