Skip to content

Commit 472da42

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 d30f043 commit 472da42

File tree

6 files changed

+256
-59
lines changed

6 files changed

+256
-59
lines changed

include/wabt/ir.h

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -255,12 +255,25 @@ struct FuncSignature {
255255
TypeVector param_types;
256256
TypeVector result_types;
257257

258-
// Some types can have names, for example (ref $foo) has type $foo.
259-
// So to use this type we need to translate its name into
260-
// a proper index from the module type section.
261-
// 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;
258+
// Reference types can have names, for example (ref $foo) represents
259+
// a type which name is $foo. These types are translated to their
260+
// corresponding index after the parsing is completed. The position
261+
// and names of these reference types are stored in a ReferenceVars
262+
// vector. The names are stored as variables, because the error
263+
// message construction requires a location when a name is not found.
264+
// TODO: move out this parser specific structure from IR.
265+
struct ReferenceVar {
266+
ReferenceVar(uint32_t index, Var var)
267+
: index(index), var(var) {}
268+
269+
uint32_t index;
270+
Var var;
271+
};
272+
273+
typedef std::vector<ReferenceVar> ReferenceVars;
274+
275+
ReferenceVars param_type_vars;
276+
ReferenceVars result_type_vars;
264277

265278
Index GetNumParams() const { return param_types.size(); }
266279
Index GetNumResults() const { return result_types.size(); }
@@ -925,6 +938,12 @@ struct Func {
925938
std::string name;
926939
FuncDeclaration decl;
927940
LocalTypes local_types;
941+
// When some locals are named references, the parser keeps the
942+
// non-compressed local vector until the module parsing is
943+
// completed. After the locals are resolved, local_types are
944+
// constructed from this vector, and then this vector is freed.
945+
// TODO: move out this parser specific structure from IR.
946+
TypeVector local_type_list;
928947
BindingHash bindings;
929948
ExprList exprs;
930949
Location loc;

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+
FuncSignature::ReferenceVars* type_vars,
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+
FuncSignature::ReferenceVars*,
180181
Index binding_index_offset = 0);
181182
Result ParseUnboundValueTypeList(TokenType,
182183
TypeVector*,
183-
std::unordered_map<uint32_t, std::string>*);
184+
FuncSignature::ReferenceVars*);
184185
Result ParseResultList(TypeVector*,
185-
std::unordered_map<uint32_t, std::string>*);
186+
FuncSignature::ReferenceVars*);
186187
Result ParseInstrList(ExprList*);
187188
Result ParseTerminatingInstrList(ExprList*);
188189
Result ParseInstr(ExprList*);

src/wast-parser.cc

Lines changed: 101 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -319,37 +319,59 @@ 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;
322+
Result ResolveRefTypes(const Module& module,
323+
TypeVector& types,
324+
uint32_t base_index,
325+
FuncSignature::ReferenceVars& ref_vars,
326+
Errors* errors) {
327+
Result result = Result::Ok;
328+
size_t types_size = types.size();
329+
330+
for (auto& ref_var : ref_vars) {
331+
uint32_t index = ref_var.index;
332+
333+
// The index of resolved variables is converted to kInvalidIndex.
334+
if (index == kInvalidIndex || index < base_index ||
335+
(index - base_index) >= types_size) {
336+
continue;
337+
}
338+
339+
Type type = types[index - base_index];
340+
ref_var.index = kInvalidIndex;
341+
342+
assert(type.IsReferenceWithIndex());
343+
344+
if (type.GetReferenceIndex() != kInvalidIndex) {
345+
continue;
346+
}
347+
348+
const auto type_index = module.type_bindings.FindIndex(ref_var.var.name());
349+
350+
if (type_index == kInvalidIndex) {
351+
errors->emplace_back(ErrorLevel::Error, ref_var.var.loc,
352+
StringPrintf("undefined reference type name %s",
353+
ref_var.var.name().c_str()));
354+
result = Result::Error;
355+
continue;
356+
}
357+
358+
types[index - base_index] = Type(static_cast<Type::Enum>(type), type_index);
329359
}
330360

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);
361+
return Result::Ok;
336362
}
337363

338-
void ResolveTypeNames(const Module& module, FuncDeclaration* decl) {
339-
assert(decl);
340-
auto& signature = decl->sig;
364+
Result ResolveTypeNames(const Module& module,
365+
FuncSignature& signature,
366+
Errors* errors) {
367+
Result result = Result::Ok;
341368

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-
}
369+
result |= ResolveRefTypes(module, signature.param_types, 0,
370+
signature.param_type_vars, errors);
347371

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-
}
372+
result |= ResolveRefTypes(module, signature.result_types, 0,
373+
signature.result_type_vars, errors);
374+
return result;
353375
}
354376

