Skip to content

Commit

Permalink
wasm2c: Implement EHv4
Browse files Browse the repository at this point in the history
  • Loading branch information
SoniEx2 committed Oct 1, 2024
1 parent ac81073 commit eb741af
Show file tree
Hide file tree
Showing 22 changed files with 258 additions and 55 deletions.
16 changes: 16 additions & 0 deletions src/binary-reader-ir.cc
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,13 @@ Result BinaryReaderIR::OnFuncType(Index index,
std::any_of(func_type->sig.result_types.begin(),
func_type->sig.result_types.end(),
[](auto x) { return x == Type::V128; });
module_->features_used.exceptions |=
std::any_of(func_type->sig.param_types.begin(),
func_type->sig.param_types.end(),
[](auto x) { return x == Type::ExnRef; }) ||
std::any_of(func_type->sig.result_types.begin(),
func_type->sig.result_types.end(),
[](auto x) { return x == Type::ExnRef; });

field->type = std::move(func_type);
module_->AppendField(std::move(field));
Expand All @@ -555,6 +562,7 @@ Result BinaryReaderIR::OnStructType(Index index,
struct_type->fields[i].type = fields[i].type;
struct_type->fields[i].mutable_ = fields[i].mutable_;
module_->features_used.simd |= (fields[i].type == Type::V128);
module_->features_used.exceptions |= (fields[i].type == Type::ExnRef);
}
field->type = std::move(struct_type);
module_->AppendField(std::move(field));
Expand All @@ -567,6 +575,7 @@ Result BinaryReaderIR::OnArrayType(Index index, TypeMut type_mut) {
array_type->field.type = type_mut.type;
array_type->field.mutable_ = type_mut.mutable_;
module_->features_used.simd |= (type_mut.type == Type::V128);
module_->features_used.exceptions |= (type_mut.type == Type::ExnRef);
field->type = std::move(array_type);
module_->AppendField(std::move(field));
return Result::Ok;
Expand Down Expand Up @@ -640,6 +649,7 @@ Result BinaryReaderIR::OnImportGlobal(Index import_index,
module_->AppendField(
std::make_unique<ImportModuleField>(std::move(import), GetLocation()));
module_->features_used.simd |= (type == Type::V128);
module_->features_used.exceptions |= (type == Type::ExnRef);
return Result::Ok;
}

Expand Down Expand Up @@ -687,6 +697,7 @@ Result BinaryReaderIR::OnTable(Index index,
Table& table = field->table;
table.elem_limits = *elem_limits;
table.elem_type = elem_type;
module_->features_used.exceptions |= (elem_type == Type::ExnRef);
module_->AppendField(std::move(field));
return Result::Ok;
}
Expand Down Expand Up @@ -723,6 +734,7 @@ Result BinaryReaderIR::BeginGlobal(Index index, Type type, bool mutable_) {
global.mutable_ = mutable_;
module_->AppendField(std::move(field));
module_->features_used.simd |= (type == Type::V128);
module_->features_used.exceptions |= (type == Type::ExnRef);
return Result::Ok;
}

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

module_->features_used.simd |= (type == Type::V128);
module_->features_used.exceptions |= (type == Type::ExnRef);
return Result::Ok;
}

Expand Down Expand Up @@ -1130,6 +1143,7 @@ Result BinaryReaderIR::OnRefFuncExpr(Index func_index) {
}

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

Expand Down Expand Up @@ -1174,10 +1188,12 @@ Result BinaryReaderIR::OnStoreExpr(Opcode opcode,
}

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

Result BinaryReaderIR::OnThrowRefExpr() {
module_->features_used.exceptions = true;
return AppendExpr(std::make_unique<ThrowRefExpr>());
}

Expand Down
118 changes: 109 additions & 9 deletions src/c-writer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ class CWriter {
void WriteTryDelegate(const TryExpr& tryexpr);
void Write(const TryTableExpr& try_table_expr);
void Write(const Catch& c);
void Write(const TableCatch& c);
void WriteThrow();

void PushTryCatch(const std::string& name);
Expand Down Expand Up @@ -647,6 +648,7 @@ constexpr char CWriter::MangleType(Type type) {
case Type::V128: return 'o';
case Type::FuncRef: return 'r';
case Type::ExternRef: return 'e';
case Type::ExnRef: return 'x';
default:
WABT_UNREACHABLE;
}
Expand Down Expand Up @@ -1219,6 +1221,7 @@ const char* CWriter::GetCTypeName(const Type& type) {
case Type::V128: return "v128";
case Type::FuncRef: return "wasm_rt_funcref_t";
case Type::ExternRef: return "wasm_rt_externref_t";
case Type::ExnRef: return "wasm_rt_exnref_t";
default:
WABT_UNREACHABLE;
}
Expand All @@ -1239,6 +1242,7 @@ void CWriter::Write(TypeEnum type) {
case Type::V128: Write("WASM_RT_V128"); break;
case Type::FuncRef: Write("WASM_RT_FUNCREF"); break;
case Type::ExternRef: Write("WASM_RT_EXTERNREF"); break;
case Type::ExnRef: Write("WASM_RT_EXNREF"); break;
default:
WABT_UNREACHABLE;
}
Expand Down Expand Up @@ -2285,7 +2289,8 @@ void CWriter::WriteElemInitializerDecls() {
continue;
}

if (elem_segment->elem_type == Type::ExternRef) {
if (elem_segment->elem_type == Type::ExternRef ||
elem_segment->elem_type == Type::ExnRef) {
// no need to store externref elem initializers because only
// ref.null is possible
continue;
Expand Down Expand Up @@ -2357,7 +2362,8 @@ void CWriter::WriteElemInitializers() {
continue;
}

if (elem_segment->elem_type == Type::ExternRef) {
if (elem_segment->elem_type == Type::ExternRef ||
elem_segment->elem_type == Type::ExnRef) {
// no need to store externref elem initializers because only
// ref.null is possible
continue;
Expand Down Expand Up @@ -2461,7 +2467,8 @@ void CWriter::WriteElemTableInit(bool active_initialization,
const ElemSegment* src_segment,
const Table* dst_table) {
assert(dst_table->elem_type == Type::FuncRef ||
dst_table->elem_type == Type::ExternRef);
dst_table->elem_type == Type::ExternRef ||
dst_table->elem_type == Type::ExnRef);
assert(dst_table->elem_type == src_segment->elem_type);

Write(GetReferenceTypeName(dst_table->elem_type), "_table_init(",
Expand Down Expand Up @@ -3106,7 +3113,7 @@ void CWriter::WriteVarsByType(const Vars& vars,
const ToDo& todo,
bool setjmp_safe) {
for (Type type : {Type::I32, Type::I64, Type::F32, Type::F64, Type::V128,
Type::FuncRef, Type::ExternRef}) {
Type::FuncRef, Type::ExternRef, Type::ExnRef}) {
Index var_index = 0;
size_t count = 0;
for (const auto& var : vars) {
Expand Down Expand Up @@ -3250,7 +3257,8 @@ void CWriter::WriteLocals(const std::vector<std::string>& index_to_name) {
func_->local_types, [](auto x) { return x; },
[&](Index local_index, Type local_type) {
Write(DefineParamName(index_to_name[num_params + local_index]), " = ");
if (local_type == Type::FuncRef || local_type == Type::ExternRef) {
if (local_type == Type::FuncRef || local_type == Type::ExternRef ||
local_type == Type::ExnRef) {
Write(GetReferenceNullValue(local_type));
} else if (local_type == Type::V128) {
Write("simde_wasm_i64x2_make(0, 0)");
Expand Down Expand Up @@ -3465,9 +3473,82 @@ void CWriter::WriteTryDelegate(const TryExpr& tryexpr) {
}

void CWriter::Write(const TryTableExpr& try_table_expr) {
// const size_t mark = BeginTry(try_table_expr.block);
const size_t mark = BeginTry(try_table_expr.block);

assert(false && "NYI");
/* exception has been thrown -- do we catch it? */

const LabelName tlabel = LabelName(try_table_expr.block.label);

Write("wasm_rt_set_unwind_target(", tlabel, "_outer_target);", Newline());
PopTryCatch();

ResetTypeStack(mark);
assert(!label_stack_.empty());
assert(label_stack_.back().name == try_table_expr.block.label);
Write(LabelDecl(GetLocalName(try_table_expr.block.label, true)));
PopLabel();

assert(!try_table_expr.catches.empty());
bool has_catch_all{};
for (auto it = try_table_expr.catches.cbegin();
it != try_table_expr.catches.cend(); ++it) {
if (it == try_table_expr.catches.cbegin()) {
Write(Newline());
} else {
Write(" else ");
}
ResetTypeStack(mark);
Write(*it);
if (it->IsCatchAll()) {
has_catch_all = true;
break;
}
}
if (!has_catch_all) {
/* if not caught, rethrow */
Write(" else ", OpenBrace());
WriteThrow();
Write(CloseBrace(), Newline());
}
Write(CloseBrace(), Newline()); /* end of catch blocks */
Write(CloseBrace(), Newline()); /* end of try-catch */

ResetTypeStack(mark);
PushTypes(try_table_expr.block.decl.sig.result_types);
}

void CWriter::Write(const TableCatch& c) {
if (!c.IsCatchAll()) {
Write("if (wasm_rt_exception_tag() == ",
TagSymbol(module_->GetTag(c.tag)->name), ") ", OpenBrace());

const Tag* tag = module_->GetTag(c.tag);
const FuncDeclaration& tag_type = tag->decl;
const Index num_params = tag_type.GetNumParams();
PushTypes(tag_type.sig.param_types);
if (num_params == 1) {
Write("wasm_rt_memcpy(&", StackVar(0), ", wasm_rt_exception(), sizeof(",
tag_type.GetParamType(0), "));", Newline());
} else if (num_params > 1) {
Write(OpenBrace(), tag_type.sig.param_types, " tmp;", Newline());
Write("wasm_rt_memcpy(&tmp, wasm_rt_exception(), sizeof(tmp));",
Newline());
Unspill(tag_type.sig.param_types);
Write(CloseBrace(), Newline());
}
}
if (c.IsRef()) {
PushType(Type::ExnRef);
Write(StackVar(0), ".tag = wasm_rt_exception_tag();", Newline());
Write(StackVar(0), ".size = wasm_rt_exception_size();", Newline());
Write("wasm_rt_memcpy(&", StackVar(0),
".data, wasm_rt_exception(), wasm_rt_exception_size());", Newline());
}

Write(GotoLabel(c.target), Newline());
if (!c.IsCatchAll()) {
Write(CloseBrace());
}
}

void CWriter::Write(const ExprList& exprs) {
Expand Down Expand Up @@ -3869,6 +3950,10 @@ void CWriter::Write(const ExprList& exprs) {
" == ", GetReferenceNullValue(Type::ExternRef), ");",
Newline());
break;
case Type::ExnRef:
Write(StackVar(0, Type::I32), " = (", StackVar(0), ".tag == NULL",
");", Newline());
break;
default:
WABT_UNREACHABLE;
}
Expand Down Expand Up @@ -3985,7 +4070,19 @@ void CWriter::Write(const ExprList& exprs) {
}

WriteThrow();
} break;
// Stop processing this ExprList, since the following are unreachable.
}
return;

case ExprType::ThrowRef: {
Write("if (", StackVar(0), ".tag == NULL) { TRAP(NULL_REF); }");
Write("wasm_rt_load_exception(", StackVar(0), ".tag, ", StackVar(0),
".size, ", StackVar(0), ".data);", Newline());
DropTypes(1);
WriteThrow();
// Stop processing this ExprList, since the following are unreachable.
}
return;

case ExprType::Rethrow: {
const RethrowExpr* rethrow = cast<RethrowExpr>(&expr);
Expand Down Expand Up @@ -4145,7 +4242,6 @@ void CWriter::Write(const ExprList& exprs) {
case ExprType::AtomicWait:
case ExprType::AtomicNotify:
case ExprType::CallRef:
case ExprType::ThrowRef:
UNIMPLEMENTED("...");
break;
}
Expand Down Expand Up @@ -5996,6 +6092,8 @@ const char* CWriter::GetReferenceTypeName(const Type& type) {
return "funcref";
case Type::ExternRef:
return "externref";
case Type::ExnRef:
return "exnref";
default:
WABT_UNREACHABLE;
}
Expand All @@ -6008,6 +6106,8 @@ const char* CWriter::GetReferenceNullValue(const Type& type) {
return "wasm_rt_funcref_null_value";
case Type::ExternRef:
return "wasm_rt_externref_null_value";
case Type::ExnRef:
return "wasm_rt_exnref_null_value";
default:
WABT_UNREACHABLE;
}
Expand Down
6 changes: 6 additions & 0 deletions src/generate-names.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class NameGenerator : public ExprVisitor::DelegateNop {
// Implementation of ExprVisitor::DelegateNop.
Result BeginBlockExpr(BlockExpr* expr) override;
Result BeginTryExpr(TryExpr* expr) override;
Result BeginTryTableExpr(TryTableExpr* expr) override;
Result BeginLoopExpr(LoopExpr* expr) override;
Result BeginIfExpr(IfExpr* expr) override;

Expand Down Expand Up @@ -218,6 +219,11 @@ Result NameGenerator::BeginTryExpr(TryExpr* expr) {
return Result::Ok;
}

Result NameGenerator::BeginTryTableExpr(TryTableExpr* expr) {
MaybeGenerateName("T", label_count_++, &expr->block.label);
return Result::Ok;
}

Result NameGenerator::BeginLoopExpr(LoopExpr* expr) {
MaybeGenerateName("L", label_count_++, &expr->block.label);
return Result::Ok;
Expand Down
8 changes: 0 additions & 8 deletions src/prebuilt/wasm2c_header_top.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,6 @@ R"w2c_template(typedef float f32;
)w2c_template"
R"w2c_template(typedef double f64;
)w2c_template"
R"w2c_template(#ifndef WASM_EXN_MAX_SIZE
)w2c_template"
R"w2c_template(/* default value; runtime may override this */
)w2c_template"
R"w2c_template(#define WASM_EXN_MAX_SIZE 256
)w2c_template"
R"w2c_template(#endif
)w2c_template"
R"w2c_template(#endif
)w2c_template"
R"w2c_template(
Expand Down
4 changes: 0 additions & 4 deletions src/template/wasm2c.top.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ typedef uint64_t u64;
typedef int64_t s64;
typedef float f32;
typedef double f64;
#ifndef WASM_EXN_MAX_SIZE
/* default value; runtime may override this */
#define WASM_EXN_MAX_SIZE 256
#endif
#endif

#ifdef __cplusplus
Expand Down
2 changes: 1 addition & 1 deletion src/wast-parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2479,7 +2479,7 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) {

case TokenType::ThrowRef:
ErrorUnlessOpcodeEnabled(Consume());
out_expr->reset(new UnreachableExpr(loc));
out_expr->reset(new ThrowRefExpr(loc));
break;

case TokenType::Rethrow:
Expand Down
8 changes: 7 additions & 1 deletion test/run-spec-wasm2c.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def F64ToC(f64_bits):

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


def MangleTypes(types):
Expand Down Expand Up @@ -321,6 +321,7 @@ def _WriteAssertReturnCommand(self, command):
'i64': 'ASSERT_RETURN_I64',
'f64': 'ASSERT_RETURN_F64',
'externref': 'ASSERT_RETURN_EXTERNREF',
'exnref': 'ASSERT_RETURN_EXNREF',
'funcref': 'ASSERT_RETURN_FUNCREF',
}

Expand Down Expand Up @@ -385,6 +386,11 @@ def _Constant(self, const):
return 'wasm_rt_funcref_null_value'
else:
assert False # can't make an arbitrary funcref from an integer value
elif type_ == 'exnref':
if value == 'null':
return 'wasm_rt_exnref_null_value'
else:
assert False # can't make an arbitrary exnref from an integer value
else:
assert False

Expand Down
Loading

0 comments on commit eb741af

Please sign in to comment.