Skip to content

Commit ee87962

Browse files
authored
Add support for (ref ...) / (ref null ...) constructs (#2562)
This large patch adds function references support for those parts of the wabt library, which already present in the code. The current code is designed for an older (outdated) variant of the function references proposal. Key changes: - Var variables can optionally store type data. This way there is no need for a Var/Type field pair in many cases. - CallRef now needs to explicitly provide its reference type (no auto detection) - Tracking local reference initialization (non nullable refs must be set before using them) - Supporting type equality comparisons in the validator and in the interpreter - Adds a code for reading/writing 33 bit integers (leb format) - Remove EndTypeSection in shared validator, types can be validated earlier - Improve named reference resolving in the text parser Co-authored-by: Zoltan Herczeg <hzmester@freemail.hu>
1 parent d5a9913 commit ee87962

Some content is hidden

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

55 files changed

+1831
-564
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/interp/interp-inl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ inline bool FuncType::classof(const ExternType* type) {
4242
}
4343

4444
inline FuncType::FuncType(ValueTypes params, ValueTypes results)
45-
: ExternType(ExternKind::Func), params(params), results(results) {}
45+
: ExternType(ExternKind::Func), params(params), results(results), func_types(nullptr) {}
4646

4747
//// TableType ////
4848
// static

include/wabt/interp/interp.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ struct FuncType : ExternType {
184184

185185
ValueTypes params;
186186
ValueTypes results;
187+
// When params or results contain references, the referenced
188+
// types are also needed for type equality comparisons.
189+
// An example for these comparisons is import validation.
190+
std::vector<FuncType>* func_types;
187191
};
188192

189193
struct TableType : ExternType {

include/wabt/ir.h

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

3737
struct Module;
3838

39-
enum class VarType {
39+
// VarType (16 bit) and the opt_type_ (16 bit)
40+
// fields of Var forms a 32 bit field.
41+
enum class VarType : uint16_t {
4042
Index,
4143
Name,
4244
};
4345

4446
struct Var {
47+
// Var can represent variables or types.
48+
49+
// Represent a variable:
50+
// has_opt_type() is false
51+
// Only used by wast-parser
52+
53+
// Represent a type:
54+
// has_opt_type() is true, is_index() is true
55+
// type can be get by to_type()
56+
// Binary reader only constructs this variant
57+
58+
// Represent both a variable and a type:
59+
// has_opt_type() is true, is_name() is true
60+
// A reference, which index is unknown
61+
// Only used by wast-parser
62+
4563
explicit Var();
4664
explicit Var(Index index, const Location& loc);
4765
explicit Var(std::string_view name, const Location& loc);
66+
explicit Var(Type type, const Location& loc);
4867
Var(Var&&);
4968
Var(const Var&);
5069
Var& operator=(const Var&);
5170
Var& operator=(Var&&);
5271
~Var();
5372

54-
VarType type() const { return type_; }
5573
bool is_index() const { return type_ == VarType::Index; }
5674
bool is_name() const { return type_ == VarType::Name; }
75+
bool has_opt_type() const { return opt_type_ < 0; }
5776

5877
Index index() const {
5978
assert(is_index());
@@ -63,17 +82,25 @@ struct Var {
6382
assert(is_name());
6483
return name_;
6584
}
85+
Type::Enum opt_type() const {
86+
assert(has_opt_type());
87+
return static_cast<Type::Enum>(opt_type_);
88+
}
6689

6790
void set_index(Index);
6891
void set_name(std::string&&);
6992
void set_name(std::string_view);
93+
void set_opt_type(Type::Enum);
94+
Type to_type() const;
7095

7196
Location loc;
7297

7398
private:
7499
void Destroy();
75100

76101
VarType type_;
102+
// Can be set to Type::Enum types, Type::Any represent no optional type.
103+
int16_t opt_type_;
77104
union {
78105
Index index_;
79106
std::string name_;
@@ -155,6 +182,7 @@ struct Const {
155182
}
156183
void set_funcref() { From<uintptr_t>(Type::FuncRef, 0); }
157184
void set_externref(uintptr_t x) { From(Type::ExternRef, x); }
185+
void set_extern(uintptr_t x) { From(Type(Type::ExternRef, Type::ReferenceNonNull), x); }
158186
void set_null(Type type) { From<uintptr_t>(type, kRefNullBits); }
159187

160188
bool is_expected_nan(int lane = 0) const {
@@ -537,10 +565,10 @@ using MemoryCopyExpr = MemoryBinaryExpr<ExprType::MemoryCopy>;
537565
template <ExprType TypeEnum>
538566
class RefTypeExpr : public ExprMixin<TypeEnum> {
539567
public:
540-
RefTypeExpr(Type type, const Location& loc = Location())
568+
RefTypeExpr(Var type, const Location& loc = Location())
541569
: ExprMixin<TypeEnum>(loc), type(type) {}
542570

543-
Type type;
571+
Var type;
544572
};
545573

546574
using RefNullExpr = RefTypeExpr<ExprType::RefNull>;
@@ -662,8 +690,8 @@ using MemoryInitExpr = MemoryVarExpr<ExprType::MemoryInit>;
662690

663691
class SelectExpr : public ExprMixin<ExprType::Select> {
664692
public:
665-
SelectExpr(TypeVector type, const Location& loc = Location())
666-
: ExprMixin<ExprType::Select>(loc), result_type(type) {}
693+
SelectExpr(const Location& loc = Location())
694+
: ExprMixin<ExprType::Select>(loc) {}
667695
TypeVector result_type;
668696
};
669697

@@ -727,9 +755,7 @@ class CallRefExpr : public ExprMixin<ExprType::CallRef> {
727755
explicit CallRefExpr(const Location& loc = Location())
728756
: ExprMixin<ExprType::CallRef>(loc) {}
729757

730-
// This field is setup only during Validate phase,
731-
// so keep that in mind when you use it.
732-
Var function_type_index;
758+
Var sig_type;
733759
};
734760

735761
template <ExprType TypeEnum>

include/wabt/shared-validator.h

Lines changed: 16 additions & 15 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?
@@ -72,7 +73,6 @@ class SharedValidator {
7273
Index type_index);
7374
Result OnStructType(const Location&, Index field_count, TypeMut* fields);
7475
Result OnArrayType(const Location&, TypeMut field);
75-
Result EndTypeSection();
7676

7777
Result OnFunction(const Location&, Var sig_var);
7878
Result OnTable(const Location&, Type elem_type, const Limits&);
@@ -141,7 +141,7 @@ class SharedValidator {
141141
Result EndBrTable(const Location&);
142142
Result OnCall(const Location&, Var func_var);
143143
Result OnCallIndirect(const Location&, Var sig_var, Var table_var);
144-
Result OnCallRef(const Location&, Index* function_type_index);
144+
Result OnCallRef(const Location&, Var function_type_var);
145145
Result OnCatch(const Location&, Var tag_var, bool is_catch_all);
146146
Result OnCompare(const Location&, Opcode);
147147
Result OnConst(const Location&, Type);
@@ -178,7 +178,7 @@ class SharedValidator {
178178
Result OnNop(const Location&);
179179
Result OnRefFunc(const Location&, Var func_var);
180180
Result OnRefIsNull(const Location&);
181-
Result OnRefNull(const Location&, Type type);
181+
Result OnRefNull(const Location&, Var func_type_var);
182182
Result OnRethrow(const Location&, Var depth);
183183
Result OnReturnCall(const Location&, Var func_var);
184184
Result OnReturnCallIndirect(const Location&, Var sig_var, Var table_var);
@@ -221,18 +221,6 @@ class SharedValidator {
221221
Result OnUnreachable(const Location&);
222222

223223
private:
224-
struct FuncType {
225-
FuncType() = default;
226-
FuncType(const TypeVector& params,
227-
const TypeVector& results,
228-
Index type_index)
229-
: params(params), results(results), type_index(type_index) {}
230-
231-
TypeVector params;
232-
TypeVector results;
233-
Index type_index;
234-
};
235-
236224
struct StructType {
237225
StructType() = default;
238226
StructType(const TypeMutVector& fields) : fields(fields) {}
@@ -289,6 +277,13 @@ class SharedValidator {
289277
Index end;
290278
};
291279

280+
struct LocalReferenceMap {
281+
Type type;
282+
// An index for a single bit value, which represents that
283+
// the corresponding local reference has been set before.
284+
size_t local_ref_is_set;
285+
};
286+
292287
bool ValidInitOpcode(Opcode opcode) const;
293288
Result CheckInstr(Opcode opcode, const Location& loc);
294289
Result CheckType(const Location&,
@@ -336,6 +331,10 @@ class SharedValidator {
336331

337332
TypeVector ToTypeVector(Index count, const Type* types);
338333

334+
void SaveLocalRefs();
335+
void RestoreLocalRefs(Result result);
336+
void IgnoreLocalRefs();
337+
339338
ValidateOptions options_;
340339
Errors* errors_;
341340
TypeChecker typechecker_; // TODO: Move into SharedValidator.
@@ -361,6 +360,8 @@ class SharedValidator {
361360
// Includes parameters, since this is only used for validating
362361
// local.{get,set,tee} instructions.
363362
std::vector<LocalDecl> locals_;
363+
std::map<Index, LocalReferenceMap> local_refs_map_;
364+
std::vector<bool> local_ref_is_set_;
364365

365366
std::set<std::string> export_names_; // Used to check for duplicates.
366367
std::set<Index> declared_funcs_; // TODO: optimize?

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: 20 additions & 4 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,
@@ -46,9 +59,11 @@ class TypeChecker {
4659
TypeVector result_types;
4760
size_t type_stack_limit;
4861
bool unreachable;
62+
std::vector<bool> local_ref_is_set_;
4963
};
5064

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

5368
void set_error_callback(const ErrorCallback& error_callback) {
5469
error_callback_ = error_callback;
@@ -80,7 +95,7 @@ class TypeChecker {
8095
Result OnCallIndirect(const TypeVector& param_types,
8196
const TypeVector& result_types,
8297
const Limits& table_limits);
83-
Result OnIndexedFuncRef(Index* out_index);
98+
Result OnCallRef(Type);
8499
Result OnReturnCall(const TypeVector& param_types,
85100
const TypeVector& result_types);
86101
Result OnReturnCallIndirect(const TypeVector& param_types,
@@ -115,7 +130,7 @@ class TypeChecker {
115130
Result OnTableGrow(Type elem_type, const Limits& limits);
116131
Result OnTableSize(const Limits& limits);
117132
Result OnTableFill(Type elem_type, const Limits& limits);
118-
Result OnRefFuncExpr(Index func_type, bool force_generic_funcref);
133+
Result OnRefFuncExpr(Index func_type);
119134
Result OnRefNullExpr(Type type);
120135
Result OnRefIsNullExpr();
121136
Result OnRethrow(Index depth);
@@ -141,7 +156,7 @@ class TypeChecker {
141156
Result BeginInitExpr(Type type);
142157
Result EndInitExpr();
143158

144-
static Result CheckType(Type actual, Type expected);
159+
Result CheckType(Type actual, Type expected);
145160

146161
private:
147162
void WABT_PRINTF_FORMAT(2, 3) PrintError(const char* fmt, ...);
@@ -210,6 +225,7 @@ class TypeChecker {
210225
// to represent "any".
211226
TypeVector* br_table_sig_ = nullptr;
212227
Features features_;
228+
std::map<Index, FuncType>& func_types_;
213229
};
214230

215231
} // namespace wabt

0 commit comments

Comments
 (0)