355377
void ResolveImplicitlyDefinedFunctionType(const Location& loc,
@@ -457,7 +479,7 @@ class ResolveFuncTypesExprVisitorDelegate : public ExprVisitor::DelegateNop {
457479
: module_(module), errors_(errors) {}
458480

459481
void ResolveBlockDeclaration(const Location& loc, BlockDeclaration* decl) {
460-
ResolveTypeNames(*module_, decl);
482+
ResolveTypeNames(*module_, decl->sig, errors_);
461483
ResolveFuncTypeWithEmptySignature(*module_, decl);
462484
if (!IsInlinableFuncSignature(decl->sig)) {
463485
ResolveImplicitlyDefinedFunctionType(loc, module_, *decl);
@@ -529,14 +551,22 @@ Result ResolveFuncTypes(Module* module, Errors* errors) {
529551
} else {
530552
continue;
531553
}
554+
} else if (auto* type_field = dyn_cast<TypeModuleField>(&field)) {
555+
TypeEntry* entry = type_field->type.get();
556+
557+
if (entry->kind() == TypeEntryKind::Func) {
558+
FuncType* func_type = cast<FuncType>(entry);
559+
result |= ResolveTypeNames(*module, func_type->sig, errors);
560+
}
561+
continue;
532562
} else {
533563
continue;
534564
}
535565

536566
bool has_func_type_and_empty_signature = false;
537567

538568
if (decl) {
539-
ResolveTypeNames(*module, decl);
569+
result |= ResolveTypeNames(*module, decl->sig, errors);
540570
has_func_type_and_empty_signature =
541571
ResolveFuncTypeWithEmptySignature(*module, decl);
542572
ResolveImplicitlyDefinedFunctionType(field.loc, module, *decl);
@@ -545,6 +575,15 @@ Result ResolveFuncTypes(Module* module, Errors* errors) {
545575
}
546576

547577
if (func) {
578+
if (!func->local_type_list.empty()) {
579+
result |= ResolveRefTypes(*module, func->local_type_list,
580+
func->GetNumParams(),
581+
decl->sig.param_type_vars, errors);
582+
583+
func->local_types.Set(func->local_type_list);
584+
func->local_type_list.clear();
585+
}
586+
548587
if (has_func_type_and_empty_signature) {
549588
// The call to ResolveFuncTypeWithEmptySignature may have updated the
550589
// function signature so there are parameters. Since parameters and
@@ -960,9 +999,9 @@ Result WastParser::ParseValueType(Var* out_type) {
960999
return Result::Ok;
9611000
}
9621001

963-
Result WastParser::ParseValueTypeList(
964-
TypeVector* out_type_list,
965-
std::unordered_map<uint32_t, std::string>* type_names) {
1002+
Result WastParser::ParseValueTypeList(TypeVector* out_type_list,
1003+
FuncSignature::ReferenceVars* type_vars,
1004+
Index binding_index_offset) {
9661005
WABT_TRACE(ParseValueTypeList);
9671006
while (true) {
9681007
if (!PeekMatchRefType() && !PeekMatch(TokenType::ValueType)) {
@@ -973,11 +1012,17 @@ Result WastParser::ParseValueTypeList(
9731012
CHECK_RESULT(ParseValueType(&type));
9741013

9751014
if (type.is_index()) {
976-
out_type_list->push_back(Type(type.index()));
1015+
// TODO: Incorrect values can be misinterpreted by the parser.
1016+
if (type.index() >= static_cast<Index>(Type::Void)) {
1017+
out_type_list->push_back(Type(type.index()));
1018+
} else {
1019+
out_type_list->push_back(Type(Type::Reference, type.index()));
1020+
}
9771021
} else {
9781022
assert(type.is_name());
9791023
assert(options_->features.function_references_enabled());
980-
type_names->emplace(out_type_list->size(), type.name());
1024+
uint32_t index = binding_index_offset + out_type_list->size();
1025+
type_vars->push_back(FuncSignature::ReferenceVar(index, type));
9811026
out_type_list->push_back(Type(Type::Reference, kInvalidIndex));
9821027
}
9831028
}
@@ -1539,11 +1584,18 @@ Result WastParser::ParseFuncModuleField(Module* module) {
15391584
func.loc = GetLocation();
15401585
CHECK_RESULT(ParseTypeUseOpt(&func.decl));
15411586
CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings));
1542-
TypeVector local_types;
1587+
1588+
size_t names_size = func.decl.sig.param_type_vars.size();
15431589
CHECK_RESULT(ParseBoundValueTypeList(
1544-
TokenType::Local, &local_types, &func.bindings,
1545-
&func.decl.sig.param_type_names, func.GetNumParams()));
1546-
func.local_types.Set(local_types);
1590+
TokenType::Local, &func.local_type_list, &func.bindings,
1591+
&func.decl.sig.param_type_vars, func.GetNumParams()));
1592+
1593+
if (names_size == func.decl.sig.param_type_vars.size()) {
1594+
// No named references in the list, local types can be processed now.
1595+
func.local_types.Set(func.local_type_list);
1596+
func.local_type_list.clear();
1597+
}
1598+
15471599
CHECK_RESULT(ParseTerminatingInstrList(&func.exprs));
15481600
module->AppendField(std::move(field));
15491601
}
@@ -1965,24 +2017,24 @@ Result WastParser::ParseFuncSignature(FuncSignature* sig,
19652017
BindingHash* param_bindings) {
19662018
WABT_TRACE(ParseFuncSignature);
19672019
CHECK_RESULT(ParseBoundValueTypeList(TokenType::Param, &sig->param_types,
1968-
param_bindings, &sig->param_type_names));
1969-
CHECK_RESULT(ParseResultList(&sig->result_types, &sig->result_type_names));
2020+
param_bindings, &sig->param_type_vars));
2021+
CHECK_RESULT(ParseResultList(&sig->result_types, &sig->result_type_vars));
19702022
return Result::Ok;
19712023
}
19722024

19732025
Result WastParser::ParseUnboundFuncSignature(FuncSignature* sig) {
19742026
WABT_TRACE(ParseUnboundFuncSignature);
19752027
CHECK_RESULT(ParseUnboundValueTypeList(TokenType::Param, &sig->param_types,
1976-
&sig->param_type_names));
1977-
CHECK_RESULT(ParseResultList(&sig->result_types, &sig->result_type_names));
2028+
&sig->param_type_vars));
2029+
CHECK_RESULT(ParseResultList(&sig->result_types, &sig->result_type_vars));
19782030
return Result::Ok;
19792031
}
19802032

19812033
Result WastParser::ParseBoundValueTypeList(
19822034
TokenType token,
19832035
TypeVector* types,
19842036
BindingHash* bindings,
1985-
std::unordered_map<uint32_t, std::string>* type_names,
2037+
FuncSignature::ReferenceVars* type_vars,
19862038
Index binding_index_offset) {
19872039
WABT_TRACE(ParseBoundValueTypeList);
19882040
while (MatchLpar(token)) {
@@ -1999,11 +2051,12 @@ Result WastParser::ParseBoundValueTypeList(
19992051
} else {
20002052
assert(type.is_name());
20012053
assert(options_->features.function_references_enabled());
2002-
type_names->emplace(binding_index_offset + types->size(), type.name());
2054+
uint32_t index = binding_index_offset + types->size();
2055+
type_vars->push_back(FuncSignature::ReferenceVar(index, type));
20032056
types->push_back(Type(Type::Reference, kInvalidIndex));
20042057
}
20052058
} else {
2006-
CHECK_RESULT(ParseValueTypeList(types, type_names));
2059+
CHECK_RESULT(ParseValueTypeList(types, type_vars, binding_index_offset));
20072060
}
20082061
EXPECT(Rpar);
20092062
}
@@ -2013,20 +2066,19 @@ Result WastParser::ParseBoundValueTypeList(
20132066
Result WastParser::ParseUnboundValueTypeList(
20142067
TokenType token,
20152068
TypeVector* types,
2016-
std::unordered_map<uint32_t, std::string>* type_names) {
2069+
FuncSignature::ReferenceVars* type_vars) {
20172070
WABT_TRACE(ParseUnboundValueTypeList);
20182071
while (MatchLpar(token)) {
2019-
CHECK_RESULT(ParseValueTypeList(types, type_names));
2072+
CHECK_RESULT(ParseValueTypeList(types, type_vars, 0));
20202073
EXPECT(Rpar);
20212074
}
20222075
return Result::Ok;
20232076
}
20242077

2025-
Result WastParser::ParseResultList(
2026-
TypeVector* result_types,
2027-
std::unordered_map<uint32_t, std::string>* type_names) {
2078+
Result WastParser::ParseResultList(TypeVector* result_types,
2079+
FuncSignature::ReferenceVars* type_vars) {
20282080
WABT_TRACE(ParseResultList);
2029-
return ParseUnboundValueTypeList(TokenType::Result, result_types, type_names);
2081+
return ParseUnboundValueTypeList(TokenType::Result, result_types, type_vars);
20302082
}
20312083

20322084
Result WastParser::ParseInstrList(ExprList* exprs) {

0 commit comments

Comments
 (0)