Skip to content

Commit 60050a9

Browse files
authored
Initial implementation of extended-const proposal. (#1824)
The primary changes here are to the interpreter and how it handles initializer expressions. With this change we model these are normal function that we run during module initialization. I imagine we could optimize this further by creating one long function and encoding the `global.set`/`memory.init`/`table.init` into the function itself, but this change seems like a good first step to make the current tests pass.
1 parent 30fe555 commit 60050a9

20 files changed

+373
-148
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Wabt has been compiled to JavaScript via emscripten. Some of the functionality i
5959
| [annotations][] | `--enable-annotations` | | || | |
6060
| [memory64][] | `--enable-memory64` | | | | | |
6161
| [multi-memory][] | `--enable-multi-memory` | |||||
62+
| [extended-const][] | `--enable-extended-const` | | | | | |
6263

6364
[exception handling]: https://github.com/WebAssembly/exception-handling
6465
[mutable globals]: https://github.com/WebAssembly/mutable-global

src/feature.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ WABT_FEATURE(annotations, "annotations", false, "Custom an
3737
WABT_FEATURE(gc, "gc", false, "Garbage collection")
3838
WABT_FEATURE(memory64, "memory64", false, "64-bit memory")
3939
WABT_FEATURE(multi_memory, "multi-memory", false, "Multi-memory")
40+
WABT_FEATURE(extended_const, "extended-const", false, "Extended constant expressions")

src/interp/binary-reader-interp.cc

Lines changed: 29 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,6 @@ class BinaryReaderInterp : public BinaryReaderNop {
7878
Errors* errors,
7979
const Features& features);
8080

81-
ValueType GetType(InitExpr);
82-
8381
// Implement BinaryReader.
8482
bool OnError(const Error&) override;
8583

@@ -301,7 +299,7 @@ class BinaryReaderInterp : public BinaryReaderNop {
301299
Index keep_extra,
302300
Index* out_drop_count,
303301
Index* out_keep_count);
304-
Result BeginInitExpr(Type type);
302+
Result BeginInitExpr(Type type, FuncDesc* init_func);
305303
Result EndInitExpr();
306304

307305
void EmitBr(Index depth,
@@ -326,8 +324,6 @@ class BinaryReaderInterp : public BinaryReaderNop {
326324
FixupMap depth_fixups_;
327325
FixupMap func_fixups_;
328326

329-
bool reading_init_expr_ = false;
330-
InitExpr init_expr_;
331327
u32 local_decl_count_;
332328
u32 local_count_;
333329

@@ -619,37 +615,37 @@ Result BinaryReaderInterp::OnGlobalCount(Index count) {
619615
Result BinaryReaderInterp::BeginGlobal(Index index, Type type, bool mutable_) {
620616
CHECK_RESULT(validator_.OnGlobal(GetLocation(), type, mutable_));
621617
GlobalType global_type{type, ToMutability(mutable_)};
622-
module_.globals.push_back(GlobalDesc{global_type, InitExpr{}});
618+
FuncDesc init_func{FuncType{{}, {type}}, {}, Istream::kInvalidOffset, {}};
619+
module_.globals.push_back(GlobalDesc{global_type, init_func});
623620
global_types_.push_back(global_type);
624-
init_expr_.kind = InitExprKind::None;
625621
return Result::Ok;
626622
}
627623

628624
Result BinaryReaderInterp::BeginGlobalInitExpr(Index index) {
629-
GlobalType type = global_types_[index];
630-
return BeginInitExpr(type.type);
625+
GlobalDesc& global = module_.globals.back();
626+
return BeginInitExpr(global.type.type, &global.init_func);
631627
}
632628

633629
Result BinaryReaderInterp::EndInitExpr() {
634-
assert(reading_init_expr_);
635-
reading_init_expr_ = false;
630+
FixupTopLabel();
636631
CHECK_RESULT(validator_.EndInitExpr());
632+
istream_.Emit(Opcode::Return);
633+
PopLabel();
637634
return Result::Ok;
638635
}
639636

640-
Result BinaryReaderInterp::BeginInitExpr(Type type) {
641-
assert(!reading_init_expr_);
642-
reading_init_expr_ = true;
643-
init_expr_.kind = InitExprKind::None;
637+
Result BinaryReaderInterp::BeginInitExpr(Type type, FuncDesc* func) {
638+
label_stack_.clear();
639+
func_ = func;
640+
func_->code_offset = istream_.end();
644641
CHECK_RESULT(validator_.BeginInitExpr(GetLocation(), type));
642+
// Push implicit init func label (equivalent to return).
643+
PushLabel(LabelKind::Try, Istream::kInvalidOffset, Istream::kInvalidOffset);
645644
return Result::Ok;
646645
}
647646

648647
Result BinaryReaderInterp::EndGlobalInitExpr(Index index) {
649-
CHECK_RESULT(EndInitExpr());
650-
GlobalDesc& global = module_.globals.back();
651-
global.init = init_expr_;
652-
return Result::Ok;
648+
return EndInitExpr();
653649
}
654650

655651
Result BinaryReaderInterp::OnTagCount(Index count) {
@@ -702,24 +698,20 @@ Result BinaryReaderInterp::BeginElemSegment(Index index,
702698
auto mode = ToSegmentMode(flags);
703699
CHECK_RESULT(validator_.OnElemSegment(GetLocation(), Var(table_index), mode));
704700

705-
ElemDesc desc;
706-
desc.type = ValueType::Void; // Initialized later in OnElemSegmentElemType.
707-
desc.mode = mode;
708-
desc.table_index = table_index;
701+
FuncDesc init_func{
702+
FuncType{{}, {ValueType::I32}}, {}, Istream::kInvalidOffset, {}};
703+
ElemDesc desc{{}, ValueType::Void, mode, table_index, init_func};
709704
module_.elems.push_back(desc);
710-
init_expr_.kind = InitExprKind::None;
711705
return Result::Ok;
712706
}
713707

714708
Result BinaryReaderInterp::BeginElemSegmentInitExpr(Index index) {
715-
return BeginInitExpr(Type::I32);
709+
ElemDesc& elem = module_.elems.back();
710+
return BeginInitExpr(Type::I32, &elem.init_func);
716711
}
717712

718713
Result BinaryReaderInterp::EndElemSegmentInitExpr(Index index) {
719-
CHECK_RESULT(EndInitExpr());
720-
ElemDesc& elem = module_.elems.back();
721-
elem.offset = init_expr_;
722-
return Result::Ok;
714+
return EndInitExpr();
723715
}
724716

725717
Result BinaryReaderInterp::OnElemSegmentElemType(Index index, Type elem_type) {
@@ -761,14 +753,12 @@ Result BinaryReaderInterp::OnDataCount(Index count) {
761753

762754
Result BinaryReaderInterp::BeginDataSegmentInitExpr(Index index) {
763755
MemoryType t = memory_types_[0];
764-
return BeginInitExpr(t.limits.is_64 ? Type::I64 : Type::I32);
756+
DataDesc& data = module_.datas.back();
757+
return BeginInitExpr(t.limits.is_64 ? Type::I64 : Type::I32, &data.init_func);
765758
}
766759

767760
Result BinaryReaderInterp::EndDataSegmentInitExpr(Index index) {
768-
CHECK_RESULT(EndInitExpr());
769-
DataDesc& data = module_.datas.back();
770-
data.offset = init_expr_;
771-
return Result::Ok;
761+
return EndInitExpr();
772762
}
773763

774764
Result BinaryReaderInterp::BeginDataSegment(Index index,
@@ -778,11 +768,10 @@ Result BinaryReaderInterp::BeginDataSegment(Index index,
778768
CHECK_RESULT(
779769
validator_.OnDataSegment(GetLocation(), Var(memory_index), mode));
780770

781-
DataDesc desc;
782-
desc.mode = mode;
783-
desc.memory_index = memory_index;
771+
FuncDesc init_func{
772+
FuncType{{}, {ValueType::I32}}, {}, Istream::kInvalidOffset, {}};
773+
DataDesc desc{{}, mode, memory_index, init_func};
784774
module_.datas.push_back(desc);
785-
init_expr_.kind = InitExprKind::None;
786775
return Result::Ok;
787776
}
788777

@@ -873,7 +862,7 @@ Index BinaryReaderInterp::num_func_imports() const {
873862
}
874863

875864
Result BinaryReaderInterp::OnOpcode(Opcode opcode) {
876-
if ((func_ == nullptr || label_stack_.empty()) && !reading_init_expr_) {
865+
if (func_ == nullptr || label_stack_.empty()) {
877866
PrintError("Unexpected instruction after end of function");
878867
return Result::Error;
879868
}
@@ -1021,7 +1010,7 @@ Result BinaryReaderInterp::OnElseExpr() {
10211010
}
10221011

10231012
Result BinaryReaderInterp::OnEndExpr() {
1024-
if (reading_init_expr_ || label_stack_.size() == 1) {
1013+
if (label_stack_.size() == 1) {
10251014
return Result::Ok;
10261015
}
10271016
SharedValidator::Label* label;
@@ -1188,66 +1177,36 @@ Result BinaryReaderInterp::OnDropExpr() {
11881177

11891178
Result BinaryReaderInterp::OnI32ConstExpr(uint32_t value) {
11901179
CHECK_RESULT(validator_.OnConst(GetLocation(), Type::I32));
1191-
if (reading_init_expr_) {
1192-
init_expr_.kind = InitExprKind::I32;
1193-
init_expr_.i32_ = value;
1194-
return Result::Ok;
1195-
}
11961180
istream_.Emit(Opcode::I32Const, value);
11971181
return Result::Ok;
11981182
}
11991183

12001184
Result BinaryReaderInterp::OnI64ConstExpr(uint64_t value) {
12011185
CHECK_RESULT(validator_.OnConst(GetLocation(), Type::I64));
1202-
if (reading_init_expr_) {
1203-
init_expr_.kind = InitExprKind::I64;
1204-
init_expr_.i64_ = value;
1205-
return Result::Ok;
1206-
}
12071186
istream_.Emit(Opcode::I64Const, value);
12081187
return Result::Ok;
12091188
}
12101189

12111190
Result BinaryReaderInterp::OnF32ConstExpr(uint32_t value_bits) {
12121191
CHECK_RESULT(validator_.OnConst(GetLocation(), Type::F32));
1213-
if (reading_init_expr_) {
1214-
init_expr_.kind = InitExprKind::F32;
1215-
init_expr_.f32_ = Bitcast<f32>(value_bits);
1216-
return Result::Ok;
1217-
}
12181192
istream_.Emit(Opcode::F32Const, value_bits);
12191193
return Result::Ok;
12201194
}
12211195

12221196
Result BinaryReaderInterp::OnF64ConstExpr(uint64_t value_bits) {
12231197
CHECK_RESULT(validator_.OnConst(GetLocation(), Type::F64));
1224-
if (reading_init_expr_) {
1225-
init_expr_.kind = InitExprKind::F64;
1226-
init_expr_.f64_ = Bitcast<f64>(value_bits);
1227-
return Result::Ok;
1228-
}
12291198
istream_.Emit(Opcode::F64Const, value_bits);
12301199
return Result::Ok;
12311200
}
12321201

12331202
Result BinaryReaderInterp::OnV128ConstExpr(v128 value_bits) {
12341203
CHECK_RESULT(validator_.OnConst(GetLocation(), Type::V128));
1235-
if (reading_init_expr_) {
1236-
init_expr_.kind = InitExprKind::V128;
1237-
init_expr_.v128_ = Bitcast<v128>(value_bits);
1238-
return Result::Ok;
1239-
}
12401204
istream_.Emit(Opcode::V128Const, value_bits);
12411205
return Result::Ok;
12421206
}
12431207

12441208
Result BinaryReaderInterp::OnGlobalGetExpr(Index global_index) {
12451209
CHECK_RESULT(validator_.OnGlobalGet(GetLocation(), Var(global_index)));
1246-
if (reading_init_expr_) {
1247-
init_expr_.kind = InitExprKind::GlobalGet;
1248-
init_expr_.index_ = global_index;
1249-
return Result::Ok;
1250-
}
12511210
istream_.Emit(Opcode::GlobalGet, global_index);
12521211
return Result::Ok;
12531212
}
@@ -1339,22 +1298,12 @@ Result BinaryReaderInterp::OnTableFillExpr(Index table_index) {
13391298

13401299
Result BinaryReaderInterp::OnRefFuncExpr(Index func_index) {
13411300
CHECK_RESULT(validator_.OnRefFunc(GetLocation(), Var(func_index)));
1342-
if (reading_init_expr_) {
1343-
init_expr_.kind = InitExprKind::RefFunc;
1344-
init_expr_.index_ = func_index;
1345-
return Result::Ok;
1346-
}
13471301
istream_.Emit(Opcode::RefFunc, func_index);
13481302
return Result::Ok;
13491303
}
13501304

13511305
Result BinaryReaderInterp::OnRefNullExpr(Type type) {
13521306
CHECK_RESULT(validator_.OnRefNull(GetLocation(), type));
1353-
if (reading_init_expr_) {
1354-
init_expr_.kind = InitExprKind::RefNull;
1355-
init_expr_.type_ = type;
1356-
return Result::Ok;
1357-
}
13581307
istream_.Emit(Opcode::RefNull);
13591308
return Result::Ok;
13601309
}

src/interp/interp.cc

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -632,31 +632,18 @@ Result Memory::Copy(Memory& dst,
632632
return Result::Error;
633633
}
634634

635-
Value Instance::ResolveInitExpr(Store& store, InitExpr init) {
636-
Value result;
637-
switch (init.kind) {
638-
case InitExprKind::I32: result.Set(init.i32_); break;
639-
case InitExprKind::I64: result.Set(init.i64_); break;
640-
case InitExprKind::F32: result.Set(init.f32_); break;
641-
case InitExprKind::F64: result.Set(init.f64_); break;
642-
case InitExprKind::V128: result.Set(init.v128_); break;
643-
case InitExprKind::GlobalGet: {
644-
Global::Ptr global{store, globals_[init.index_]};
645-
result = global->Get();
646-
break;
647-
}
648-
case InitExprKind::RefFunc: {
649-
result.Set(funcs_[init.index_]);
650-
break;
651-
}
652-
case InitExprKind::RefNull:
653-
result.Set(Ref::Null);
654-
break;
655-
656-
case InitExprKind::None:
657-
WABT_UNREACHABLE;
635+
Result Instance::CallInitFunc(Store& store,
636+
const Ref func_ref,
637+
Value* result,
638+
Trap::Ptr* out_trap) {
639+
Values results;
640+
Func::Ptr func{store, func_ref};
641+
if (Failed(func->Call(store, {}, results, out_trap))) {
642+
return Result::Error;
658643
}
659-
return result;
644+
assert(results.size() == 1);
645+
*result = results[0];
646+
return Result::Ok;
660647
}
661648

662649
//// Global ////
@@ -811,9 +798,12 @@ Instance::Ptr Instance::Instantiate(Store& store,
811798

812799
// Globals.
813800
for (auto&& desc : mod->desc().globals) {
814-
inst->globals_.push_back(
815-
Global::New(store, desc.type, inst->ResolveInitExpr(store, desc.init))
816-
.ref());
801+
Value value;
802+
Ref func_ref = DefinedFunc::New(store, inst.ref(), desc.init_func).ref();
803+
if (Failed(inst->CallInitFunc(store, func_ref, &value, out_trap))) {
804+
return {};
805+
}
806+
inst->globals_.push_back(Global::New(store, desc.type, value).ref());
817807
}
818808

819809
// Tags.
@@ -858,7 +848,13 @@ Instance::Ptr Instance::Instantiate(Store& store,
858848
if (desc.mode == SegmentMode::Active) {
859849
Result result;
860850
Table::Ptr table{store, inst->tables_[desc.table_index]};
861-
u32 offset = inst->ResolveInitExpr(store, desc.offset).Get<u32>();
851+
Value value;
852+
Ref func_ref =
853+
DefinedFunc::New(store, inst.ref(), desc.init_func).ref();
854+
if (Failed(inst->CallInitFunc(store, func_ref, &value, out_trap))) {
855+
return {};
856+
}
857+
u32 offset = value.Get<u32>();
862858
if (pass == Check) {
863859
result = table->IsValidRange(offset, segment.size()) ? Result::Ok
864860
: Result::Error;
@@ -888,7 +884,12 @@ Instance::Ptr Instance::Instantiate(Store& store,
888884
if (desc.mode == SegmentMode::Active) {
889885
Result result;
890886
Memory::Ptr memory{store, inst->memories_[desc.memory_index]};
891-
Value offset_op = inst->ResolveInitExpr(store, desc.offset);
887+
Value offset_op;
888+
Ref func_ref =
889+
DefinedFunc::New(store, inst.ref(), desc.init_func).ref();
890+
if (Failed(inst->CallInitFunc(store, func_ref, &offset_op, out_trap))) {
891+
return {};
892+
}
892893
u64 offset = memory->type().limits.is_64 ? offset_op.Get<u64>()
893894
: offset_op.Get<u32>();
894895
if (pass == Check) {

0 commit comments

Comments
 (0)