diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/feature.def | 1 | ||||
-rw-r--r-- | src/interp/binary-reader-interp.cc | 109 | ||||
-rw-r--r-- | src/interp/interp.cc | 59 | ||||
-rw-r--r-- | src/interp/interp.h | 38 | ||||
-rw-r--r-- | src/shared-validator.cc | 20 | ||||
-rw-r--r-- | src/shared-validator.h | 1 | ||||
-rw-r--r-- | src/test-interp.cc | 8 |
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. |