Skip to content

Commit cad84dc

Browse files
committed
Fix reference type processing
Parse (ref index) form, not just (ref $name) form Resolve references in types and locals Display location when a named reference is not found
1 parent f81dff0 commit cad84dc

File tree

8 files changed

+229
-47
lines changed

8 files changed

+229
-47
lines changed

include/wabt/ir.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,8 @@ struct FuncSignature {
259259
// So to use this type we need to translate its name into
260260
// a proper index from the module type section.
261261
// 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;
262+
std::unordered_map<uint32_t, Var> param_type_names;
263+
std::unordered_map<uint32_t, Var> result_type_names;
264264

265265
Index GetNumParams() const { return param_types.size(); }
266266
Index GetNumResults() const { return result_types.size(); }
@@ -925,6 +925,9 @@ struct Func {
925925
std::string name;
926926
FuncDeclaration decl;
927927
LocalTypes local_types;
928+
// When some locals are named references, the conversion
929+
// to local_types is done after the parsing is completed.
930+
TypeVector local_type_list;
928931
BindingHash bindings;
929932
ExprList exprs;
930933
Location loc;

include/wabt/type.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ class Type {
7979
return IsRef();
8080
}
8181

82+
// The == comparison only compares the enum_ member.
83+
bool IsSame(const Type& rhs) const {
84+
return enum_ == rhs.enum_ && type_index_ == rhs.type_index_;
85+
}
86+
8287
std::string GetName() const {
8388
switch (enum_) {
8489
case Type::I32: return "i32";

include/wabt/wast-parser.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ class WastParser {
137137
Result ParseValueType(Var* out_type);
138138
Result ParseValueTypeList(
139139
TypeVector* out_type_list,
140-
std::unordered_map<uint32_t, std::string>* type_names);
140+
std::unordered_map<uint32_t, Var>* type_names,
141+
Index binding_index_offset);
141142
Result ParseRefKind(Type* out_type);
142143
Result ParseRefType(Type* out_type);
143144
bool ParseRefTypeOpt(Type* out_type);
@@ -176,13 +177,13 @@ class WastParser {
176177
Result ParseBoundValueTypeList(TokenType,
177178
TypeVector*,
178179
BindingHash*,
179-
std::unordered_map<uint32_t, std::string>*,
180+
std::unordered_map<uint32_t, Var>*,
180181
Index binding_index_offset = 0);
181182
Result ParseUnboundValueTypeList(TokenType,
182183
TypeVector*,
183-
std::unordered_map<uint32_t, std::string>*);
184+
std::unordered_map<uint32_t, Var>*);
184185
Result ParseResultList(TypeVector*,
185-
std::unordered_map<uint32_t, std::string>*);
186+
std::unordered_map<uint32_t, Var>*);
186187
Result ParseInstrList(ExprList*);
187188
Result ParseTerminatingInstrList(ExprList*);
188189
Result ParseInstr(ExprList*);

src/ir.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ void LocalTypes::Set(const TypeVector& types) {
181181
Type type = types[0];
182182
Index count = 1;
183183
for (Index i = 1; i < types.size(); ++i) {
184-
if (types[i] != type) {
184+
if (!types[i].IsSame(type)) {
185185
decls_.emplace_back(type, count);
186186
type = types[i];
187187
count = 1;

src/wast-parser.cc

Lines changed: 87 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -319,37 +319,54 @@ bool ResolveFuncTypeWithEmptySignature(const Module& module,
319319
return false;
320320
}
321321

322-
void ResolveTypeName(
323-
const Module& module,
324-
Type& type,
325-
Index index,
326-
const std::unordered_map<uint32_t, std::string>& bindings) {
327-
if (type != Type::Reference || type.GetReferenceIndex() != kInvalidIndex) {
328-
return;
329-
}
322+
Result ResolveRefTypes(const Module& module,
323+
TypeVector& types,
324+
uint32_t base_index,
325+
const std::unordered_map<uint32_t, Var>& bindings,
326+
Errors* errors) {
327+
Result result = Result::Ok;
328+
size_t types_size = types.size();
329+
330+
for (auto& [index, binding] : bindings) {
331+
if (index < base_index || (index - base_index) >= types_size) {
332+
continue;
333+
}
334+
335+
Type type = types[index - base_index];
336+
337+
assert(type.IsReferenceWithIndex());
338+
339+
if (type.GetReferenceIndex() != kInvalidIndex) {
340+
continue;
341+
}
342+
343+
const auto type_index = module.type_bindings.FindIndex(binding.name());
330344

331-
const auto name_iterator = bindings.find(index);
332-
assert(name_iterator != bindings.cend());
333-
const auto type_index = module.type_bindings.FindIndex(name_iterator->second);
334-
assert(type_index != kInvalidIndex);
335-
type = Type(Type::Reference, type_index);
345+
if (type_index == kInvalidIndex) {
346+
errors->emplace_back(
347+
ErrorLevel::Error, binding.loc,
348+
StringPrintf("Unknown reference: %s", binding.name().c_str()));
349+
result = Result::Error;
350+
continue;
351+
}
352+
353+
types[index - base_index] = Type(static_cast<Type::Enum>(type), type_index);
354+
}
355+
356+
return Result::Ok;
336357
}
337358

338-
void ResolveTypeNames(const Module& module, FuncDeclaration* decl) {
339-
assert(decl);
340-
auto& signature = decl->sig;
359+
Result ResolveTypeNames(const Module& module,
360+
FuncSignature& signature,
361+
Errors* errors) {
362+
Result result = Result::Ok;
341363

342-
for (uint32_t param_index = 0; param_index < signature.GetNumParams();
343-
++param_index) {
344-
ResolveTypeName(module, signature.param_types[param_index], param_index,
345-
signature.param_type_names);
346-
}
364+
result |= ResolveRefTypes(module, signature.param_types, 0,
365+
signature.param_type_names, errors);
347366

348-
for (uint32_t result_index = 0; result_index < signature.GetNumResults();
349-
++result_index) {
350-
ResolveTypeName(module, signature.result_types[result_index], result_index,
351-
signature.result_type_names);
352-
}
367+
result |= ResolveRefTypes(module, signature.result_types, 0,
368+
signature.result_type_names, errors);
369+
return result;
353370
}
354371

355372
void ResolveImplicitlyDefinedFunctionType(const Location& loc,
@@ -457,7 +474,7 @@ class ResolveFuncTypesExprVisitorDelegate : public ExprVisitor::DelegateNop {
457474
: module_(module), errors_(errors) {}
458475

459476
void ResolveBlockDeclaration(const Location& loc, BlockDeclaration* decl) {
460-
ResolveTypeNames(*module_, decl);
477+
ResolveTypeNames(*module_, decl->sig, errors_);
461478
ResolveFuncTypeWithEmptySignature(*module_, decl);
462479
if (!IsInlinableFuncSignature(decl->sig)) {
463480
ResolveImplicitlyDefinedFunctionType(loc, module_, *decl);
@@ -529,14 +546,22 @@ Result ResolveFuncTypes(Module* module, Errors* errors) {
529546
} else {
530547
continue;
531548
}
549+
} else if (auto* type_field = dyn_cast<TypeModuleField>(&field)) {
550+
TypeEntry* entry = type_field->type.get();
551+
552+
if (entry->kind() == TypeEntryKind::Func) {
553+
FuncType* func_type = cast<FuncType>(entry);
554+
result |= ResolveTypeNames(*module, func_type->sig, errors);
555+
}
556+
continue;
532557
} else {
533558
continue;
534559
}
535560

536561
bool has_func_type_and_empty_signature = false;
537562

538563
if (decl) {
539-
ResolveTypeNames(*module, decl);
564+
result |= ResolveTypeNames(*module, decl->sig, errors);
540565
has_func_type_and_empty_signature =
541566
ResolveFuncTypeWithEmptySignature(*module, decl);
542567
ResolveImplicitlyDefinedFunctionType(field.loc, module, *decl);
@@ -545,6 +570,15 @@ Result ResolveFuncTypes(Module* module, Errors* errors) {
545570
}
546571

547572
if (func) {
573+
if (!func->local_type_list.empty()) {
574+
result |= ResolveRefTypes(*module, func->local_type_list,
575+
func->GetNumParams(),
576+
decl->sig.param_type_names, errors);
577+
578+
func->local_types.Set(func->local_type_list);
579+
func->local_type_list.clear();
580+
}
581+
548582
if (has_func_type_and_empty_signature) {
549583
// The call to ResolveFuncTypeWithEmptySignature may have updated the
550584
// function signature so there are parameters. Since parameters and
@@ -962,7 +996,8 @@ Result WastParser::ParseValueType(Var* out_type) {
962996

963997
Result WastParser::ParseValueTypeList(
964998
TypeVector* out_type_list,
965-
std::unordered_map<uint32_t, std::string>* type_names) {
999+
std::unordered_map<uint32_t, Var>* type_names,
1000+
Index binding_index_offset) {
9661001
WABT_TRACE(ParseValueTypeList);
9671002
while (true) {
9681003
if (!PeekMatchRefType() && !PeekMatch(TokenType::ValueType)) {
@@ -973,11 +1008,16 @@ Result WastParser::ParseValueTypeList(
9731008
CHECK_RESULT(ParseValueType(&type));
9741009

9751010
if (type.is_index()) {
976-
out_type_list->push_back(Type(type.index()));
1011+
// TODO: Temporary fix.
1012+
if (type.index() >= static_cast<Index>(Type::Void)) {
1013+
out_type_list->push_back(Type(type.index()));
1014+
} else {
1015+
out_type_list->push_back(Type(Type::Reference, type.index()));
1016+
}
9771017
} else {
9781018
assert(type.is_name());
9791019
assert(options_->features.function_references_enabled());
980-
type_names->emplace(out_type_list->size(), type.name());
1020+
type_names->emplace(binding_index_offset + out_type_list->size(), type);
9811021
out_type_list->push_back(Type(Type::Reference, kInvalidIndex));
9821022
}
9831023
}
@@ -1539,11 +1579,18 @@ Result WastParser::ParseFuncModuleField(Module* module) {
15391579
func.loc = GetLocation();
15401580
CHECK_RESULT(ParseTypeUseOpt(&func.decl));
15411581
CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings));
1542-
TypeVector local_types;
1582+
1583+
size_t names_size = func.decl.sig.param_type_names.size();
15431584
CHECK_RESULT(ParseBoundValueTypeList(
1544-
TokenType::Local, &local_types, &func.bindings,
1585+
TokenType::Local, &func.local_type_list, &func.bindings,
15451586
&func.decl.sig.param_type_names, func.GetNumParams()));
1546-
func.local_types.Set(local_types);
1587+
1588+
if (names_size == func.decl.sig.param_type_names.size()) {
1589+
// No named references in the list, local types can be processed now.
1590+
func.local_types.Set(func.local_type_list);
1591+
func.local_type_list.clear();
1592+
}
1593+
15471594
CHECK_RESULT(ParseTerminatingInstrList(&func.exprs));
15481595
module->AppendField(std::move(field));
15491596
}
@@ -1982,7 +2029,7 @@ Result WastParser::ParseBoundValueTypeList(
19822029
TokenType token,
19832030
TypeVector* types,
19842031
BindingHash* bindings,
1985-
std::unordered_map<uint32_t, std::string>* type_names,
2032+
std::unordered_map<uint32_t, Var>* type_names,
19862033
Index binding_index_offset) {
19872034
WABT_TRACE(ParseBoundValueTypeList);
19882035
while (MatchLpar(token)) {
@@ -1999,11 +2046,11 @@ Result WastParser::ParseBoundValueTypeList(
19992046
} else {
20002047
assert(type.is_name());
20012048
assert(options_->features.function_references_enabled());
2002-
type_names->emplace(binding_index_offset + types->size(), type.name());
2049+
type_names->emplace(binding_index_offset + types->size(), type);
20032050
types->push_back(Type(Type::Reference, kInvalidIndex));
20042051
}
20052052
} else {
2006-
CHECK_RESULT(ParseValueTypeList(types, type_names));
2053+
CHECK_RESULT(ParseValueTypeList(types, type_names, binding_index_offset));
20072054
}
20082055
EXPECT(Rpar);
20092056
}
@@ -2013,18 +2060,18 @@ Result WastParser::ParseBoundValueTypeList(
20132060
Result WastParser::ParseUnboundValueTypeList(
20142061
TokenType token,
20152062
TypeVector* types,
2016-
std::unordered_map<uint32_t, std::string>* type_names) {
2063+
std::unordered_map<uint32_t, Var>* type_names) {
20172064
WABT_TRACE(ParseUnboundValueTypeList);
20182065
while (MatchLpar(token)) {
2019-
CHECK_RESULT(ParseValueTypeList(types, type_names));
2066+
CHECK_RESULT(ParseValueTypeList(types, type_names, 0));
20202067
EXPECT(Rpar);
20212068
}
20222069
return Result::Ok;
20232070
}
20242071

20252072
Result WastParser::ParseResultList(
20262073
TypeVector* result_types,
2027-
std::unordered_map<uint32_t, std::string>* type_names) {
2074+
std::unordered_map<uint32_t, Var>* type_names) {
20282075
WABT_TRACE(ParseResultList);
20292076
return ParseUnboundValueTypeList(TokenType::Result, result_types, type_names);
20302077
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
;;; TOOL: run-objdump
2+
;;; ARGS0: -v --enable-function-references
3+
4+
(module
5+
(type $t0 (func))
6+
7+
;; Self reference
8+
(type $t1 (func (param (ref $t0) (ref $t1) (ref 1))))
9+
10+
(func $f1 (param (ref $t0) (ref 0))
11+
(local (ref $t0) (ref 0)
12+
(ref $t1) (ref 1))
13+
)
14+
)
15+
16+
(;; STDERR ;;;
17+
0000000: 0061 736d ; WASM_BINARY_MAGIC
18+
0000004: 0100 0000 ; WASM_BINARY_VERSION
19+
; section "Type" (1)
20+
0000008: 01 ; section code
21+
0000009: 00 ; section size (guess)
22+
000000a: 03 ; num types
23+
; func type 0
24+
000000b: 60 ; func
25+
000000c: 00 ; num params
26+
000000d: 00 ; num results
27+
; func type 1
28+
000000e: 60 ; func
29+
000000f: 03 ; num params
30+
0000010: 6b ; (ref 0)
31+
0000011: 00 ; (ref 0)
32+
0000012: 6b ; (ref 1)
33+
0000013: 01 ; (ref 1)
34+
0000014: 6b ; (ref 1)
35+
0000015: 01 ; (ref 1)
36+
0000016: 00 ; num results
37+
; func type 2
38+
0000017: 60 ; func
39+
0000018: 02 ; num params
40+
0000019: 6b ; (ref 0)
41+
000001a: 00 ; (ref 0)
42+
000001b: 6b ; (ref 0)
43+
000001c: 00 ; (ref 0)
44+
000001d: 00 ; num results
45+
0000009: 14 ; FIXUP section size
46+
; section "Function" (3)
47+
000001e: 03 ; section code
48+
000001f: 00 ; section size (guess)
49+
0000020: 01 ; num functions
50+
0000021: 02 ; function 0 signature index
51+
000001f: 02 ; FIXUP section size
52+
; section "Code" (10)
53+
0000022: 0a ; section code
54+
0000023: 00 ; section size (guess)
55+
0000024: 01 ; num functions
56+
; function body 0
57+
0000025: 00 ; func body size (guess)
58+
0000026: 02 ; local decl count
59+
0000027: 02 ; local type count
60+
0000028: 6b ; (ref 0)
61+
0000029: 00 ; (ref 0)
62+
000002a: 02 ; local type count
63+
000002b: 6b ; (ref 1)
64+
000002c: 01 ; (ref 1)
65+
000002d: 0b ; end
66+
0000025: 08 ; FIXUP func body size
67+
0000023: 0a ; FIXUP section size
68+
;;; STDERR ;;)
69+
(;; STDOUT ;;;
70+
71+
typed-func-refs-locals.wasm: file format wasm 0x1
72+
73+
Code Disassembly:
74+
75+
000026 func[0]:
76+
000027: 02 6b 00 | local[2..3] type=(ref 0)
77+
00002a: 02 6b 01 | local[4..5] type=(ref 1)
78+
00002d: 0b | end
79+
;;; STDOUT ;;)

test/roundtrip/typed-func-refs.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
;;; TOOL: run-roundtrip
2+
;;; ARGS: --stdout --enable-function-references --debug-names
3+
(module
4+
(type $t0 (func))
5+
6+
;; Self reference
7+
(type $t1 (func (param (ref $t0) (ref $t1) (ref 1))))
8+
9+
(func $f1 (param (ref $t0) (ref 0))
10+
(local (ref $t0) (ref 0)
11+
(ref $t1) (ref 1))
12+
)
13+
)
14+
(;; STDOUT ;;;
15+
(module
16+
(type $t0 (func))
17+
(type $t1 (func (param (ref 0) (ref 1) (ref 1))))
18+
(type (;2;) (func (param (ref 0) (ref 0))))
19+
(func $f1 (type 2) (param (ref 0) (ref 0))
20+
(local (ref 0) (ref 0) (ref 1) (ref 1))))
21+
;;; STDOUT ;;)

0 commit comments

Comments
 (0)