summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/feature.def1
-rw-r--r--src/interp/binary-reader-interp.cc109
-rw-r--r--src/interp/interp.cc59
-rw-r--r--src/interp/interp.h38
-rw-r--r--src/shared-validator.cc20
-rw-r--r--src/shared-validator.h1
-rw-r--r--src/test-interp.cc8
7 files changed, 89 insertions, 147 deletions
diff --git a/src/feature.def b/src/feature.def
index cecab3e6..63f920df 100644
--- a/src/feature.def
+++ b/src/feature.def
@@ -37,3 +37,4 @@ WABT_FEATURE(annotations, "annotations", false, "Custom an
WABT_FEATURE(gc, "gc", false, "Garbage collection")
WABT_FEATURE(memory64, "memory64", false, "64-bit memory")
WABT_FEATURE(multi_memory, "multi-memory", false, "Multi-memory")
+WABT_FEATURE(extended_const, "extended-const", false, "Extended constant expressions")
diff --git a/src/interp/binary-reader-interp.cc b/src/interp/binary-reader-interp.cc
index 62803fc7..47a2d256 100644
--- a/src/interp/binary-reader-interp.cc
+++ b/src/interp/binary-reader-interp.cc
@@ -78,8 +78,6 @@ class BinaryReaderInterp : public BinaryReaderNop {
Errors* errors,
const Features& features);
- ValueType GetType(InitExpr);
-
// Implement BinaryReader.
bool OnError(const Error&) override;
@@ -301,7 +299,7 @@ class BinaryReaderInterp : public BinaryReaderNop {
Index keep_extra,
Index* out_drop_count,
Index* out_keep_count);
- Result BeginInitExpr(Type type);
+ Result BeginInitExpr(Type type, FuncDesc* init_func);
Result EndInitExpr();
void EmitBr(Index depth,
@@ -326,8 +324,6 @@ class BinaryReaderInterp : public BinaryReaderNop {
FixupMap depth_fixups_;
FixupMap func_fixups_;
- bool reading_init_expr_ = false;
- InitExpr init_expr_;
u32 local_decl_count_;
u32 local_count_;
@@ -619,37 +615,37 @@ Result BinaryReaderInterp::OnGlobalCount(Index count) {
Result BinaryReaderInterp::BeginGlobal(Index index, Type type, bool mutable_) {
CHECK_RESULT(validator_.OnGlobal(GetLocation(), type, mutable_));
GlobalType global_type{type, ToMutability(mutable_)};
- module_.globals.push_back(GlobalDesc{global_type, InitExpr{}});
+ FuncDesc init_func{FuncType{{}, {type}}, {}, Istream::kInvalidOffset, {}};
+ module_.globals.push_back(GlobalDesc{global_type, init_func});
global_types_.push_back(global_type);
- init_expr_.kind = InitExprKind::None;
return Result::Ok;
}
Result BinaryReaderInterp::BeginGlobalInitExpr(Index index) {
- GlobalType type = global_types_[index];
- return BeginInitExpr(type.type);
+ GlobalDesc& global = module_.globals.back();
+ return BeginInitExpr(global.type.type, &global.init_func);
}
Result BinaryReaderInterp::EndInitExpr() {
- assert(reading_init_expr_);
- reading_init_expr_ = false;
+ FixupTopLabel();
CHECK_RESULT(validator_.EndInitExpr());
+ istream_.Emit(Opcode::Return);
+ PopLabel();
return Result::Ok;
}
-Result BinaryReaderInterp::BeginInitExpr(Type type) {
- assert(!reading_init_expr_);
- reading_init_expr_ = true;
- init_expr_.kind = InitExprKind::None;
+Result BinaryReaderInterp::BeginInitExpr(Type type, FuncDesc* func) {
+ label_stack_.clear();
+ func_ = func;
+ func_->code_offset = istream_.end();
CHECK_RESULT(validator_.BeginInitExpr(GetLocation(), type));
+ // Push implicit init func label (equivalent to return).
+ PushLabel(LabelKind::Try, Istream::kInvalidOffset, Istream::kInvalidOffset);
return Result::Ok;
}
Result BinaryReaderInterp::EndGlobalInitExpr(Index index) {
- CHECK_RESULT(EndInitExpr());
- GlobalDesc& global = module_.globals.back();
- global.init = init_expr_;
- return Result::Ok;
+ return EndInitExpr();
}
Result BinaryReaderInterp::OnTagCount(Index count) {
@@ -702,24 +698,20 @@ Result BinaryReaderInterp::BeginElemSegment(Index index,
auto mode = ToSegmentMode(flags);
CHECK_RESULT(validator_.OnElemSegment(GetLocation(), Var(table_index), mode));
- ElemDesc desc;
- desc.type = ValueType::Void; // Initialized later in OnElemSegmentElemType.
- desc.mode = mode;
- desc.table_index = table_index;
+ FuncDesc init_func{
+ FuncType{{}, {ValueType::I32}}, {}, Istream::kInvalidOffset, {}};
+ ElemDesc desc{{}, ValueType::Void, mode, table_index, init_func};
module_.elems.push_back(desc);
- init_expr_.kind = InitExprKind::None;
return Result::Ok;
}
Result BinaryReaderInterp::BeginElemSegmentInitExpr(Index index) {
- return BeginInitExpr(Type::I32);
+ ElemDesc& elem = module_.elems.back();
+ return BeginInitExpr(Type::I32, &elem.init_func);
}
Result BinaryReaderInterp::EndElemSegmentInitExpr(Index index) {
- CHECK_RESULT(EndInitExpr());
- ElemDesc& elem = module_.elems.back();
- elem.offset = init_expr_;
- return Result::Ok;
+ return EndInitExpr();
}
Result BinaryReaderInterp::OnElemSegmentElemType(Index index, Type elem_type) {
@@ -761,14 +753,12 @@ Result BinaryReaderInterp::OnDataCount(Index count) {
Result BinaryReaderInterp::BeginDataSegmentInitExpr(Index index) {
MemoryType t = memory_types_[0];
- return BeginInitExpr(t.limits.is_64 ? Type::I64 : Type::I32);
+ DataDesc& data = module_.datas.back();
+ return BeginInitExpr(t.limits.is_64 ? Type::I64 : Type::I32, &data.init_func);
}
Result BinaryReaderInterp::EndDataSegmentInitExpr(Index index) {
- CHECK_RESULT(EndInitExpr());
- DataDesc& data = module_.datas.back();
- data.offset = init_expr_;
- return Result::Ok;
+ return EndInitExpr();
}
Result BinaryReaderInterp::BeginDataSegment(Index index,
@@ -778,11 +768,10 @@ Result BinaryReaderInterp::BeginDataSegment(Index index,
CHECK_RESULT(
validator_.OnDataSegment(GetLocation(), Var(memory_index), mode));
- DataDesc desc;
- desc.mode = mode;
- desc.memory_index = memory_index;
+ FuncDesc init_func{
+ FuncType{{}, {ValueType::I32}}, {}, Istream::kInvalidOffset, {}};
+ DataDesc desc{{}, mode, memory_index, init_func};
module_.datas.push_back(desc);
- init_expr_.kind = InitExprKind::None;
return Result::Ok;
}
@@ -873,7 +862,7 @@ Index BinaryReaderInterp::num_func_imports() const {
}
Result BinaryReaderInterp::OnOpcode(Opcode opcode) {
- if ((func_ == nullptr || label_stack_.empty()) && !reading_init_expr_) {
+ if (func_ == nullptr || label_stack_.empty()) {
PrintError("Unexpected instruction after end of function");
return Result::Error;
}
@@ -1021,7 +1010,7 @@ Result BinaryReaderInterp::OnElseExpr() {
}
Result BinaryReaderInterp::OnEndExpr() {
- if (reading_init_expr_ || label_stack_.size() == 1) {
+ if (label_stack_.size() == 1) {
return Result::Ok;
}
SharedValidator::Label* label;
@@ -1188,66 +1177,36 @@ Result BinaryReaderInterp::OnDropExpr() {
Result BinaryReaderInterp::OnI32ConstExpr(uint32_t value) {
CHECK_RESULT(validator_.OnConst(GetLocation(), Type::I32));
- if (reading_init_expr_) {
- init_expr_.kind = InitExprKind::I32;
- init_expr_.i32_ = value;
- return Result::Ok;
- }
istream_.Emit(Opcode::I32Const, value);
return Result::Ok;
}
Result BinaryReaderInterp::OnI64ConstExpr(uint64_t value) {
CHECK_RESULT(validator_.OnConst(GetLocation(), Type::I64));
- if (reading_init_expr_) {
- init_expr_.kind = InitExprKind::I64;
- init_expr_.i64_ = value;
- return Result::Ok;
- }
istream_.Emit(Opcode::I64Const, value);
return Result::Ok;
}
Result BinaryReaderInterp::OnF32ConstExpr(uint32_t value_bits) {
CHECK_RESULT(validator_.OnConst(GetLocation(), Type::F32));
- if (reading_init_expr_) {
- init_expr_.kind = InitExprKind::F32;
- init_expr_.f32_ = Bitcast<f32>(value_bits);
- return Result::Ok;
- }
istream_.Emit(Opcode::F32Const, value_bits);
return Result::Ok;
}
Result BinaryReaderInterp::OnF64ConstExpr(uint64_t value_bits) {
CHECK_RESULT(validator_.OnConst(GetLocation(), Type::F64));
- if (reading_init_expr_) {
- init_expr_.kind = InitExprKind::F64;
- init_expr_.f64_ = Bitcast<f64>(value_bits);
- return Result::Ok;
- }
istream_.Emit(Opcode::F64Const, value_bits);
return Result::Ok;
}
Result BinaryReaderInterp::OnV128ConstExpr(v128 value_bits) {
CHECK_RESULT(validator_.OnConst(GetLocation(), Type::V128));
- if (reading_init_expr_) {
- init_expr_.kind = InitExprKind::V128;
- init_expr_.v128_ = Bitcast<v128>(value_bits);
- return Result::Ok;
- }
istream_.Emit(Opcode::V128Const, value_bits);
return Result::Ok;
}
Result BinaryReaderInterp::OnGlobalGetExpr(Index global_index) {
CHECK_RESULT(validator_.OnGlobalGet(GetLocation(), Var(global_index)));
- if (reading_init_expr_) {
- init_expr_.kind = InitExprKind::GlobalGet;
- init_expr_.index_ = global_index;
- return Result::Ok;
- }
istream_.Emit(Opcode::GlobalGet, global_index);
return Result::Ok;
}
@@ -1339,22 +1298,12 @@ Result BinaryReaderInterp::OnTableFillExpr(Index table_index) {
Result BinaryReaderInterp::OnRefFuncExpr(Index func_index) {
CHECK_RESULT(validator_.OnRefFunc(GetLocation(), Var(func_index)));
- if (reading_init_expr_) {
- init_expr_.kind = InitExprKind::RefFunc;
- init_expr_.index_ = func_index;
- return Result::Ok;
- }
istream_.Emit(Opcode::RefFunc, func_index);
return Result::Ok;
}
Result BinaryReaderInterp::OnRefNullExpr(Type type) {
CHECK_RESULT(validator_.OnRefNull(GetLocation(), type));
- if (reading_init_expr_) {
- init_expr_.kind = InitExprKind::RefNull;
- init_expr_.type_ = type;
- return Result::Ok;
- }
istream_.Emit(Opcode::RefNull);
return Result::Ok;
}
diff --git a/src/interp/interp.cc b/src/interp/interp.cc
index 4c38b2e1..b4f8403e 100644
--- a/src/interp/interp.cc
+++ b/src/interp/interp.cc
@@ -632,31 +632,18 @@ Result Memory::Copy(Memory& dst,
return Result::Error;
}
-Value Instance::ResolveInitExpr(Store& store, InitExpr init) {
- Value result;
- switch (init.kind) {
- case InitExprKind::I32: result.Set(init.i32_); break;
- case InitExprKind::I64: result.Set(init.i64_); break;
- case InitExprKind::F32: result.Set(init.f32_); break;
- case InitExprKind::F64: result.Set(init.f64_); break;
- case InitExprKind::V128: result.Set(init.v128_); break;
- case InitExprKind::GlobalGet: {
- Global::Ptr global{store, globals_[init.index_]};
- result = global->Get();
- break;
- }
- case InitExprKind::RefFunc: {
- result.Set(funcs_[init.index_]);
- break;
- }
- case InitExprKind::RefNull:
- result.Set(Ref::Null);
- break;
-
- case InitExprKind::None:
- WABT_UNREACHABLE;
+Result Instance::CallInitFunc(Store& store,
+ const Ref func_ref,
+ Value* result,
+ Trap::Ptr* out_trap) {
+ Values results;
+ Func::Ptr func{store, func_ref};
+ if (Failed(func->Call(store, {}, results, out_trap))) {
+ return Result::Error;
}
- return result;
+ assert(results.size() == 1);
+ *result = results[0];
+ return Result::Ok;
}
//// Global ////
@@ -811,9 +798,12 @@ Instance::Ptr Instance::Instantiate(Store& store,
// Globals.
for (auto&& desc : mod->desc().globals) {
- inst->globals_.push_back(
- Global::New(store, desc.type, inst->ResolveInitExpr(store, desc.init))
- .ref());
+ Value value;
+ Ref func_ref = DefinedFunc::New(store, inst.ref(), desc.init_func).ref();
+ if (Failed(inst->CallInitFunc(store, func_ref, &value, out_trap))) {
+ return {};
+ }
+ inst->globals_.push_back(Global::New(store, desc.type, value).ref());
}
// Tags.
@@ -858,7 +848,13 @@ Instance::Ptr Instance::Instantiate(Store& store,
if (desc.mode == SegmentMode::Active) {
Result result;
Table::Ptr table{store, inst->tables_[desc.table_index]};
- u32 offset = inst->ResolveInitExpr(store, desc.offset).Get<u32>();
+ Value value;
+ Ref func_ref =
+ DefinedFunc::New(store, inst.ref(), desc.init_func).ref();
+ if (Failed(inst->CallInitFunc(store, func_ref, &value, out_trap))) {
+ return {};
+ }
+ u32 offset = value.Get<u32>();
if (pass == Check) {
result = table->IsValidRange(offset, segment.size()) ? Result::Ok
: Result::Error;
@@ -888,7 +884,12 @@ Instance::Ptr Instance::Instantiate(Store& store,
if (desc.mode == SegmentMode::Active) {
Result result;
Memory::Ptr memory{store, inst->memories_[desc.memory_index]};
- Value offset_op = inst->ResolveInitExpr(store, desc.offset);
+ Value offset_op;
+ Ref func_ref =
+ DefinedFunc::New(store, inst.ref(), desc.init_func).ref();
+ if (Failed(inst->CallInitFunc(store, func_ref, &offset_op, out_trap))) {
+ return {};
+ }
u64 offset = memory->type().limits.is_64 ? offset_op.Get<u64>()
: offset_op.Get<u32>();
if (pass == Check) {
diff --git a/src/interp/interp.h b/src/interp/interp.h
index aa397f04..a3fee5f4 100644
--- a/src/interp/interp.h
+++ b/src/interp/interp.h
@@ -98,31 +98,6 @@ const std::string GetName(ValueType);
const char* GetName(ExternKind);
const char* GetName(ObjectKind);
-enum class InitExprKind {
- None,
- I32,
- I64,
- F32,
- F64,
- V128,
- GlobalGet,
- RefNull,
- RefFunc
-};
-
-struct InitExpr {
- InitExprKind kind;
- union {
- u32 i32_;
- u64 i64_;
- f32 f32_;
- f64 f64_;
- v128 v128_;
- Index index_;
- Type type_;
- };
-};
-
struct Ref {
static const Ref Null;
@@ -341,7 +316,7 @@ struct FuncDesc {
FuncType type;
std::vector<LocalDesc> locals;
- u32 code_offset;
+ u32 code_offset; // Istream offset.
std::vector<HandlerDesc> handlers;
};
@@ -355,7 +330,7 @@ struct MemoryDesc {
struct GlobalDesc {
GlobalType type;
- InitExpr init;
+ FuncDesc init_func;
};
struct TagDesc {
@@ -375,7 +350,7 @@ struct DataDesc {
Buffer data;
SegmentMode mode;
Index memory_index;
- InitExpr offset;
+ FuncDesc init_func;
};
struct ElemExpr {
@@ -388,7 +363,7 @@ struct ElemDesc {
ValueType type;
SegmentMode mode;
Index table_index;
- InitExpr offset;
+ FuncDesc init_func;
};
struct ModuleDesc {
@@ -1069,7 +1044,10 @@ class Instance : public Object {
explicit Instance(Store&, Ref module);
void Mark(Store&) override;
- Value ResolveInitExpr(Store&, InitExpr);
+ Result CallInitFunc(Store&,
+ const Ref func_ref,
+ Value* result,
+ Trap::Ptr* out_trap);
Ref module_;
RefVec imports_;
diff --git a/src/shared-validator.cc b/src/shared-validator.cc
index 8932012e..68630182 100644
--- a/src/shared-validator.cc
+++ b/src/shared-validator.cc
@@ -519,11 +519,21 @@ Result SharedValidator::CheckAtomicAlign(const Location& loc,
return Result::Ok;
}
-static bool ValidInitOpcode(Opcode opcode) {
- return opcode == Opcode::GlobalGet || opcode == Opcode::I32Const ||
- opcode == Opcode::I64Const || opcode == Opcode::F32Const ||
- opcode == Opcode::F64Const || opcode == Opcode::RefFunc ||
- opcode == Opcode::RefNull;
+bool SharedValidator::ValidInitOpcode(Opcode opcode) const {
+ if (opcode == Opcode::GlobalGet || opcode == Opcode::I32Const ||
+ opcode == Opcode::I64Const || opcode == Opcode::F32Const ||
+ opcode == Opcode::F64Const || opcode == Opcode::RefFunc ||
+ opcode == Opcode::RefNull) {
+ return true;
+ }
+ if (options_.features.extended_const_enabled()) {
+ if (opcode == Opcode::I32Mul || opcode == Opcode::I64Mul ||
+ opcode == Opcode::I32Sub || opcode == Opcode::I64Sub ||
+ opcode == Opcode::I32Add || opcode == Opcode::I64Add) {
+ return true;
+ }
+ }
+ return false;
}
Result SharedValidator::CheckInstr(Opcode opcode, const Location& loc) {
diff --git a/src/shared-validator.h b/src/shared-validator.h
index c84503ec..33fe09ba 100644
--- a/src/shared-validator.h
+++ b/src/shared-validator.h
@@ -244,6 +244,7 @@ class SharedValidator {
Index end;
};
+ bool ValidInitOpcode(Opcode opcode) const;
Result CheckInstr(Opcode opcode, const Location& loc);
Result CheckType(const Location&,
Type actual,
diff --git a/src/test-interp.cc b/src/test-interp.cc
index 1ba6b0b1..93a524c6 100644
--- a/src/test-interp.cc
+++ b/src/test-interp.cc
@@ -680,11 +680,13 @@ TEST_F(InterpGCTest, Collect_InstanceExport) {
});
Instantiate();
auto after_new = store_.object_count();
- EXPECT_EQ(before_new + 6, after_new); // module, instance, f, t, m, g
+ EXPECT_EQ(before_new + 7,
+ after_new); // module, instance, f, t, m, g, g-init-func
- // Instance keeps all exports alive.
+ // Instance keeps all exports alive, except the init func which can be
+ // collected once its has been run
store_.Collect();
- EXPECT_EQ(after_new, store_.object_count());
+ EXPECT_EQ(after_new - 1, store_.object_count());
}
// TODO: Test for Thread keeping references alive as locals/params/stack values.