Skip to content

Commit eb741af

Browse files
committed
wasm2c: Implement EHv4
1 parent ac81073 commit eb741af

22 files changed

+258
-55
lines changed

src/binary-reader-ir.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,13 @@ Result BinaryReaderIR::OnFuncType(Index index,
539539
std::any_of(func_type->sig.result_types.begin(),
540540
func_type->sig.result_types.end(),
541541
[](auto x) { return x == Type::V128; });
542+
module_->features_used.exceptions |=
543+
std::any_of(func_type->sig.param_types.begin(),
544+
func_type->sig.param_types.end(),
545+
[](auto x) { return x == Type::ExnRef; }) ||
546+
std::any_of(func_type->sig.result_types.begin(),
547+
func_type->sig.result_types.end(),
548+
[](auto x) { return x == Type::ExnRef; });
542549

543550
field->type = std::move(func_type);
544551
module_->AppendField(std::move(field));
@@ -555,6 +562,7 @@ Result BinaryReaderIR::OnStructType(Index index,
555562
struct_type->fields[i].type = fields[i].type;
556563
struct_type->fields[i].mutable_ = fields[i].mutable_;
557564
module_->features_used.simd |= (fields[i].type == Type::V128);
565+
module_->features_used.exceptions |= (fields[i].type == Type::ExnRef);
558566
}
559567
field->type = std::move(struct_type);
560568
module_->AppendField(std::move(field));
@@ -567,6 +575,7 @@ Result BinaryReaderIR::OnArrayType(Index index, TypeMut type_mut) {
567575
array_type->field.type = type_mut.type;
568576
array_type->field.mutable_ = type_mut.mutable_;
569577
module_->features_used.simd |= (type_mut.type == Type::V128);
578+
module_->features_used.exceptions |= (type_mut.type == Type::ExnRef);
570579
field->type = std::move(array_type);
571580
module_->AppendField(std::move(field));
572581
return Result::Ok;
@@ -640,6 +649,7 @@ Result BinaryReaderIR::OnImportGlobal(Index import_index,
640649
module_->AppendField(
641650
std::make_unique<ImportModuleField>(std::move(import), GetLocation()));
642651
module_->features_used.simd |= (type == Type::V128);
652+
module_->features_used.exceptions |= (type == Type::ExnRef);
643653
return Result::Ok;
644654
}
645655

@@ -687,6 +697,7 @@ Result BinaryReaderIR::OnTable(Index index,
687697
Table& table = field->table;
688698
table.elem_limits = *elem_limits;
689699
table.elem_type = elem_type;
700+
module_->features_used.exceptions |= (elem_type == Type::ExnRef);
690701
module_->AppendField(std::move(field));
691702
return Result::Ok;
692703
}
@@ -723,6 +734,7 @@ Result BinaryReaderIR::BeginGlobal(Index index, Type type, bool mutable_) {
723734
global.mutable_ = mutable_;
724735
module_->AppendField(std::move(field));
725736
module_->features_used.simd |= (type == Type::V128);
737+
module_->features_used.exceptions |= (type == Type::ExnRef);
726738
return Result::Ok;
727739
}
728740

@@ -789,6 +801,7 @@ Result BinaryReaderIR::OnLocalDecl(Index decl_index, Index count, Type type) {
789801
}
790802

791803
module_->features_used.simd |= (type == Type::V128);
804+
module_->features_used.exceptions |= (type == Type::ExnRef);
792805
return Result::Ok;
793806
}
794807

@@ -1130,6 +1143,7 @@ Result BinaryReaderIR::OnRefFuncExpr(Index func_index) {
11301143
}
11311144

11321145
Result BinaryReaderIR::OnRefNullExpr(Type type) {
1146+
module_->features_used.exceptions |= (type == Type::ExnRef);
11331147
return AppendExpr(std::make_unique<RefNullExpr>(type));
11341148
}
11351149

@@ -1174,10 +1188,12 @@ Result BinaryReaderIR::OnStoreExpr(Opcode opcode,
11741188
}
11751189

11761190
Result BinaryReaderIR::OnThrowExpr(Index tag_index) {
1191+
module_->features_used.exceptions = true;
11771192
return AppendExpr(std::make_unique<ThrowExpr>(Var(tag_index, GetLocation())));
11781193
}
11791194

11801195
Result BinaryReaderIR::OnThrowRefExpr() {
1196+
module_->features_used.exceptions = true;
11811197
return AppendExpr(std::make_unique<ThrowRefExpr>());
11821198
}
11831199

src/c-writer.cc

Lines changed: 109 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ class CWriter {
488488
void WriteTryDelegate(const TryExpr& tryexpr);
489489
void Write(const TryTableExpr& try_table_expr);
490490
void Write(const Catch& c);
491+
void Write(const TableCatch& c);
491492
void WriteThrow();
492493

493494
void PushTryCatch(const std::string& name);
@@ -647,6 +648,7 @@ constexpr char CWriter::MangleType(Type type) {
647648
case Type::V128: return 'o';
648649
case Type::FuncRef: return 'r';
649650
case Type::ExternRef: return 'e';
651+
case Type::ExnRef: return 'x';
650652
default:
651653
WABT_UNREACHABLE;
652654
}
@@ -1219,6 +1221,7 @@ const char* CWriter::GetCTypeName(const Type& type) {
12191221
case Type::V128: return "v128";
12201222
case Type::FuncRef: return "wasm_rt_funcref_t";
12211223
case Type::ExternRef: return "wasm_rt_externref_t";
1224+
case Type::ExnRef: return "wasm_rt_exnref_t";
12221225
default:
12231226
WABT_UNREACHABLE;
12241227
}
@@ -1239,6 +1242,7 @@ void CWriter::Write(TypeEnum type) {
12391242
case Type::V128: Write("WASM_RT_V128"); break;
12401243
case Type::FuncRef: Write("WASM_RT_FUNCREF"); break;
12411244
case Type::ExternRef: Write("WASM_RT_EXTERNREF"); break;
1245+
case Type::ExnRef: Write("WASM_RT_EXNREF"); break;
12421246
default:
12431247
WABT_UNREACHABLE;
12441248
}
@@ -2285,7 +2289,8 @@ void CWriter::WriteElemInitializerDecls() {
22852289
continue;
22862290
}
22872291

2288-
if (elem_segment->elem_type == Type::ExternRef) {
2292+
if (elem_segment->elem_type == Type::ExternRef ||
2293+
elem_segment->elem_type == Type::ExnRef) {
22892294
// no need to store externref elem initializers because only
22902295
// ref.null is possible
22912296
continue;
@@ -2357,7 +2362,8 @@ void CWriter::WriteElemInitializers() {
23572362
continue;
23582363
}
23592364

2360-
if (elem_segment->elem_type == Type::ExternRef) {
2365+
if (elem_segment->elem_type == Type::ExternRef ||
2366+
elem_segment->elem_type == Type::ExnRef) {
23612367
// no need to store externref elem initializers because only
23622368
// ref.null is possible
23632369
continue;
@@ -2461,7 +2467,8 @@ void CWriter::WriteElemTableInit(bool active_initialization,
24612467
const ElemSegment* src_segment,
24622468
const Table* dst_table) {
24632469
assert(dst_table->elem_type == Type::FuncRef ||
2464-
dst_table->elem_type == Type::ExternRef);
2470+
dst_table->elem_type == Type::ExternRef ||
2471+
dst_table->elem_type == Type::ExnRef);
24652472
assert(dst_table->elem_type == src_segment->elem_type);
24662473

24672474
Write(GetReferenceTypeName(dst_table->elem_type), "_table_init(",
@@ -3106,7 +3113,7 @@ void CWriter::WriteVarsByType(const Vars& vars,
31063113
const ToDo& todo,
31073114
bool setjmp_safe) {
31083115
for (Type type : {Type::I32, Type::I64, Type::F32, Type::F64, Type::V128,
3109-
Type::FuncRef, Type::ExternRef}) {
3116+
Type::FuncRef, Type::ExternRef, Type::ExnRef}) {
31103117
Index var_index = 0;
31113118
size_t count = 0;
31123119
for (const auto& var : vars) {
@@ -3250,7 +3257,8 @@ void CWriter::WriteLocals(const std::vector<std::string>& index_to_name) {
32503257
func_->local_types, [](auto x) { return x; },
32513258
[&](Index local_index, Type local_type) {
32523259
Write(DefineParamName(index_to_name[num_params + local_index]), " = ");
3253-
if (local_type == Type::FuncRef || local_type == Type::ExternRef) {
3260+
if (local_type == Type::FuncRef || local_type == Type::ExternRef ||
3261+
local_type == Type::ExnRef) {
32543262
Write(GetReferenceNullValue(local_type));
32553263
} else if (local_type == Type::V128) {
32563264
Write("simde_wasm_i64x2_make(0, 0)");
@@ -3465,9 +3473,82 @@ void CWriter::WriteTryDelegate(const TryExpr& tryexpr) {
34653473
}
34663474

34673475
void CWriter::Write(const TryTableExpr& try_table_expr) {
3468-
// const size_t mark = BeginTry(try_table_expr.block);
3476+
const size_t mark = BeginTry(try_table_expr.block);
34693477

3470-
assert(false && "NYI");
3478+
/* exception has been thrown -- do we catch it? */
3479+
3480+
const LabelName tlabel = LabelName(try_table_expr.block.label);
3481+
3482+
Write("wasm_rt_set_unwind_target(", tlabel, "_outer_target);", Newline());
3483+
PopTryCatch();
3484+
3485+
ResetTypeStack(mark);
3486+
assert(!label_stack_.empty());
3487+
assert(label_stack_.back().name == try_table_expr.block.label);
3488+
Write(LabelDecl(GetLocalName(try_table_expr.block.label, true)));
3489+
PopLabel();
3490+
3491+
assert(!try_table_expr.catches.empty());
3492+
bool has_catch_all{};
3493+
for (auto it = try_table_expr.catches.cbegin();
3494+
it != try_table_expr.catches.cend(); ++it) {
3495+
if (it == try_table_expr.catches.cbegin()) {
3496+
Write(Newline());
3497+
} else {
3498+
Write(" else ");
3499+
}
3500+
ResetTypeStack(mark);
3501+
Write(*it);
3502+
if (it->IsCatchAll()) {
3503+
has_catch_all = true;
3504+
break;
3505+
}
3506+
}
3507+
if (!has_catch_all) {
3508+
/* if not caught, rethrow */
3509+
Write(" else ", OpenBrace());
3510+
WriteThrow();
3511+
Write(CloseBrace(), Newline());
3512+
}
3513+
Write(CloseBrace(), Newline()); /* end of catch blocks */
3514+
Write(CloseBrace(), Newline()); /* end of try-catch */
3515+
3516+
ResetTypeStack(mark);
3517+
PushTypes(try_table_expr.block.decl.sig.result_types);
3518+
}
3519+
3520+
void CWriter::Write(const TableCatch& c) {
3521+
if (!c.IsCatchAll()) {
3522+
Write("if (wasm_rt_exception_tag() == ",
3523+
TagSymbol(module_->GetTag(c.tag)->name), ") ", OpenBrace());
3524+
3525+
const Tag* tag = module_->GetTag(c.tag);
3526+
const FuncDeclaration& tag_type = tag->decl;
3527+
const Index num_params = tag_type.GetNumParams();
3528+
PushTypes(tag_type.sig.param_types);
3529+
if (num_params == 1) {
3530+
Write("wasm_rt_memcpy(&", StackVar(0), ", wasm_rt_exception(), sizeof(",
3531+
tag_type.GetParamType(0), "));", Newline());
3532+
} else if (num_params > 1) {
3533+
Write(OpenBrace(), tag_type.sig.param_types, " tmp;", Newline());
3534+
Write("wasm_rt_memcpy(&tmp, wasm_rt_exception(), sizeof(tmp));",
3535+
Newline());
3536+
Unspill(tag_type.sig.param_types);
3537+
Write(CloseBrace(), Newline());
3538+
}
3539+
}
3540+
if (c.IsRef()) {
3541+
PushType(Type::ExnRef);
3542+
Write(StackVar(0), ".tag = wasm_rt_exception_tag();", Newline());
3543+
Write(StackVar(0), ".size = wasm_rt_exception_size();", Newline());
3544+
Write("wasm_rt_memcpy(&", StackVar(0),
3545+
".data, wasm_rt_exception(), wasm_rt_exception_size());", Newline());
3546+
}
3547+
3548+
Write(GotoLabel(c.target), Newline());
3549+
if (!c.IsCatchAll()) {
3550+
Write(CloseBrace());
3551+
}
34713552
}
34723553

34733554
void CWriter::Write(const ExprList& exprs) {
@@ -3869,6 +3950,10 @@ void CWriter::Write(const ExprList& exprs) {
38693950
" == ", GetReferenceNullValue(Type::ExternRef), ");",
38703951
Newline());
38713952
break;
3953+
case Type::ExnRef:
3954+
Write(StackVar(0, Type::I32), " = (", StackVar(0), ".tag == NULL",
3955+
");", Newline());
3956+
break;
38723957
default:
38733958
WABT_UNREACHABLE;
38743959
}
@@ -3985,7 +4070,19 @@ void CWriter::Write(const ExprList& exprs) {
39854070
}
39864071

39874072
WriteThrow();
3988-
} break;
4073+
// Stop processing this ExprList, since the following are unreachable.
4074+
}
4075+
return;
4076+
4077+
case ExprType::ThrowRef: {
4078+
Write("if (", StackVar(0), ".tag == NULL) { TRAP(NULL_REF); }");
4079+
Write("wasm_rt_load_exception(", StackVar(0), ".tag, ", StackVar(0),
4080+
".size, ", StackVar(0), ".data);", Newline());
4081+
DropTypes(1);
4082+
WriteThrow();
4083+
// Stop processing this ExprList, since the following are unreachable.
4084+
}
4085+
return;
39894086

39904087
case ExprType::Rethrow: {
39914088
const RethrowExpr* rethrow = cast<RethrowExpr>(&expr);
@@ -4145,7 +4242,6 @@ void CWriter::Write(const ExprList& exprs) {
41454242
case ExprType::AtomicWait:
41464243
case ExprType::AtomicNotify:
41474244
case ExprType::CallRef:
4148-
case ExprType::ThrowRef:
41494245
UNIMPLEMENTED("...");
41504246
break;
41514247
}
@@ -5996,6 +6092,8 @@ const char* CWriter::GetReferenceTypeName(const Type& type) {
59966092
return "funcref";
59976093
case Type::ExternRef:
59986094
return "externref";
6095+
case Type::ExnRef:
6096+
return "exnref";
59996097
default:
60006098
WABT_UNREACHABLE;
60016099
}
@@ -6008,6 +6106,8 @@ const char* CWriter::GetReferenceNullValue(const Type& type) {
60086106
return "wasm_rt_funcref_null_value";
60096107
case Type::ExternRef:
60106108
return "wasm_rt_externref_null_value";
6109+
case Type::ExnRef:
6110+
return "wasm_rt_exnref_null_value";
60116111
default:
60126112
WABT_UNREACHABLE;
60136113
}

src/generate-names.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class NameGenerator : public ExprVisitor::DelegateNop {
3838
// Implementation of ExprVisitor::DelegateNop.
3939
Result BeginBlockExpr(BlockExpr* expr) override;
4040
Result BeginTryExpr(TryExpr* expr) override;
41+
Result BeginTryTableExpr(TryTableExpr* expr) override;
4142
Result BeginLoopExpr(LoopExpr* expr) override;
4243
Result BeginIfExpr(IfExpr* expr) override;
4344

@@ -218,6 +219,11 @@ Result NameGenerator::BeginTryExpr(TryExpr* expr) {
218219
return Result::Ok;
219220
}
220221

222+
Result NameGenerator::BeginTryTableExpr(TryTableExpr* expr) {
223+
MaybeGenerateName("T", label_count_++, &expr->block.label);
224+
return Result::Ok;
225+
}
226+
221227
Result NameGenerator::BeginLoopExpr(LoopExpr* expr) {
222228
MaybeGenerateName("L", label_count_++, &expr->block.label);
223229
return Result::Ok;

src/prebuilt/wasm2c_header_top.cc

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,6 @@ R"w2c_template(typedef float f32;
2525
)w2c_template"
2626
R"w2c_template(typedef double f64;
2727
)w2c_template"
28-
R"w2c_template(#ifndef WASM_EXN_MAX_SIZE
29-
)w2c_template"
30-
R"w2c_template(/* default value; runtime may override this */
31-
)w2c_template"
32-
R"w2c_template(#define WASM_EXN_MAX_SIZE 256
33-
)w2c_template"
34-
R"w2c_template(#endif
35-
)w2c_template"
3628
R"w2c_template(#endif
3729
)w2c_template"
3830
R"w2c_template(

src/template/wasm2c.top.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ typedef uint64_t u64;
1212
typedef int64_t s64;
1313
typedef float f32;
1414
typedef double f64;
15-
#ifndef WASM_EXN_MAX_SIZE
16-
/* default value; runtime may override this */
17-
#define WASM_EXN_MAX_SIZE 256
18-
#endif
1915
#endif
2016

2117
#ifdef __cplusplus

src/wast-parser.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2479,7 +2479,7 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) {
24792479

24802480
case TokenType::ThrowRef:
24812481
ErrorUnlessOpcodeEnabled(Consume());
2482-
out_expr->reset(new UnreachableExpr(loc));
2482+
out_expr->reset(new ThrowRefExpr(loc));
24832483
break;
24842484

24852485
case TokenType::Rethrow:

test/run-spec-wasm2c.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def F64ToC(f64_bits):
9090

9191
def MangleType(t):
9292
return {'i32': 'i', 'i64': 'j', 'f32': 'f', 'f64': 'd', 'v128': 'o',
93-
'externref': 'e', 'funcref': 'r'}[t]
93+
'externref': 'e', 'funcref': 'r', 'exnref': 'x'}[t]
9494

9595

9696
def MangleTypes(types):
@@ -321,6 +321,7 @@ def _WriteAssertReturnCommand(self, command):
321321
'i64': 'ASSERT_RETURN_I64',
322322
'f64': 'ASSERT_RETURN_F64',
323323
'externref': 'ASSERT_RETURN_EXTERNREF',
324+
'exnref': 'ASSERT_RETURN_EXNREF',
324325
'funcref': 'ASSERT_RETURN_FUNCREF',
325326
}
326327

@@ -385,6 +386,11 @@ def _Constant(self, const):
385386
return 'wasm_rt_funcref_null_value'
386387
else:
387388
assert False # can't make an arbitrary funcref from an integer value
389+
elif type_ == 'exnref':
390+
if value == 'null':
391+
return 'wasm_rt_exnref_null_value'
392+
else:
393+
assert False # can't make an arbitrary exnref from an integer value
388394
else:
389395
assert False
390396

0 commit comments

Comments
 (0)