diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binary-reader-interpreter.cc | 99 | ||||
-rw-r--r-- | src/type-checker.cc | 473 | ||||
-rw-r--r-- | src/type-checker.h | 152 | ||||
-rw-r--r-- | src/validator.cc | 100 |
4 files changed, 407 insertions, 417 deletions
diff --git a/src/binary-reader-interpreter.cc b/src/binary-reader-interpreter.cc index 23f5d745..0acd40fe 100644 --- a/src/binary-reader-interpreter.cc +++ b/src/binary-reader-interpreter.cc @@ -208,7 +208,6 @@ class BinaryReaderInterpreter : public BinaryReaderNop { bool HandleError(Offset offset, const char* message); void PrintError(const char* format, ...); - static void OnTypecheckerError(const char* msg, void* user_data); Index TranslateSigIndexToEnv(Index sig_index); FuncSignature* GetSignatureByModuleIndex(Index sig_index); @@ -267,7 +266,6 @@ class BinaryReaderInterpreter : public BinaryReaderNop { Environment* env = nullptr; DefinedModule* module = nullptr; DefinedFunc* current_func = nullptr; - TypeCheckerErrorHandler tc_error_handler; TypeChecker typechecker; std::vector<Label> label_stack; IstreamOffsetVectorVector func_fixups; @@ -307,9 +305,8 @@ BinaryReaderInterpreter::BinaryReaderInterpreter( module(module), istream_writer(std::move(istream)), istream_offset(istream_writer.output_buffer().size()) { - tc_error_handler.on_error = OnTypecheckerError; - tc_error_handler.user_data = this; - typechecker.error_handler = &tc_error_handler; + typechecker.set_error_callback( + [this](const char* msg) { PrintError("%s", msg); }); } std::unique_ptr<OutputBuffer> BinaryReaderInterpreter::ReleaseOutputBuffer() { @@ -335,12 +332,6 @@ void WABT_PRINTF_FORMAT(2, 3) HandleError(kInvalidOffset, buffer); } -// static -void BinaryReaderInterpreter::OnTypecheckerError(const char* msg, - void* user_data) { - static_cast<BinaryReaderInterpreter*>(user_data)->PrintError("%s", msg); -} - Index BinaryReaderInterpreter::TranslateSigIndexToEnv(Index sig_index) { assert(sig_index < sig_index_mapping.size()); return sig_index_mapping[sig_index]; @@ -467,15 +458,15 @@ wabt::Result BinaryReaderInterpreter::GetBrDropKeepCount( Index depth, Index* out_drop_count, Index* out_keep_count) { - TypeCheckerLabel* label; - CHECK_RESULT(typechecker_get_label(&typechecker, depth, &label)); + TypeChecker::Label* label; + CHECK_RESULT(typechecker.GetLabel(depth, &label)); *out_keep_count = label->label_type != LabelType::Loop ? label->sig.size() : 0; - if (typechecker_is_unreachable(&typechecker)) { + if (typechecker.IsUnreachable()) { *out_drop_count = 0; } else { *out_drop_count = - (typechecker.type_stack.size() - label->type_stack_limit) - + (typechecker.type_stack_size() - label->type_stack_limit) - *out_keep_count; } return wabt::Result::Ok; @@ -1077,7 +1068,7 @@ wabt::Result BinaryReaderInterpreter::BeginFunctionBody(Index index) { for (Type param_type : sig->param_types) func->param_and_local_types.push_back(param_type); - CHECK_RESULT(typechecker_begin_function(&typechecker, &sig->result_types)); + CHECK_RESULT(typechecker.BeginFunction(&sig->result_types)); /* push implicit func label (equivalent to return) */ PushLabel(kInvalidIstreamOffset, kInvalidIstreamOffset); @@ -1088,7 +1079,7 @@ wabt::Result BinaryReaderInterpreter::EndFunctionBody(Index index) { FixupTopLabel(); Index drop_count, keep_count; CHECK_RESULT(GetReturnDropKeepCount(&drop_count, &keep_count)); - CHECK_RESULT(typechecker_end_function(&typechecker)); + CHECK_RESULT(typechecker.EndFunction()); CHECK_RESULT(EmitDropKeep(drop_count, keep_count)); CHECK_RESULT(EmitOpcode(interpreter::Opcode::Return)); PopLabel(); @@ -1137,13 +1128,13 @@ wabt::Result BinaryReaderInterpreter::CheckAlign(uint32_t alignment_log2, } wabt::Result BinaryReaderInterpreter::OnUnaryExpr(wabt::Opcode opcode) { - CHECK_RESULT(typechecker_on_unary(&typechecker, opcode)); + CHECK_RESULT(typechecker.OnUnary(opcode)); CHECK_RESULT(EmitOpcode(opcode)); return wabt::Result::Ok; } wabt::Result BinaryReaderInterpreter::OnBinaryExpr(wabt::Opcode opcode) { - CHECK_RESULT(typechecker_on_binary(&typechecker, opcode)); + CHECK_RESULT(typechecker.OnBinary(opcode)); CHECK_RESULT(EmitOpcode(opcode)); return wabt::Result::Ok; } @@ -1151,7 +1142,7 @@ wabt::Result BinaryReaderInterpreter::OnBinaryExpr(wabt::Opcode opcode) { wabt::Result BinaryReaderInterpreter::OnBlockExpr(Index num_types, Type* sig_types) { TypeVector sig(sig_types, sig_types + num_types); - CHECK_RESULT(typechecker_on_block(&typechecker, &sig)); + CHECK_RESULT(typechecker.OnBlock(&sig)); PushLabel(kInvalidIstreamOffset, kInvalidIstreamOffset); return wabt::Result::Ok; } @@ -1159,7 +1150,7 @@ wabt::Result BinaryReaderInterpreter::OnBlockExpr(Index num_types, wabt::Result BinaryReaderInterpreter::OnLoopExpr(Index num_types, Type* sig_types) { TypeVector sig(sig_types, sig_types + num_types); - CHECK_RESULT(typechecker_on_loop(&typechecker, &sig)); + CHECK_RESULT(typechecker.OnLoop(&sig)); PushLabel(GetIstreamOffset(), kInvalidIstreamOffset); return wabt::Result::Ok; } @@ -1167,7 +1158,7 @@ wabt::Result BinaryReaderInterpreter::OnLoopExpr(Index num_types, wabt::Result BinaryReaderInterpreter::OnIfExpr(Index num_types, Type* sig_types) { TypeVector sig(sig_types, sig_types + num_types); - CHECK_RESULT(typechecker_on_if(&typechecker, &sig)); + CHECK_RESULT(typechecker.OnIf(&sig)); CHECK_RESULT(EmitOpcode(interpreter::Opcode::BrUnless)); IstreamOffset fixup_offset = GetIstreamOffset(); CHECK_RESULT(EmitI32(kInvalidIstreamOffset)); @@ -1176,7 +1167,7 @@ wabt::Result BinaryReaderInterpreter::OnIfExpr(Index num_types, } wabt::Result BinaryReaderInterpreter::OnElseExpr() { - CHECK_RESULT(typechecker_on_else(&typechecker)); + CHECK_RESULT(typechecker.OnElse()); Label* label = TopLabel(); IstreamOffset fixup_cond_offset = label->fixup_offset; CHECK_RESULT(EmitOpcode(interpreter::Opcode::Br)); @@ -1187,10 +1178,10 @@ wabt::Result BinaryReaderInterpreter::OnElseExpr() { } wabt::Result BinaryReaderInterpreter::OnEndExpr() { - TypeCheckerLabel* label; - CHECK_RESULT(typechecker_get_label(&typechecker, 0, &label)); + TypeChecker::Label* label; + CHECK_RESULT(typechecker.GetLabel(0, &label)); LabelType label_type = label->label_type; - CHECK_RESULT(typechecker_on_end(&typechecker)); + CHECK_RESULT(typechecker.OnEnd()); if (label_type == LabelType::If || label_type == LabelType::Else) { CHECK_RESULT(EmitI32At(TopLabel()->fixup_offset, GetIstreamOffset())); } @@ -1202,14 +1193,14 @@ wabt::Result BinaryReaderInterpreter::OnEndExpr() { wabt::Result BinaryReaderInterpreter::OnBrExpr(Index depth) { Index drop_count, keep_count; CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count)); - CHECK_RESULT(typechecker_on_br(&typechecker, depth)); + CHECK_RESULT(typechecker.OnBr(depth)); CHECK_RESULT(EmitBr(depth, drop_count, keep_count)); return wabt::Result::Ok; } wabt::Result BinaryReaderInterpreter::OnBrIfExpr(Index depth) { Index drop_count, keep_count; - CHECK_RESULT(typechecker_on_br_if(&typechecker, depth)); + CHECK_RESULT(typechecker.OnBrIf(depth)); CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count)); /* flip the br_if so if <cond> is true it can drop values from the stack */ CHECK_RESULT(EmitOpcode(interpreter::Opcode::BrUnless)); @@ -1224,7 +1215,7 @@ wabt::Result BinaryReaderInterpreter::OnBrTableExpr( Index num_targets, Index* target_depths, Index default_target_depth) { - CHECK_RESULT(typechecker_begin_br_table(&typechecker)); + CHECK_RESULT(typechecker.BeginBrTable()); CHECK_RESULT(EmitOpcode(interpreter::Opcode::BrTable)); CHECK_RESULT(EmitI32(num_targets)); IstreamOffset fixup_table_offset = GetIstreamOffset(); @@ -1237,11 +1228,11 @@ wabt::Result BinaryReaderInterpreter::OnBrTableExpr( for (Index i = 0; i <= num_targets; ++i) { Index depth = i != num_targets ? target_depths[i] : default_target_depth; - CHECK_RESULT(typechecker_on_br_table_target(&typechecker, depth)); + CHECK_RESULT(typechecker.OnBrTableTarget(depth)); CHECK_RESULT(EmitBrTableOffset(depth)); } - CHECK_RESULT(typechecker_end_br_table(&typechecker)); + CHECK_RESULT(typechecker.EndBrTable()); return wabt::Result::Ok; } @@ -1249,7 +1240,7 @@ wabt::Result BinaryReaderInterpreter::OnCallExpr(Index func_index) { Func* func = GetFuncByModuleIndex(func_index); FuncSignature* sig = env->GetFuncSignature(func->sig_index); CHECK_RESULT( - typechecker_on_call(&typechecker, &sig->param_types, &sig->result_types)); + typechecker.OnCall(&sig->param_types, &sig->result_types)); if (func->is_host) { CHECK_RESULT(EmitOpcode(interpreter::Opcode::CallHost)); @@ -1268,7 +1259,7 @@ wabt::Result BinaryReaderInterpreter::OnCallIndirectExpr(Index sig_index) { return wabt::Result::Error; } FuncSignature* sig = GetSignatureByModuleIndex(sig_index); - CHECK_RESULT(typechecker_on_call_indirect(&typechecker, &sig->param_types, + CHECK_RESULT(typechecker.OnCallIndirect(&sig->param_types, &sig->result_types)); CHECK_RESULT(EmitOpcode(interpreter::Opcode::CallIndirect)); @@ -1286,34 +1277,34 @@ wabt::Result BinaryReaderInterpreter::OnConvertExpr(wabt::Opcode opcode) { } wabt::Result BinaryReaderInterpreter::OnDropExpr() { - CHECK_RESULT(typechecker_on_drop(&typechecker)); + CHECK_RESULT(typechecker.OnDrop()); CHECK_RESULT(EmitOpcode(interpreter::Opcode::Drop)); return wabt::Result::Ok; } wabt::Result BinaryReaderInterpreter::OnI32ConstExpr(uint32_t value) { - CHECK_RESULT(typechecker_on_const(&typechecker, Type::I32)); + CHECK_RESULT(typechecker.OnConst(Type::I32)); CHECK_RESULT(EmitOpcode(interpreter::Opcode::I32Const)); CHECK_RESULT(EmitI32(value)); return wabt::Result::Ok; } wabt::Result BinaryReaderInterpreter::OnI64ConstExpr(uint64_t value) { - CHECK_RESULT(typechecker_on_const(&typechecker, Type::I64)); + CHECK_RESULT(typechecker.OnConst(Type::I64)); CHECK_RESULT(EmitOpcode(interpreter::Opcode::I64Const)); CHECK_RESULT(EmitI64(value)); return wabt::Result::Ok; } wabt::Result BinaryReaderInterpreter::OnF32ConstExpr(uint32_t value_bits) { - CHECK_RESULT(typechecker_on_const(&typechecker, Type::F32)); + CHECK_RESULT(typechecker.OnConst(Type::F32)); CHECK_RESULT(EmitOpcode(interpreter::Opcode::F32Const)); CHECK_RESULT(EmitI32(value_bits)); return wabt::Result::Ok; } wabt::Result BinaryReaderInterpreter::OnF64ConstExpr(uint64_t value_bits) { - CHECK_RESULT(typechecker_on_const(&typechecker, Type::F64)); + CHECK_RESULT(typechecker.OnConst(Type::F64)); CHECK_RESULT(EmitOpcode(interpreter::Opcode::F64Const)); CHECK_RESULT(EmitI64(value_bits)); return wabt::Result::Ok; @@ -1322,7 +1313,7 @@ wabt::Result BinaryReaderInterpreter::OnF64ConstExpr(uint64_t value_bits) { wabt::Result BinaryReaderInterpreter::OnGetGlobalExpr(Index global_index) { CHECK_RESULT(CheckGlobal(global_index)); Type type = GetGlobalTypeByModuleIndex(global_index); - CHECK_RESULT(typechecker_on_get_global(&typechecker, type)); + CHECK_RESULT(typechecker.OnGetGlobal(type)); CHECK_RESULT(EmitOpcode(interpreter::Opcode::GetGlobal)); CHECK_RESULT(EmitI32(TranslateGlobalIndexToEnv(global_index))); return wabt::Result::Ok; @@ -1337,25 +1328,25 @@ wabt::Result BinaryReaderInterpreter::OnSetGlobalExpr(Index global_index) { return wabt::Result::Error; } CHECK_RESULT( - typechecker_on_set_global(&typechecker, global->typed_value.type)); + typechecker.OnSetGlobal(global->typed_value.type)); CHECK_RESULT(EmitOpcode(interpreter::Opcode::SetGlobal)); CHECK_RESULT(EmitI32(TranslateGlobalIndexToEnv(global_index))); return wabt::Result::Ok; } Index BinaryReaderInterpreter::TranslateLocalIndex(Index local_index) { - return typechecker.type_stack.size() + + return typechecker.type_stack_size() + current_func->param_and_local_types.size() - local_index; } wabt::Result BinaryReaderInterpreter::OnGetLocalExpr(Index local_index) { CHECK_RESULT(CheckLocal(local_index)); Type type = GetLocalTypeByIndex(current_func, local_index); - /* Get the translated index before calling typechecker_on_get_local - * because it will update the type stack size. We need the index to be - * relative to the old stack size. */ + // Get the translated index before calling typechecker.OnGetLocal because it + // will update the type stack size. We need the index to be relative to the + // old stack size. Index translated_local_index = TranslateLocalIndex(local_index); - CHECK_RESULT(typechecker_on_get_local(&typechecker, type)); + CHECK_RESULT(typechecker.OnGetLocal(type)); CHECK_RESULT(EmitOpcode(interpreter::Opcode::GetLocal)); CHECK_RESULT(EmitI32(translated_local_index)); return wabt::Result::Ok; @@ -1364,7 +1355,7 @@ wabt::Result BinaryReaderInterpreter::OnGetLocalExpr(Index local_index) { wabt::Result BinaryReaderInterpreter::OnSetLocalExpr(Index local_index) { CHECK_RESULT(CheckLocal(local_index)); Type type = GetLocalTypeByIndex(current_func, local_index); - CHECK_RESULT(typechecker_on_set_local(&typechecker, type)); + CHECK_RESULT(typechecker.OnSetLocal(type)); CHECK_RESULT(EmitOpcode(interpreter::Opcode::SetLocal)); CHECK_RESULT(EmitI32(TranslateLocalIndex(local_index))); return wabt::Result::Ok; @@ -1373,7 +1364,7 @@ wabt::Result BinaryReaderInterpreter::OnSetLocalExpr(Index local_index) { wabt::Result BinaryReaderInterpreter::OnTeeLocalExpr(Index local_index) { CHECK_RESULT(CheckLocal(local_index)); Type type = GetLocalTypeByIndex(current_func, local_index); - CHECK_RESULT(typechecker_on_tee_local(&typechecker, type)); + CHECK_RESULT(typechecker.OnTeeLocal(type)); CHECK_RESULT(EmitOpcode(interpreter::Opcode::TeeLocal)); CHECK_RESULT(EmitI32(TranslateLocalIndex(local_index))); return wabt::Result::Ok; @@ -1381,7 +1372,7 @@ wabt::Result BinaryReaderInterpreter::OnTeeLocalExpr(Index local_index) { wabt::Result BinaryReaderInterpreter::OnGrowMemoryExpr() { CHECK_RESULT(CheckHasMemory(wabt::Opcode::GrowMemory)); - CHECK_RESULT(typechecker_on_grow_memory(&typechecker)); + CHECK_RESULT(typechecker.OnGrowMemory()); CHECK_RESULT(EmitOpcode(interpreter::Opcode::GrowMemory)); CHECK_RESULT(EmitI32(module->memory_index)); return wabt::Result::Ok; @@ -1392,7 +1383,7 @@ wabt::Result BinaryReaderInterpreter::OnLoadExpr(wabt::Opcode opcode, Address offset) { CHECK_RESULT(CheckHasMemory(opcode)); CHECK_RESULT(CheckAlign(alignment_log2, get_opcode_memory_size(opcode))); - CHECK_RESULT(typechecker_on_load(&typechecker, opcode)); + CHECK_RESULT(typechecker.OnLoad(opcode)); CHECK_RESULT(EmitOpcode(opcode)); CHECK_RESULT(EmitI32(module->memory_index)); CHECK_RESULT(EmitI32(offset)); @@ -1404,7 +1395,7 @@ wabt::Result BinaryReaderInterpreter::OnStoreExpr(wabt::Opcode opcode, Address offset) { CHECK_RESULT(CheckHasMemory(opcode)); CHECK_RESULT(CheckAlign(alignment_log2, get_opcode_memory_size(opcode))); - CHECK_RESULT(typechecker_on_store(&typechecker, opcode)); + CHECK_RESULT(typechecker.OnStore(opcode)); CHECK_RESULT(EmitOpcode(opcode)); CHECK_RESULT(EmitI32(module->memory_index)); CHECK_RESULT(EmitI32(offset)); @@ -1413,7 +1404,7 @@ wabt::Result BinaryReaderInterpreter::OnStoreExpr(wabt::Opcode opcode, wabt::Result BinaryReaderInterpreter::OnCurrentMemoryExpr() { CHECK_RESULT(CheckHasMemory(wabt::Opcode::CurrentMemory)); - CHECK_RESULT(typechecker_on_current_memory(&typechecker)); + CHECK_RESULT(typechecker.OnCurrentMemory()); CHECK_RESULT(EmitOpcode(interpreter::Opcode::CurrentMemory)); CHECK_RESULT(EmitI32(module->memory_index)); return wabt::Result::Ok; @@ -1426,20 +1417,20 @@ wabt::Result BinaryReaderInterpreter::OnNopExpr() { wabt::Result BinaryReaderInterpreter::OnReturnExpr() { Index drop_count, keep_count; CHECK_RESULT(GetReturnDropKeepCount(&drop_count, &keep_count)); - CHECK_RESULT(typechecker_on_return(&typechecker)); + CHECK_RESULT(typechecker.OnReturn()); CHECK_RESULT(EmitDropKeep(drop_count, keep_count)); CHECK_RESULT(EmitOpcode(interpreter::Opcode::Return)); return wabt::Result::Ok; } wabt::Result BinaryReaderInterpreter::OnSelectExpr() { - CHECK_RESULT(typechecker_on_select(&typechecker)); + CHECK_RESULT(typechecker.OnSelect()); CHECK_RESULT(EmitOpcode(interpreter::Opcode::Select)); return wabt::Result::Ok; } wabt::Result BinaryReaderInterpreter::OnUnreachableExpr() { - CHECK_RESULT(typechecker_on_unreachable(&typechecker)); + CHECK_RESULT(typechecker.OnUnreachable()); CHECK_RESULT(EmitOpcode(interpreter::Opcode::Unreachable)); return wabt::Result::Ok; } diff --git a/src/type-checker.cc b/src/type-checker.cc index d7af7e59..eba23c75 100644 --- a/src/type-checker.cc +++ b/src/type-checker.cc @@ -16,10 +16,10 @@ #include "type-checker.h" -#define CHECK_RESULT(expr) \ - do { \ - if (WABT_FAILED(expr)) \ - return Result::Error; \ +#define CHECK_RESULT(expr) \ + do { \ + if (WABT_FAILED(expr)) \ + return Result::Error; \ } while (0) #define COMBINE_RESULT(result_var, result) \ @@ -30,300 +30,284 @@ namespace wabt { -TypeCheckerLabel::TypeCheckerLabel(LabelType label_type, - const TypeVector& sig, - size_t limit) +TypeChecker::Label::Label(LabelType label_type, + const TypeVector& sig, + size_t limit) : label_type(label_type), sig(sig), type_stack_limit(limit), unreachable(false) {} -static void WABT_PRINTF_FORMAT(2, 3) - print_error(TypeChecker* tc, const char* fmt, ...) { - if (tc->error_handler->on_error) { +TypeChecker::TypeChecker(const ErrorCallback& error_callback) + : error_callback_(error_callback) {} + +void TypeChecker::PrintError(const char* fmt, ...) { + if (error_callback_) { WABT_SNPRINTF_ALLOCA(buffer, length, fmt); - tc->error_handler->on_error(buffer, tc->error_handler->user_data); + error_callback_(buffer); } } -Result typechecker_get_label(TypeChecker* tc, - Index depth, - TypeCheckerLabel** out_label) { - if (depth >= tc->label_stack.size()) { - assert(tc->label_stack.size() > 0); - print_error(tc, "invalid depth: %" PRIindex " (max %" PRIzd ")", depth, - tc->label_stack.size() - 1); +Result TypeChecker::GetLabel(Index depth, Label** out_label) { + if (depth >= label_stack_.size()) { + assert(label_stack_.size() > 0); + PrintError("invalid depth: %" PRIindex " (max %" PRIzd ")", depth, + label_stack_.size() - 1); *out_label = nullptr; return Result::Error; } - *out_label = &tc->label_stack[tc->label_stack.size() - depth - 1]; + *out_label = &label_stack_[label_stack_.size() - depth - 1]; return Result::Ok; } -static Result top_label(TypeChecker* tc, TypeCheckerLabel** out_label) { - return typechecker_get_label(tc, 0, out_label); +Result TypeChecker::TopLabel(Label** out_label) { + return GetLabel(0, out_label); } -bool typechecker_is_unreachable(TypeChecker* tc) { - TypeCheckerLabel* label; - if (WABT_FAILED(top_label(tc, &label))) +bool TypeChecker::IsUnreachable() { + Label* label; + if (WABT_FAILED(TopLabel(&label))) return true; return label->unreachable; } -static void reset_type_stack_to_label(TypeChecker* tc, - TypeCheckerLabel* label) { - tc->type_stack.resize(label->type_stack_limit); +void TypeChecker::ResetTypeStackToLabel(Label* label) { + type_stack_.resize(label->type_stack_limit); } -static Result set_unreachable(TypeChecker* tc) { - TypeCheckerLabel* label; - CHECK_RESULT(top_label(tc, &label)); +Result TypeChecker::SetUnreachable() { + Label* label; + CHECK_RESULT(TopLabel(&label)); label->unreachable = true; - reset_type_stack_to_label(tc, label); + ResetTypeStackToLabel(label); return Result::Ok; } -static void push_label(TypeChecker* tc, - LabelType label_type, - const TypeVector& sig) { - tc->label_stack.emplace_back(label_type, sig, tc->type_stack.size()); +void TypeChecker::PushLabel(LabelType label_type, const TypeVector& sig) { + label_stack_.emplace_back(label_type, sig, type_stack_.size()); } -static Result pop_label(TypeChecker* tc) { - tc->label_stack.pop_back(); +Result TypeChecker::PopLabel() { + label_stack_.pop_back(); return Result::Ok; } -static Result check_label_type(TypeCheckerLabel* label, LabelType label_type) { +Result TypeChecker::CheckLabelType(Label* label, LabelType label_type) { return label->label_type == label_type ? Result::Ok : Result::Error; } -static Result peek_type(TypeChecker* tc, Index depth, Type* out_type) { - TypeCheckerLabel* label; - CHECK_RESULT(top_label(tc, &label)); +Result TypeChecker::PeekType(Index depth, Type* out_type) { + Label* label; + CHECK_RESULT(TopLabel(&label)); - if (label->type_stack_limit + depth >= tc->type_stack.size()) { + if (label->type_stack_limit + depth >= type_stack_.size()) { *out_type = Type::Any; return label->unreachable ? Result::Ok : Result::Error; } - *out_type = tc->type_stack[tc->type_stack.size() - depth - 1]; + *out_type = type_stack_[type_stack_.size() - depth - 1]; return Result::Ok; } -static Result top_type(TypeChecker* tc, Type* out_type) { - return peek_type(tc, 0, out_type); +Result TypeChecker::TopType(Type* out_type) { + return PeekType(0, out_type); } -static Result pop_type(TypeChecker* tc, Type* out_type) { - TypeCheckerLabel* label; - CHECK_RESULT(top_label(tc, &label)); - Result result = top_type(tc, out_type); - if (tc->type_stack.size() > label->type_stack_limit) - tc->type_stack.pop_back(); +Result TypeChecker::PopType(Type* out_type) { + Label* label; + CHECK_RESULT(TopLabel(&label)); + Result result = TopType(out_type); + if (type_stack_.size() > label->type_stack_limit) + type_stack_.pop_back(); return result; } -static Result drop_types(TypeChecker* tc, size_t drop_count) { - TypeCheckerLabel* label; - CHECK_RESULT(top_label(tc, &label)); - if (label->type_stack_limit + drop_count > tc->type_stack.size()) { +Result TypeChecker::DropTypes(size_t drop_count) { + Label* label; + CHECK_RESULT(TopLabel(&label)); + if (label->type_stack_limit + drop_count > type_stack_.size()) { if (label->unreachable) { - reset_type_stack_to_label(tc, label); + ResetTypeStackToLabel(label); return Result::Ok; } return Result::Error; } - tc->type_stack.erase(tc->type_stack.end() - drop_count, tc->type_stack.end()); + type_stack_.erase(type_stack_.end() - drop_count, type_stack_.end()); return Result::Ok; } -static void push_type(TypeChecker* tc, Type type) { +void TypeChecker::PushType(Type type) { if (type != Type::Void) - tc->type_stack.push_back(type); + type_stack_.push_back(type); } -static void push_types(TypeChecker* tc, const TypeVector& types) { - for (Type type: types) - push_type(tc, type); +void TypeChecker::PushTypes(const TypeVector& types) { + for (Type type : types) + PushType(type); } -static Result check_type_stack_limit(TypeChecker* tc, - size_t expected, - const char* desc) { - TypeCheckerLabel* label; - CHECK_RESULT(top_label(tc, &label)); - size_t avail = tc->type_stack.size() - label->type_stack_limit; +Result TypeChecker::CheckTypeStackLimit(size_t expected, const char* desc) { + Label* label; + CHECK_RESULT(TopLabel(&label)); + size_t avail = type_stack_.size() - label->type_stack_limit; if (!label->unreachable && expected > avail) { - print_error(tc, "type stack size too small at %s. got %" PRIzd - ", expected at least %" PRIzd, - desc, avail, expected); + PrintError("type stack size too small at %s. got %" PRIzd + ", expected at least %" PRIzd, + desc, avail, expected); return Result::Error; } return Result::Ok; } -static Result check_type_stack_end(TypeChecker* tc, const char* desc) { - TypeCheckerLabel* label; - CHECK_RESULT(top_label(tc, &label)); - if (tc->type_stack.size() != label->type_stack_limit) { - print_error(tc, "type stack at end of %s is %" PRIzd ", expected %" PRIzd, - desc, tc->type_stack.size(), label->type_stack_limit); +Result TypeChecker::CheckTypeStackEnd(const char* desc) { + Label* label; + CHECK_RESULT(TopLabel(&label)); + if (type_stack_.size() != label->type_stack_limit) { + PrintError("type stack at end of %s is %" PRIzd ", expected %" PRIzd, desc, + type_stack_.size(), label->type_stack_limit); return Result::Error; } return Result::Ok; } -static Result check_type(TypeChecker* tc, - Type actual, - Type expected, - const char* desc) { +Result TypeChecker::CheckType(Type actual, Type expected, const char* desc) { if (expected != actual && expected != Type::Any && actual != Type::Any) { - print_error(tc, "type mismatch in %s, expected %s but got %s.", desc, - get_type_name(expected), get_type_name(actual)); + PrintError("type mismatch in %s, expected %s but got %s.", desc, + get_type_name(expected), get_type_name(actual)); return Result::Error; } return Result::Ok; } -static Result check_signature(TypeChecker* tc, - const TypeVector& sig, - const char* desc) { +Result TypeChecker::CheckSignature(const TypeVector& sig, const char* desc) { Result result = Result::Ok; - COMBINE_RESULT(result, check_type_stack_limit(tc, sig.size(), desc)); + COMBINE_RESULT(result, CheckTypeStackLimit(sig.size(), desc)); for (size_t i = 0; i < sig.size(); ++i) { Type actual = Type::Any; - COMBINE_RESULT(result, peek_type(tc, sig.size() - i - 1, &actual)); - COMBINE_RESULT(result, check_type(tc, actual, sig[i], desc)); + COMBINE_RESULT(result, PeekType(sig.size() - i - 1, &actual)); + COMBINE_RESULT(result, CheckType(actual, sig[i], desc)); } return result; } -static Result pop_and_check_signature(TypeChecker* tc, - const TypeVector& sig, - const char* desc) { +Result TypeChecker::PopAndCheckSignature(const TypeVector& sig, + const char* desc) { Result result = Result::Ok; - COMBINE_RESULT(result, check_signature(tc, sig, desc)); - COMBINE_RESULT(result, drop_types(tc, sig.size())); + COMBINE_RESULT(result, CheckSignature(sig, desc)); + COMBINE_RESULT(result, DropTypes(sig.size())); return result; } -static Result pop_and_check_call(TypeChecker* tc, - const TypeVector& param_types, - const TypeVector& result_types, - const char* desc) { +Result TypeChecker::PopAndCheckCall(const TypeVector& param_types, + const TypeVector& result_types, + const char* desc) { Result result = Result::Ok; - COMBINE_RESULT(result, check_type_stack_limit(tc, param_types.size(), desc)); + COMBINE_RESULT(result, CheckTypeStackLimit(param_types.size(), desc)); for (size_t i = 0; i < param_types.size(); ++i) { Type actual = Type::Any; - COMBINE_RESULT(result, peek_type(tc, param_types.size() - i - 1, &actual)); - COMBINE_RESULT(result, check_type(tc, actual, param_types[i], desc)); + COMBINE_RESULT(result, PeekType(param_types.size() - i - 1, &actual)); + COMBINE_RESULT(result, CheckType(actual, param_types[i], desc)); } - COMBINE_RESULT(result, drop_types(tc, param_types.size())); - push_types(tc, result_types); + COMBINE_RESULT(result, DropTypes(param_types.size())); + PushTypes(result_types); return result; } -static Result pop_and_check_1_type(TypeChecker* tc, - Type expected, - const char* desc) { +Result TypeChecker::PopAndCheck1Type(Type expected, const char* desc) { Result result = Result::Ok; Type actual = Type::Any; - COMBINE_RESULT(result, check_type_stack_limit(tc, 1, desc)); - COMBINE_RESULT(result, pop_type(tc, &actual)); - COMBINE_RESULT(result, check_type(tc, actual, expected, desc)); + COMBINE_RESULT(result, CheckTypeStackLimit(1, desc)); + COMBINE_RESULT(result, PopType(&actual)); + COMBINE_RESULT(result, CheckType(actual, expected, desc)); return result; } -static Result pop_and_check_2_types(TypeChecker* tc, - Type expected1, - Type expected2, - const char* desc) { +Result TypeChecker::PopAndCheck2Types(Type expected1, + Type expected2, + const char* desc) { Result result = Result::Ok; Type actual1 = Type::Any; Type actual2 = Type::Any; - COMBINE_RESULT(result, check_type_stack_limit(tc, 2, desc)); - COMBINE_RESULT(result, pop_type(tc, &actual2)); - COMBINE_RESULT(result, pop_type(tc, &actual1)); - COMBINE_RESULT(result, check_type(tc, actual1, expected1, desc)); - COMBINE_RESULT(result, check_type(tc, actual2, expected2, desc)); + COMBINE_RESULT(result, CheckTypeStackLimit(2, desc)); + COMBINE_RESULT(result, PopType(&actual2)); + COMBINE_RESULT(result, PopType(&actual1)); + COMBINE_RESULT(result, CheckType(actual1, expected1, desc)); + COMBINE_RESULT(result, CheckType(actual2, expected2, desc)); return result; } -static Result pop_and_check_2_types_are_equal(TypeChecker* tc, - Type* out_type, +Result TypeChecker::PopAndCheck2TypesAreEqual(Type* out_type, const char* desc) { Result result = Result::Ok; Type right = Type::Any; Type left = Type::Any; - COMBINE_RESULT(result, check_type_stack_limit(tc, 2, desc)); - COMBINE_RESULT(result, pop_type(tc, &right)); - COMBINE_RESULT(result, pop_type(tc, &left)); - COMBINE_RESULT(result, check_type(tc, left, right, desc)); + COMBINE_RESULT(result, CheckTypeStackLimit(2, desc)); + COMBINE_RESULT(result, PopType(&right)); + COMBINE_RESULT(result, PopType(&left)); + COMBINE_RESULT(result, CheckType(left, right, desc)); *out_type = right; return result; } -static Result check_opcode1(TypeChecker* tc, Opcode opcode) { - Result result = pop_and_check_1_type(tc, get_opcode_param_type_1(opcode), - get_opcode_name(opcode)); - push_type(tc, get_opcode_result_type(opcode)); +Result TypeChecker::CheckOpcode1(Opcode opcode) { + Result result = PopAndCheck1Type(get_opcode_param_type_1(opcode), + get_opcode_name(opcode)); + PushType(get_opcode_result_type(opcode)); return result; } -static Result check_opcode2(TypeChecker* tc, Opcode opcode) { - Result result = pop_and_check_2_types(tc, get_opcode_param_type_1(opcode), - get_opcode_param_type_2(opcode), - get_opcode_name(opcode)); - push_type(tc, get_opcode_result_type(opcode)); +Result TypeChecker::CheckOpcode2(Opcode opcode) { + Result result = PopAndCheck2Types(get_opcode_param_type_1(opcode), + get_opcode_param_type_2(opcode), + get_opcode_name(opcode)); + PushType(get_opcode_result_type(opcode)); return result; } -Result typechecker_begin_function(TypeChecker* tc, const TypeVector* sig) { - tc->type_stack.clear(); - tc->label_stack.clear(); - push_label(tc, LabelType::Func, *sig); +Result TypeChecker::BeginFunction(const TypeVector* sig) { + type_stack_.clear(); + label_stack_.clear(); + PushLabel(LabelType::Func, *sig); return Result::Ok; } -Result typechecker_on_binary(TypeChecker* tc, Opcode opcode) { - return check_opcode2(tc, opcode); +Result TypeChecker::OnBinary(Opcode opcode) { + return CheckOpcode2(opcode); } -Result typechecker_on_block(TypeChecker* tc, const TypeVector* sig) { - push_label(tc, LabelType::Block, *sig); +Result TypeChecker::OnBlock(const TypeVector* sig) { + PushLabel(LabelType::Block, *sig); return Result::Ok; } -Result typechecker_on_br(TypeChecker* tc, Index depth) { +Result TypeChecker::OnBr(Index depth) { Result result = Result::Ok; - TypeCheckerLabel* label; - CHECK_RESULT(typechecker_get_label(tc, depth, &label)); + Label* label; + CHECK_RESULT(GetLabel(depth, &label)); if (label->label_type != LabelType::Loop) - COMBINE_RESULT(result, check_signature(tc, label->sig, "br")); - CHECK_RESULT(set_unreachable(tc)); + COMBINE_RESULT(result, CheckSignature(label->sig, "br")); + CHECK_RESULT(SetUnreachable()); return result; } -Result typechecker_on_br_if(TypeChecker* tc, Index depth) { +Result TypeChecker::OnBrIf(Index depth) { Result result = Result::Ok; - COMBINE_RESULT(result, pop_and_check_1_type(tc, Type::I32, "br_if")); - TypeCheckerLabel* label; - CHECK_RESULT(typechecker_get_label(tc, depth, &label)); + COMBINE_RESULT(result, PopAndCheck1Type(Type::I32, "br_if")); + Label* label; + CHECK_RESULT(GetLabel(depth, &label)); if (label->label_type != LabelType::Loop) - COMBINE_RESULT(result, check_signature(tc, label->sig, "br_if")); + COMBINE_RESULT(result, CheckSignature(label->sig, "br_if")); return result; } -Result typechecker_begin_br_table(TypeChecker* tc) { - tc->br_table_sig = Type::Any; - return pop_and_check_1_type(tc, Type::I32, "br_table"); +Result TypeChecker::BeginBrTable() { + br_table_sig_ = Type::Any; + return PopAndCheck1Type(Type::I32, "br_table"); } -Result typechecker_on_br_table_target(TypeChecker* tc, Index depth) { +Result TypeChecker::OnBrTableTarget(Index depth) { Result result = Result::Ok; - TypeCheckerLabel* label; - CHECK_RESULT(typechecker_get_label(tc, depth, &label)); + Label* label; + CHECK_RESULT(GetLabel(depth, &label)); Type label_sig; if (label->label_type == LabelType::Loop) { label_sig = Type::Void; @@ -332,191 +316,184 @@ Result typechecker_on_br_table_target(TypeChecker* tc, Index depth) { label_sig = label->sig.size() == 0 ? Type::Void : label->sig[0]; } - COMBINE_RESULT(result, - check_type(tc, tc->br_table_sig, label_sig, "br_table")); - tc->br_table_sig = label_sig; + COMBINE_RESULT(result, CheckType(br_table_sig_, label_sig, "br_table")); + br_table_sig_ = label_sig; if (label->label_type != LabelType::Loop) - COMBINE_RESULT(result, check_signature(tc, label->sig, "br_table")); + COMBINE_RESULT(result, CheckSignature(label->sig, "br_table")); return result; } -Result typechecker_end_br_table(TypeChecker* tc) { - return set_unreachable(tc); +Result TypeChecker::EndBrTable() { + return SetUnreachable(); } -Result typechecker_on_call(TypeChecker* tc, - const TypeVector* param_types, +Result TypeChecker::OnCall(const TypeVector* param_types, const TypeVector* result_types) { - return pop_and_check_call(tc, *param_types, *result_types, "call"); + return PopAndCheckCall(*param_types, *result_types, "call"); } -Result typechecker_on_call_indirect(TypeChecker* tc, - const TypeVector* param_types, - const TypeVector* result_types) { +Result TypeChecker::OnCallIndirect(const TypeVector* param_types, + const TypeVector* result_types) { Result result = Result::Ok; - COMBINE_RESULT(result, pop_and_check_1_type(tc, Type::I32, "call_indirect")); - COMBINE_RESULT(result, pop_and_check_call(tc, *param_types, *result_types, - "call_indirect")); + COMBINE_RESULT(result, PopAndCheck1Type(Type::I32, "call_indirect")); + COMBINE_RESULT(result, + PopAndCheckCall(*param_types, *result_types, "call_indirect")); return result; } -Result typechecker_on_compare(TypeChecker* tc, Opcode opcode) { - return check_opcode2(tc, opcode); +Result TypeChecker::OnCompare(Opcode opcode) { + return CheckOpcode2(opcode); } -Result typechecker_on_const(TypeChecker* tc, Type type) { - push_type(tc, type); +Result TypeChecker::OnConst(Type type) { + PushType(type); return Result::Ok; } -Result typechecker_on_convert(TypeChecker* tc, Opcode opcode) { - return check_opcode1(tc, opcode); +Result TypeChecker::OnConvert(Opcode opcode) { + return CheckOpcode1(opcode); } -Result typechecker_on_current_memory(TypeChecker* tc) { - push_type(tc, Type::I32); +Result TypeChecker::OnCurrentMemory() { + PushType(Type::I32); return Result::Ok; } -Result typechecker_on_drop(TypeChecker* tc) { +Result TypeChecker::OnDrop() { Result result = Result::Ok; Type type = Type::Any; - COMBINE_RESULT(result, check_type_stack_limit(tc, 1, "drop")); - COMBINE_RESULT(result, pop_type(tc, &type)); + COMBINE_RESULT(result, CheckTypeStackLimit(1, "drop")); + COMBINE_RESULT(result, PopType(&type)); return result; } -Result typechecker_on_else(TypeChecker* tc) { +Result TypeChecker::OnElse() { Result result = Result::Ok; - TypeCheckerLabel* label; - CHECK_RESULT(top_label(tc, &label)); - COMBINE_RESULT(result, check_label_type(label, LabelType::If)); - COMBINE_RESULT(result, - pop_and_check_signature(tc, label->sig, "if true branch")); - COMBINE_RESULT(result, check_type_stack_end(tc, "if true branch")); - reset_type_stack_to_label(tc, label); + Label* label; + CHECK_RESULT(TopLabel(&label)); + COMBINE_RESULT(result, CheckLabelType(label, LabelType::If)); + COMBINE_RESULT(result, PopAndCheckSignature(label->sig, "if true branch")); + COMBINE_RESULT(result, CheckTypeStackEnd("if true branch")); + ResetTypeStackToLabel(label); label->label_type = LabelType::Else; label->unreachable = false; return result; } -static Result on_end(TypeChecker* tc, - TypeCheckerLabel* label, - const char* sig_desc, - const char* end_desc) { +Result TypeChecker::OnEnd(Label* label, + const char* sig_desc, + const char* end_desc) { Result result = Result::Ok; - COMBINE_RESULT(result, pop_and_check_signature(tc, label->sig, sig_desc)); - COMBINE_RESULT(result, check_type_stack_end(tc, end_desc)); - reset_type_stack_to_label(tc, label); - push_types(tc, label->sig); - pop_label(tc); + COMBINE_RESULT(result, PopAndCheckSignature(label->sig, sig_desc)); + COMBINE_RESULT(result, CheckTypeStackEnd(end_desc)); + ResetTypeStackToLabel(label); + PushTypes(label->sig); + PopLabel(); return result; } -Result typechecker_on_end(TypeChecker* tc) { +Result TypeChecker::OnEnd() { Result result = Result::Ok; static const char* s_label_type_name[] = {"function", "block", "loop", "if", "if false branch"}; WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(s_label_type_name) == kLabelTypeCount); - TypeCheckerLabel* label; - CHECK_RESULT(top_label(tc, &label)); + Label* label; + CHECK_RESULT(TopLabel(&label)); assert(static_cast<int>(label->label_type) < kLabelTypeCount); if (label->label_type == LabelType::If) { if (label->sig.size() != 0) { - print_error(tc, "if without else cannot have type signature."); + PrintError("if without else cannot have type signature."); result = Result::Error; } } const char* desc = s_label_type_name[static_cast<int>(label->label_type)]; - COMBINE_RESULT(result, on_end(tc, label, desc, desc)); + COMBINE_RESULT(result, OnEnd(label, desc, desc)); return result; } -Result typechecker_on_grow_memory(TypeChecker* tc) { - return check_opcode1(tc, Opcode::GrowMemory); +Result TypeChecker::OnGrowMemory() { + return CheckOpcode1(Opcode::GrowMemory); } -Result typechecker_on_if(TypeChecker* tc, const TypeVector* sig) { - Result result = pop_and_check_1_type(tc, Type::I32, "if"); - push_label(tc, LabelType::If, *sig); +Result TypeChecker::OnIf(const TypeVector* sig) { + Result result = PopAndCheck1Type(Type::I32, "if"); + PushLabel(LabelType::If, *sig); return result; } -Result typechecker_on_get_global(TypeChecker* tc, Type type) { - push_type(tc, type); +Result TypeChecker::OnGetGlobal(Type type) { + PushType(type); return Result::Ok; } -Result typechecker_on_get_local(TypeChecker* tc, Type type) { - push_type(tc, type); +Result TypeChecker::OnGetLocal(Type type) { + PushType(type); return Result::Ok; } -Result typechecker_on_load(TypeChecker* tc, Opcode opcode) { - return check_opcode1(tc, opcode); +Result TypeChecker::OnLoad(Opcode opcode) { + return CheckOpcode1(opcode); } -Result typechecker_on_loop(TypeChecker* tc, const TypeVector* sig) { - push_label(tc, LabelType::Loop, *sig); +Result TypeChecker::OnLoop(const TypeVector* sig) { + PushLabel(LabelType::Loop, *sig); return Result::Ok; } -Result typechecker_on_return(TypeChecker* tc) { +Result TypeChecker::OnReturn() { Result result = Result::Ok; - TypeCheckerLabel* func_label; - CHECK_RESULT( - typechecker_get_label(tc, tc->label_stack.size() - 1, &func_label)); - COMBINE_RESULT(result, - pop_and_check_signature(tc, func_label->sig, "return")); - CHECK_RESULT(set_unreachable(tc)); + Label* func_label; + CHECK_RESULT(GetLabel(label_stack_.size() - 1, &func_label)); + COMBINE_RESULT(result, PopAndCheckSignature(func_label->sig, "return")); + CHECK_RESULT(SetUnreachable()); return result; } -Result typechecker_on_select(TypeChecker* tc) { +Result TypeChecker::OnSelect() { Result result = Result::Ok; - COMBINE_RESULT(result, pop_and_check_1_type(tc, Type::I32, "select")); + COMBINE_RESULT(result, PopAndCheck1Type(Type::I32, "select")); Type type = Type::Any; - COMBINE_RESULT(result, pop_and_check_2_types_are_equal(tc, &type, "select")); - push_type(tc, type); + COMBINE_RESULT(result, PopAndCheck2TypesAreEqual(&type, "select")); + PushType(type); return result; } -Result typechecker_on_set_global(TypeChecker* tc, Type type) { - return pop_and_check_1_type(tc, type, "set_global"); +Result TypeChecker::OnSetGlobal(Type type) { + return PopAndCheck1Type(type, "set_global"); } -Result typechecker_on_set_local(TypeChecker* tc, Type type) { - return pop_and_check_1_type(tc, type, "set_local"); +Result TypeChecker::OnSetLocal(Type type) { + return PopAndCheck1Type(type, "set_local"); } -Result typechecker_on_store(TypeChecker* tc, Opcode opcode) { - return check_opcode2(tc, opcode); +Result TypeChecker::OnStore(Opcode opcode) { + return CheckOpcode2(opcode); } -Result typechecker_on_tee_local(TypeChecker* tc, Type type) { +Result TypeChecker::OnTeeLocal(Type type) { Result result = Result::Ok; Type value = Type::Any; - COMBINE_RESULT(result, check_type_stack_limit(tc, 1, "tee_local")); - COMBINE_RESULT(result, top_type(tc, &value)); - COMBINE_RESULT(result, check_type(tc, value, type, "tee_local")); + COMBINE_RESULT(result, CheckTypeStackLimit(1, "tee_local")); + COMBINE_RESULT(result, TopType(&value)); + COMBINE_RESULT(result, CheckType(value, type, "tee_local")); return result; } -Result typechecker_on_unary(TypeChecker* tc, Opcode opcode) { - return check_opcode1(tc, opcode); +Result TypeChecker::OnUnary(Opcode opcode) { + return CheckOpcode1(opcode); } -Result typechecker_on_unreachable(TypeChecker* tc) { - return set_unreachable(tc); +Result TypeChecker::OnUnreachable() { + return SetUnreachable(); } -Result typechecker_end_function(TypeChecker* tc) { +Result TypeChecker::EndFunction() { Result result = Result::Ok; - TypeCheckerLabel* label; - CHECK_RESULT(top_label(tc, &label)); - COMBINE_RESULT(result, check_label_type(label, LabelType::Func)); - COMBINE_RESULT(result, on_end(tc, label, "implicit return", "function")); + Label* label; + CHECK_RESULT(TopLabel(&label)); + COMBINE_RESULT(result, CheckLabelType(label, LabelType::Func)); + COMBINE_RESULT(result, OnEnd(label, "implicit return", "function")); return result; } diff --git a/src/type-checker.h b/src/type-checker.h index 483293da..f7238365 100644 --- a/src/type-checker.h +++ b/src/type-checker.h @@ -17,6 +17,7 @@ #ifndef WABT_TYPE_CHECKER_H_ #define WABT_TYPE_CHECKER_H_ +#include <functional> #include <vector> #include "common.h" @@ -24,72 +25,101 @@ namespace wabt { -typedef void (*TypeCheckerErrorCallback)(const char* msg, void* user_data); +class TypeChecker { + public: + typedef std::function<void(const char* msg)> ErrorCallback; -struct TypeCheckerErrorHandler { - TypeCheckerErrorCallback on_error; - void* user_data; -}; + struct Label { + Label(LabelType, const TypeVector& sig, size_t limit); -struct TypeCheckerLabel { - TypeCheckerLabel(LabelType, const TypeVector& sig, size_t limit); + LabelType label_type; + TypeVector sig; + size_t type_stack_limit; + bool unreachable; + }; - LabelType label_type; - TypeVector sig; - size_t type_stack_limit; - bool unreachable; -}; + TypeChecker() = default; + explicit TypeChecker(const ErrorCallback&); -struct TypeChecker { - TypeCheckerErrorHandler* error_handler = nullptr; - TypeVector type_stack; - std::vector<TypeCheckerLabel> label_stack; - /* TODO(binji): will need to be complete signature when signatures with - * multiple types are allowed. */ - Type br_table_sig; -}; + void set_error_callback(const ErrorCallback& error_callback) { + error_callback_ = error_callback; + } + + size_t type_stack_size() const { return type_stack_.size(); } -bool typechecker_is_unreachable(TypeChecker* tc); -Result typechecker_get_label(TypeChecker* tc, - Index depth, - TypeCheckerLabel** out_label); - -Result typechecker_begin_function(TypeChecker*, const TypeVector* sig); -Result typechecker_on_binary(TypeChecker*, Opcode); -Result typechecker_on_block(TypeChecker*, const TypeVector* sig); -Result typechecker_on_br(TypeChecker*, Index depth); -Result typechecker_on_br_if(TypeChecker*, Index depth); -Result typechecker_begin_br_table(TypeChecker*); -Result typechecker_on_br_table_target(TypeChecker*, Index depth); -Result typechecker_end_br_table(TypeChecker*); -Result typechecker_on_call(TypeChecker*, - const TypeVector* param_types, - const TypeVector* result_types); -Result typechecker_on_call_indirect(TypeChecker*, - const TypeVector* param_types, - const TypeVector* result_types); -Result typechecker_on_compare(TypeChecker*, Opcode); -Result typechecker_on_const(TypeChecker*, Type); -Result typechecker_on_convert(TypeChecker*, Opcode); -Result typechecker_on_current_memory(TypeChecker*); -Result typechecker_on_drop(TypeChecker*); -Result typechecker_on_else(TypeChecker*); -Result typechecker_on_end(TypeChecker*); -Result typechecker_on_get_global(TypeChecker*, Type); -Result typechecker_on_get_local(TypeChecker*, Type); -Result typechecker_on_grow_memory(TypeChecker*); -Result typechecker_on_if(TypeChecker*, const TypeVector* sig); -Result typechecker_on_load(TypeChecker*, Opcode); -Result typechecker_on_loop(TypeChecker*, const TypeVector* sig); -Result typechecker_on_return(TypeChecker*); -Result typechecker_on_select(TypeChecker*); -Result typechecker_on_set_global(TypeChecker*, Type); -Result typechecker_on_set_local(TypeChecker*, Type); -Result typechecker_on_store(TypeChecker*, Opcode); -Result typechecker_on_tee_local(TypeChecker*, Type); -Result typechecker_on_unary(TypeChecker*, Opcode); -Result typechecker_on_unreachable(TypeChecker*); -Result typechecker_end_function(TypeChecker*); + bool IsUnreachable(); + Result GetLabel(Index depth, Label** out_label); + + Result BeginFunction(const TypeVector* sig); + Result OnBinary(Opcode); + Result OnBlock(const TypeVector* sig); + Result OnBr(Index depth); + Result OnBrIf(Index depth); + Result BeginBrTable(); + Result OnBrTableTarget(Index depth); + Result EndBrTable(); + Result OnCall(const TypeVector* param_types, const TypeVector* result_types); + Result OnCallIndirect(const TypeVector* param_types, + const TypeVector* result_types); + Result OnCompare(Opcode); + Result OnConst(Type); + Result OnConvert(Opcode); + Result OnCurrentMemory(); + Result OnDrop(); + Result OnElse(); + Result OnEnd(); + Result OnGetGlobal(Type); + Result OnGetLocal(Type); + Result OnGrowMemory(); + Result OnIf(const TypeVector* sig); + Result OnLoad(Opcode); + Result OnLoop(const TypeVector* sig); + Result OnReturn(); + Result OnSelect(); + Result OnSetGlobal(Type); + Result OnSetLocal(Type); + Result OnStore(Opcode); + Result OnTeeLocal(Type); + Result OnUnary(Opcode); + Result OnUnreachable(); + Result EndFunction(); + + private: + void WABT_PRINTF_FORMAT(2, 3) PrintError(const char* fmt, ...); + Result TopLabel(Label** out_label); + void ResetTypeStackToLabel(Label* label); + Result SetUnreachable(); + void PushLabel(LabelType label_type, const TypeVector& sig); + Result PopLabel(); + Result CheckLabelType(Label* label, LabelType label_type); + Result PeekType(Index depth, Type* out_type); + Result TopType(Type* out_type); + Result PopType(Type* out_type); + Result DropTypes(size_t drop_count); + void PushType(Type type); + void PushTypes(const TypeVector& types); + Result CheckTypeStackLimit(size_t expected, const char* desc); + Result CheckTypeStackEnd(const char* desc); + Result CheckType(Type actual, Type expected, const char* desc); + Result CheckSignature(const TypeVector& sig, const char* desc); + Result PopAndCheckSignature(const TypeVector& sig, const char* desc); + Result PopAndCheckCall(const TypeVector& param_types, + const TypeVector& result_types, + const char* desc); + Result PopAndCheck1Type(Type expected, const char* desc); + Result PopAndCheck2Types(Type expected1, Type expected2, const char* desc); + Result PopAndCheck2TypesAreEqual(Type* out_type, const char* desc); + Result CheckOpcode1(Opcode opcode); + Result CheckOpcode2(Opcode opcode); + Result OnEnd(Label* label, const char* sig_desc, const char* end_desc); + + ErrorCallback error_callback_; + TypeVector type_stack_; + std::vector<Label> label_stack_; + // TODO(binji): This will need to be complete signature when signatures with + // multiple types are allowed. + Type br_table_sig_ = Type::Void; +}; } // namespace wabt diff --git a/src/validator.cc b/src/validator.cc index c69490a5..d9179ba5 100644 --- a/src/validator.cc +++ b/src/validator.cc @@ -48,6 +48,8 @@ struct Context { WABT_DISALLOW_COPY_AND_ASSIGN(Context); Context(SourceErrorHandler*, WastLexer*, const Script*); + void OnTypecheckerError(const char* msg); + SourceErrorHandler* error_handler = nullptr; WastLexer* lexer = nullptr; const Script* script = nullptr; @@ -58,7 +60,7 @@ struct Context { Index current_global_index = 0; Index num_imported_globals = 0; TypeChecker typechecker; - /* Cached for access by on_typechecker_error */ + // Cached for access by OnTypecheckerError. const Location* expr_loc = nullptr; Result result = Result::Ok; }; @@ -66,7 +68,10 @@ struct Context { Context::Context(SourceErrorHandler* error_handler, WastLexer* lexer, const Script* script) - : error_handler(error_handler), lexer(lexer), script(script) {} + : error_handler(error_handler), lexer(lexer), script(script) { + typechecker.set_error_callback( + [this](const char* msg) { OnTypecheckerError(msg); }); +} } // namespace @@ -79,9 +84,8 @@ static void WABT_PRINTF_FORMAT(3, 4) va_end(args); } -static void on_typechecker_error(const char* msg, void* user_data) { - Context* ctx = static_cast<Context*>(user_data); - print_error(ctx, ctx->expr_loc, "%s", msg); +void Context::OnTypecheckerError(const char* msg) { + print_error(this, expr_loc, "%s", msg); } static bool is_power_of_two(uint32_t x) { @@ -348,39 +352,38 @@ static void check_expr(Context* ctx, const Expr* expr) { switch (expr->type) { case ExprType::Binary: - typechecker_on_binary(&ctx->typechecker, expr->binary.opcode); + ctx->typechecker.OnBinary(expr->binary.opcode); break; case ExprType::Block: - typechecker_on_block(&ctx->typechecker, &expr->block->sig); + ctx->typechecker.OnBlock(&expr->block->sig); check_expr_list(ctx, &expr->loc, expr->block->first); - typechecker_on_end(&ctx->typechecker); + ctx->typechecker.OnEnd(); break; case ExprType::Br: - typechecker_on_br(&ctx->typechecker, expr->br.var.index); + ctx->typechecker.OnBr(expr->br.var.index); break; case ExprType::BrIf: - typechecker_on_br_if(&ctx->typechecker, expr->br_if.var.index); + ctx->typechecker.OnBrIf(expr->br_if.var.index); break; case ExprType::BrTable: { - typechecker_begin_br_table(&ctx->typechecker); + ctx->typechecker.BeginBrTable(); for (Var& var: *expr->br_table.targets) { - typechecker_on_br_table_target(&ctx->typechecker, var.index); + ctx->typechecker.OnBrTableTarget(var.index); } - typechecker_on_br_table_target(&ctx->typechecker, - expr->br_table.default_target.index); - typechecker_end_br_table(&ctx->typechecker); + ctx->typechecker.OnBrTableTarget(expr->br_table.default_target.index); + ctx->typechecker.EndBrTable(); break; } case ExprType::Call: { const Func* callee; if (WABT_SUCCEEDED(check_func_var(ctx, &expr->call.var, &callee))) { - typechecker_on_call(&ctx->typechecker, &callee->decl.sig.param_types, - &callee->decl.sig.result_types); + ctx->typechecker.OnCall(&callee->decl.sig.param_types, + &callee->decl.sig.result_types); } break; } @@ -393,54 +396,51 @@ static void check_expr(Context* ctx, const Expr* expr) { } if (WABT_SUCCEEDED( check_func_type_var(ctx, &expr->call_indirect.var, &func_type))) { - typechecker_on_call_indirect(&ctx->typechecker, - &func_type->sig.param_types, - &func_type->sig.result_types); + ctx->typechecker.OnCallIndirect(&func_type->sig.param_types, + &func_type->sig.result_types); } break; } case ExprType::Compare: - typechecker_on_compare(&ctx->typechecker, expr->compare.opcode); + ctx->typechecker.OnCompare(expr->compare.opcode); break; case ExprType::Const: - typechecker_on_const(&ctx->typechecker, expr->const_.type); + ctx->typechecker.OnConst(expr->const_.type); break; case ExprType::Convert: - typechecker_on_convert(&ctx->typechecker, expr->convert.opcode); + ctx->typechecker.OnConvert(expr->convert.opcode); break; case ExprType::Drop: - typechecker_on_drop(&ctx->typechecker); + ctx->typechecker.OnDrop(); break; case ExprType::GetGlobal: - typechecker_on_get_global( - &ctx->typechecker, + ctx->typechecker.OnGetGlobal( get_global_var_type_or_any(ctx, &expr->get_global.var)); break; case ExprType::GetLocal: - typechecker_on_get_local( - &ctx->typechecker, + ctx->typechecker.OnGetLocal( get_local_var_type_or_any(ctx, &expr->get_local.var)); break; case ExprType::GrowMemory: check_has_memory(ctx, &expr->loc, Opcode::GrowMemory); - typechecker_on_grow_memory(&ctx->typechecker); + ctx->typechecker.OnGrowMemory(); break; case ExprType::If: - typechecker_on_if(&ctx->typechecker, &expr->if_.true_->sig); + ctx->typechecker.OnIf(&expr->if_.true_->sig); check_expr_list(ctx, &expr->loc, expr->if_.true_->first); if (expr->if_.false_) { - typechecker_on_else(&ctx->typechecker); + ctx->typechecker.OnElse(); check_expr_list(ctx, &expr->loc, expr->if_.false_); } - typechecker_on_end(&ctx->typechecker); + ctx->typechecker.OnEnd(); break; case ExprType::Load: @@ -448,40 +448,38 @@ static void check_expr(Context* ctx, const Expr* expr) { check_align(ctx, &expr->loc, expr->load.align, get_opcode_natural_alignment(expr->load.opcode)); check_offset(ctx, &expr->loc, expr->load.offset); - typechecker_on_load(&ctx->typechecker, expr->load.opcode); + ctx->typechecker.OnLoad(expr->load.opcode); break; case ExprType::Loop: - typechecker_on_loop(&ctx->typechecker, &expr->loop->sig); + ctx->typechecker.OnLoop(&expr->loop->sig); check_expr_list(ctx, &expr->loc, expr->loop->first); - typechecker_on_end(&ctx->typechecker); + ctx->typechecker.OnEnd(); break; case ExprType::CurrentMemory: check_has_memory(ctx, &expr->loc, Opcode::CurrentMemory); - typechecker_on_current_memory(&ctx->typechecker); + ctx->typechecker.OnCurrentMemory(); break; case ExprType::Nop: break; case ExprType::Return: - typechecker_on_return(&ctx->typechecker); + ctx->typechecker.OnReturn(); break; case ExprType::Select: - typechecker_on_select(&ctx->typechecker); + ctx->typechecker.OnSelect(); break; case ExprType::SetGlobal: - typechecker_on_set_global( - &ctx->typechecker, + ctx->typechecker.OnSetGlobal( get_global_var_type_or_any(ctx, &expr->set_global.var)); break; case ExprType::SetLocal: - typechecker_on_set_local( - &ctx->typechecker, + ctx->typechecker.OnSetLocal( get_local_var_type_or_any(ctx, &expr->set_local.var)); break; @@ -490,21 +488,20 @@ static void check_expr(Context* ctx, const Expr* expr) { check_align(ctx, &expr->loc, expr->store.align, get_opcode_natural_alignment(expr->store.opcode)); check_offset(ctx, &expr->loc, expr->store.offset); - typechecker_on_store(&ctx->typechecker, expr->store.opcode); + ctx->typechecker.OnStore(expr->store.opcode); break; case ExprType::TeeLocal: - typechecker_on_tee_local( - &ctx->typechecker, + ctx->typechecker.OnTeeLocal( get_local_var_type_or_any(ctx, &expr->tee_local.var)); break; case ExprType::Unary: - typechecker_on_unary(&ctx->typechecker, expr->unary.opcode); + ctx->typechecker.OnUnary(expr->unary.opcode); break; case ExprType::Unreachable: - typechecker_on_unreachable(&ctx->typechecker); + ctx->typechecker.OnUnreachable(); break; } } @@ -536,9 +533,9 @@ static void check_func(Context* ctx, const Location* loc, const Func* func) { } ctx->expr_loc = loc; - typechecker_begin_function(&ctx->typechecker, &func->decl.sig.result_types); + ctx->typechecker.BeginFunction(&func->decl.sig.result_types); check_expr_list(ctx, loc, func->first_expr); - typechecker_end_function(&ctx->typechecker); + ctx->typechecker.EndFunction(); ctx->current_func = nullptr; } @@ -1007,11 +1004,6 @@ Result validate_script(WastLexer* lexer, SourceErrorHandler* error_handler) { Context ctx(error_handler, lexer, script); - TypeCheckerErrorHandler tc_error_handler; - tc_error_handler.on_error = on_typechecker_error; - tc_error_handler.user_data = &ctx; - ctx.typechecker.error_handler = &tc_error_handler; - for (const std::unique_ptr<Command>& command : script->commands) check_command(&ctx, command.get()); return ctx.result; |