Backed out 2 changesets (bug 903746) for causing non-unified build bustages on nsIPri...
[gecko.git] / third_party / wasm2c / src / shared-validator.cc
blobec596cad9870f5e278e8c6a82c16b6e594c4efbe
1 /*
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"
19 #include <algorithm>
20 #include <cinttypes>
21 #include <limits>
23 namespace wabt {
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,
36 const char* format,
37 ...) {
38 WABT_SNPRINTF_ALLOCA(buffer, length, format);
39 errors_->emplace_back(ErrorLevel::Error, loc, buffer);
40 return Result::Error;
43 void SharedValidator::OnTypecheckerError(const char* msg) {
44 PrintError(expr_loc_, "%s", msg);
47 Result SharedValidator::OnFuncType(const Location& loc,
48 Index param_count,
49 const Type* param_types,
50 Index result_count,
51 const Type* result_types,
52 Index type_index) {
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.");
59 func_types_.emplace(
60 num_types_++,
61 FuncType{ToTypeVector(param_count, param_types),
62 ToTypeVector(result_count, result_types), type_index});
63 return result;
66 Result SharedValidator::OnStructType(const Location&,
67 Index field_count,
68 TypeMut* fields) {
69 struct_types_.emplace(num_types_++, StructType{TypeMutVector(
70 &fields[0], &fields[field_count])});
71 return Result::Ok;
74 Result SharedValidator::OnArrayType(const Location&, TypeMut field) {
75 array_types_.emplace(num_types_++, ArrayType{field});
76 return Result::Ok;
79 Result SharedValidator::OnFunction(const Location& loc, Var sig_var) {
80 Result result = Result::Ok;
81 FuncType type;
82 result |= CheckFuncTypeIndex(sig_var, &type);
83 funcs_.push_back(type);
84 return result;
87 Result SharedValidator::CheckLimits(const Location& loc,
88 const Limits& limits,
89 uint64_t absolute_max,
90 const char* desc) {
91 Result result = Result::Ok;
92 if (limits.initial > absolute_max) {
93 result |=
94 PrintError(loc, "initial %s (%" PRIu64 ") must be <= (%" PRIu64 ")",
95 desc, limits.initial, absolute_max);
98 if (limits.has_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);
110 return result;
113 Result SharedValidator::OnTable(const Location& loc,
114 Type elem_type,
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});
134 return result;
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});
154 return result;
157 Result SharedValidator::OnGlobalImport(const Location& loc,
158 Type type,
159 bool mutable_) {
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_;
166 return result;
169 Result SharedValidator::OnGlobal(const Location& loc,
170 Type type,
171 bool mutable_) {
172 globals_.push_back(GlobalType{type, mutable_});
173 return Result::Ok;
176 Result SharedValidator::CheckType(const Location& loc,
177 Type actual,
178 Type expected,
179 const char* desc) {
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;
185 return Result::Ok;
188 Result SharedValidator::OnTag(const Location& loc, Var sig_var) {
189 Result result = Result::Ok;
190 FuncType type;
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});
196 return result;
199 Result SharedValidator::OnExport(const Location& loc,
200 ExternalKind kind,
201 Var item_var,
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);
211 switch (kind) {
212 case ExternalKind::Func:
213 result |= CheckFuncIndex(item_var);
214 declared_funcs_.insert(item_var.index());
215 break;
217 case ExternalKind::Table:
218 result |= CheckTableIndex(item_var);
219 break;
221 case ExternalKind::Memory:
222 result |= CheckMemoryIndex(item_var);
223 break;
225 case ExternalKind::Global:
226 result |= CheckGlobalIndex(item_var);
227 break;
229 case ExternalKind::Tag:
230 result |= CheckTagIndex(item_var);
231 break;
233 return result;
236 Result SharedValidator::OnStart(const Location& loc, Var func_var) {
237 Result result = Result::Ok;
238 if (starts_++ > 0) {
239 result |= PrintError(loc, "only one start function allowed");
241 FuncType func_type;
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");
249 return result;
252 Result SharedValidator::OnElemSegment(const Location& loc,
253 Var table_var,
254 SegmentKind kind) {
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.
261 elems_.push_back(
262 ElemType{Type::Void, kind == SegmentKind::Active, table_type.element});
263 return result;
266 Result SharedValidator::OnElemSegmentElemType(const Location& loc,
267 Type elem_type) {
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
272 // it is active.
273 result |= CheckType(loc, elem.table_type, elem_type, "elem segment");
275 elem.element = elem_type;
276 return result;
279 Result SharedValidator::OnElemSegmentElemExpr_RefNull(const Location& loc,
280 Type type) {
281 return CheckType(loc, type, elems_.back().element, "elem expression");
284 Result SharedValidator::OnElemSegmentElemExpr_RefFunc(const Location& loc,
285 Var func_var) {
286 Result result = Result::Ok;
287 result |=
288 CheckType(loc, Type::FuncRef, elems_.back().element, "elem expression");
289 result |= CheckFuncIndex(func_var);
290 declared_funcs_.insert(func_var.index());
291 return result;
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,
305 Var memory_var,
306 SegmentKind kind) {
307 Result result = Result::Ok;
308 if (kind == SegmentKind::Active) {
309 result |= CheckMemoryIndex(memory_var);
311 return result;
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",
319 func_var.index());
321 return Result::Ok;
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);
332 return result;
335 Result SharedValidator::CheckIndex(Var var, Index max_index, const char* desc) {
336 if (var.index() >= max_index) {
337 return PrintError(
338 var.loc, "%s variable out of range: %" PRIindex " (max %" PRIindex ")",
339 desc, var.index(), max_index);
341 return Result::Ok;
344 template <typename T>
345 Result SharedValidator::CheckIndexWithValue(Var var,
346 const std::vector<T>& values,
347 T* out,
348 const char* desc) {
349 Result result = CheckIndex(var, values.size(), desc);
350 if (out) {
351 *out = Succeeded(result) ? values[var.index()] : T{};
353 return result;
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)",
363 GetLocalCount());
365 *out_type = iter->type;
366 return Result::Ok;
369 Result SharedValidator::CheckFuncTypeIndex(Var sig_var, FuncType* out) {
370 Result result = CheckIndex(sig_var, num_types_, "function type");
371 if (Failed(result)) {
372 *out = FuncType{};
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",
379 sig_var.index());
382 if (out) {
383 *out = iter->second;
385 return Result::Ok;
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,
409 ElemType* out) {
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,
418 Opcode opcode,
419 Type sig_type,
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();
426 FuncType func_type;
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.",
431 opcode.GetName());
433 // Multiple results without --enable-multi-value is checked above in
434 // OnType.
436 *out_param_types = func_type.params;
437 *out_result_types = func_type.results;
438 } else {
439 out_param_types->clear();
440 *out_result_types = sig_type.GetInlineVector();
443 return result;
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) {
452 expr_loc_ = loc;
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,
463 Index func_index) {
464 expr_loc_ = loc;
465 locals_.clear();
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);
472 } else {
473 // Signature isn't available, use empty.
474 return typechecker_.BeginFunction(TypeVector());
478 Result SharedValidator::EndFunctionBody(const Location& loc) {
479 expr_loc_ = loc;
480 return typechecker_.EndFunction();
483 Result SharedValidator::OnLocalDecl(const Location& loc,
484 Index count,
485 Type type) {
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});
492 return Result::Ok;
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,
504 Address alignment,
505 Address natural_alignment) {
506 if (!is_power_of_two(alignment)) {
507 PrintError(loc, "alignment (%" PRIaddress ") must be a power of 2",
508 alignment);
509 return Result::Error;
511 if (alignment > natural_alignment) {
512 PrintError(
513 loc,
514 "alignment must not be larger than natural alignment (%" PRIaddress ")",
515 natural_alignment);
516 return Result::Error;
518 return Result::Ok;
521 Result SharedValidator::CheckAtomicAlign(const Location& loc,
522 Address alignment,
523 Address natural_alignment) {
524 if (!is_power_of_two(alignment)) {
525 PrintError(loc, "alignment (%" PRIaddress ") must be a power of 2",
526 alignment);
527 return Result::Error;
529 if (alignment != natural_alignment) {
530 PrintError(loc,
531 "alignment must be equal to natural alignment (%" PRIaddress ")",
532 natural_alignment);
533 return Result::Error;
535 return Result::Ok;
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) {
543 return true;
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) {
549 return true;
552 return false;
555 Result SharedValidator::CheckInstr(Opcode opcode, const Location& loc) {
556 expr_loc_ = loc;
557 if (in_init_expr_ && !ValidInitOpcode(opcode)) {
558 PrintError(loc,
559 "invalid initializer: instruction not valid in initializer "
560 "expression: %s",
561 opcode.GetName());
562 return Result::Error;
564 return Result::Ok;
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",
573 consistency_model);
575 result |= typechecker_.OnAtomicFence(consistency_model);
576 return result;
579 Result SharedValidator::OnAtomicLoad(const Location& loc,
580 Opcode opcode,
581 Var memidx,
582 Address alignment) {
583 Result result = CheckInstr(opcode, loc);
584 MemoryType mt;
585 result |= CheckMemoryIndex(memidx, &mt);
586 result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
587 result |= typechecker_.OnAtomicLoad(opcode, mt.limits);
588 return result;
591 Result SharedValidator::OnAtomicNotify(const Location& loc,
592 Opcode opcode,
593 Var memidx,
594 Address alignment) {
595 Result result = CheckInstr(opcode, loc);
596 MemoryType mt;
597 result |= CheckMemoryIndex(memidx, &mt);
598 result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
599 result |= typechecker_.OnAtomicNotify(opcode, mt.limits);
600 return result;
603 Result SharedValidator::OnAtomicRmwCmpxchg(const Location& loc,
604 Opcode opcode,
605 Var memidx,
606 Address alignment) {
607 Result result = CheckInstr(opcode, loc);
608 MemoryType mt;
609 result |= CheckMemoryIndex(memidx, &mt);
610 result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
611 result |= typechecker_.OnAtomicRmwCmpxchg(opcode, mt.limits);
612 return result;
615 Result SharedValidator::OnAtomicRmw(const Location& loc,
616 Opcode opcode,
617 Var memidx,
618 Address alignment) {
619 Result result = CheckInstr(opcode, loc);
620 MemoryType mt;
621 result |= CheckMemoryIndex(memidx, &mt);
622 result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
623 result |= typechecker_.OnAtomicRmw(opcode, mt.limits);
624 return result;
627 Result SharedValidator::OnAtomicStore(const Location& loc,
628 Opcode opcode,
629 Var memidx,
630 Address alignment) {
631 Result result = CheckInstr(opcode, loc);
632 MemoryType mt;
633 result |= CheckMemoryIndex(memidx, &mt);
634 result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
635 result |= typechecker_.OnAtomicStore(opcode, mt.limits);
636 return result;
639 Result SharedValidator::OnAtomicWait(const Location& loc,
640 Opcode opcode,
641 Var memidx,
642 Address alignment) {
643 Result result = CheckInstr(opcode, loc);
644 MemoryType mt;
645 result |= CheckMemoryIndex(memidx, &mt);
646 result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
647 result |= typechecker_.OnAtomicWait(opcode, mt.limits);
648 return result;
651 Result SharedValidator::OnBinary(const Location& loc, Opcode opcode) {
652 Result result = CheckInstr(opcode, loc);
653 result |= typechecker_.OnBinary(opcode);
654 return result;
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, &param_types,
661 &result_types);
662 result |= typechecker_.OnBlock(param_types, result_types);
663 return result;
666 Result SharedValidator::OnBr(const Location& loc, Var depth) {
667 Result result = CheckInstr(Opcode::Br, loc);
668 result |= typechecker_.OnBr(depth.index());
669 return result;
672 Result SharedValidator::OnBrIf(const Location& loc, Var depth) {
673 Result result = CheckInstr(Opcode::BrIf, loc);
674 result |= typechecker_.OnBrIf(depth.index());
675 return result;
678 Result SharedValidator::BeginBrTable(const Location& loc) {
679 Result result = CheckInstr(Opcode::BrTable, loc);
680 result |= typechecker_.BeginBrTable();
681 return result;
684 Result SharedValidator::OnBrTableTarget(const Location& loc, Var depth) {
685 Result result = Result::Ok;
686 expr_loc_ = loc;
687 result |= typechecker_.OnBrTableTarget(depth.index());
688 return result;
691 Result SharedValidator::EndBrTable(const Location& loc) {
692 Result result = CheckInstr(Opcode::BrTable, loc);
693 result |= typechecker_.EndBrTable();
694 return result;
697 Result SharedValidator::OnCall(const Location& loc, Var func_var) {
698 Result result = CheckInstr(Opcode::Call, loc);
699 FuncType func_type;
700 result |= CheckFuncIndex(func_var, &func_type);
701 result |= typechecker_.OnCall(func_type.params, func_type.results);
702 return result;
705 Result SharedValidator::OnCallIndirect(const Location& loc,
706 Var sig_var,
707 Var table_var) {
708 Result result = CheckInstr(Opcode::CallIndirect, loc);
709 FuncType func_type;
710 result |= CheckFuncTypeIndex(sig_var, &func_type);
711 result |= CheckTableIndex(table_var);
712 result |= typechecker_.OnCallIndirect(func_type.params, func_type.results);
713 return result;
716 Result SharedValidator::OnCallRef(const Location& loc,
717 Index* function_type_index) {
718 Result result = CheckInstr(Opcode::CallRef, loc);
719 Index func_index;
720 result |= typechecker_.OnIndexedFuncRef(&func_index);
721 if (Failed(result)) {
722 return result;
724 FuncType func_type;
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;
730 return result;
733 Result SharedValidator::OnCatch(const Location& loc,
734 Var tag_var,
735 bool is_catch_all) {
736 Result result = CheckInstr(Opcode::Catch, loc);
737 if (is_catch_all) {
738 TypeVector empty;
739 result |= typechecker_.OnCatch(empty);
740 } else {
741 TagType tag_type;
742 result |= CheckTagIndex(tag_var, &tag_type);
743 result |= typechecker_.OnCatch(tag_type.params);
745 return result;
748 Result SharedValidator::OnCompare(const Location& loc, Opcode opcode) {
749 Result result = CheckInstr(opcode, loc);
750 result |= typechecker_.OnCompare(opcode);
751 return result;
754 Result SharedValidator::OnConst(const Location& loc, Type type) {
755 Result result = Result::Ok;
756 expr_loc_ = loc;
757 result |= typechecker_.OnConst(type);
758 return result;
761 Result SharedValidator::OnConvert(const Location& loc, Opcode opcode) {
762 Result result = CheckInstr(opcode, loc);
763 result |= typechecker_.OnConvert(opcode);
764 return result;
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());
771 return result;
774 Result SharedValidator::OnDelegate(const Location& loc, Var depth) {
775 Result result = CheckInstr(Opcode::Delegate, loc);
776 result |= typechecker_.OnDelegate(depth.index());
777 return result;
780 Result SharedValidator::OnDrop(const Location& loc) {
781 Result result = CheckInstr(Opcode::Drop, loc);
782 result |= typechecker_.OnDrop();
783 return result;
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());
790 return result;
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();
799 return result;
802 Result SharedValidator::OnEnd(const Location& loc) {
803 Result result = CheckInstr(Opcode::End, loc);
804 result |= typechecker_.OnEnd();
805 return result;
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(
816 global_var.loc,
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");
825 return result;
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 ".",
835 global_var.index());
837 result |= typechecker_.OnGlobalSet(global_type.type);
838 return result;
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, &param_types,
845 &result_types);
846 result |= typechecker_.OnIf(param_types, result_types);
847 return result;
850 Result SharedValidator::OnLoad(const Location& loc,
851 Opcode opcode,
852 Var memidx,
853 Address alignment) {
854 Result result = CheckInstr(opcode, loc);
855 MemoryType mt;
856 result |= CheckMemoryIndex(memidx, &mt);
857 result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
858 result |= typechecker_.OnLoad(opcode, mt.limits);
859 return result;
862 Result SharedValidator::OnLoadSplat(const Location& loc,
863 Opcode opcode,
864 Var memidx,
865 Address alignment) {
866 Result result = CheckInstr(opcode, loc);
867 MemoryType mt;
868 result |= CheckMemoryIndex(memidx, &mt);
869 result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
870 result |= typechecker_.OnLoad(opcode, mt.limits);
871 return result;
874 Result SharedValidator::OnLoadZero(const Location& loc,
875 Opcode opcode,
876 Var memidx,
877 Address alignment) {
878 Result result = CheckInstr(opcode, loc);
879 MemoryType mt;
880 result |= CheckMemoryIndex(memidx, &mt);
881 result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
882 result |= typechecker_.OnLoad(opcode, mt.limits);
883 return result;
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);
892 return result;
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);
901 return result;
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);
910 return result;
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, &param_types,
917 &result_types);
918 result |= typechecker_.OnLoop(param_types, result_types);
919 return result;
922 Result SharedValidator::OnMemoryCopy(const Location& loc,
923 Var srcmemidx,
924 Var destmemidx) {
925 Result result = CheckInstr(Opcode::MemoryCopy, loc);
926 MemoryType srcmt;
927 MemoryType dstmt;
928 result |= CheckMemoryIndex(srcmemidx, &srcmt);
929 result |= CheckMemoryIndex(destmemidx, &dstmt);
930 result |= typechecker_.OnMemoryCopy(srcmt.limits, dstmt.limits);
931 return result;
934 Result SharedValidator::OnMemoryFill(const Location& loc, Var memidx) {
935 Result result = CheckInstr(Opcode::MemoryFill, loc);
936 MemoryType mt;
937 result |= CheckMemoryIndex(memidx, &mt);
938 result |= typechecker_.OnMemoryFill(mt.limits);
939 return result;
942 Result SharedValidator::OnMemoryGrow(const Location& loc, Var memidx) {
943 Result result = CheckInstr(Opcode::MemoryGrow, loc);
944 MemoryType mt;
945 result |= CheckMemoryIndex(memidx, &mt);
946 result |= typechecker_.OnMemoryGrow(mt.limits);
947 return result;
950 Result SharedValidator::OnMemoryInit(const Location& loc,
951 Var segment_var,
952 Var memidx) {
953 Result result = CheckInstr(Opcode::MemoryInit, loc);
954 MemoryType mt;
955 result |= CheckMemoryIndex(memidx, &mt);
956 result |= CheckDataSegmentIndex(segment_var);
957 result |= typechecker_.OnMemoryInit(segment_var.index(), mt.limits);
958 return result;
961 Result SharedValidator::OnMemorySize(const Location& loc, Var memidx) {
962 Result result = CheckInstr(Opcode::MemorySize, loc);
963 MemoryType mt;
964 result |= CheckMemoryIndex(memidx, &mt);
965 result |= typechecker_.OnMemorySize(mt.limits);
966 return result;
969 Result SharedValidator::OnNop(const Location& loc) {
970 Result result = CheckInstr(Opcode::Nop, loc);
971 return result;
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.
980 if (in_init_expr_) {
981 declared_funcs_.insert(func_var.index());
982 } else {
983 check_declared_funcs_.push_back(func_var);
985 Index func_type = GetFunctionTypeIndex(func_var.index());
986 result |= typechecker_.OnRefFuncExpr(func_type);
988 return result;
991 Result SharedValidator::OnRefIsNull(const Location& loc) {
992 Result result = CheckInstr(Opcode::RefIsNull, loc);
993 result |= typechecker_.OnRefIsNullExpr();
994 return result;
997 Result SharedValidator::OnRefNull(const Location& loc, Type type) {
998 Result result = CheckInstr(Opcode::RefNull, loc);
999 result |= typechecker_.OnRefNullExpr(type);
1000 return result;
1003 Result SharedValidator::OnRethrow(const Location& loc, Var depth) {
1004 Result result = CheckInstr(Opcode::Rethrow, loc);
1005 result |= typechecker_.OnRethrow(depth.index());
1006 return result;
1009 Result SharedValidator::OnReturnCall(const Location& loc, Var func_var) {
1010 Result result = CheckInstr(Opcode::ReturnCall, loc);
1011 FuncType func_type;
1012 result |= CheckFuncIndex(func_var, &func_type);
1013 result |= typechecker_.OnReturnCall(func_type.params, func_type.results);
1014 return result;
1017 Result SharedValidator::OnReturnCallIndirect(const Location& loc,
1018 Var sig_var,
1019 Var table_var) {
1020 Result result = CheckInstr(Opcode::CallIndirect, loc);
1021 result |= CheckTableIndex(table_var);
1022 FuncType func_type;
1023 result |= CheckFuncTypeIndex(sig_var, &func_type);
1024 result |=
1025 typechecker_.OnReturnCallIndirect(func_type.params, func_type.results);
1026 return result;
1029 Result SharedValidator::OnReturn(const Location& loc) {
1030 Result result = CheckInstr(Opcode::Return, loc);
1031 result |= typechecker_.OnReturn();
1032 return result;
1035 Result SharedValidator::OnSelect(const Location& loc,
1036 Index result_count,
1037 Type* result_types) {
1038 Result result = CheckInstr(Opcode::Select, loc);
1039 if (result_count > 1) {
1040 result |=
1041 PrintError(loc, "invalid arity in select instruction: %" PRIindex ".",
1042 result_count);
1043 } else {
1044 result |= typechecker_.OnSelect(ToTypeVector(result_count, result_types));
1046 return result;
1049 Result SharedValidator::OnSimdLaneOp(const Location& loc,
1050 Opcode opcode,
1051 uint64_t value) {
1052 Result result = CheckInstr(opcode, loc);
1053 result |= typechecker_.OnSimdLaneOp(opcode, value);
1054 return result;
1057 Result SharedValidator::OnSimdLoadLane(const Location& loc,
1058 Opcode opcode,
1059 Var memidx,
1060 Address alignment,
1061 uint64_t value) {
1062 Result result = CheckInstr(opcode, loc);
1063 MemoryType mt;
1064 result |= CheckMemoryIndex(memidx, &mt);
1065 result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
1066 result |= typechecker_.OnSimdLoadLane(opcode, mt.limits, value);
1067 return result;
1070 Result SharedValidator::OnSimdStoreLane(const Location& loc,
1071 Opcode opcode,
1072 Var memidx,
1073 Address alignment,
1074 uint64_t value) {
1075 Result result = CheckInstr(opcode, loc);
1076 MemoryType mt;
1077 result |= CheckMemoryIndex(memidx, &mt);
1078 result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
1079 result |= typechecker_.OnSimdStoreLane(opcode, mt.limits, value);
1080 return result;
1083 Result SharedValidator::OnSimdShuffleOp(const Location& loc,
1084 Opcode opcode,
1085 v128 value) {
1086 Result result = CheckInstr(opcode, loc);
1087 result |= typechecker_.OnSimdShuffleOp(opcode, value);
1088 return result;
1091 Result SharedValidator::OnStore(const Location& loc,
1092 Opcode opcode,
1093 Var memidx,
1094 Address alignment) {
1095 Result result = CheckInstr(opcode, loc);
1096 MemoryType mt;
1097 result |= CheckMemoryIndex(memidx, &mt);
1098 result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
1099 result |= typechecker_.OnStore(opcode, mt.limits);
1100 return result;
1103 Result SharedValidator::OnTableCopy(const Location& loc,
1104 Var dst_var,
1105 Var src_var) {
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");
1113 return result;
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);
1121 return result;
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);
1129 return result;
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);
1137 return result;
1140 Result SharedValidator::OnTableInit(const Location& loc,
1141 Var segment_var,
1142 Var table_var) {
1143 Result result = CheckInstr(Opcode::TableInit, loc);
1144 TableType table_type;
1145 ElemType elem_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");
1150 return result;
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);
1158 return result;
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();
1165 return result;
1168 Result SharedValidator::OnTernary(const Location& loc, Opcode opcode) {
1169 Result result = CheckInstr(opcode, loc);
1170 result |= typechecker_.OnTernary(opcode);
1171 return result;
1174 Result SharedValidator::OnThrow(const Location& loc, Var tag_var) {
1175 Result result = CheckInstr(Opcode::Throw, loc);
1176 TagType tag_type;
1177 result |= CheckTagIndex(tag_var, &tag_type);
1178 result |= typechecker_.OnThrow(tag_type.params);
1179 return result;
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, &param_types,
1186 &result_types);
1187 result |= typechecker_.OnTry(param_types, result_types);
1188 return result;
1191 Result SharedValidator::OnUnary(const Location& loc, Opcode opcode) {
1192 Result result = CheckInstr(opcode, loc);
1193 result |= typechecker_.OnUnary(opcode);
1194 return result;
1197 Result SharedValidator::OnUnreachable(const Location& loc) {
1198 Result result = CheckInstr(Opcode::Unreachable, loc);
1199 result |= typechecker_.OnUnreachable();
1200 return result;
1203 } // namespace wabt