summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binary-reader-interp.cc62
-rw-r--r--src/binary-reader-ir.cc49
-rw-r--r--src/binary-reader-logging.cc46
-rw-r--r--src/binary-reader-logging.h15
-rw-r--r--src/binary-reader-nop.h24
-rw-r--r--src/binary-reader-objdump.cc35
-rw-r--r--src/binary-reader-opcnt.cc19
-rw-r--r--src/binary-reader.cc92
-rw-r--r--src/binary-reader.h14
-rw-r--r--src/binary-writer.cc35
-rw-r--r--src/c-writer.cc31
-rw-r--r--src/common.h59
-rw-r--r--src/feature.def1
-rw-r--r--src/interp.cc21
-rw-r--r--src/interp.h6
-rw-r--r--src/ir.h6
-rw-r--r--src/type-checker.cc145
-rw-r--r--src/type-checker.h46
-rw-r--r--src/validator.cc70
-rw-r--r--src/wast-parser.cc73
-rw-r--r--src/wast-parser.h1
-rw-r--r--src/wat-writer.cc44
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, &param_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, &param_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, &param_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(&param_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();
diff --git a/src/ir.h b/src/ir.h
index 521a250f..0a38087e 100644
--- a/src/ir.h
+++ b/src/ir.h
@@ -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) {