2 * Copyright 2020 WebAssembly Community Group participants
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "wabt/shared-validator.h"
25 TypeVector
SharedValidator::ToTypeVector(Index count
, const Type
* types
) {
26 return TypeVector(&types
[0], &types
[count
]);
29 SharedValidator::SharedValidator(Errors
* errors
, const ValidateOptions
& options
)
30 : options_(options
), errors_(errors
), typechecker_(options
.features
) {
31 typechecker_
.set_error_callback(
32 [this](const char* msg
) { OnTypecheckerError(msg
); });
35 Result
WABT_PRINTF_FORMAT(3, 4) SharedValidator::PrintError(const Location
& loc
,
38 WABT_SNPRINTF_ALLOCA(buffer
, length
, format
);
39 errors_
->emplace_back(ErrorLevel::Error
, loc
, buffer
);
43 void SharedValidator::OnTypecheckerError(const char* msg
) {
44 PrintError(expr_loc_
, "%s", msg
);
47 Result
SharedValidator::OnFuncType(const Location
& loc
,
49 const Type
* param_types
,
51 const Type
* result_types
,
53 Result result
= Result::Ok
;
54 if (!options_
.features
.multi_value_enabled() && result_count
> 1) {
55 result
|= PrintError(loc
,
56 "multiple result values are not supported without "
57 "multi-value enabled.");
61 FuncType
{ToTypeVector(param_count
, param_types
),
62 ToTypeVector(result_count
, result_types
), type_index
});
66 Result
SharedValidator::OnStructType(const Location
&,
69 struct_types_
.emplace(num_types_
++, StructType
{TypeMutVector(
70 &fields
[0], &fields
[field_count
])});
74 Result
SharedValidator::OnArrayType(const Location
&, TypeMut field
) {
75 array_types_
.emplace(num_types_
++, ArrayType
{field
});
79 Result
SharedValidator::OnFunction(const Location
& loc
, Var sig_var
) {
80 Result result
= Result::Ok
;
82 result
|= CheckFuncTypeIndex(sig_var
, &type
);
83 funcs_
.push_back(type
);
87 Result
SharedValidator::CheckLimits(const Location
& loc
,
89 uint64_t absolute_max
,
91 Result result
= Result::Ok
;
92 if (limits
.initial
> absolute_max
) {
94 PrintError(loc
, "initial %s (%" PRIu64
") must be <= (%" PRIu64
")",
95 desc
, limits
.initial
, absolute_max
);
99 if (limits
.max
> absolute_max
) {
100 result
|= PrintError(loc
, "max %s (%" PRIu64
") must be <= (%" PRIu64
")",
101 desc
, limits
.max
, absolute_max
);
104 if (limits
.max
< limits
.initial
) {
105 result
|= PrintError(
106 loc
, "max %s (%" PRIu64
") must be >= initial %s (%" PRIu64
")", desc
,
107 limits
.max
, desc
, limits
.initial
);
113 Result
SharedValidator::OnTable(const Location
& loc
,
115 const Limits
& limits
) {
116 Result result
= Result::Ok
;
117 if (tables_
.size() > 0 && !options_
.features
.reference_types_enabled()) {
118 result
|= PrintError(loc
, "only one table allowed");
120 result
|= CheckLimits(loc
, limits
, UINT32_MAX
, "elems");
122 if (limits
.is_shared
) {
123 result
|= PrintError(loc
, "tables may not be shared");
125 if (elem_type
!= Type::FuncRef
&&
126 !options_
.features
.reference_types_enabled()) {
127 result
|= PrintError(loc
, "tables must have funcref type");
129 if (!elem_type
.IsRef()) {
130 result
|= PrintError(loc
, "tables must have reference types");
133 tables_
.push_back(TableType
{elem_type
, limits
});
137 Result
SharedValidator::OnMemory(const Location
& loc
, const Limits
& limits
) {
138 Result result
= Result::Ok
;
139 if (memories_
.size() > 0 && !options_
.features
.multi_memory_enabled()) {
140 result
|= PrintError(loc
, "only one memory block allowed");
142 result
|= CheckLimits(
143 loc
, limits
, limits
.is_64
? WABT_MAX_PAGES64
: WABT_MAX_PAGES32
, "pages");
145 if (limits
.is_shared
) {
146 if (!options_
.features
.threads_enabled()) {
147 result
|= PrintError(loc
, "memories may not be shared");
148 } else if (!limits
.has_max
) {
149 result
|= PrintError(loc
, "shared memories must have max sizes");
153 memories_
.push_back(MemoryType
{limits
});
157 Result
SharedValidator::OnGlobalImport(const Location
& loc
,
160 Result result
= Result::Ok
;
161 if (mutable_
&& !options_
.features
.mutable_globals_enabled()) {
162 result
|= PrintError(loc
, "mutable globals cannot be imported");
164 globals_
.push_back(GlobalType
{type
, mutable_
});
165 ++num_imported_globals_
;
169 Result
SharedValidator::OnGlobal(const Location
& loc
,
172 globals_
.push_back(GlobalType
{type
, mutable_
});
176 Result
SharedValidator::CheckType(const Location
& loc
,
180 if (Failed(TypeChecker::CheckType(actual
, expected
))) {
181 PrintError(loc
, "type mismatch at %s. got %s, expected %s", desc
,
182 actual
.GetName().c_str(), expected
.GetName().c_str());
183 return Result::Error
;
188 Result
SharedValidator::OnTag(const Location
& loc
, Var sig_var
) {
189 Result result
= Result::Ok
;
191 result
|= CheckFuncTypeIndex(sig_var
, &type
);
192 if (!type
.results
.empty()) {
193 result
|= PrintError(loc
, "Tag signature must have 0 results.");
195 tags_
.push_back(TagType
{type
.params
});
199 Result
SharedValidator::OnExport(const Location
& loc
,
202 std::string_view name
) {
203 Result result
= Result::Ok
;
204 auto name_str
= std::string(name
);
205 if (export_names_
.find(name_str
) != export_names_
.end()) {
206 result
|= PrintError(loc
, "duplicate export \"" PRIstringview
"\"",
207 WABT_PRINTF_STRING_VIEW_ARG(name
));
209 export_names_
.insert(name_str
);
212 case ExternalKind::Func
:
213 result
|= CheckFuncIndex(item_var
);
214 declared_funcs_
.insert(item_var
.index());
217 case ExternalKind::Table
:
218 result
|= CheckTableIndex(item_var
);
221 case ExternalKind::Memory
:
222 result
|= CheckMemoryIndex(item_var
);
225 case ExternalKind::Global
:
226 result
|= CheckGlobalIndex(item_var
);
229 case ExternalKind::Tag
:
230 result
|= CheckTagIndex(item_var
);
236 Result
SharedValidator::OnStart(const Location
& loc
, Var func_var
) {
237 Result result
= Result::Ok
;
239 result
|= PrintError(loc
, "only one start function allowed");
242 result
|= CheckFuncIndex(func_var
, &func_type
);
243 if (func_type
.params
.size() != 0) {
244 result
|= PrintError(loc
, "start function must be nullary");
246 if (func_type
.results
.size() != 0) {
247 result
|= PrintError(loc
, "start function must not return anything");
252 Result
SharedValidator::OnElemSegment(const Location
& loc
,
255 Result result
= Result::Ok
;
256 TableType table_type
;
257 if (kind
== SegmentKind::Active
) {
258 result
|= CheckTableIndex(table_var
, &table_type
);
260 // Type gets set later in OnElemSegmentElemType.
262 ElemType
{Type::Void
, kind
== SegmentKind::Active
, table_type
.element
});
266 Result
SharedValidator::OnElemSegmentElemType(const Location
& loc
,
268 Result result
= Result::Ok
;
269 auto& elem
= elems_
.back();
270 if (elem
.is_active
) {
271 // Check that the type of the elem segment matches the table in which
273 result
|= CheckType(loc
, elem
.table_type
, elem_type
, "elem segment");
275 elem
.element
= elem_type
;
279 Result
SharedValidator::OnElemSegmentElemExpr_RefNull(const Location
& loc
,
281 return CheckType(loc
, type
, elems_
.back().element
, "elem expression");
284 Result
SharedValidator::OnElemSegmentElemExpr_RefFunc(const Location
& loc
,
286 Result result
= Result::Ok
;
288 CheckType(loc
, Type::FuncRef
, elems_
.back().element
, "elem expression");
289 result
|= CheckFuncIndex(func_var
);
290 declared_funcs_
.insert(func_var
.index());
294 Result
SharedValidator::OnElemSegmentElemExpr_Other(const Location
& loc
) {
295 return PrintError(loc
,
296 "invalid elem expression expression; must be either "
297 "ref.null or ref.func.");
300 void SharedValidator::OnDataCount(Index count
) {
301 data_segments_
= count
;
304 Result
SharedValidator::OnDataSegment(const Location
& loc
,
307 Result result
= Result::Ok
;
308 if (kind
== SegmentKind::Active
) {
309 result
|= CheckMemoryIndex(memory_var
);
314 Result
SharedValidator::CheckDeclaredFunc(Var func_var
) {
315 if (declared_funcs_
.count(func_var
.index()) == 0) {
316 return PrintError(func_var
.loc
,
317 "function %" PRIindex
318 " is not declared in any elem sections",
324 Result
SharedValidator::EndModule() {
325 // Verify that any ref.func used in init expressions for globals are
326 // mentioned in an elems section. This can't be done while process the
327 // globals because the global section comes before the elem section.
328 Result result
= Result::Ok
;
329 for (Var func_var
: check_declared_funcs_
) {
330 result
|= CheckDeclaredFunc(func_var
);
335 Result
SharedValidator::CheckIndex(Var var
, Index max_index
, const char* desc
) {
336 if (var
.index() >= max_index
) {
338 var
.loc
, "%s variable out of range: %" PRIindex
" (max %" PRIindex
")",
339 desc
, var
.index(), max_index
);
344 template <typename T
>
345 Result
SharedValidator::CheckIndexWithValue(Var var
,
346 const std::vector
<T
>& values
,
349 Result result
= CheckIndex(var
, values
.size(), desc
);
351 *out
= Succeeded(result
) ? values
[var
.index()] : T
{};
356 Result
SharedValidator::CheckLocalIndex(Var local_var
, Type
* out_type
) {
357 auto iter
= std::upper_bound(
358 locals_
.begin(), locals_
.end(), local_var
.index(),
359 [](Index index
, const LocalDecl
& decl
) { return index
< decl
.end
; });
360 if (iter
== locals_
.end()) {
361 // TODO: better error
362 return PrintError(local_var
.loc
, "local variable out of range (max %u)",
365 *out_type
= iter
->type
;
369 Result
SharedValidator::CheckFuncTypeIndex(Var sig_var
, FuncType
* out
) {
370 Result result
= CheckIndex(sig_var
, num_types_
, "function type");
371 if (Failed(result
)) {
373 return Result::Error
;
376 auto iter
= func_types_
.find(sig_var
.index());
377 if (iter
== func_types_
.end()) {
378 return PrintError(sig_var
.loc
, "type %d is not a function",
388 Result
SharedValidator::CheckFuncIndex(Var func_var
, FuncType
* out
) {
389 return CheckIndexWithValue(func_var
, funcs_
, out
, "function");
392 Result
SharedValidator::CheckMemoryIndex(Var memory_var
, MemoryType
* out
) {
393 return CheckIndexWithValue(memory_var
, memories_
, out
, "memory");
396 Result
SharedValidator::CheckTableIndex(Var table_var
, TableType
* out
) {
397 return CheckIndexWithValue(table_var
, tables_
, out
, "table");
400 Result
SharedValidator::CheckGlobalIndex(Var global_var
, GlobalType
* out
) {
401 return CheckIndexWithValue(global_var
, globals_
, out
, "global");
404 Result
SharedValidator::CheckTagIndex(Var tag_var
, TagType
* out
) {
405 return CheckIndexWithValue(tag_var
, tags_
, out
, "tag");
408 Result
SharedValidator::CheckElemSegmentIndex(Var elem_segment_var
,
410 return CheckIndexWithValue(elem_segment_var
, elems_
, out
, "elem_segment");
413 Result
SharedValidator::CheckDataSegmentIndex(Var data_segment_var
) {
414 return CheckIndex(data_segment_var
, data_segments_
, "data_segment");
417 Result
SharedValidator::CheckBlockSignature(const Location
& loc
,
420 TypeVector
* out_param_types
,
421 TypeVector
* out_result_types
) {
422 Result result
= Result::Ok
;
424 if (sig_type
.IsIndex()) {
425 Index sig_index
= sig_type
.GetIndex();
427 result
|= CheckFuncTypeIndex(Var(sig_index
, loc
), &func_type
);
429 if (!func_type
.params
.empty() && !options_
.features
.multi_value_enabled()) {
430 result
|= PrintError(loc
, "%s params not currently supported.",
433 // Multiple results without --enable-multi-value is checked above in
436 *out_param_types
= func_type
.params
;
437 *out_result_types
= func_type
.results
;
439 out_param_types
->clear();
440 *out_result_types
= sig_type
.GetInlineVector();
446 Index
SharedValidator::GetFunctionTypeIndex(Index func_index
) const {
447 assert(func_index
< funcs_
.size());
448 return funcs_
[func_index
].type_index
;
451 Result
SharedValidator::BeginInitExpr(const Location
& loc
, Type type
) {
453 in_init_expr_
= true;
454 return typechecker_
.BeginInitExpr(type
);
457 Result
SharedValidator::EndInitExpr() {
458 in_init_expr_
= false;
459 return typechecker_
.EndInitExpr();
462 Result
SharedValidator::BeginFunctionBody(const Location
& loc
,
466 if (func_index
< funcs_
.size()) {
467 for (Type type
: funcs_
[func_index
].params
) {
468 // TODO: Coalesce parameters of the same type?
469 locals_
.push_back(LocalDecl
{type
, GetLocalCount() + 1});
471 return typechecker_
.BeginFunction(funcs_
[func_index
].results
);
473 // Signature isn't available, use empty.
474 return typechecker_
.BeginFunction(TypeVector());
478 Result
SharedValidator::EndFunctionBody(const Location
& loc
) {
480 return typechecker_
.EndFunction();
483 Result
SharedValidator::OnLocalDecl(const Location
& loc
,
486 const auto max_locals
= std::numeric_limits
<Index
>::max();
487 if (count
> max_locals
- GetLocalCount()) {
488 PrintError(loc
, "local count must be < 0x10000000");
489 return Result::Error
;
491 locals_
.push_back(LocalDecl
{type
, GetLocalCount() + count
});
495 Index
SharedValidator::GetLocalCount() const {
496 return locals_
.empty() ? 0 : locals_
.back().end
;
499 static bool is_power_of_two(uint32_t x
) {
500 return x
&& ((x
& (x
- 1)) == 0);
503 Result
SharedValidator::CheckAlign(const Location
& loc
,
505 Address natural_alignment
) {
506 if (!is_power_of_two(alignment
)) {
507 PrintError(loc
, "alignment (%" PRIaddress
") must be a power of 2",
509 return Result::Error
;
511 if (alignment
> natural_alignment
) {
514 "alignment must not be larger than natural alignment (%" PRIaddress
")",
516 return Result::Error
;
521 Result
SharedValidator::CheckAtomicAlign(const Location
& loc
,
523 Address natural_alignment
) {
524 if (!is_power_of_two(alignment
)) {
525 PrintError(loc
, "alignment (%" PRIaddress
") must be a power of 2",
527 return Result::Error
;
529 if (alignment
!= natural_alignment
) {
531 "alignment must be equal to natural alignment (%" PRIaddress
")",
533 return Result::Error
;
538 bool SharedValidator::ValidInitOpcode(Opcode opcode
) const {
539 if (opcode
== Opcode::GlobalGet
|| opcode
== Opcode::I32Const
||
540 opcode
== Opcode::I64Const
|| opcode
== Opcode::F32Const
||
541 opcode
== Opcode::F64Const
|| opcode
== Opcode::RefFunc
||
542 opcode
== Opcode::RefNull
) {
545 if (options_
.features
.extended_const_enabled()) {
546 if (opcode
== Opcode::I32Mul
|| opcode
== Opcode::I64Mul
||
547 opcode
== Opcode::I32Sub
|| opcode
== Opcode::I64Sub
||
548 opcode
== Opcode::I32Add
|| opcode
== Opcode::I64Add
) {
555 Result
SharedValidator::CheckInstr(Opcode opcode
, const Location
& loc
) {
557 if (in_init_expr_
&& !ValidInitOpcode(opcode
)) {
559 "invalid initializer: instruction not valid in initializer "
562 return Result::Error
;
567 Result
SharedValidator::OnAtomicFence(const Location
& loc
,
568 uint32_t consistency_model
) {
569 Result result
= CheckInstr(Opcode::AtomicFence
, loc
);
570 if (consistency_model
!= 0) {
571 result
|= PrintError(
572 loc
, "unexpected atomic.fence consistency model (expected 0): %u",
575 result
|= typechecker_
.OnAtomicFence(consistency_model
);
579 Result
SharedValidator::OnAtomicLoad(const Location
& loc
,
583 Result result
= CheckInstr(opcode
, loc
);
585 result
|= CheckMemoryIndex(memidx
, &mt
);
586 result
|= CheckAtomicAlign(loc
, alignment
, opcode
.GetMemorySize());
587 result
|= typechecker_
.OnAtomicLoad(opcode
, mt
.limits
);
591 Result
SharedValidator::OnAtomicNotify(const Location
& loc
,
595 Result result
= CheckInstr(opcode
, loc
);
597 result
|= CheckMemoryIndex(memidx
, &mt
);
598 result
|= CheckAtomicAlign(loc
, alignment
, opcode
.GetMemorySize());
599 result
|= typechecker_
.OnAtomicNotify(opcode
, mt
.limits
);
603 Result
SharedValidator::OnAtomicRmwCmpxchg(const Location
& loc
,
607 Result result
= CheckInstr(opcode
, loc
);
609 result
|= CheckMemoryIndex(memidx
, &mt
);
610 result
|= CheckAtomicAlign(loc
, alignment
, opcode
.GetMemorySize());
611 result
|= typechecker_
.OnAtomicRmwCmpxchg(opcode
, mt
.limits
);
615 Result
SharedValidator::OnAtomicRmw(const Location
& loc
,
619 Result result
= CheckInstr(opcode
, loc
);
621 result
|= CheckMemoryIndex(memidx
, &mt
);
622 result
|= CheckAtomicAlign(loc
, alignment
, opcode
.GetMemorySize());
623 result
|= typechecker_
.OnAtomicRmw(opcode
, mt
.limits
);
627 Result
SharedValidator::OnAtomicStore(const Location
& loc
,
631 Result result
= CheckInstr(opcode
, loc
);
633 result
|= CheckMemoryIndex(memidx
, &mt
);
634 result
|= CheckAtomicAlign(loc
, alignment
, opcode
.GetMemorySize());
635 result
|= typechecker_
.OnAtomicStore(opcode
, mt
.limits
);
639 Result
SharedValidator::OnAtomicWait(const Location
& loc
,
643 Result result
= CheckInstr(opcode
, loc
);
645 result
|= CheckMemoryIndex(memidx
, &mt
);
646 result
|= CheckAtomicAlign(loc
, alignment
, opcode
.GetMemorySize());
647 result
|= typechecker_
.OnAtomicWait(opcode
, mt
.limits
);
651 Result
SharedValidator::OnBinary(const Location
& loc
, Opcode opcode
) {
652 Result result
= CheckInstr(opcode
, loc
);
653 result
|= typechecker_
.OnBinary(opcode
);
657 Result
SharedValidator::OnBlock(const Location
& loc
, Type sig_type
) {
658 Result result
= CheckInstr(Opcode::Block
, loc
);
659 TypeVector param_types
, result_types
;
660 result
|= CheckBlockSignature(loc
, Opcode::Block
, sig_type
, ¶m_types
,
662 result
|= typechecker_
.OnBlock(param_types
, result_types
);
666 Result
SharedValidator::OnBr(const Location
& loc
, Var depth
) {
667 Result result
= CheckInstr(Opcode::Br
, loc
);
668 result
|= typechecker_
.OnBr(depth
.index());
672 Result
SharedValidator::OnBrIf(const Location
& loc
, Var depth
) {
673 Result result
= CheckInstr(Opcode::BrIf
, loc
);
674 result
|= typechecker_
.OnBrIf(depth
.index());
678 Result
SharedValidator::BeginBrTable(const Location
& loc
) {
679 Result result
= CheckInstr(Opcode::BrTable
, loc
);
680 result
|= typechecker_
.BeginBrTable();
684 Result
SharedValidator::OnBrTableTarget(const Location
& loc
, Var depth
) {
685 Result result
= Result::Ok
;
687 result
|= typechecker_
.OnBrTableTarget(depth
.index());
691 Result
SharedValidator::EndBrTable(const Location
& loc
) {
692 Result result
= CheckInstr(Opcode::BrTable
, loc
);
693 result
|= typechecker_
.EndBrTable();
697 Result
SharedValidator::OnCall(const Location
& loc
, Var func_var
) {
698 Result result
= CheckInstr(Opcode::Call
, loc
);
700 result
|= CheckFuncIndex(func_var
, &func_type
);
701 result
|= typechecker_
.OnCall(func_type
.params
, func_type
.results
);
705 Result
SharedValidator::OnCallIndirect(const Location
& loc
,
708 Result result
= CheckInstr(Opcode::CallIndirect
, loc
);
710 result
|= CheckFuncTypeIndex(sig_var
, &func_type
);
711 result
|= CheckTableIndex(table_var
);
712 result
|= typechecker_
.OnCallIndirect(func_type
.params
, func_type
.results
);
716 Result
SharedValidator::OnCallRef(const Location
& loc
,
717 Index
* function_type_index
) {
718 Result result
= CheckInstr(Opcode::CallRef
, loc
);
720 result
|= typechecker_
.OnIndexedFuncRef(&func_index
);
721 if (Failed(result
)) {
725 result
|= CheckFuncTypeIndex(Var(func_index
, loc
), &func_type
);
726 result
|= typechecker_
.OnCall(func_type
.params
, func_type
.results
);
727 if (Succeeded(result
)) {
728 *function_type_index
= func_index
;
733 Result
SharedValidator::OnCatch(const Location
& loc
,
736 Result result
= CheckInstr(Opcode::Catch
, loc
);
739 result
|= typechecker_
.OnCatch(empty
);
742 result
|= CheckTagIndex(tag_var
, &tag_type
);
743 result
|= typechecker_
.OnCatch(tag_type
.params
);
748 Result
SharedValidator::OnCompare(const Location
& loc
, Opcode opcode
) {
749 Result result
= CheckInstr(opcode
, loc
);
750 result
|= typechecker_
.OnCompare(opcode
);
754 Result
SharedValidator::OnConst(const Location
& loc
, Type type
) {
755 Result result
= Result::Ok
;
757 result
|= typechecker_
.OnConst(type
);
761 Result
SharedValidator::OnConvert(const Location
& loc
, Opcode opcode
) {
762 Result result
= CheckInstr(opcode
, loc
);
763 result
|= typechecker_
.OnConvert(opcode
);
767 Result
SharedValidator::OnDataDrop(const Location
& loc
, Var segment_var
) {
768 Result result
= CheckInstr(Opcode::DataDrop
, loc
);
769 result
|= CheckDataSegmentIndex(segment_var
);
770 result
|= typechecker_
.OnDataDrop(segment_var
.index());
774 Result
SharedValidator::OnDelegate(const Location
& loc
, Var depth
) {
775 Result result
= CheckInstr(Opcode::Delegate
, loc
);
776 result
|= typechecker_
.OnDelegate(depth
.index());
780 Result
SharedValidator::OnDrop(const Location
& loc
) {
781 Result result
= CheckInstr(Opcode::Drop
, loc
);
782 result
|= typechecker_
.OnDrop();
786 Result
SharedValidator::OnElemDrop(const Location
& loc
, Var segment_var
) {
787 Result result
= CheckInstr(Opcode::ElemDrop
, loc
);
788 result
|= CheckElemSegmentIndex(segment_var
);
789 result
|= typechecker_
.OnElemDrop(segment_var
.index());
793 Result
SharedValidator::OnElse(const Location
& loc
) {
794 // Don't call CheckInstr or update expr_loc_ here because if we fail we want
795 // the last expression in the If block to be reported as the error location,
796 // not the else itself.
797 Result result
= Result::Ok
;
798 result
|= typechecker_
.OnElse();
802 Result
SharedValidator::OnEnd(const Location
& loc
) {
803 Result result
= CheckInstr(Opcode::End
, loc
);
804 result
|= typechecker_
.OnEnd();
808 Result
SharedValidator::OnGlobalGet(const Location
& loc
, Var global_var
) {
809 Result result
= CheckInstr(Opcode::GlobalGet
, loc
);
810 GlobalType global_type
;
811 result
|= CheckGlobalIndex(global_var
, &global_type
);
812 result
|= typechecker_
.OnGlobalGet(global_type
.type
);
813 if (Succeeded(result
) && in_init_expr_
) {
814 if (global_var
.index() >= num_imported_globals_
) {
815 result
|= PrintError(
817 "initializer expression can only reference an imported global");
819 if (global_type
.mutable_
) {
820 result
|= PrintError(
821 loc
, "initializer expression cannot reference a mutable global");
828 Result
SharedValidator::OnGlobalSet(const Location
& loc
, Var global_var
) {
829 Result result
= CheckInstr(Opcode::GlobalSet
, loc
);
830 GlobalType global_type
;
831 result
|= CheckGlobalIndex(global_var
, &global_type
);
832 if (!global_type
.mutable_
) {
833 result
|= PrintError(
834 loc
, "can't global.set on immutable global at index %" PRIindex
".",
837 result
|= typechecker_
.OnGlobalSet(global_type
.type
);
841 Result
SharedValidator::OnIf(const Location
& loc
, Type sig_type
) {
842 Result result
= CheckInstr(Opcode::If
, loc
);
843 TypeVector param_types
, result_types
;
844 result
|= CheckBlockSignature(loc
, Opcode::If
, sig_type
, ¶m_types
,
846 result
|= typechecker_
.OnIf(param_types
, result_types
);
850 Result
SharedValidator::OnLoad(const Location
& loc
,
854 Result result
= CheckInstr(opcode
, loc
);
856 result
|= CheckMemoryIndex(memidx
, &mt
);
857 result
|= CheckAlign(loc
, alignment
, opcode
.GetMemorySize());
858 result
|= typechecker_
.OnLoad(opcode
, mt
.limits
);
862 Result
SharedValidator::OnLoadSplat(const Location
& loc
,
866 Result result
= CheckInstr(opcode
, loc
);
868 result
|= CheckMemoryIndex(memidx
, &mt
);
869 result
|= CheckAlign(loc
, alignment
, opcode
.GetMemorySize());
870 result
|= typechecker_
.OnLoad(opcode
, mt
.limits
);
874 Result
SharedValidator::OnLoadZero(const Location
& loc
,
878 Result result
= CheckInstr(opcode
, loc
);
880 result
|= CheckMemoryIndex(memidx
, &mt
);
881 result
|= CheckAlign(loc
, alignment
, opcode
.GetMemorySize());
882 result
|= typechecker_
.OnLoad(opcode
, mt
.limits
);
886 Result
SharedValidator::OnLocalGet(const Location
& loc
, Var local_var
) {
887 CHECK_RESULT(CheckInstr(Opcode::LocalGet
, loc
));
888 Result result
= Result::Ok
;
889 Type type
= Type::Any
;
890 result
|= CheckLocalIndex(local_var
, &type
);
891 result
|= typechecker_
.OnLocalGet(type
);
895 Result
SharedValidator::OnLocalSet(const Location
& loc
, Var local_var
) {
896 CHECK_RESULT(CheckInstr(Opcode::LocalSet
, loc
));
897 Result result
= Result::Ok
;
898 Type type
= Type::Any
;
899 result
|= CheckLocalIndex(local_var
, &type
);
900 result
|= typechecker_
.OnLocalSet(type
);
904 Result
SharedValidator::OnLocalTee(const Location
& loc
, Var local_var
) {
905 CHECK_RESULT(CheckInstr(Opcode::LocalTee
, loc
));
906 Result result
= Result::Ok
;
907 Type type
= Type::Any
;
908 result
|= CheckLocalIndex(local_var
, &type
);
909 result
|= typechecker_
.OnLocalTee(type
);
913 Result
SharedValidator::OnLoop(const Location
& loc
, Type sig_type
) {
914 Result result
= CheckInstr(Opcode::Loop
, loc
);
915 TypeVector param_types
, result_types
;
916 result
|= CheckBlockSignature(loc
, Opcode::Loop
, sig_type
, ¶m_types
,
918 result
|= typechecker_
.OnLoop(param_types
, result_types
);
922 Result
SharedValidator::OnMemoryCopy(const Location
& loc
,
925 Result result
= CheckInstr(Opcode::MemoryCopy
, loc
);
928 result
|= CheckMemoryIndex(srcmemidx
, &srcmt
);
929 result
|= CheckMemoryIndex(destmemidx
, &dstmt
);
930 result
|= typechecker_
.OnMemoryCopy(srcmt
.limits
, dstmt
.limits
);
934 Result
SharedValidator::OnMemoryFill(const Location
& loc
, Var memidx
) {
935 Result result
= CheckInstr(Opcode::MemoryFill
, loc
);
937 result
|= CheckMemoryIndex(memidx
, &mt
);
938 result
|= typechecker_
.OnMemoryFill(mt
.limits
);
942 Result
SharedValidator::OnMemoryGrow(const Location
& loc
, Var memidx
) {
943 Result result
= CheckInstr(Opcode::MemoryGrow
, loc
);
945 result
|= CheckMemoryIndex(memidx
, &mt
);
946 result
|= typechecker_
.OnMemoryGrow(mt
.limits
);
950 Result
SharedValidator::OnMemoryInit(const Location
& loc
,
953 Result result
= CheckInstr(Opcode::MemoryInit
, loc
);
955 result
|= CheckMemoryIndex(memidx
, &mt
);
956 result
|= CheckDataSegmentIndex(segment_var
);
957 result
|= typechecker_
.OnMemoryInit(segment_var
.index(), mt
.limits
);
961 Result
SharedValidator::OnMemorySize(const Location
& loc
, Var memidx
) {
962 Result result
= CheckInstr(Opcode::MemorySize
, loc
);
964 result
|= CheckMemoryIndex(memidx
, &mt
);
965 result
|= typechecker_
.OnMemorySize(mt
.limits
);
969 Result
SharedValidator::OnNop(const Location
& loc
) {
970 Result result
= CheckInstr(Opcode::Nop
, loc
);
974 Result
SharedValidator::OnRefFunc(const Location
& loc
, Var func_var
) {
975 Result result
= CheckInstr(Opcode::RefFunc
, loc
);
976 result
|= CheckFuncIndex(func_var
);
977 if (Succeeded(result
)) {
978 // References in initializer expressions are considered declarations, as
979 // opposed to references in function bodies that are considered usages.
981 declared_funcs_
.insert(func_var
.index());
983 check_declared_funcs_
.push_back(func_var
);
985 Index func_type
= GetFunctionTypeIndex(func_var
.index());
986 result
|= typechecker_
.OnRefFuncExpr(func_type
);
991 Result
SharedValidator::OnRefIsNull(const Location
& loc
) {
992 Result result
= CheckInstr(Opcode::RefIsNull
, loc
);
993 result
|= typechecker_
.OnRefIsNullExpr();
997 Result
SharedValidator::OnRefNull(const Location
& loc
, Type type
) {
998 Result result
= CheckInstr(Opcode::RefNull
, loc
);
999 result
|= typechecker_
.OnRefNullExpr(type
);
1003 Result
SharedValidator::OnRethrow(const Location
& loc
, Var depth
) {
1004 Result result
= CheckInstr(Opcode::Rethrow
, loc
);
1005 result
|= typechecker_
.OnRethrow(depth
.index());
1009 Result
SharedValidator::OnReturnCall(const Location
& loc
, Var func_var
) {
1010 Result result
= CheckInstr(Opcode::ReturnCall
, loc
);
1012 result
|= CheckFuncIndex(func_var
, &func_type
);
1013 result
|= typechecker_
.OnReturnCall(func_type
.params
, func_type
.results
);
1017 Result
SharedValidator::OnReturnCallIndirect(const Location
& loc
,
1020 Result result
= CheckInstr(Opcode::CallIndirect
, loc
);
1021 result
|= CheckTableIndex(table_var
);
1023 result
|= CheckFuncTypeIndex(sig_var
, &func_type
);
1025 typechecker_
.OnReturnCallIndirect(func_type
.params
, func_type
.results
);
1029 Result
SharedValidator::OnReturn(const Location
& loc
) {
1030 Result result
= CheckInstr(Opcode::Return
, loc
);
1031 result
|= typechecker_
.OnReturn();
1035 Result
SharedValidator::OnSelect(const Location
& loc
,
1037 Type
* result_types
) {
1038 Result result
= CheckInstr(Opcode::Select
, loc
);
1039 if (result_count
> 1) {
1041 PrintError(loc
, "invalid arity in select instruction: %" PRIindex
".",
1044 result
|= typechecker_
.OnSelect(ToTypeVector(result_count
, result_types
));
1049 Result
SharedValidator::OnSimdLaneOp(const Location
& loc
,
1052 Result result
= CheckInstr(opcode
, loc
);
1053 result
|= typechecker_
.OnSimdLaneOp(opcode
, value
);
1057 Result
SharedValidator::OnSimdLoadLane(const Location
& loc
,
1062 Result result
= CheckInstr(opcode
, loc
);
1064 result
|= CheckMemoryIndex(memidx
, &mt
);
1065 result
|= CheckAlign(loc
, alignment
, opcode
.GetMemorySize());
1066 result
|= typechecker_
.OnSimdLoadLane(opcode
, mt
.limits
, value
);
1070 Result
SharedValidator::OnSimdStoreLane(const Location
& loc
,
1075 Result result
= CheckInstr(opcode
, loc
);
1077 result
|= CheckMemoryIndex(memidx
, &mt
);
1078 result
|= CheckAlign(loc
, alignment
, opcode
.GetMemorySize());
1079 result
|= typechecker_
.OnSimdStoreLane(opcode
, mt
.limits
, value
);
1083 Result
SharedValidator::OnSimdShuffleOp(const Location
& loc
,
1086 Result result
= CheckInstr(opcode
, loc
);
1087 result
|= typechecker_
.OnSimdShuffleOp(opcode
, value
);
1091 Result
SharedValidator::OnStore(const Location
& loc
,
1094 Address alignment
) {
1095 Result result
= CheckInstr(opcode
, loc
);
1097 result
|= CheckMemoryIndex(memidx
, &mt
);
1098 result
|= CheckAlign(loc
, alignment
, opcode
.GetMemorySize());
1099 result
|= typechecker_
.OnStore(opcode
, mt
.limits
);
1103 Result
SharedValidator::OnTableCopy(const Location
& loc
,
1106 Result result
= CheckInstr(Opcode::TableCopy
, loc
);
1107 TableType dst_table
;
1108 TableType src_table
;
1109 result
|= CheckTableIndex(dst_var
, &dst_table
);
1110 result
|= CheckTableIndex(src_var
, &src_table
);
1111 result
|= typechecker_
.OnTableCopy();
1112 result
|= CheckType(loc
, src_table
.element
, dst_table
.element
, "table.copy");
1116 Result
SharedValidator::OnTableFill(const Location
& loc
, Var table_var
) {
1117 Result result
= CheckInstr(Opcode::TableFill
, loc
);
1118 TableType table_type
;
1119 result
|= CheckTableIndex(table_var
, &table_type
);
1120 result
|= typechecker_
.OnTableFill(table_type
.element
);
1124 Result
SharedValidator::OnTableGet(const Location
& loc
, Var table_var
) {
1125 Result result
= CheckInstr(Opcode::TableGet
, loc
);
1126 TableType table_type
;
1127 result
|= CheckTableIndex(table_var
, &table_type
);
1128 result
|= typechecker_
.OnTableGet(table_type
.element
);
1132 Result
SharedValidator::OnTableGrow(const Location
& loc
, Var table_var
) {
1133 Result result
= CheckInstr(Opcode::TableGrow
, loc
);
1134 TableType table_type
;
1135 result
|= CheckTableIndex(table_var
, &table_type
);
1136 result
|= typechecker_
.OnTableGrow(table_type
.element
);
1140 Result
SharedValidator::OnTableInit(const Location
& loc
,
1143 Result result
= CheckInstr(Opcode::TableInit
, loc
);
1144 TableType table_type
;
1146 result
|= CheckTableIndex(table_var
, &table_type
);
1147 result
|= CheckElemSegmentIndex(segment_var
, &elem_type
);
1148 result
|= typechecker_
.OnTableInit(table_var
.index(), segment_var
.index());
1149 result
|= CheckType(loc
, elem_type
.element
, table_type
.element
, "table.init");
1153 Result
SharedValidator::OnTableSet(const Location
& loc
, Var table_var
) {
1154 Result result
= CheckInstr(Opcode::TableSet
, loc
);
1155 TableType table_type
;
1156 result
|= CheckTableIndex(table_var
, &table_type
);
1157 result
|= typechecker_
.OnTableSet(table_type
.element
);
1161 Result
SharedValidator::OnTableSize(const Location
& loc
, Var table_var
) {
1162 Result result
= CheckInstr(Opcode::TableSize
, loc
);
1163 result
|= CheckTableIndex(table_var
);
1164 result
|= typechecker_
.OnTableSize();
1168 Result
SharedValidator::OnTernary(const Location
& loc
, Opcode opcode
) {
1169 Result result
= CheckInstr(opcode
, loc
);
1170 result
|= typechecker_
.OnTernary(opcode
);
1174 Result
SharedValidator::OnThrow(const Location
& loc
, Var tag_var
) {
1175 Result result
= CheckInstr(Opcode::Throw
, loc
);
1177 result
|= CheckTagIndex(tag_var
, &tag_type
);
1178 result
|= typechecker_
.OnThrow(tag_type
.params
);
1182 Result
SharedValidator::OnTry(const Location
& loc
, Type sig_type
) {
1183 Result result
= CheckInstr(Opcode::Try
, loc
);
1184 TypeVector param_types
, result_types
;
1185 result
|= CheckBlockSignature(loc
, Opcode::Try
, sig_type
, ¶m_types
,
1187 result
|= typechecker_
.OnTry(param_types
, result_types
);
1191 Result
SharedValidator::OnUnary(const Location
& loc
, Opcode opcode
) {
1192 Result result
= CheckInstr(opcode
, loc
);
1193 result
|= typechecker_
.OnUnary(opcode
);
1197 Result
SharedValidator::OnUnreachable(const Location
& loc
) {
1198 Result result
= CheckInstr(Opcode::Unreachable
, loc
);
1199 result
|= typechecker_
.OnUnreachable();