diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binary-reader-interp.cc | 62 | ||||
-rw-r--r-- | src/binary-reader-ir.cc | 49 | ||||
-rw-r--r-- | src/binary-reader-logging.cc | 46 | ||||
-rw-r--r-- | src/binary-reader-logging.h | 15 | ||||
-rw-r--r-- | src/binary-reader-nop.h | 24 | ||||
-rw-r--r-- | src/binary-reader-objdump.cc | 35 | ||||
-rw-r--r-- | src/binary-reader-opcnt.cc | 19 | ||||
-rw-r--r-- | src/binary-reader.cc | 92 | ||||
-rw-r--r-- | src/binary-reader.h | 14 | ||||
-rw-r--r-- | src/binary-writer.cc | 35 | ||||
-rw-r--r-- | src/c-writer.cc | 31 | ||||
-rw-r--r-- | src/common.h | 59 | ||||
-rw-r--r-- | src/feature.def | 1 | ||||
-rw-r--r-- | src/interp.cc | 21 | ||||
-rw-r--r-- | src/interp.h | 6 | ||||
-rw-r--r-- | src/ir.h | 6 | ||||
-rw-r--r-- | src/type-checker.cc | 145 | ||||
-rw-r--r-- | src/type-checker.h | 46 | ||||
-rw-r--r-- | src/validator.cc | 70 | ||||
-rw-r--r-- | src/wast-parser.cc | 73 | ||||
-rw-r--r-- | src/wast-parser.h | 1 | ||||
-rw-r--r-- | src/wat-writer.cc | 44 |
22 files changed, 545 insertions, 349 deletions
diff --git a/src/binary-reader-interp.cc b/src/binary-reader-interp.cc index 9f4940a2..fe98947c 100644 --- a/src/binary-reader-interp.cc +++ b/src/binary-reader-interp.cc @@ -155,7 +155,7 @@ class BinaryReaderInterp : public BinaryReaderNop { uint32_t alignment_log2, Address offset) override; wabt::Result OnBinaryExpr(wabt::Opcode opcode) override; - wabt::Result OnBlockExpr(Index num_types, Type* sig_types) override; + wabt::Result OnBlockExpr(Type sig_type) override; wabt::Result OnBrExpr(Index depth) override; wabt::Result OnBrIfExpr(Index depth) override; wabt::Result OnBrTableExpr(Index num_targets, @@ -175,11 +175,11 @@ class BinaryReaderInterp : public BinaryReaderNop { wabt::Result OnGetLocalExpr(Index local_index) override; wabt::Result OnI32ConstExpr(uint32_t value) override; wabt::Result OnI64ConstExpr(uint64_t value) override; - wabt::Result OnIfExpr(Index num_types, Type* sig_types) override; + wabt::Result OnIfExpr(Type sig_type) override; wabt::Result OnLoadExpr(wabt::Opcode opcode, uint32_t alignment_log2, Address offset) override; - wabt::Result OnLoopExpr(Index num_types, Type* sig_types) override; + wabt::Result OnLoopExpr(Type sig_type) override; wabt::Result OnMemoryGrowExpr() override; wabt::Result OnMemorySizeExpr() override; wabt::Result OnNopExpr() override; @@ -226,6 +226,9 @@ class BinaryReaderInterp : public BinaryReaderNop { void PrintError(const char* format, ...); Index TranslateSigIndexToEnv(Index sig_index); + void GetBlockSignature(Type sig_type, + TypeVector* out_param_types, + TypeVector* out_result_types); FuncSignature* GetSignatureByModuleIndex(Index sig_index); Index TranslateFuncIndexToEnv(Index func_index); Index TranslateModuleFuncIndexToDefined(Index func_index); @@ -248,7 +251,7 @@ class BinaryReaderInterp : public BinaryReaderNop { wabt::Result EmitI64(uint64_t value); wabt::Result EmitV128(v128 value); wabt::Result EmitI32At(IstreamOffset offset, uint32_t value); - wabt::Result EmitDropKeep(uint32_t drop, uint8_t keep); + wabt::Result EmitDropKeep(uint32_t drop, uint32_t keep); wabt::Result AppendFixup(IstreamOffsetVectorVector* fixups_vector, Index index); wabt::Result EmitBrOffset(Index depth, IstreamOffset offset); @@ -357,6 +360,19 @@ Index BinaryReaderInterp::TranslateSigIndexToEnv(Index sig_index) { return sig_index_mapping_[sig_index]; } +void BinaryReaderInterp::GetBlockSignature(Type sig_type, + TypeVector* out_param_types, + TypeVector* out_result_types) { + if (IsTypeIndex(sig_type)) { + FuncSignature* func_sig = GetSignatureByModuleIndex(GetTypeIndex(sig_type)); + *out_param_types = func_sig->param_types; + *out_result_types = func_sig->result_types; + } else { + out_param_types->clear(); + *out_result_types = GetInlineTypeVector(sig_type); + } +} + FuncSignature* BinaryReaderInterp::GetSignatureByModuleIndex(Index sig_index) { return env_->GetFuncSignature(TranslateSigIndexToEnv(sig_index)); } @@ -442,16 +458,16 @@ wabt::Result BinaryReaderInterp::EmitI32At(IstreamOffset offset, return EmitDataAt(offset, &value, sizeof(value)); } -wabt::Result BinaryReaderInterp::EmitDropKeep(uint32_t drop, uint8_t keep) { +wabt::Result BinaryReaderInterp::EmitDropKeep(uint32_t drop, uint32_t keep) { assert(drop != UINT32_MAX); - assert(keep <= 1); + assert(keep != UINT32_MAX); if (drop > 0) { if (drop == 1 && keep == 0) { CHECK_RESULT(EmitOpcode(Opcode::Drop)); } else { CHECK_RESULT(EmitOpcode(Opcode::InterpDropKeep)); CHECK_RESULT(EmitI32(drop)); - CHECK_RESULT(EmitI8(keep)); + CHECK_RESULT(EmitI32(keep)); } } return wabt::Result::Ok; @@ -484,8 +500,7 @@ wabt::Result BinaryReaderInterp::GetBrDropKeepCount(Index depth, Index* out_keep_count) { TypeChecker::Label* label; CHECK_RESULT(typechecker_.GetLabel(depth, &label)); - *out_keep_count = - label->label_type != LabelType::Loop ? label->sig.size() : 0; + *out_keep_count = label->br_types().size(); if (typechecker_.IsUnreachable()) { *out_drop_count = 0; } else { @@ -518,7 +533,7 @@ wabt::Result BinaryReaderInterp::EmitBrTableOffset(Index depth) { CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count)); CHECK_RESULT(EmitBrOffset(depth, GetLabel(depth)->offset)); CHECK_RESULT(EmitI32(drop_count)); - CHECK_RESULT(EmitI8(keep_count)); + CHECK_RESULT(EmitI32(keep_count)); return wabt::Result::Ok; } @@ -1103,7 +1118,7 @@ wabt::Result BinaryReaderInterp::BeginFunctionBody(Index index) { for (Type param_type : sig->param_types) func->param_and_local_types.push_back(param_type); - CHECK_RESULT(typechecker_.BeginFunction(&sig->result_types)); + CHECK_RESULT(typechecker_.BeginFunction(sig->result_types)); /* push implicit func label (equivalent to return) */ PushLabel(kInvalidIstreamOffset, kInvalidIstreamOffset); @@ -1253,23 +1268,26 @@ wabt::Result BinaryReaderInterp::OnBinaryExpr(wabt::Opcode opcode) { return wabt::Result::Ok; } -wabt::Result BinaryReaderInterp::OnBlockExpr(Index num_types, Type* sig_types) { - TypeVector sig(sig_types, sig_types + num_types); - CHECK_RESULT(typechecker_.OnBlock(&sig)); +wabt::Result BinaryReaderInterp::OnBlockExpr(Type sig_type) { + TypeVector param_types, result_types; + GetBlockSignature(sig_type, ¶m_types, &result_types); + CHECK_RESULT(typechecker_.OnBlock(param_types, result_types)); PushLabel(kInvalidIstreamOffset, kInvalidIstreamOffset); return wabt::Result::Ok; } -wabt::Result BinaryReaderInterp::OnLoopExpr(Index num_types, Type* sig_types) { - TypeVector sig(sig_types, sig_types + num_types); - CHECK_RESULT(typechecker_.OnLoop(&sig)); +wabt::Result BinaryReaderInterp::OnLoopExpr(Type sig_type) { + TypeVector param_types, result_types; + GetBlockSignature(sig_type, ¶m_types, &result_types); + CHECK_RESULT(typechecker_.OnLoop(param_types, result_types)); PushLabel(GetIstreamOffset(), kInvalidIstreamOffset); return wabt::Result::Ok; } -wabt::Result BinaryReaderInterp::OnIfExpr(Index num_types, Type* sig_types) { - TypeVector sig(sig_types, sig_types + num_types); - CHECK_RESULT(typechecker_.OnIf(&sig)); +wabt::Result BinaryReaderInterp::OnIfExpr(Type sig_type) { + TypeVector param_types, result_types; + GetBlockSignature(sig_type, ¶m_types, &result_types); + CHECK_RESULT(typechecker_.OnIf(param_types, result_types)); CHECK_RESULT(EmitOpcode(Opcode::InterpBrUnless)); IstreamOffset fixup_offset = GetIstreamOffset(); CHECK_RESULT(EmitI32(kInvalidIstreamOffset)); @@ -1349,7 +1367,7 @@ wabt::Result BinaryReaderInterp::OnBrTableExpr(Index num_targets, wabt::Result BinaryReaderInterp::OnCallExpr(Index func_index) { Func* func = GetFuncByModuleIndex(func_index); FuncSignature* sig = env_->GetFuncSignature(func->sig_index); - CHECK_RESULT(typechecker_.OnCall(&sig->param_types, &sig->result_types)); + CHECK_RESULT(typechecker_.OnCall(sig->param_types, sig->result_types)); if (func->is_host) { CHECK_RESULT(EmitOpcode(Opcode::InterpCallHost)); @@ -1369,7 +1387,7 @@ wabt::Result BinaryReaderInterp::OnCallIndirectExpr(Index sig_index) { } FuncSignature* sig = GetSignatureByModuleIndex(sig_index); CHECK_RESULT( - typechecker_.OnCallIndirect(&sig->param_types, &sig->result_types)); + typechecker_.OnCallIndirect(sig->param_types, sig->result_types)); CHECK_RESULT(EmitOpcode(Opcode::CallIndirect)); CHECK_RESULT(EmitI32(module_->table_index)); diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index 030e1e81..3207fc07 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -135,7 +135,7 @@ class BinaryReaderIR : public BinaryReaderNop { uint32_t alignment_log2, Address offset) override; Result OnBinaryExpr(Opcode opcode) override; - Result OnBlockExpr(Index num_types, Type* sig_types) override; + Result OnBlockExpr(Type sig_type) override; Result OnBrExpr(Index depth) override; Result OnBrIfExpr(Index depth) override; Result OnBrTableExpr(Index num_targets, @@ -156,14 +156,12 @@ class BinaryReaderIR : public BinaryReaderNop { Result OnGetLocalExpr(Index local_index) override; Result OnI32ConstExpr(uint32_t value) override; Result OnI64ConstExpr(uint64_t value) override; - Result OnIfExpr(Index num_types, Type* sig_types) override; - Result OnIfExceptExpr(Index num_types, - Type* sig_types, - Index except_index) override; + Result OnIfExpr(Type sig_type) override; + Result OnIfExceptExpr(Type sig_type, Index except_index) override; Result OnLoadExpr(Opcode opcode, uint32_t alignment_log2, Address offset) override; - Result OnLoopExpr(Index num_types, Type* sig_types) override; + Result OnLoopExpr(Type sig_type) override; Result OnMemoryGrowExpr() override; Result OnMemorySizeExpr() override; Result OnNopExpr() override; @@ -177,7 +175,7 @@ class BinaryReaderIR : public BinaryReaderNop { Address offset) override; Result OnThrowExpr(Index except_index) override; Result OnTeeLocalExpr(Index local_index) override; - Result OnTryExpr(Index num_types, Type* sig_types) override; + Result OnTryExpr(Type sig_type) override; Result OnUnaryExpr(Opcode opcode) override; Result OnTernaryExpr(Opcode opcode) override; Result OnUnreachableExpr() override; @@ -233,6 +231,7 @@ class BinaryReaderIR : public BinaryReaderNop { Result TopLabel(LabelNode** label); Result TopLabelExpr(LabelNode** label, Expr** expr); Result AppendExpr(std::unique_ptr<Expr> expr); + void SetBlockDeclaration(BlockDeclaration* decl, Type sig_type); ErrorHandler* error_handler_ = nullptr; Module* module_ = nullptr; @@ -308,6 +307,20 @@ Result BinaryReaderIR::AppendExpr(std::unique_ptr<Expr> expr) { return Result::Ok; } +void BinaryReaderIR::SetBlockDeclaration(BlockDeclaration* decl, + Type sig_type) { + if (IsTypeIndex(sig_type)) { + Index type_index = GetTypeIndex(sig_type); + decl->has_func_type = true; + decl->type_var = Var(type_index); + decl->sig = module_->func_types[type_index]->sig; + } else { + decl->has_func_type = false; + decl->sig.param_types.clear(); + decl->sig.result_types = GetInlineTypeVector(sig_type); + } +} + bool BinaryReaderIR::HandleError(ErrorLevel error_level, Offset offset, const char* message) { @@ -603,9 +616,9 @@ Result BinaryReaderIR::OnBinaryExpr(Opcode opcode) { return AppendExpr(MakeUnique<BinaryExpr>(opcode)); } -Result BinaryReaderIR::OnBlockExpr(Index num_types, Type* sig_types) { +Result BinaryReaderIR::OnBlockExpr(Type sig_type) { auto expr = MakeUnique<BlockExpr>(); - expr->block.sig.assign(sig_types, sig_types + num_types); + SetBlockDeclaration(&expr->block.decl, sig_type); ExprList* expr_list = &expr->block.exprs; CHECK_RESULT(AppendExpr(std::move(expr))); PushLabel(LabelType::Block, expr_list); @@ -748,21 +761,19 @@ Result BinaryReaderIR::OnI64ConstExpr(uint64_t value) { return AppendExpr(MakeUnique<ConstExpr>(Const::I64(value, GetLocation()))); } -Result BinaryReaderIR::OnIfExpr(Index num_types, Type* sig_types) { +Result BinaryReaderIR::OnIfExpr(Type sig_type) { auto expr = MakeUnique<IfExpr>(); - expr->true_.sig.assign(sig_types, sig_types + num_types); + SetBlockDeclaration(&expr->true_.decl, sig_type); ExprList* expr_list = &expr->true_.exprs; CHECK_RESULT(AppendExpr(std::move(expr))); PushLabel(LabelType::If, expr_list); return Result::Ok; } -Result BinaryReaderIR::OnIfExceptExpr(Index num_types, - Type* sig_types, - Index except_index) { +Result BinaryReaderIR::OnIfExceptExpr(Type sig_type, Index except_index) { auto expr = MakeUnique<IfExceptExpr>(); expr->except_var = Var(except_index, GetLocation()); - expr->true_.sig.assign(sig_types, sig_types + num_types); + SetBlockDeclaration(&expr->true_.decl, sig_type); ExprList* expr_list = &expr->true_.exprs; CHECK_RESULT(AppendExpr(std::move(expr))); PushLabel(LabelType::IfExcept, expr_list); @@ -775,9 +786,9 @@ Result BinaryReaderIR::OnLoadExpr(Opcode opcode, return AppendExpr(MakeUnique<LoadExpr>(opcode, 1 << alignment_log2, offset)); } -Result BinaryReaderIR::OnLoopExpr(Index num_types, Type* sig_types) { +Result BinaryReaderIR::OnLoopExpr(Type sig_type) { auto expr = MakeUnique<LoopExpr>(); - expr->block.sig.assign(sig_types, sig_types + num_types); + SetBlockDeclaration(&expr->block.decl, sig_type); ExprList* expr_list = &expr->block.exprs; CHECK_RESULT(AppendExpr(std::move(expr))); PushLabel(LabelType::Loop, expr_list); @@ -831,12 +842,12 @@ Result BinaryReaderIR::OnTeeLocalExpr(Index local_index) { return AppendExpr(MakeUnique<TeeLocalExpr>(Var(local_index, GetLocation()))); } -Result BinaryReaderIR::OnTryExpr(Index num_types, Type* sig_types) { +Result BinaryReaderIR::OnTryExpr(Type sig_type) { auto expr_ptr = MakeUnique<TryExpr>(); // Save expr so it can be used below, after expr_ptr has been moved. TryExpr* expr = expr_ptr.get(); ExprList* expr_list = &expr->block.exprs; - expr->block.sig.assign(sig_types, sig_types + num_types); + SetBlockDeclaration(&expr->block.decl, sig_type); CHECK_RESULT(AppendExpr(std::move(expr_ptr))); PushLabel(LabelType::Try, expr_list, expr); return Result::Ok; diff --git a/src/binary-reader-logging.cc b/src/binary-reader-logging.cc index b1896c73..f730a865 100644 --- a/src/binary-reader-logging.cc +++ b/src/binary-reader-logging.cc @@ -76,10 +76,18 @@ void BinaryReaderLogging::WriteIndent() { } } +void BinaryReaderLogging::LogType(Type type) { + if (IsTypeIndex(type)) { + LOGF_NOINDENT("funcidx[%d]", static_cast<int>(type)); + } else { + LOGF_NOINDENT("%s", GetTypeName(type)); + } +} + void BinaryReaderLogging::LogTypes(Index type_count, Type* types) { LOGF_NOINDENT("["); for (Index i = 0; i < type_count; ++i) { - LOGF_NOINDENT("%s", GetTypeName(types[i])); + LogType(types[i]); if (i != type_count - 1) { LOGF_NOINDENT(", "); } @@ -254,11 +262,11 @@ Result BinaryReaderLogging::OnLocalDecl(Index decl_index, return reader_->OnLocalDecl(decl_index, count, type); } -Result BinaryReaderLogging::OnBlockExpr(Index num_types, Type* sig_types) { +Result BinaryReaderLogging::OnBlockExpr(Type sig_type) { LOGF("OnBlockExpr(sig: "); - LogTypes(num_types, sig_types); + LogType(sig_type); LOGF_NOINDENT(")\n"); - return reader_->OnBlockExpr(num_types, sig_types); + return reader_->OnBlockExpr(sig_type); } Result BinaryReaderLogging::OnBrExpr(Index depth) { @@ -323,34 +331,32 @@ Result BinaryReaderLogging::OnI64ConstExpr(uint64_t value) { return reader_->OnI64ConstExpr(value); } -Result BinaryReaderLogging::OnIfExpr(Index num_types, Type* sig_types) { +Result BinaryReaderLogging::OnIfExpr(Type sig_type) { LOGF("OnIfExpr(sig: "); - LogTypes(num_types, sig_types); + LogType(sig_type); LOGF_NOINDENT(")\n"); - return reader_->OnIfExpr(num_types, sig_types); + return reader_->OnIfExpr(sig_type); } -Result BinaryReaderLogging::OnIfExceptExpr(Index num_types, - Type* sig_types, - Index except_index) { +Result BinaryReaderLogging::OnIfExceptExpr(Type sig_type, Index except_index) { LOGF("OnIfExceptExpr(sig: "); - LogTypes(num_types, sig_types); + LogType(sig_type); LOGF_NOINDENT(", except: %" PRIindex ")\n", except_index); - return reader_->OnIfExceptExpr(num_types, sig_types, except_index); + return reader_->OnIfExceptExpr(sig_type, except_index); } -Result BinaryReaderLogging::OnLoopExpr(Index num_types, Type* sig_types) { +Result BinaryReaderLogging::OnLoopExpr(Type sig_type) { LOGF("OnLoopExpr(sig: "); - LogTypes(num_types, sig_types); + LogType(sig_type); LOGF_NOINDENT(")\n"); - return reader_->OnLoopExpr(num_types, sig_types); + return reader_->OnLoopExpr(sig_type); } -Result BinaryReaderLogging::OnTryExpr(Index num_types, Type* sig_types) { +Result BinaryReaderLogging::OnTryExpr(Type sig_type) { LOGF("OnTryExpr(sig: "); - LogTypes(num_types, sig_types); + LogType(sig_type); LOGF_NOINDENT(")\n"); - return reader_->OnTryExpr(num_types, sig_types); + return reader_->OnTryExpr(sig_type); } Result BinaryReaderLogging::OnSimdLaneOpExpr(Opcode opcode, uint64_t value) { @@ -753,8 +759,8 @@ Result BinaryReaderLogging::OnOpcodeV128(v128 value) { return reader_->OnOpcodeV128(value); } -Result BinaryReaderLogging::OnOpcodeBlockSig(Index num_types, Type* sig_types) { - return reader_->OnOpcodeBlockSig(num_types, sig_types); +Result BinaryReaderLogging::OnOpcodeBlockSig(Type sig_type) { + return reader_->OnOpcodeBlockSig(sig_type); } Result BinaryReaderLogging::OnEndFunc() { diff --git a/src/binary-reader-logging.h b/src/binary-reader-logging.h index 26b38506..d0424954 100644 --- a/src/binary-reader-logging.h +++ b/src/binary-reader-logging.h @@ -133,7 +133,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnOpcodeF32(uint32_t value) override; Result OnOpcodeF64(uint64_t value) override; Result OnOpcodeV128(v128 value) override; - Result OnOpcodeBlockSig(Index num_types, Type* sig_types) override; + Result OnOpcodeBlockSig(Type sig_type) override; Result OnAtomicLoadExpr(Opcode opcode, uint32_t alignment_log2, Address offset) override; @@ -147,7 +147,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate { uint32_t alignment_log2, Address offset) override; Result OnBinaryExpr(Opcode opcode) override; - Result OnBlockExpr(Index num_types, Type* sig_types) override; + Result OnBlockExpr(Type sig_type) override; Result OnBrExpr(Index depth) override; Result OnBrIfExpr(Index depth) override; Result OnBrTableExpr(Index num_targets, @@ -169,14 +169,12 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnGetLocalExpr(Index local_index) override; Result OnI32ConstExpr(uint32_t value) override; Result OnI64ConstExpr(uint64_t value) override; - Result OnIfExpr(Index num_types, Type* sig_types) override; - Result OnIfExceptExpr(Index num_types, - Type* sig_types, - Index except_index) override; + Result OnIfExpr(Type sig_type) override; + Result OnIfExceptExpr(Type sig_type, Index except_index) override; Result OnLoadExpr(Opcode opcode, uint32_t alignment_log2, Address offset) override; - Result OnLoopExpr(Index num_types, Type* sig_types) override; + Result OnLoopExpr(Type sig_type) override; Result OnMemoryGrowExpr() override; Result OnMemorySizeExpr() override; Result OnNopExpr() override; @@ -190,7 +188,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Address offset) override; Result OnTeeLocalExpr(Index local_index) override; Result OnThrowExpr(Index except_index) override; - Result OnTryExpr(Index num_types, Type* sig_types) override; + Result OnTryExpr(Type sig_type) override; Result OnUnaryExpr(Opcode opcode) override; Result OnTernaryExpr(Opcode opcode) override; Result OnUnreachableExpr() override; @@ -300,6 +298,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate { void Indent(); void Dedent(); void WriteIndent(); + void LogType(Type type); void LogTypes(Index type_count, Type* types); void LogTypes(TypeVector& types); diff --git a/src/binary-reader-nop.h b/src/binary-reader-nop.h index 37fa0ff5..a08eddd2 100644 --- a/src/binary-reader-nop.h +++ b/src/binary-reader-nop.h @@ -173,9 +173,7 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnOpcodeF32(uint32_t value) override { return Result::Ok; } Result OnOpcodeF64(uint64_t value) override { return Result::Ok; } Result OnOpcodeV128(v128 value) override { return Result::Ok; } - Result OnOpcodeBlockSig(Index num_types, Type* sig_types) override { - return Result::Ok; - } + Result OnOpcodeBlockSig(Type sig_type) override { return Result::Ok; } Result OnAtomicLoadExpr(Opcode opcode, uint32_t alignment_log2, Address offset) override { @@ -203,9 +201,7 @@ class BinaryReaderNop : public BinaryReaderDelegate { return Result::Ok; } Result OnBinaryExpr(Opcode opcode) override { return Result::Ok; } - Result OnBlockExpr(Index num_types, Type* sig_types) override { - return Result::Ok; - } + Result OnBlockExpr(Type sig_type) override { return Result::Ok; } Result OnBrExpr(Index depth) override { return Result::Ok; } Result OnBrIfExpr(Index depth) override { return Result::Ok; } Result OnBrTableExpr(Index num_targets, @@ -229,12 +225,8 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnGetLocalExpr(Index local_index) override { return Result::Ok; } Result OnI32ConstExpr(uint32_t value) override { return Result::Ok; } Result OnI64ConstExpr(uint64_t value) override { return Result::Ok; } - Result OnIfExpr(Index num_types, Type* sig_types) override { - return Result::Ok; - } - Result OnIfExceptExpr(Index num_types, - Type* sig_types, - Index except_index) override { + Result OnIfExpr(Type sig_type) override { return Result::Ok; } + Result OnIfExceptExpr(Type sig_type, Index except_index) override { return Result::Ok; } Result OnLoadExpr(Opcode opcode, @@ -242,9 +234,7 @@ class BinaryReaderNop : public BinaryReaderDelegate { Address offset) override { return Result::Ok; } - Result OnLoopExpr(Index num_types, Type* sig_types) override { - return Result::Ok; - } + Result OnLoopExpr(Type sig_type) override { return Result::Ok; } Result OnMemoryGrowExpr() override { return Result::Ok; } Result OnMemorySizeExpr() override { return Result::Ok; } Result OnNopExpr() override { return Result::Ok; } @@ -260,9 +250,7 @@ class BinaryReaderNop : public BinaryReaderDelegate { } Result OnTeeLocalExpr(Index local_index) override { return Result::Ok; } Result OnThrowExpr(Index depth) override { return Result::Ok; } - Result OnTryExpr(Index num_types, Type* sig_types) override { - return Result::Ok; - } + Result OnTryExpr(Type sig_type) override { return Result::Ok; } Result OnUnaryExpr(Opcode opcode) override { return Result::Ok; } Result OnTernaryExpr(Opcode opcode) override { return Result::Ok; } Result OnUnreachableExpr() override { return Result::Ok; } diff --git a/src/binary-reader-objdump.cc b/src/binary-reader-objdump.cc index 29117ad8..a9752920 100644 --- a/src/binary-reader-objdump.cc +++ b/src/binary-reader-objdump.cc @@ -327,6 +327,8 @@ class BinaryReaderObjdumpDisassemble : public BinaryReaderObjdumpBase { public: using BinaryReaderObjdumpBase::BinaryReaderObjdumpBase; + std::string BlockSigToString(Type type) const; + Result BeginFunctionBody(Index index) override; Result OnLocalDeclCount(Index count) override; @@ -340,14 +342,12 @@ class BinaryReaderObjdumpDisassemble : public BinaryReaderObjdumpBase { Result OnOpcodeUint64(uint64_t value) override; Result OnOpcodeF32(uint32_t value) override; Result OnOpcodeF64(uint64_t value) override; - Result OnOpcodeBlockSig(Index num_types, Type* sig_types) override; + Result OnOpcodeBlockSig(Type sig_type) override; Result OnBrTableExpr(Index num_targets, Index* target_depths, Index default_target_depth) override; - Result OnIfExceptExpr(Index num_types, - Type* sig_types, - Index except_index) override; + Result OnIfExceptExpr(Type sig_type, Index except_index) override; Result OnEndExpr() override; Result OnEndFunc() override; @@ -362,6 +362,16 @@ class BinaryReaderObjdumpDisassemble : public BinaryReaderObjdumpBase { Index local_index_ = 0; }; +std::string BinaryReaderObjdumpDisassemble::BlockSigToString(Type type) const { + if (IsTypeIndex(type)) { + return StringPrintf("type[%d]", GetTypeIndex(type)); + } else if (type == Type::Void) { + return ""; + } else { + return GetTypeName(type); + } +} + Result BinaryReaderObjdumpDisassemble::OnOpcode(Opcode opcode) { if (options_->debug) { const char* opcode_name = opcode.GetName(); @@ -545,12 +555,11 @@ Result BinaryReaderObjdumpDisassemble::OnBrTableExpr( return Result::Ok; } -Result BinaryReaderObjdumpDisassemble::OnIfExceptExpr(Index num_types, - Type* sig_types, +Result BinaryReaderObjdumpDisassemble::OnIfExceptExpr(Type sig_type, Index except_index) { Offset immediate_len = state->offset - current_opcode_offset; - if (num_types) { - LogOpcode(data_, immediate_len, "%s %u", GetTypeName(*sig_types), + if (sig_type != Type::Void) { + LogOpcode(data_, immediate_len, "%s %u", BlockSigToString(sig_type).c_str(), except_index); } else { LogOpcode(data_, immediate_len, "%u", except_index); @@ -583,12 +592,12 @@ Result BinaryReaderObjdumpDisassemble::BeginFunctionBody(Index index) { return Result::Ok; } -Result BinaryReaderObjdumpDisassemble::OnOpcodeBlockSig(Index num_types, - Type* sig_types) { - if (num_types) { - LogOpcode(data_, 1, "%s", GetTypeName(*sig_types)); +Result BinaryReaderObjdumpDisassemble::OnOpcodeBlockSig(Type sig_type) { + Offset immediate_len = state->offset - current_opcode_offset; + if (sig_type != Type::Void) { + LogOpcode(data_, immediate_len, "%s", BlockSigToString(sig_type).c_str()); } else { - LogOpcode(data_, 1, nullptr); + LogOpcode(data_, immediate_len, nullptr); } indent_level++; return Result::Ok; diff --git a/src/binary-reader-opcnt.cc b/src/binary-reader-opcnt.cc index 9338572c..a5f041d5 100644 --- a/src/binary-reader-opcnt.cc +++ b/src/binary-reader-opcnt.cc @@ -118,11 +118,15 @@ void OpcodeInfo::Write(Stream& stream) { stream, [&stream](uint32_t value) { stream.Writef("%u", value); }); break; - case Kind::BlockSig: - WriteArray<Type>(stream, [&stream](Type type) { - stream.Writef("%s", GetTypeName(type)); - }); + case Kind::BlockSig: { + auto type = *GetData<Type>(); + if (IsTypeIndex(type)) { + stream.Writef(" type:%d", static_cast<int>(type)); + } else if (type != Type::Void) { + stream.Writef(" %s", GetTypeName(type)); + } break; + } case Kind::BrTable: { WriteArray<Index>(stream, [&stream](Index index) { @@ -190,7 +194,7 @@ class BinaryReaderOpcnt : public BinaryReaderNop { Result OnOpcodeUint64(uint64_t value) override; Result OnOpcodeF32(uint32_t value) override; Result OnOpcodeF64(uint64_t value) override; - Result OnOpcodeBlockSig(Index num_types, Type* sig_types) override; + Result OnOpcodeBlockSig(Type sig_type) override; Result OnBrTableExpr(Index num_targets, Index* target_depths, Index default_target_depth) override; @@ -254,9 +258,8 @@ Result BinaryReaderOpcnt::OnOpcodeF64(uint64_t value) { return Emplace(current_opcode_, OpcodeInfo::Kind::Float64, &value); } -Result BinaryReaderOpcnt::OnOpcodeBlockSig(Index num_types, Type* sig_types) { - return Emplace(current_opcode_, OpcodeInfo::Kind::BlockSig, sig_types, - num_types); +Result BinaryReaderOpcnt::OnOpcodeBlockSig(Type sig_type) { + return Emplace(current_opcode_, OpcodeInfo::Kind::BlockSig, &sig_type); } Result BinaryReaderOpcnt::OnBrTableExpr(Index num_targets, diff --git a/src/binary-reader.cc b/src/binary-reader.cc index 5c958f7e..586b3335 100644 --- a/src/binary-reader.cc +++ b/src/binary-reader.cc @@ -105,8 +105,8 @@ class BinaryReader { Result ReadOffset(Offset* offset, const char* desc) WABT_WARN_UNUSED; Result ReadCount(Index* index, const char* desc) WABT_WARN_UNUSED; - bool is_concrete_type(Type); - bool is_inline_sig_type(Type); + bool IsConcreteType(Type); + bool IsBlockType(Type); Index NumTotalFuncs(); Index NumTotalTables(); @@ -145,6 +145,7 @@ class BinaryReader { BinaryReaderLogging logging_delegate_; BinaryReaderDelegate* delegate_ = nullptr; TypeVector param_types_; + TypeVector result_types_; std::vector<Index> target_depths_; const ReadBinaryOptions* options_ = nullptr; BinarySection last_known_section_ = BinarySection::Invalid; @@ -291,8 +292,8 @@ Result BinaryReader::ReadS64Leb128(uint64_t* out_value, const char* desc) { } Result BinaryReader::ReadType(Type* out_value, const char* desc) { - uint8_t type = 0; - CHECK_RESULT(ReadU8(&type, desc)); + uint32_t type = 0; + CHECK_RESULT(ReadS32Leb128(&type, desc)); *out_value = static_cast<Type>(type); return Result::Ok; } @@ -363,7 +364,7 @@ static bool is_valid_external_kind(uint8_t kind) { return kind < kExternalKindCount; } -bool BinaryReader::is_concrete_type(Type type) { +bool BinaryReader::IsConcreteType(Type type) { switch (type) { case Type::I32: case Type::I64: @@ -379,8 +380,16 @@ bool BinaryReader::is_concrete_type(Type type) { } } -bool BinaryReader::is_inline_sig_type(Type type) { - return is_concrete_type(type) || type == Type::Void; +bool BinaryReader::IsBlockType(Type type) { + if (IsConcreteType(type) || type == Type::Void) { + return true; + } + + if (!(options_->features.multi_value_enabled() && IsTypeIndex(type))) { + return false; + } + + return GetTypeIndex(type) < num_signatures_; } Index BinaryReader::NumTotalFuncs() { @@ -523,7 +532,7 @@ Result BinaryReader::ReadGlobalHeader(Type* out_type, bool* out_mutable) { Type global_type = Type::Void; uint8_t mutable_ = 0; CHECK_RESULT(ReadType(&global_type, "global type")); - ERROR_UNLESS(is_concrete_type(global_type), "invalid global type: %#x", + ERROR_UNLESS(IsConcreteType(global_type), "invalid global type: %#x", static_cast<int>(global_type)); CHECK_RESULT(ReadU8(&mutable_, "global mutability")); @@ -549,33 +558,30 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { case Opcode::Block: { Type sig_type; CHECK_RESULT(ReadType(&sig_type, "block signature type")); - ERROR_UNLESS(is_inline_sig_type(sig_type), + ERROR_UNLESS(IsBlockType(sig_type), "expected valid block signature type"); - Index num_types = sig_type == Type::Void ? 0 : 1; - CALLBACK(OnBlockExpr, num_types, &sig_type); - CALLBACK(OnOpcodeBlockSig, num_types, &sig_type); + CALLBACK(OnBlockExpr, sig_type); + CALLBACK(OnOpcodeBlockSig, sig_type); break; } case Opcode::Loop: { Type sig_type; CHECK_RESULT(ReadType(&sig_type, "loop signature type")); - ERROR_UNLESS(is_inline_sig_type(sig_type), + ERROR_UNLESS(IsBlockType(sig_type), "expected valid block signature type"); - Index num_types = sig_type == Type::Void ? 0 : 1; - CALLBACK(OnLoopExpr, num_types, &sig_type); - CALLBACK(OnOpcodeBlockSig, num_types, &sig_type); + CALLBACK(OnLoopExpr, sig_type); + CALLBACK(OnOpcodeBlockSig, sig_type); break; } case Opcode::If: { Type sig_type; CHECK_RESULT(ReadType(&sig_type, "if signature type")); - ERROR_UNLESS(is_inline_sig_type(sig_type), + ERROR_UNLESS(IsBlockType(sig_type), "expected valid block signature type"); - Index num_types = sig_type == Type::Void ? 0 : 1; - CALLBACK(OnIfExpr, num_types, &sig_type); - CALLBACK(OnOpcodeBlockSig, num_types, &sig_type); + CALLBACK(OnIfExpr, sig_type); + CALLBACK(OnOpcodeBlockSig, sig_type); break; } @@ -1124,11 +1130,10 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { ERROR_UNLESS_OPCODE_ENABLED(opcode); Type sig_type; CHECK_RESULT(ReadType(&sig_type, "try signature type")); - ERROR_UNLESS(is_inline_sig_type(sig_type), + ERROR_UNLESS(IsBlockType(sig_type), "expected valid block signature type"); - Index num_types = sig_type == Type::Void ? 0 : 1; - CALLBACK(OnTryExpr, num_types, &sig_type); - CALLBACK(OnOpcodeBlockSig, num_types, &sig_type); + CALLBACK(OnTryExpr, sig_type); + CALLBACK(OnOpcodeBlockSig, sig_type); break; } @@ -1159,12 +1164,11 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { ERROR_UNLESS_OPCODE_ENABLED(opcode); Type sig_type; CHECK_RESULT(ReadType(&sig_type, "if signature type")); - ERROR_UNLESS(is_inline_sig_type(sig_type), + ERROR_UNLESS(IsBlockType(sig_type), "expected valid block signature type"); - Index num_types = sig_type == Type::Void ? 0 : 1; Index except_index; CHECK_RESULT(ReadIndex(&except_index, "exception index")); - CALLBACK(OnIfExceptExpr, num_types, &sig_type, except_index); + CALLBACK(OnIfExceptExpr, sig_type, except_index); break; } @@ -1577,7 +1581,7 @@ Result BinaryReader::ReadExceptionType(TypeVector& sig) { for (Index j = 0; j < num_values; ++j) { Type value_type; CHECK_RESULT(ReadType(&value_type, "exception value type")); - ERROR_UNLESS(is_concrete_type(value_type), + ERROR_UNLESS(IsConcreteType(value_type), "excepted valid exception value type (got %d)", static_cast<int>(value_type)); sig[j] = value_type; @@ -1634,8 +1638,9 @@ Result BinaryReader::ReadTypeSection(Offset section_size) { for (Index i = 0; i < num_signatures_; ++i) { Type form; CHECK_RESULT(ReadType(&form, "type form")); - ERROR_UNLESS(form == Type::Func, "unexpected type form: %d", - static_cast<int>(form)); + ERROR_UNLESS(form == Type::Func, + "unexpected type form (got " PRItypecode ")", + WABT_PRINTF_TYPE_CODE(form)); Index num_params; CHECK_RESULT(ReadCount(&num_params, "function param count")); @@ -1645,27 +1650,32 @@ Result BinaryReader::ReadTypeSection(Offset section_size) { for (Index j = 0; j < num_params; ++j) { Type param_type; CHECK_RESULT(ReadType(¶m_type, "function param type")); - ERROR_UNLESS(is_concrete_type(param_type), - "expected valid param type (got %#x)", - static_cast<int>(param_type)); + ERROR_UNLESS(IsConcreteType(param_type), + "expected valid param type (got " PRItypecode ")", + WABT_PRINTF_TYPE_CODE(param_type)); param_types_[j] = param_type; } Index num_results; CHECK_RESULT(ReadCount(&num_results, "function result count")); - ERROR_UNLESS(num_results <= 1, "result count must be 0 or 1"); + ERROR_UNLESS(num_results <= 1 || options_->features.multi_value_enabled(), + "result count must be 0 or 1"); + + result_types_.resize(num_results); - Type result_type = Type::Void; - if (num_results) { + for (Index j = 0; j < num_results; ++j) { + Type result_type; CHECK_RESULT(ReadType(&result_type, "function result type")); - ERROR_UNLESS(is_concrete_type(result_type), - "expected valid result type: %#x", - static_cast<int>(result_type)); + ERROR_UNLESS(IsConcreteType(result_type), + "expected valid result type (got " PRItypecode ")", + WABT_PRINTF_TYPE_CODE(result_type)); + result_types_[j] = result_type; } Type* param_types = num_params ? param_types_.data() : nullptr; + Type* result_types = num_results ? result_types_.data() : nullptr; - CALLBACK(OnType, i, num_params, param_types, num_results, &result_type); + CALLBACK(OnType, i, num_params, param_types, num_results, result_types); } CALLBACK0(EndTypeSection); return Result::Ok; @@ -1924,7 +1934,7 @@ Result BinaryReader::ReadCodeSection(Offset section_size) { ERROR_UNLESS(num_local_types > 0, "local count must be > 0"); Type local_type; CHECK_RESULT(ReadType(&local_type, "local type")); - ERROR_UNLESS(is_concrete_type(local_type), "expected valid local type"); + ERROR_UNLESS(IsConcreteType(local_type), "expected valid local type"); CALLBACK(OnLocalDecl, k, num_local_types, local_type); } diff --git a/src/binary-reader.h b/src/binary-reader.h index cf09ddba..c64b490e 100644 --- a/src/binary-reader.h +++ b/src/binary-reader.h @@ -182,7 +182,7 @@ class BinaryReaderDelegate { virtual Result OnOpcodeF32(uint32_t value) = 0; virtual Result OnOpcodeF64(uint64_t value) = 0; virtual Result OnOpcodeV128(v128 value) = 0; - virtual Result OnOpcodeBlockSig(Index num_types, Type* sig_types) = 0; + virtual Result OnOpcodeBlockSig(Type sig_type) = 0; virtual Result OnAtomicLoadExpr(Opcode opcode, uint32_t alignment_log2, Address offset) = 0; @@ -202,7 +202,7 @@ class BinaryReaderDelegate { uint32_t alignment_log2, Address offset) = 0; virtual Result OnBinaryExpr(Opcode opcode) = 0; - virtual Result OnBlockExpr(Index num_types, Type* sig_types) = 0; + virtual Result OnBlockExpr(Type sig_type) = 0; virtual Result OnBrExpr(Index depth) = 0; virtual Result OnBrIfExpr(Index depth) = 0; virtual Result OnBrTableExpr(Index num_targets, @@ -224,14 +224,12 @@ class BinaryReaderDelegate { virtual Result OnGetLocalExpr(Index local_index) = 0; virtual Result OnI32ConstExpr(uint32_t value) = 0; virtual Result OnI64ConstExpr(uint64_t value) = 0; - virtual Result OnIfExpr(Index num_types, Type* sig_types) = 0; - virtual Result OnIfExceptExpr(Index num_types, - Type* sig_types, - Index except_index) = 0; + virtual Result OnIfExpr(Type sig_type) = 0; + virtual Result OnIfExceptExpr(Type sig_type, Index except_index) = 0; virtual Result OnLoadExpr(Opcode opcode, uint32_t alignment_log2, Address offset) = 0; - virtual Result OnLoopExpr(Index num_types, Type* sig_types) = 0; + virtual Result OnLoopExpr(Type sig_type) = 0; virtual Result OnMemoryGrowExpr() = 0; virtual Result OnMemorySizeExpr() = 0; virtual Result OnNopExpr() = 0; @@ -245,7 +243,7 @@ class BinaryReaderDelegate { Address offset) = 0; virtual Result OnTeeLocalExpr(Index local_index) = 0; virtual Result OnThrowExpr(Index except_index) = 0; - virtual Result OnTryExpr(Index num_types, Type* sig_types) = 0; + virtual Result OnTryExpr(Type sig_type) = 0; virtual Result OnUnaryExpr(Opcode opcode) = 0; virtual Result OnTernaryExpr(Opcode opcode) = 0; diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 2408c062..24543da2 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -55,7 +55,7 @@ void WriteOpcode(Stream* stream, Opcode opcode) { } void WriteType(Stream* stream, Type type) { - stream->WriteU8Enum(type, GetTypeName(type)); + WriteS32Leb128(stream, type, GetTypeName(type)); } void WriteLimits(Stream* stream, const Limits* limits) { @@ -129,6 +129,7 @@ class BinaryWriter { Index GetLocalIndex(const Func* func, const Var& var); Index GetSymbolIndex(RelocType reloc_type, Index index); void AddReloc(RelocType reloc_type, Index index); + void WriteBlockDecl(const BlockDeclaration& decl); void WriteU32Leb128WithReloc(Index index, const char* desc, RelocType reloc_type); @@ -224,16 +225,20 @@ Offset BinaryWriter::WriteFixupU32Leb128Size(Offset offset, } } -static void write_inline_signature_type(Stream* stream, - const BlockSignature& sig) { - if (sig.size() == 0) { - WriteType(stream, Type::Void); - } else if (sig.size() == 1) { - WriteType(stream, sig[0]); - } else { - /* this is currently unrepresentable */ - stream->WriteU8(0xff, "INVALID INLINE SIGNATURE"); +void BinaryWriter::WriteBlockDecl(const BlockDeclaration& decl) { + if (decl.sig.GetNumParams() == 0 && decl.sig.GetNumResults() <= 1) { + if (decl.sig.GetNumResults() == 0) { + WriteType(stream_, Type::Void); + } else if (decl.sig.GetNumResults() == 1) { + WriteType(stream_, decl.sig.GetResultType(0)); + } + return; } + + Index index = decl.has_func_type ? module_->GetFuncTypeIndex(decl.type_var) + : module_->GetFuncTypeIndex(decl.sig); + assert(index != kInvalidIndex); + WriteS32Leb128(stream_, index, "block type function index"); } void BinaryWriter::WriteSectionHeader(const char* desc, @@ -400,7 +405,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { break; case ExprType::Block: WriteOpcode(stream_, Opcode::Block); - write_inline_signature_type(stream_, cast<BlockExpr>(expr)->block.sig); + WriteBlockDecl(cast<BlockExpr>(expr)->block.decl); WriteExprList(func, cast<BlockExpr>(expr)->block.exprs); WriteOpcode(stream_, Opcode::End); break; @@ -495,7 +500,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { case ExprType::If: { auto* if_expr = cast<IfExpr>(expr); WriteOpcode(stream_, Opcode::If); - write_inline_signature_type(stream_, if_expr->true_.sig); + WriteBlockDecl(if_expr->true_.decl); WriteExprList(func, if_expr->true_.exprs); if (!if_expr->false_.empty()) { WriteOpcode(stream_, Opcode::Else); @@ -507,7 +512,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { case ExprType::IfExcept: { auto* if_except_expr = cast<IfExceptExpr>(expr); WriteOpcode(stream_, Opcode::IfExcept); - write_inline_signature_type(stream_, if_except_expr->true_.sig); + WriteBlockDecl(if_except_expr->true_.decl); Index index = module_->GetExceptIndex(if_except_expr->except_var); WriteU32Leb128(stream_, index, "exception index"); WriteExprList(func, if_except_expr->true_.exprs); @@ -523,7 +528,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { break; case ExprType::Loop: WriteOpcode(stream_, Opcode::Loop); - write_inline_signature_type(stream_, cast<LoopExpr>(expr)->block.sig); + WriteBlockDecl(cast<LoopExpr>(expr)->block.decl); WriteExprList(func, cast<LoopExpr>(expr)->block.exprs); WriteOpcode(stream_, Opcode::End); break; @@ -576,7 +581,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { case ExprType::Try: { auto* try_expr = cast<TryExpr>(expr); WriteOpcode(stream_, Opcode::Try); - write_inline_signature_type(stream_, try_expr->block.sig); + WriteBlockDecl(try_expr->block.decl); WriteExprList(func, try_expr->block.exprs); WriteOpcode(stream_, Opcode::Catch); WriteExprList(func, try_expr->catch_); diff --git a/src/c-writer.cc b/src/c-writer.cc index 4039e6f9..0c969d52 100644 --- a/src/c-writer.cc +++ b/src/c-writer.cc @@ -39,7 +39,7 @@ namespace { struct Label { Label(LabelType label_type, const std::string& name, - const BlockSignature& sig, + const TypeVector& sig, size_t type_stack_size, bool used = false) : label_type(label_type), @@ -54,7 +54,7 @@ struct Label { LabelType label_type; const std::string& name; - const BlockSignature& sig; + const TypeVector& sig; size_t type_stack_size; bool used = false; }; @@ -152,7 +152,7 @@ class CWriter { void PushLabel(LabelType, const std::string& name, - const BlockSignature&, + const FuncSignature&, bool used = false); const Label* FindLabel(const Var& var); bool IsTopLabelUsed() const; @@ -424,9 +424,16 @@ void CWriter::DropTypes(size_t count) { void CWriter::PushLabel(LabelType label_type, const std::string& name, - const BlockSignature& sig, + const FuncSignature& sig, bool used) { - label_stack_.emplace_back(label_type, name, sig, type_stack_.size(), used); + // TODO(binji): Add multi-value support. + if ((label_type != LabelType::Func && sig.GetNumParams() != 0) || + sig.GetNumResults() > 1) { + UNIMPLEMENTED("multi value support"); + } + + label_stack_.emplace_back(label_type, name, sig.result_types, + type_stack_.size(), used); } const Label* CWriter::FindLabel(const Var& var) { @@ -1284,7 +1291,7 @@ void CWriter::Write(const Func& func) { std::string label = DefineLocalScopeName(kImplicitFuncLabel); ResetTypeStack(0); std::string empty; // Must not be temporary, since address is taken by Label. - PushLabel(LabelType::Func, empty, func.decl.sig.result_types); + PushLabel(LabelType::Func, empty, func.decl.sig); Write(func.exprs, LabelDecl(label)); PopLabel(); ResetTypeStack(0); @@ -1400,11 +1407,11 @@ void CWriter::Write(const ExprList& exprs) { const Block& block = cast<BlockExpr>(&expr)->block; std::string label = DefineLocalScopeName(block.label); size_t mark = MarkTypeStack(); - PushLabel(LabelType::Block, block.label, block.sig); + PushLabel(LabelType::Block, block.label, block.decl.sig); Write(block.exprs, LabelDecl(label)); ResetTypeStack(mark); PopLabel(); - PushTypes(block.sig); + PushTypes(block.decl.sig.result_types); break; } @@ -1525,7 +1532,7 @@ void CWriter::Write(const ExprList& exprs) { DropTypes(1); std::string label = DefineLocalScopeName(if_.true_.label); size_t mark = MarkTypeStack(); - PushLabel(LabelType::If, if_.true_.label, if_.true_.sig); + PushLabel(LabelType::If, if_.true_.label, if_.true_.decl.sig); Write(if_.true_.exprs, CloseBrace()); if (!if_.false_.empty()) { ResetTypeStack(mark); @@ -1534,7 +1541,7 @@ void CWriter::Write(const ExprList& exprs) { ResetTypeStack(mark); Write(Newline(), LabelDecl(label)); PopLabel(); - PushTypes(if_.true_.sig); + PushTypes(if_.true_.decl.sig.result_types); break; } @@ -1548,11 +1555,11 @@ void CWriter::Write(const ExprList& exprs) { Write(DefineLocalScopeName(block.label), ": "); Indent(); size_t mark = MarkTypeStack(); - PushLabel(LabelType::Loop, block.label, block.sig); + PushLabel(LabelType::Loop, block.label, block.decl.sig); Write(Newline(), block.exprs); ResetTypeStack(mark); PopLabel(); - PushTypes(block.sig); + PushTypes(block.decl.sig.result_types); Dedent(); } break; diff --git a/src/common.h b/src/common.h index f4c9f5ef..a77b7afd 100644 --- a/src/common.h +++ b/src/common.h @@ -52,6 +52,10 @@ #define WABT_PRINTF_STRING_VIEW_ARG(x) \ static_cast<int>((x).length()), (x).data() +#define PRItypecode "%s%#x" +#define WABT_PRINTF_TYPE_CODE(x) \ + (static_cast<int32_t>(x) < 0 ? "-" : ""), std::abs(static_cast<int32_t>(x)) + #define WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE 128 #define WABT_SNPRINTF_ALLOCA(buffer, len, format) \ va_list args; \ @@ -200,19 +204,19 @@ struct Location { }; }; -/* matches binary format, do not change */ -enum class Type { - I32 = 0x7F, - I64 = 0x7E, - F32 = 0x7D, - F64 = 0x7C, - V128 = 0x7B, - Anyfunc = 0x70, - Func = 0x60, - Void = 0x40, - ExceptRef = 0x3f, - ___ = Void, /* convenient for the opcode table in opcode.h */ - Any = 0, /* Not actually specified, but useful for type-checking */ +// Matches binary format, do not change. +enum class Type : int32_t { + I32 = -0x01, // 0x7f + I64 = -0x02, // 0x7e + F32 = -0x03, // 0x7d + F64 = -0x04, // 0x7c + V128 = -0x05, // 0x7b + Anyfunc = -0x10, // 0x70 + ExceptRef = -0x18, // 0x68 + Func = -0x20, // 0x60 + Void = -0x40, // 0x40 + ___ = Void, // Convenient for the opcode table in opcode.h + Any = 0, // Not actually specified, but useful for type-checking }; typedef std::vector<Type> TypeVector; @@ -355,10 +359,39 @@ static WABT_INLINE const char* GetTypeName(Type type) { return "void"; case Type::Any: return "any"; + default: + return "<type index>"; } WABT_UNREACHABLE; } +static WABT_INLINE bool IsTypeIndex(Type type) { + return static_cast<int32_t>(type) >= 0; +} + +static WABT_INLINE Index GetTypeIndex(Type type) { + assert(IsTypeIndex(type)); + return static_cast<Index>(type); +} + +static WABT_INLINE TypeVector GetInlineTypeVector(Type type) { + assert(!IsTypeIndex(type)); + switch (type) { + case Type::Void: + return TypeVector(); + + case Type::I32: + case Type::I64: + case Type::F32: + case Type::F64: + case Type::V128: + return TypeVector(&type, &type + 1); + + default: + WABT_UNREACHABLE; + } +} + /* error level */ static WABT_INLINE const char* GetErrorLevelName(ErrorLevel error_level) { diff --git a/src/feature.def b/src/feature.def index a74918e1..0e21fadc 100644 --- a/src/feature.def +++ b/src/feature.def @@ -28,3 +28,4 @@ WABT_FEATURE(sat_float_to_int, "saturating-float-to-int", "Saturating float-to-i WABT_FEATURE(sign_extension, "sign-extension", "Sign-extension operators") WABT_FEATURE(simd, "simd", "SIMD support") WABT_FEATURE(threads, "threads", "Threading support") +WABT_FEATURE(multi_value, "multi-value", "Multi-value") diff --git a/src/interp.cc b/src/interp.cc index 1125247c..bca8de7a 100644 --- a/src/interp.cc +++ b/src/interp.cc @@ -647,10 +647,10 @@ inline Opcode ReadOpcode(const uint8_t** pc) { inline void read_table_entry_at(const uint8_t* pc, IstreamOffset* out_offset, uint32_t* out_drop, - uint8_t* out_keep) { + uint32_t* out_keep) { *out_offset = ReadU32At(pc + WABT_TABLE_ENTRY_OFFSET_OFFSET); *out_drop = ReadU32At(pc + WABT_TABLE_ENTRY_DROP_OFFSET); - *out_keep = ReadU8At(pc + WABT_TABLE_ENTRY_KEEP_OFFSET); + *out_keep = ReadU32At(pc + WABT_TABLE_ENTRY_KEEP_OFFSET); } Memory* Thread::ReadMemory(const uint8_t** pc) { @@ -728,10 +728,9 @@ ValueTypeRep<T> Thread::PopRep() { return GetValue<T>(Pop()); } -void Thread::DropKeep(uint32_t drop_count, uint8_t keep_count) { - assert(keep_count <= 1); - if (keep_count == 1) { - Pick(drop_count + 1) = Top(); +void Thread::DropKeep(uint32_t drop_count, uint32_t keep_count) { + for (uint32_t i = 0; i < keep_count; ++i) { + Pick(drop_count + i + 1) = Pick(i + 1); } value_stack_top_ -= drop_count; } @@ -1474,7 +1473,7 @@ Result Thread::Run(int num_instructions) { const uint8_t* entry = istream + table_offset + key_offset; IstreamOffset new_pc; uint32_t drop_count; - uint8_t keep_count; + uint32_t keep_count; read_table_entry_at(entry, &new_pc, &drop_count, &keep_count); DropKeep(drop_count, keep_count); GOTO(new_pc); @@ -2389,7 +2388,7 @@ Result Thread::Run(int num_instructions) { case Opcode::InterpDropKeep: { uint32_t drop_count = ReadU32(&pc); - uint8_t keep_count = *pc++; + uint32_t keep_count = ReadU32(&pc); DropKeep(drop_count, keep_count); break; } @@ -3610,7 +3609,7 @@ void Thread::Trace(Stream* stream) { case Opcode::InterpDropKeep: stream->Writef("%s $%u $%u\n", opcode.GetName(), ReadU32At(pc), - *(pc + 4)); + ReadU32At(pc + 4)); break; case Opcode::V128Const: { @@ -4366,7 +4365,7 @@ void Environment::Disassemble(Stream* stream, case Opcode::InterpDropKeep: { uint32_t drop = ReadU32(&pc); - uint8_t keep = *pc++; + uint32_t keep = ReadU32(&pc); stream->Writef("%s $%u $%u\n", opcode.GetName(), drop, keep); break; } @@ -4382,7 +4381,7 @@ void Environment::Disassemble(Stream* stream, stream->Writef("%4" PRIzd "| ", pc - istream); IstreamOffset offset; uint32_t drop; - uint8_t keep; + uint32_t keep; read_table_entry_at(pc, &offset, &drop, &keep); stream->Writef(" entry %" PRIindex ": offset: %u drop: %u keep: %u\n", diff --git a/src/interp.h b/src/interp.h index 48863deb..dcbf9385 100644 --- a/src/interp.h +++ b/src/interp.h @@ -85,10 +85,10 @@ static const IstreamOffset kInvalidIstreamOffset = ~0; // struct { // IstreamOffset offset; // uint32_t drop_count; -// uint8_t keep_count; +// uint32_t keep_count; // }; #define WABT_TABLE_ENTRY_SIZE \ - (sizeof(IstreamOffset) + sizeof(uint32_t) + sizeof(uint8_t)) + (sizeof(IstreamOffset) + sizeof(uint32_t) + sizeof(uint32_t)) #define WABT_TABLE_ENTRY_OFFSET_OFFSET 0 #define WABT_TABLE_ENTRY_DROP_OFFSET sizeof(IstreamOffset) #define WABT_TABLE_ENTRY_KEEP_OFFSET (sizeof(IstreamOffset) + sizeof(uint32_t)) @@ -522,7 +522,7 @@ class Thread { template <typename T> ValueTypeRep<T> PopRep(); - void DropKeep(uint32_t drop_count, uint8_t keep_count); + void DropKeep(uint32_t drop_count, uint32_t keep_count); Result PushCall(const uint8_t* pc) WABT_WARN_UNUSED; IstreamOffset PopCall(); @@ -203,17 +203,17 @@ enum class ExprType { const char* GetExprTypeName(ExprType type); -typedef TypeVector BlockSignature; - class Expr; typedef intrusive_list<Expr> ExprList; +typedef FuncDeclaration BlockDeclaration; + struct Block { Block() = default; explicit Block(ExprList exprs) : exprs(std::move(exprs)) {} std::string label; - BlockSignature sig; + BlockDeclaration decl; ExprList exprs; Location end_loc; }; diff --git a/src/type-checker.cc b/src/type-checker.cc index ac9b79ed..a1e0c28f 100644 --- a/src/type-checker.cc +++ b/src/type-checker.cc @@ -21,10 +21,12 @@ namespace wabt { TypeChecker::Label::Label(LabelType label_type, - const TypeVector& sig, + const TypeVector& param_types, + const TypeVector& result_types, size_t limit) : label_type(label_type), - sig(sig), + param_types(param_types), + result_types(result_types), type_stack_limit(limit), unreachable(false) {} @@ -74,8 +76,11 @@ Result TypeChecker::SetUnreachable() { return Result::Ok; } -void TypeChecker::PushLabel(LabelType label_type, const TypeVector& sig) { - label_stack_.emplace_back(label_type, sig, type_stack_.size()); +void TypeChecker::PushLabel(LabelType label_type, + const TypeVector& param_types, + const TypeVector& result_types) { + label_stack_.emplace_back(label_type, param_types, result_types, + type_stack_.size()); } Result TypeChecker::PopLabel() { @@ -109,11 +114,8 @@ 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) { - ResetTypeStackToLabel(label); - return Result::Ok; - } - return Result::Error; + ResetTypeStackToLabel(label); + return label->unreachable ? Result::Ok : Result::Error; } type_stack_.erase(type_stack_.end() - drop_count, type_stack_.end()); return Result::Ok; @@ -147,18 +149,18 @@ Result TypeChecker::CheckType(Type actual, Type expected) { : Result::Error; } -Result TypeChecker::CheckSignature(const TypeVector& sig) { +Result TypeChecker::CheckSignature(const TypeVector& sig, const char* desc) { Result result = Result::Ok; for (size_t i = 0; i < sig.size(); ++i) { result |= PeekAndCheckType(sig.size() - i - 1, sig[i]); } + PrintStackIfFailed(result, desc, sig); return result; } Result TypeChecker::PopAndCheckSignature(const TypeVector& sig, const char* desc) { - Result result = CheckSignature(sig); - PrintStackIfFailed(result, desc, sig); + Result result = CheckSignature(sig, desc); result |= DropTypes(sig.size()); return result; } @@ -166,8 +168,7 @@ Result TypeChecker::PopAndCheckSignature(const TypeVector& sig, Result TypeChecker::PopAndCheckCall(const TypeVector& param_types, const TypeVector& result_types, const char* desc) { - Result result = CheckSignature(param_types); - PrintStackIfFailed(result, desc, param_types); + Result result = CheckSignature(param_types, desc); result |= DropTypes(param_types.size()); PushTypes(result_types); return result; @@ -291,10 +292,10 @@ void TypeChecker::PrintStackIfFailed(Result result, PrintError("%s", message.c_str()); } -Result TypeChecker::BeginFunction(const TypeVector* sig) { +Result TypeChecker::BeginFunction(const TypeVector& sig) { type_stack_.clear(); label_stack_.clear(); - PushLabel(LabelType::Func, *sig); + PushLabel(LabelType::Func, TypeVector(), sig); return Result::Ok; } @@ -326,19 +327,19 @@ Result TypeChecker::OnBinary(Opcode opcode) { return CheckOpcode2(opcode); } -Result TypeChecker::OnBlock(const TypeVector* sig) { - PushLabel(LabelType::Block, *sig); - return Result::Ok; +Result TypeChecker::OnBlock(const TypeVector& param_types, + const TypeVector& result_types) { + Result result = PopAndCheckSignature(param_types, "block"); + PushLabel(LabelType::Block, param_types, result_types); + PushTypes(param_types); + return result; } Result TypeChecker::OnBr(Index depth) { Result result = Result::Ok; Label* label; CHECK_RESULT(GetLabel(depth, &label)); - if (label->label_type != LabelType::Loop) { - result |= CheckSignature(label->sig); - } - PrintStackIfFailed(result, "br", label->sig); + result |= CheckSignature(label->br_types(), "br"); CHECK_RESULT(SetUnreachable()); return result; } @@ -347,15 +348,13 @@ Result TypeChecker::OnBrIf(Index depth) { Result result = PopAndCheck1Type(Type::I32, "br_if"); Label* label; CHECK_RESULT(GetLabel(depth, &label)); - if (label->label_type != LabelType::Loop) { - result |= PopAndCheckSignature(label->sig, "br_if"); - PushTypes(label->sig); - } + result |= PopAndCheckSignature(label->br_types(), "br_if"); + PushTypes(label->br_types()); return result; } Result TypeChecker::BeginBrTable() { - br_table_sig_ = Type::Any; + br_table_sig_ = nullptr; return PopAndCheck1Type(Type::I32, "br_table"); } @@ -363,25 +362,20 @@ Result TypeChecker::OnBrTableTarget(Index depth) { Result result = Result::Ok; Label* label; CHECK_RESULT(GetLabel(depth, &label)); - Type label_sig; - if (label->label_type == LabelType::Loop) { - label_sig = Type::Void; - } else { - assert(label->sig.size() <= 1); - label_sig = label->sig.size() == 0 ? Type::Void : label->sig[0]; - - result |= CheckSignature(label->sig); - PrintStackIfFailed(result, "br_table", label_sig); - } + TypeVector& label_sig = label->br_types(); + result |= CheckSignature(label_sig, "br_table"); // Make sure this label's signature is consistent with the previous labels' // signatures. - if (Failed(CheckType(br_table_sig_, label_sig))) { + if (br_table_sig_ == nullptr) { + br_table_sig_ = &label_sig; + } + if (*br_table_sig_ != label_sig) { result |= Result::Error; PrintError("br_table labels have inconsistent types: expected %s, got %s", - GetTypeName(br_table_sig_), GetTypeName(label_sig)); + TypesToString(*br_table_sig_).c_str(), + TypesToString(label_sig).c_str()); } - br_table_sig_ = label_sig; return result; } @@ -390,15 +384,15 @@ Result TypeChecker::EndBrTable() { return SetUnreachable(); } -Result TypeChecker::OnCall(const TypeVector* param_types, - const TypeVector* result_types) { - return PopAndCheckCall(*param_types, *result_types, "call"); +Result TypeChecker::OnCall(const TypeVector& param_types, + const TypeVector& result_types) { + return PopAndCheckCall(param_types, result_types, "call"); } -Result TypeChecker::OnCallIndirect(const TypeVector* param_types, - const TypeVector* result_types) { +Result TypeChecker::OnCallIndirect(const TypeVector& param_types, + const TypeVector& result_types) { Result result = PopAndCheck1Type(Type::I32, "call_indirect"); - result |= PopAndCheckCall(*param_types, *result_types, "call_indirect"); + result |= PopAndCheckCall(param_types, result_types, "call_indirect"); return result; } @@ -411,7 +405,7 @@ Result TypeChecker::OnCatch() { Label* label; CHECK_RESULT(TopLabel(&label)); result |= CheckLabelType(label, LabelType::Try); - result |= PopAndCheckSignature(label->sig, "try block"); + result |= PopAndCheckSignature(label->result_types, "try block"); result |= CheckTypeStackEnd("try block"); ResetTypeStackToLabel(label); label->label_type = LabelType::Catch; @@ -441,9 +435,10 @@ Result TypeChecker::OnElse() { Label* label; CHECK_RESULT(TopLabel(&label)); result |= CheckLabelType(label, LabelType::If); - result |= PopAndCheckSignature(label->sig, "if true branch"); + result |= PopAndCheckSignature(label->result_types, "if true branch"); result |= CheckTypeStackEnd("if true branch"); ResetTypeStackToLabel(label); + PushTypes(label->param_types); label->label_type = LabelType::Else; label->unreachable = false; return result; @@ -453,10 +448,10 @@ Result TypeChecker::OnEnd(Label* label, const char* sig_desc, const char* end_desc) { Result result = Result::Ok; - result |= PopAndCheckSignature(label->sig, sig_desc); + result |= PopAndCheckSignature(label->result_types, sig_desc); result |= CheckTypeStackEnd(end_desc); ResetTypeStackToLabel(label); - PushTypes(label->sig); + PushTypes(label->result_types); PopLabel(); return result; } @@ -478,8 +473,8 @@ Result TypeChecker::OnEnd() { assert(static_cast<int>(label->label_type) < kLabelTypeCount); if (label->label_type == LabelType::If || label->label_type == LabelType::IfExcept) { - if (label->sig.size() != 0) { - PrintError("if without else cannot have type signature."); + if (label->result_types.size() != 0) { + PrintError("if without else cannot have results."); result = Result::Error; } } @@ -488,17 +483,25 @@ Result TypeChecker::OnEnd() { return result; } -Result TypeChecker::OnIf(const TypeVector* sig) { +Result TypeChecker::OnIf(const TypeVector& param_types, + const TypeVector& result_types) { Result result = PopAndCheck1Type(Type::I32, "if"); - PushLabel(LabelType::If, *sig); + result |= PopAndCheckSignature(param_types, "if"); + PushLabel(LabelType::If, param_types, result_types); + PushTypes(param_types); return result; } -Result TypeChecker::OnIfExcept(const TypeVector* sig, - const TypeVector* except_sig) { +Result TypeChecker::OnIfExcept(const TypeVector& param_types, + const TypeVector& result_types, + const TypeVector& except_sig) { Result result = PopAndCheck1Type(Type::ExceptRef, "if_except"); - PushLabel(LabelType::IfExcept, *sig); - PushTypes(*except_sig); + result |= PopAndCheckSignature(param_types, "if_except"); + PushLabel(LabelType::IfExcept, param_types, result_types); + // TODO(binji): Not quite sure how multi-value and exception proposals are + // meant to interact here. + PushTypes(param_types); + PushTypes(except_sig); return result; } @@ -516,9 +519,12 @@ Result TypeChecker::OnLoad(Opcode opcode) { return CheckOpcode1(opcode); } -Result TypeChecker::OnLoop(const TypeVector* sig) { - PushLabel(LabelType::Loop, *sig); - return Result::Ok; +Result TypeChecker::OnLoop(const TypeVector& param_types, + const TypeVector& result_types) { + Result result = PopAndCheckSignature(param_types, "loop"); + PushLabel(LabelType::Loop, param_types, result_types); + PushTypes(param_types); + return result; } Result TypeChecker::OnMemoryGrow() { @@ -536,9 +542,9 @@ Result TypeChecker::OnRethrow() { return result; } -Result TypeChecker::OnThrow(const TypeVector* sig) { +Result TypeChecker::OnThrow(const TypeVector& sig) { Result result = Result::Ok; - result |= PopAndCheckSignature(*sig, "throw"); + result |= PopAndCheckSignature(sig, "throw"); CHECK_RESULT(SetUnreachable()); return result; } @@ -547,7 +553,7 @@ Result TypeChecker::OnReturn() { Result result = Result::Ok; Label* func_label; CHECK_RESULT(GetLabel(label_stack_.size() - 1, &func_label)); - result |= PopAndCheckSignature(func_label->sig, "return"); + result |= PopAndCheckSignature(func_label->result_types, "return"); CHECK_RESULT(SetUnreachable()); return result; } @@ -576,9 +582,12 @@ Result TypeChecker::OnStore(Opcode opcode) { return CheckOpcode2(opcode); } -Result TypeChecker::OnTry(const TypeVector* sig) { - PushLabel(LabelType::Try, *sig); - return Result::Ok; +Result TypeChecker::OnTry(const TypeVector& param_types, + const TypeVector& result_types) { + Result result = PopAndCheckSignature(param_types, "try"); + PushLabel(LabelType::Try, param_types, result_types); + PushTypes(param_types); + return result; } Result TypeChecker::OnTeeLocal(Type type) { diff --git a/src/type-checker.h b/src/type-checker.h index edd45d07..e142ce1c 100644 --- a/src/type-checker.h +++ b/src/type-checker.h @@ -30,10 +30,18 @@ class TypeChecker { typedef std::function<void(const char* msg)> ErrorCallback; struct Label { - Label(LabelType, const TypeVector& sig, size_t limit); + Label(LabelType, + const TypeVector& param_types, + const TypeVector& result_types, + size_t limit); + + TypeVector& br_types() { + return label_type == LabelType::Loop ? param_types : result_types; + } LabelType label_type; - TypeVector sig; + TypeVector param_types; + TypeVector result_types; size_t type_stack_limit; bool unreachable; }; @@ -50,7 +58,7 @@ class TypeChecker { bool IsUnreachable(); Result GetLabel(Index depth, Label** out_label); - Result BeginFunction(const TypeVector* sig); + Result BeginFunction(const TypeVector& sig); Result OnAtomicLoad(Opcode); Result OnAtomicStore(Opcode); Result OnAtomicRmw(Opcode); @@ -58,15 +66,15 @@ class TypeChecker { Result OnAtomicWait(Opcode); Result OnAtomicWake(Opcode); Result OnBinary(Opcode); - Result OnBlock(const TypeVector* sig); + Result OnBlock(const TypeVector& param_types, const TypeVector& result_types); 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 OnCall(const TypeVector& param_types, const TypeVector& result_types); + Result OnCallIndirect(const TypeVector& param_types, + const TypeVector& result_types); Result OnCatch(); Result OnCompare(Opcode); Result OnConst(Type); @@ -76,10 +84,12 @@ class TypeChecker { Result OnEnd(); Result OnGetGlobal(Type); Result OnGetLocal(Type); - Result OnIf(const TypeVector* sig); - Result OnIfExcept(const TypeVector* sig, const TypeVector* except_sig); + Result OnIf(const TypeVector& param_types, const TypeVector& result_types); + Result OnIfExcept(const TypeVector& param_types, + const TypeVector& result_types, + const TypeVector& except_sig); Result OnLoad(Opcode); - Result OnLoop(const TypeVector* sig); + Result OnLoop(const TypeVector& param_types, const TypeVector& result_types); Result OnMemoryGrow(); Result OnMemorySize(); Result OnRethrow(); @@ -92,8 +102,8 @@ class TypeChecker { Result OnStore(Opcode); Result OnTeeLocal(Type); Result OnTernary(Opcode); - Result OnThrow(const TypeVector* sig); - Result OnTry(const TypeVector* sig); + Result OnThrow(const TypeVector& sig); + Result OnTry(const TypeVector& param_types, const TypeVector& result_types); Result OnUnary(Opcode); Result OnUnreachable(); Result EndFunction(); @@ -103,7 +113,9 @@ class TypeChecker { Result TopLabel(Label** out_label); void ResetTypeStackToLabel(Label* label); Result SetUnreachable(); - void PushLabel(LabelType label_type, const TypeVector& sig); + void PushLabel(LabelType label_type, + const TypeVector& param_types, + const TypeVector& result_types); Result PopLabel(); Result CheckLabelType(Label* label, LabelType label_type); Result PeekType(Index depth, Type* out_type); @@ -113,7 +125,7 @@ class TypeChecker { void PushTypes(const TypeVector& types); Result CheckTypeStackEnd(const char* desc); Result CheckType(Type actual, Type expected); - Result CheckSignature(const TypeVector& sig); + 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, @@ -143,9 +155,9 @@ class TypeChecker { 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; + // Cache the expected br_table signature. It will be initialized to `nullptr` + // to represent "any". + TypeVector* br_table_sig_ = nullptr; }; } // namespace wabt diff --git a/src/validator.cc b/src/validator.cc index e505855c..880caca9 100644 --- a/src/validator.cc +++ b/src/validator.cc @@ -163,9 +163,9 @@ class Validator : public ExprVisitor::Delegate { void CheckExprList(const Location* loc, const ExprList& exprs); bool CheckHasMemory(const Location* loc, Opcode opcode); void CheckHasSharedMemory(const Location* loc, Opcode opcode); - void CheckBlockSig(const Location* loc, - Opcode opcode, - const BlockSignature* sig); + void CheckBlockDeclaration(const Location* loc, + Opcode opcode, + const BlockDeclaration* decl); template <typename T> void CheckAtomicExpr(const T* expr, Result (TypeChecker::*func)(Opcode)); void CheckFuncSignature(const Location* loc, const FuncDeclaration& decl); @@ -488,14 +488,27 @@ void Validator::CheckHasSharedMemory(const Location* loc, Opcode opcode) { } } -void Validator::CheckBlockSig(const Location* loc, - Opcode opcode, - const BlockSignature* sig) { - if (sig->size() > 1) { - PrintError(loc, - "multiple %s signature result types not currently supported.", +void Validator::CheckBlockDeclaration(const Location* loc, + Opcode opcode, + const BlockDeclaration* decl) { + if (decl->sig.GetNumParams() > 0 && + !options_->features.multi_value_enabled()) { + PrintError(loc, "%s params not currently supported.", opcode.GetName()); + } + if (decl->sig.GetNumResults() > 1 && + !options_->features.multi_value_enabled()) { + PrintError(loc, "multiple %s results not currently supported.", opcode.GetName()); } + if (decl->has_func_type) { + const FuncType* func_type; + if (Succeeded(CheckFuncTypeVar(&decl->type_var, &func_type))) { + CheckTypes(loc, decl->sig.result_types, func_type->sig.result_types, + opcode.GetName(), "result"); + CheckTypes(loc, decl->sig.param_types, func_type->sig.param_types, + opcode.GetName(), "argument"); + } + } } template <typename T> @@ -515,8 +528,9 @@ Result Validator::OnBinaryExpr(BinaryExpr* expr) { Result Validator::BeginBlockExpr(BlockExpr* expr) { expr_loc_ = &expr->loc; - CheckBlockSig(&expr->loc, Opcode::Block, &expr->block.sig); - typechecker_.OnBlock(&expr->block.sig); + CheckBlockDeclaration(&expr->loc, Opcode::Block, &expr->block.decl); + typechecker_.OnBlock(expr->block.decl.sig.param_types, + expr->block.decl.sig.result_types); return Result::Ok; } @@ -553,8 +567,8 @@ 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); + typechecker_.OnCall(callee->decl.sig.param_types, + callee->decl.sig.result_types); } return Result::Ok; } @@ -568,8 +582,8 @@ Result Validator::OnCallIndirectExpr(CallIndirectExpr* expr) { const FuncType* func_type; CheckFuncTypeVar(&expr->decl.type_var, &func_type); } - typechecker_.OnCallIndirect(&expr->decl.sig.param_types, - &expr->decl.sig.result_types); + typechecker_.OnCallIndirect(expr->decl.sig.param_types, + expr->decl.sig.result_types); return Result::Ok; } @@ -611,8 +625,9 @@ Result Validator::OnGetLocalExpr(GetLocalExpr* expr) { Result Validator::BeginIfExpr(IfExpr* expr) { expr_loc_ = &expr->loc; - CheckBlockSig(&expr->loc, Opcode::If, &expr->true_.sig); - typechecker_.OnIf(&expr->true_.sig); + CheckBlockDeclaration(&expr->loc, Opcode::If, &expr->true_.decl); + typechecker_.OnIf(expr->true_.decl.sig.param_types, + expr->true_.decl.sig.result_types); return Result::Ok; } @@ -632,13 +647,14 @@ Result Validator::EndIfExpr(IfExpr* expr) { Result Validator::BeginIfExceptExpr(IfExceptExpr* expr) { expr_loc_ = &expr->loc; - CheckBlockSig(&expr->loc, Opcode::IfExcept, &expr->true_.sig); + CheckBlockDeclaration(&expr->loc, Opcode::IfExcept, &expr->true_.decl); const Exception* except; TypeVector except_sig; if (Succeeded(CheckExceptVar(&expr->except_var, &except))) { except_sig = except->sig; } - typechecker_.OnIfExcept(&expr->true_.sig, &except_sig); + typechecker_.OnIfExcept(expr->true_.decl.sig.param_types, + expr->true_.decl.sig.result_types, except_sig); return Result::Ok; } @@ -667,8 +683,9 @@ Result Validator::OnLoadExpr(LoadExpr* expr) { Result Validator::BeginLoopExpr(LoopExpr* expr) { expr_loc_ = &expr->loc; - CheckBlockSig(&expr->loc, Opcode::Loop, &expr->block.sig); - typechecker_.OnLoop(&expr->block.sig); + CheckBlockDeclaration(&expr->loc, Opcode::Loop, &expr->block.decl); + typechecker_.OnLoop(expr->block.decl.sig.param_types, + expr->block.decl.sig.result_types); return Result::Ok; } @@ -750,8 +767,9 @@ Result Validator::OnUnreachableExpr(UnreachableExpr* expr) { Result Validator::BeginTryExpr(TryExpr* expr) { expr_loc_ = &expr->loc; - CheckBlockSig(&expr->loc, Opcode::Try, &expr->block.sig); - typechecker_.OnTry(&expr->block.sig); + CheckBlockDeclaration(&expr->loc, Opcode::Try, &expr->block.decl); + typechecker_.OnTry(expr->block.decl.sig.param_types, + expr->block.decl.sig.result_types); return Result::Ok; } @@ -770,7 +788,7 @@ Result Validator::OnThrowExpr(ThrowExpr* expr) { expr_loc_ = &expr->loc; const Exception* except; if (Succeeded(CheckExceptVar(&expr->var, &except))) { - typechecker_.OnThrow(&except->sig); + typechecker_.OnThrow(except->sig); } return Result::Ok; } @@ -851,14 +869,14 @@ void Validator::CheckFuncSignature(const Location* loc, void Validator::CheckFunc(const Location* loc, const Func* func) { current_func_ = func; CheckFuncSignature(loc, func->decl); - if (func->GetNumResults() > 1) { + if (!options_->features.multi_value_enabled() && func->GetNumResults() > 1) { PrintError(loc, "multiple result values not currently supported."); // Don't run any other checks, the won't test the result_type properly. return; } expr_loc_ = loc; - typechecker_.BeginFunction(&func->decl.sig.result_types); + typechecker_.BeginFunction(func->decl.sig.result_types); CheckExprList(loc, func->exprs); typechecker_.EndFunction(); current_func_ = nullptr; diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 6464e657..2e1d1f1d 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -288,6 +288,37 @@ class ResolveFuncTypesExprVisitorDelegate : public ExprVisitor::DelegateNop { explicit ResolveFuncTypesExprVisitorDelegate(Module* module) : module_(module) {} + void ResolveBlockDeclaration(const Location& loc, BlockDeclaration* decl) { + if (decl->GetNumParams() != 0 || decl->GetNumResults() > 1) { + ResolveFuncType(loc, module_, decl); + } + } + + Result BeginBlockExpr(BlockExpr* expr) override { + ResolveBlockDeclaration(expr->loc, &expr->block.decl); + return Result::Ok; + } + + Result BeginIfExpr(IfExpr* expr) override { + ResolveBlockDeclaration(expr->loc, &expr->true_.decl); + return Result::Ok; + } + + Result BeginIfExceptExpr(IfExceptExpr* expr) override { + ResolveBlockDeclaration(expr->loc, &expr->true_.decl); + return Result::Ok; + } + + Result BeginLoopExpr(LoopExpr* expr) override { + ResolveBlockDeclaration(expr->loc, &expr->block.decl); + return Result::Ok; + } + + Result BeginTryExpr(TryExpr* expr) override { + ResolveBlockDeclaration(expr->loc, &expr->block.decl); + return Result::Ok; + } + Result OnCallIndirectExpr(CallIndirectExpr* expr) override { ResolveFuncType(expr->loc, module_, &expr->decl); return Result::Ok; @@ -1784,9 +1815,20 @@ Result WastParser::ParseEndLabelOpt(const std::string& begin_label) { return Result::Ok; } +Result WastParser::ParseBlockDeclaration(BlockDeclaration* decl) { + WABT_TRACE(ParseBlockDeclaration); + FuncDeclaration func_decl; + CHECK_RESULT(ParseTypeUseOpt(&func_decl)); + CHECK_RESULT(ParseUnboundFuncSignature(&func_decl.sig)); + decl->has_func_type = func_decl.has_func_type; + decl->type_var = func_decl.type_var; + decl->sig = func_decl.sig; + return Result::Ok; +} + Result WastParser::ParseBlock(Block* block) { WABT_TRACE(ParseBlock); - CHECK_RESULT(ParseResultList(&block->sig)); + CHECK_RESULT(ParseBlockDeclaration(&block->decl)); CHECK_RESULT(ParseInstrList(&block->exprs)); block->end_loc = GetLocation(); return Result::Ok; @@ -1805,22 +1847,33 @@ Result WastParser::ParseIfExceptHeader(IfExceptExpr* expr) { // 3. if_except $label $except/<num> ... // 4. if_except (result...) $except/<num> ... // 5. if_except $label (result...) $except/<num> ... + // + // With the multi-value proposal, `block_type` can be (param...) (result...), + // so there are more forms: + // + // 6. if_except (param...) $except/<num> ... + // 7. if_except (param...) (result...) $except/<num> ... + // 8. if_except $label (param...) $except/<num> ... + // 9. if_except $label (param...) (result...) $except/<num> ... + // + // This case is handled by ParseBlockDeclaration, but it means we also need + // to check for the `param` token here. - if (PeekMatchLpar(TokenType::Result)) { - // Case 4. - CHECK_RESULT(ParseResultList(&expr->true_.sig)); + if (PeekMatchLpar(TokenType::Result) || PeekMatchLpar(TokenType::Param)) { + // Cases 4, 6, 7. + CHECK_RESULT(ParseBlockDeclaration(&expr->true_.decl)); CHECK_RESULT(ParseVar(&expr->except_var)); } else if (PeekMatch(TokenType::Nat)) { // Case 1. CHECK_RESULT(ParseVar(&expr->except_var)); } else if (PeekMatch(TokenType::Var)) { - // Cases 2, 3, 5. + // Cases 2, 3, 5, 8, 9. Var var; CHECK_RESULT(ParseVar(&var)); - if (PeekMatchLpar(TokenType::Result)) { - // Case 5. + if (PeekMatchLpar(TokenType::Result) || PeekMatchLpar(TokenType::Param)) { + // Cases 5, 8, 9. expr->true_.label = var.name(); - CHECK_RESULT(ParseResultList(&expr->true_.sig)); + CHECK_RESULT(ParseBlockDeclaration(&expr->true_.decl)); CHECK_RESULT(ParseVar(&expr->except_var)); } else if (ParseVarOpt(&expr->except_var, Var())) { // Case 3. @@ -1893,7 +1946,7 @@ Result WastParser::ParseExpr(ExprList* exprs) { auto expr = MakeUnique<IfExpr>(loc); CHECK_RESULT(ParseLabelOpt(&expr->true_.label)); - CHECK_RESULT(ParseResultList(&expr->true_.sig)); + CHECK_RESULT(ParseBlockDeclaration(&expr->true_.decl)); if (PeekMatchExpr()) { ExprList cond; @@ -1968,7 +2021,7 @@ Result WastParser::ParseExpr(ExprList* exprs) { auto expr = MakeUnique<TryExpr>(loc); CHECK_RESULT(ParseLabelOpt(&expr->block.label)); - CHECK_RESULT(ParseResultList(&expr->block.sig)); + CHECK_RESULT(ParseBlockDeclaration(&expr->block.decl)); CHECK_RESULT(ParseInstrList(&expr->block.exprs)); expr->block.end_loc = GetLocation(); EXPECT(Lpar); diff --git a/src/wast-parser.h b/src/wast-parser.h index bdecdec9..3a9f0413 100644 --- a/src/wast-parser.h +++ b/src/wast-parser.h @@ -162,6 +162,7 @@ class WastParser { Result ParseBlockInstr(std::unique_ptr<Expr>*); Result ParseLabelOpt(std::string*); Result ParseEndLabelOpt(const std::string&); + Result ParseBlockDeclaration(BlockDeclaration*); Result ParseBlock(Block*); Result ParseIfExceptHeader(IfExceptExpr*); Result ParseExprList(ExprList*); diff --git a/src/wat-writer.cc b/src/wat-writer.cc index 2cb38cd8..0987c617 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -96,12 +96,17 @@ struct ExprTree { struct Label { Label(LabelType label_type, const std::string& name, - const BlockSignature& sig) - : name(name), label_type(label_type), sig(sig) {} + const TypeVector& param_types, + const TypeVector& result_types) + : name(name), + label_type(label_type), + param_types(param_types), + result_types(result_types) {} std::string name; LabelType label_type; - const BlockSignature& sig; // Share with Expr. + TypeVector param_types; + TypeVector result_types; }; class WatWriter { @@ -432,12 +437,14 @@ void WatWriter::WriteBeginBlock(LabelType label_type, if (has_label) { WriteString(block.label, NextChar::Space); } - WriteTypes(block.sig, "result"); + WriteTypes(block.decl.sig.param_types, "param"); + WriteTypes(block.decl.sig.result_types, "result"); if (!has_label) { Writef(" ;; label = @%" PRIindex, GetLabelStackSize()); } WriteNewline(FORCE_NEWLINE); - label_stack_.emplace_back(label_type, block.label, block.sig); + label_stack_.emplace_back(label_type, block.label, block.decl.sig.param_types, + block.decl.sig.result_types); Indent(); } @@ -448,13 +455,16 @@ void WatWriter::WriteBeginIfExceptBlock(const IfExceptExpr* expr) { if (has_label) { WriteString(block.label, NextChar::Space); } - WriteTypes(block.sig, "result"); + WriteTypes(block.decl.sig.param_types, "param"); + WriteTypes(block.decl.sig.result_types, "result"); WriteVar(expr->except_var, NextChar::Space); if (!has_label) { Writef(" ;; label = @%" PRIindex, GetLabelStackSize()); } WriteNewline(FORCE_NEWLINE); - label_stack_.emplace_back(LabelType::IfExcept, block.label, block.sig); + label_stack_.emplace_back(LabelType::IfExcept, block.label, + block.decl.sig.param_types, + block.decl.sig.result_types); Indent(); } @@ -905,7 +915,12 @@ Label* WatWriter::GetLabel(const Var& var) { Index WatWriter::GetLabelArity(const Var& var) { Label* label = GetLabel(var); - return label && label->label_type != LabelType::Loop ? label->sig.size() : 0; + if (!label) { + return 0; + } + + return label->label_type == LabelType::Loop ? label->param_types.size() + : label->result_types.size(); } Index WatWriter::GetFuncParamCount(const Var& var) { @@ -934,7 +949,7 @@ void WatWriter::WriteFoldedExpr(const Expr* expr) { break; case ExprType::Block: - PushExpr(expr, 0, cast<BlockExpr>(expr)->block.sig.size()); + PushExpr(expr, 0, cast<BlockExpr>(expr)->block.decl.sig.GetNumResults()); break; case ExprType::Br: @@ -989,15 +1004,16 @@ void WatWriter::WriteFoldedExpr(const Expr* expr) { break; case ExprType::If: - PushExpr(expr, 1, cast<IfExpr>(expr)->true_.sig.size()); + PushExpr(expr, 1, cast<IfExpr>(expr)->true_.decl.sig.GetNumResults()); break; case ExprType::IfExcept: - PushExpr(expr, 1, cast<IfExceptExpr>(expr)->true_.sig.size()); + PushExpr(expr, 1, + cast<IfExceptExpr>(expr)->true_.decl.sig.GetNumResults()); break; case ExprType::Loop: - PushExpr(expr, 0, cast<LoopExpr>(expr)->block.sig.size()); + PushExpr(expr, 0, cast<LoopExpr>(expr)->block.decl.sig.GetNumResults()); break; case ExprType::Nop: @@ -1029,7 +1045,7 @@ void WatWriter::WriteFoldedExpr(const Expr* expr) { } case ExprType::Try: - PushExpr(expr, 0, cast<TryExpr>(expr)->block.sig.size()); + PushExpr(expr, 0, cast<TryExpr>(expr)->block.decl.sig.GetNumResults()); break; case ExprType::Ternary: @@ -1292,7 +1308,7 @@ void WatWriter::WriteFunc(const Func& func) { } WriteNewline(NO_FORCE_NEWLINE); label_stack_.clear(); - label_stack_.emplace_back(LabelType::Func, std::string(), + label_stack_.emplace_back(LabelType::Func, std::string(), TypeVector(), func.decl.sig.result_types); current_func_ = &func; if (options_->fold_exprs) { |