diff options
Diffstat (limited to 'src/validator.cc')
-rw-r--r-- | src/validator.cc | 512 |
1 files changed, 310 insertions, 202 deletions
diff --git a/src/validator.cc b/src/validator.cc index 96aa2532..b42813c3 100644 --- a/src/validator.cc +++ b/src/validator.cc @@ -35,7 +35,7 @@ namespace wabt { namespace { -class Validator { +class Validator : public ExprVisitor::Delegate { public: WABT_DISALLOW_COPY_AND_ASSIGN(Validator); Validator(ErrorHandler*, @@ -47,6 +47,51 @@ class Validator { Result CheckScript(const Script* script); Result CheckAllFuncSignatures(const Module* module); + // Implements ExprVisitor::Delegate. + Result OnBinaryExpr(BinaryExpr*) override; + Result BeginBlockExpr(BlockExpr*) override; + Result EndBlockExpr(BlockExpr*) override; + Result OnBrExpr(BrExpr*) override; + Result OnBrIfExpr(BrIfExpr*) override; + Result OnBrTableExpr(BrTableExpr*) override; + Result OnCallExpr(CallExpr*) override; + Result OnCallIndirectExpr(CallIndirectExpr*) override; + Result OnCompareExpr(CompareExpr*) override; + Result OnConstExpr(ConstExpr*) override; + Result OnConvertExpr(ConvertExpr*) override; + Result OnCurrentMemoryExpr(CurrentMemoryExpr*) override; + Result OnDropExpr(DropExpr*) override; + Result OnGetGlobalExpr(GetGlobalExpr*) override; + Result OnGetLocalExpr(GetLocalExpr*) override; + Result OnGrowMemoryExpr(GrowMemoryExpr*) override; + Result BeginIfExpr(IfExpr*) override; + Result AfterIfTrueExpr(IfExpr*) override; + Result EndIfExpr(IfExpr*) override; + Result OnLoadExpr(LoadExpr*) override; + Result BeginLoopExpr(LoopExpr*) override; + Result EndLoopExpr(LoopExpr*) override; + Result OnNopExpr(NopExpr*) override; + Result OnReturnExpr(ReturnExpr*) override; + Result OnSelectExpr(SelectExpr*) override; + Result OnSetGlobalExpr(SetGlobalExpr*) override; + Result OnSetLocalExpr(SetLocalExpr*) override; + Result OnStoreExpr(StoreExpr*) override; + Result OnTeeLocalExpr(TeeLocalExpr*) override; + Result OnUnaryExpr(UnaryExpr*) override; + Result OnUnreachableExpr(UnreachableExpr*) override; + Result BeginTryExpr(TryExpr*) override; + Result EndTryExpr(TryExpr*) override; + Result OnCatchExpr(TryExpr*, Catch*) override; + Result OnThrowExpr(ThrowExpr*) override; + Result OnRethrowExpr(RethrowExpr*) override; + Result OnAtomicWaitExpr(AtomicWaitExpr*) override; + Result OnAtomicWakeExpr(AtomicWakeExpr*) override; + Result OnAtomicLoadExpr(AtomicLoadExpr*) override; + Result OnAtomicStoreExpr(AtomicStoreExpr*) override; + Result OnAtomicRmwExpr(AtomicRmwExpr*) override; + Result OnAtomicRmwCmpxchgExpr(AtomicRmwCmpxchgExpr*) override; + Result OnTernaryExpr(TernaryExpr*) override; + private: struct ActionResult { enum class Kind { @@ -118,7 +163,6 @@ class Validator { const BlockSignature* sig); template <typename T> void CheckAtomicExpr(const T* expr, Result (TypeChecker::*func)(Opcode)); - void CheckExpr(const Expr* expr); void CheckFuncSignature(const Location* loc, const FuncDeclaration& decl); class CheckFuncSignatureExprVisitorDelegate; @@ -414,8 +458,9 @@ void Validator::CheckAssertReturnNanType(const Location* loc, } void Validator::CheckExprList(const Location* loc, const ExprList& exprs) { - for (const Expr& expr : exprs) - CheckExpr(&expr); + ExprVisitor visitor(this); + // TODO(binji): Add const-visitors. + visitor.VisitExprList(const_cast<ExprList&>(exprs)); } bool Validator::CheckHasMemory(const Location* loc, Opcode opcode) { @@ -456,245 +501,308 @@ void Validator::CheckAtomicExpr(const T* expr, (typechecker_.*func)(expr->opcode); } -void Validator::CheckExpr(const Expr* expr) { +Result Validator::OnBinaryExpr(BinaryExpr* expr) { expr_loc_ = &expr->loc; + typechecker_.OnBinary(expr->opcode); + return Result::Ok; +} - switch (expr->type()) { - case ExprType::AtomicLoad: - CheckAtomicExpr(cast<AtomicLoadExpr>(expr), &TypeChecker::OnAtomicLoad); - break; +Result Validator::BeginBlockExpr(BlockExpr* expr) { + expr_loc_ = &expr->loc; + CheckBlockSig(&expr->loc, Opcode::Block, &expr->block.sig); + typechecker_.OnBlock(&expr->block.sig); + return Result::Ok; +} - case ExprType::AtomicRmw: - CheckAtomicExpr(cast<AtomicRmwExpr>(expr), &TypeChecker::OnAtomicRmw); - break; +Result Validator::EndBlockExpr(BlockExpr* expr) { + typechecker_.OnEnd(); + return Result::Ok; +} - case ExprType::AtomicRmwCmpxchg: - CheckAtomicExpr(cast<AtomicRmwCmpxchgExpr>(expr), - &TypeChecker::OnAtomicRmwCmpxchg); - break; +Result Validator::OnBrExpr(BrExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnBr(expr->var.index()); + return Result::Ok; +} - case ExprType::AtomicStore: - CheckAtomicExpr(cast<AtomicStoreExpr>(expr), &TypeChecker::OnAtomicStore); - break; +Result Validator::OnBrIfExpr(BrIfExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnBrIf(expr->var.index()); + return Result::Ok; +} - case ExprType::AtomicWait: - CheckAtomicExpr(cast<AtomicWaitExpr>(expr), &TypeChecker::OnAtomicWait); - break; +Result Validator::OnBrTableExpr(BrTableExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.BeginBrTable(); + for (const Var& var : expr->targets) { + typechecker_.OnBrTableTarget(var.index()); + } + typechecker_.OnBrTableTarget(expr->default_target.index()); + typechecker_.EndBrTable(); + return Result::Ok; +} - case ExprType::AtomicWake: - CheckAtomicExpr(cast<AtomicWakeExpr>(expr), &TypeChecker::OnAtomicWake); - break; +Result Validator::OnCallExpr(CallExpr* expr) { + expr_loc_ = &expr->loc; + const Func* callee; + if (Succeeded(CheckFuncVar(&expr->var, &callee))) { + typechecker_.OnCall(&callee->decl.sig.param_types, + &callee->decl.sig.result_types); + } + return Result::Ok; +} - case ExprType::Binary: - typechecker_.OnBinary(cast<BinaryExpr>(expr)->opcode); - break; +Result Validator::OnCallIndirectExpr(CallIndirectExpr* expr) { + expr_loc_ = &expr->loc; + if (current_module_->tables.size() == 0) { + PrintError(&expr->loc, "found call_indirect operator, but no table"); + } + if (expr->decl.has_func_type) { + const FuncType* func_type; + CheckFuncTypeVar(&expr->decl.type_var, &func_type); + } + typechecker_.OnCallIndirect(&expr->decl.sig.param_types, + &expr->decl.sig.result_types); + return Result::Ok; +} - case ExprType::Block: { - auto block_expr = cast<BlockExpr>(expr); - CheckBlockSig(&block_expr->loc, Opcode::Block, &block_expr->block.sig); - typechecker_.OnBlock(&block_expr->block.sig); - CheckExprList(&block_expr->loc, block_expr->block.exprs); - typechecker_.OnEnd(); - break; - } +Result Validator::OnCompareExpr(CompareExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnCompare(expr->opcode); + return Result::Ok; +} - case ExprType::Br: - typechecker_.OnBr(cast<BrExpr>(expr)->var.index()); - break; +Result Validator::OnConstExpr(ConstExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnConst(expr->const_.type); + return Result::Ok; +} - case ExprType::BrIf: - typechecker_.OnBrIf(cast<BrIfExpr>(expr)->var.index()); - break; +Result Validator::OnConvertExpr(ConvertExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnConvert(expr->opcode); + return Result::Ok; +} - case ExprType::BrTable: { - auto br_table_expr = cast<BrTableExpr>(expr); - typechecker_.BeginBrTable(); - for (const Var& var : br_table_expr->targets) { - typechecker_.OnBrTableTarget(var.index()); - } - typechecker_.OnBrTableTarget(br_table_expr->default_target.index()); - typechecker_.EndBrTable(); - break; - } +Result Validator::OnCurrentMemoryExpr(CurrentMemoryExpr* expr) { + expr_loc_ = &expr->loc; + CheckHasMemory(&expr->loc, Opcode::CurrentMemory); + typechecker_.OnCurrentMemory(); + return Result::Ok; +} - case ExprType::Call: { - const Func* callee; - if (Succeeded(CheckFuncVar(&cast<CallExpr>(expr)->var, &callee))) { - typechecker_.OnCall(&callee->decl.sig.param_types, - &callee->decl.sig.result_types); - } - break; - } +Result Validator::OnDropExpr(DropExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnDrop(); + return Result::Ok; +} - case ExprType::CallIndirect: { - if (current_module_->tables.size() == 0) { - PrintError(&expr->loc, "found call_indirect operator, but no table"); - } - auto ci_expr = cast<CallIndirectExpr>(expr); - if (ci_expr->decl.has_func_type) { - const FuncType* func_type; - CheckFuncTypeVar(&ci_expr->decl.type_var, &func_type); - } - typechecker_.OnCallIndirect(&ci_expr->decl.sig.param_types, - &ci_expr->decl.sig.result_types); - break; - } +Result Validator::OnGetGlobalExpr(GetGlobalExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnGetGlobal(GetGlobalVarTypeOrAny(&expr->var)); + return Result::Ok; +} - case ExprType::Compare: - typechecker_.OnCompare(cast<CompareExpr>(expr)->opcode); - break; +Result Validator::OnGetLocalExpr(GetLocalExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnGetLocal(GetLocalVarTypeOrAny(&expr->var)); + return Result::Ok; +} - case ExprType::Const: - typechecker_.OnConst(cast<ConstExpr>(expr)->const_.type); - break; +Result Validator::OnGrowMemoryExpr(GrowMemoryExpr* expr) { + expr_loc_ = &expr->loc; + CheckHasMemory(&expr->loc, Opcode::GrowMemory); + typechecker_.OnGrowMemory(); + return Result::Ok; +} - case ExprType::Convert: - typechecker_.OnConvert(cast<ConvertExpr>(expr)->opcode); - break; +Result Validator::BeginIfExpr(IfExpr* expr) { + expr_loc_ = &expr->loc; + CheckBlockSig(&expr->loc, Opcode::If, &expr->true_.sig); + typechecker_.OnIf(&expr->true_.sig); + return Result::Ok; +} - case ExprType::Drop: - typechecker_.OnDrop(); - break; +Result Validator::AfterIfTrueExpr(IfExpr* expr) { + if (!expr->false_.empty()) { + typechecker_.OnElse(); + } + return Result::Ok; +} - case ExprType::GetGlobal: - typechecker_.OnGetGlobal( - GetGlobalVarTypeOrAny(&cast<GetGlobalExpr>(expr)->var)); - break; +Result Validator::EndIfExpr(IfExpr* expr) { + typechecker_.OnEnd(); + return Result::Ok; +} - case ExprType::GetLocal: - typechecker_.OnGetLocal( - GetLocalVarTypeOrAny(&cast<GetLocalExpr>(expr)->var)); - break; +Result Validator::OnLoadExpr(LoadExpr* expr) { + expr_loc_ = &expr->loc; + CheckHasMemory(&expr->loc, expr->opcode); + CheckAlign(&expr->loc, expr->align, + get_opcode_natural_alignment(expr->opcode)); + typechecker_.OnLoad(expr->opcode); + return Result::Ok; +} - case ExprType::GrowMemory: - CheckHasMemory(&expr->loc, Opcode::GrowMemory); - typechecker_.OnGrowMemory(); - break; +Result Validator::BeginLoopExpr(LoopExpr* expr) { + expr_loc_ = &expr->loc; + CheckBlockSig(&expr->loc, Opcode::Loop, &expr->block.sig); + typechecker_.OnLoop(&expr->block.sig); + return Result::Ok; +} - case ExprType::If: { - auto if_expr = cast<IfExpr>(expr); - CheckBlockSig(&if_expr->loc, Opcode::If, &if_expr->true_.sig); - typechecker_.OnIf(&if_expr->true_.sig); - CheckExprList(&if_expr->loc, if_expr->true_.exprs); - if (!if_expr->false_.empty()) { - typechecker_.OnElse(); - CheckExprList(&if_expr->loc, if_expr->false_); - } - typechecker_.OnEnd(); - break; - } +Result Validator::EndLoopExpr(LoopExpr* expr) { + typechecker_.OnEnd(); + return Result::Ok; +} - case ExprType::Load: { - auto load_expr = cast<LoadExpr>(expr); - CheckHasMemory(&load_expr->loc, load_expr->opcode); - CheckAlign(&load_expr->loc, load_expr->align, - get_opcode_natural_alignment(load_expr->opcode)); - typechecker_.OnLoad(load_expr->opcode); - break; - } +Result Validator::OnNopExpr(NopExpr* expr) { + expr_loc_ = &expr->loc; + return Result::Ok; +} - case ExprType::Loop: { - auto loop_expr = cast<LoopExpr>(expr); - CheckBlockSig(&loop_expr->loc, Opcode::Loop, &loop_expr->block.sig); - typechecker_.OnLoop(&loop_expr->block.sig); - CheckExprList(&loop_expr->loc, loop_expr->block.exprs); - typechecker_.OnEnd(); - break; - } +Result Validator::OnReturnExpr(ReturnExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnReturn(); + return Result::Ok; +} - case ExprType::CurrentMemory: - CheckHasMemory(&expr->loc, Opcode::CurrentMemory); - typechecker_.OnCurrentMemory(); - break; +Result Validator::OnSelectExpr(SelectExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnSelect(); + return Result::Ok; +} - case ExprType::Nop: - break; +Result Validator::OnSetGlobalExpr(SetGlobalExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnSetGlobal(GetGlobalVarTypeOrAny(&expr->var)); + return Result::Ok; +} - case ExprType::Rethrow: - typechecker_.OnRethrow(cast<RethrowExpr>(expr)->var.index()); - break; +Result Validator::OnSetLocalExpr(SetLocalExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnSetLocal(GetLocalVarTypeOrAny(&expr->var)); + return Result::Ok; +} - case ExprType::Return: - typechecker_.OnReturn(); - break; +Result Validator::OnStoreExpr(StoreExpr* expr) { + expr_loc_ = &expr->loc; + CheckHasMemory(&expr->loc, expr->opcode); + CheckAlign(&expr->loc, expr->align, + get_opcode_natural_alignment(expr->opcode)); + typechecker_.OnStore(expr->opcode); + return Result::Ok; +} - case ExprType::Select: - typechecker_.OnSelect(); - break; +Result Validator::OnTeeLocalExpr(TeeLocalExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnTeeLocal(GetLocalVarTypeOrAny(&expr->var)); + return Result::Ok; +} - case ExprType::SetGlobal: - typechecker_.OnSetGlobal( - GetGlobalVarTypeOrAny(&cast<SetGlobalExpr>(expr)->var)); - break; +Result Validator::OnUnaryExpr(UnaryExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnUnary(expr->opcode); + return Result::Ok; +} - case ExprType::SetLocal: - typechecker_.OnSetLocal( - GetLocalVarTypeOrAny(&cast<SetLocalExpr>(expr)->var)); - break; +Result Validator::OnUnreachableExpr(UnreachableExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnUnreachable(); + return Result::Ok; +} - case ExprType::Store: { - auto store_expr = cast<StoreExpr>(expr); - CheckHasMemory(&store_expr->loc, store_expr->opcode); - CheckAlign(&store_expr->loc, store_expr->align, - get_opcode_natural_alignment(store_expr->opcode)); - typechecker_.OnStore(store_expr->opcode); - break; +Result Validator::BeginTryExpr(TryExpr* expr) { + expr_loc_ = &expr->loc; + CheckBlockSig(&expr->loc, Opcode::Try, &expr->block.sig); + typechecker_.OnTryBlock(&expr->block.sig); + if (expr->catches.empty()) { + PrintError(&expr->loc, "TryBlock: doesn't have any catch clauses"); + } + bool found_catch_all = false; + for (const Catch& catch_ : expr->catches) { + if (catch_.IsCatchAll()) { + found_catch_all = true; + } else { + if (found_catch_all) { + PrintError(&catch_.loc, "Appears after catch all block"); + } } + } + return Result::Ok; +} - case ExprType::TeeLocal: - typechecker_.OnTeeLocal( - GetLocalVarTypeOrAny(&cast<TeeLocalExpr>(expr)->var)); - break; +Result Validator::EndTryExpr(TryExpr* expr) { + typechecker_.OnEnd(); + return Result::Ok; +} - case ExprType::Throw: - const Exception* except; - if (Succeeded(CheckExceptVar(&cast<ThrowExpr>(expr)->var, &except))) { - typechecker_.OnThrow(&except->sig); - } - break; +Result Validator::OnCatchExpr(TryExpr* expr, Catch* catch_) { + typechecker_.OnCatchBlock(&expr->block.sig); + if (!catch_->IsCatchAll()) { + const Exception* except = nullptr; + if (Succeeded(CheckExceptVar(&catch_->var, &except))) { + typechecker_.OnCatch(&except->sig); + } + } + return Result::Ok; +} - case ExprType::TryBlock: { - auto try_expr = cast<TryExpr>(expr); - CheckBlockSig(&try_expr->loc, Opcode::Try, &try_expr->block.sig); +Result Validator::OnThrowExpr(ThrowExpr* expr) { + expr_loc_ = &expr->loc; + const Exception* except; + if (Succeeded(CheckExceptVar(&expr->var, &except))) { + typechecker_.OnThrow(&except->sig); + } + return Result::Ok; +} - typechecker_.OnTryBlock(&try_expr->block.sig); - CheckExprList(&try_expr->loc, try_expr->block.exprs); +Result Validator::OnRethrowExpr(RethrowExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnRethrow(expr->var.index()); + return Result::Ok; +} - if (try_expr->catches.empty()) { - PrintError(&try_expr->loc, "TryBlock: doesn't have any catch clauses"); - } - bool found_catch_all = false; - for (const Catch& catch_ : try_expr->catches) { - typechecker_.OnCatchBlock(&try_expr->block.sig); - if (catch_.IsCatchAll()) { - found_catch_all = true; - } else { - if (found_catch_all) { - PrintError(&catch_.loc, "Appears after catch all block"); - } - const Exception* except = nullptr; - if (Succeeded(CheckExceptVar(&catch_.var, &except))) { - typechecker_.OnCatch(&except->sig); - } - } - CheckExprList(&catch_.loc, catch_.exprs); - } - typechecker_.OnEnd(); - break; - } +Result Validator::OnAtomicWaitExpr(AtomicWaitExpr* expr) { + expr_loc_ = &expr->loc; + CheckAtomicExpr(expr, &TypeChecker::OnAtomicWait); + return Result::Ok; +} - case ExprType::Unary: - typechecker_.OnUnary(cast<UnaryExpr>(expr)->opcode); - break; +Result Validator::OnAtomicWakeExpr(AtomicWakeExpr* expr) { + expr_loc_ = &expr->loc; + CheckAtomicExpr(expr, &TypeChecker::OnAtomicWake); + return Result::Ok; +} - case ExprType::Ternary: - typechecker_.OnTernary(cast<TernaryExpr>(expr)->opcode); - break; +Result Validator::OnAtomicLoadExpr(AtomicLoadExpr* expr) { + expr_loc_ = &expr->loc; + CheckAtomicExpr(expr, &TypeChecker::OnAtomicLoad); + return Result::Ok; +} - case ExprType::Unreachable: - typechecker_.OnUnreachable(); - break; - } +Result Validator::OnAtomicStoreExpr(AtomicStoreExpr* expr) { + expr_loc_ = &expr->loc; + CheckAtomicExpr(expr, &TypeChecker::OnAtomicStore); + return Result::Ok; +} + +Result Validator::OnAtomicRmwExpr(AtomicRmwExpr* expr) { + expr_loc_ = &expr->loc; + CheckAtomicExpr(expr, &TypeChecker::OnAtomicRmw); + return Result::Ok; +} + +Result Validator::OnAtomicRmwCmpxchgExpr(AtomicRmwCmpxchgExpr* expr) { + expr_loc_ = &expr->loc; + CheckAtomicExpr(expr, &TypeChecker::OnAtomicRmwCmpxchg); + return Result::Ok; +} + +Result Validator::OnTernaryExpr(TernaryExpr* expr) { + expr_loc_ = &expr->loc; + typechecker_.OnTernary(expr->opcode); + return Result::Ok; } void Validator::CheckFuncSignature(const Location* loc, |