diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/apply-names.cc | 6 | ||||
-rw-r--r-- | src/binary-reader-ir.cc | 5 | ||||
-rw-r--r-- | src/binary-reader-logging.cc | 1 | ||||
-rw-r--r-- | src/binary-reader-logging.h | 1 | ||||
-rw-r--r-- | src/binary-reader-nop.h | 1 | ||||
-rw-r--r-- | src/binary-reader.cc | 11 | ||||
-rw-r--r-- | src/binary-reader.h | 1 | ||||
-rw-r--r-- | src/binary-writer.cc | 6 | ||||
-rw-r--r-- | src/c-writer.cc | 1 | ||||
-rw-r--r-- | src/common.h | 2 | ||||
-rw-r--r-- | src/expr-visitor.cc | 4 | ||||
-rw-r--r-- | src/expr-visitor.h | 2 | ||||
-rw-r--r-- | src/interp/binary-reader-interp.cc | 59 | ||||
-rw-r--r-- | src/interp/interp.cc | 116 | ||||
-rw-r--r-- | src/interp/interp.h | 27 | ||||
-rw-r--r-- | src/ir-util.cc | 1 | ||||
-rw-r--r-- | src/ir.cc | 1 | ||||
-rw-r--r-- | src/ir.h | 2 | ||||
-rw-r--r-- | src/opcode.def | 2 | ||||
-rw-r--r-- | src/resolve-names.cc | 6 | ||||
-rw-r--r-- | src/type-checker.cc | 5 | ||||
-rw-r--r-- | src/type-checker.h | 1 | ||||
-rw-r--r-- | src/validator.cc | 16 | ||||
-rw-r--r-- | src/wast-parser.cc | 6 | ||||
-rw-r--r-- | src/wat-writer.cc | 7 |
25 files changed, 249 insertions, 41 deletions
diff --git a/src/apply-names.cc b/src/apply-names.cc index 8f17db27..86d63924 100644 --- a/src/apply-names.cc +++ b/src/apply-names.cc @@ -42,6 +42,7 @@ class NameApplier : public ExprVisitor::DelegateNop { Result OnBrOnExnExpr(BrOnExnExpr*) override; Result OnBrTableExpr(BrTableExpr*) override; Result OnCallExpr(CallExpr*) override; + Result OnRefFuncExpr(RefFuncExpr*) override; Result OnCallIndirectExpr(CallIndirectExpr*) override; Result OnReturnCallExpr(ReturnCallExpr*) override; Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override; @@ -332,6 +333,11 @@ Result NameApplier::OnCallExpr(CallExpr* expr) { return Result::Ok; } +Result NameApplier::OnRefFuncExpr(RefFuncExpr* expr) { + CHECK_RESULT(UseNameForFuncVar(&expr->var)); + return Result::Ok; +} + Result NameApplier::OnCallIndirectExpr(CallIndirectExpr* expr) { if (expr->decl.has_func_type) { CHECK_RESULT(UseNameForFuncTypeVar(&expr->decl.type_var)); diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index 0515f660..ff00b494 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -179,6 +179,7 @@ class BinaryReaderIR : public BinaryReaderNop { Result OnTableSetExpr(Index table_index) override; Result OnTableGrowExpr(Index table_index) override; Result OnTableSizeExpr(Index table_index) override; + Result OnRefFuncExpr(Index func_index) override; Result OnRefNullExpr() override; Result OnRefIsNullExpr() override; Result OnNopExpr() override; @@ -882,6 +883,10 @@ Result BinaryReaderIR::OnTableSizeExpr(Index table_index) { return AppendExpr(MakeUnique<TableSizeExpr>(Var(table_index))); } +Result BinaryReaderIR::OnRefFuncExpr(Index func_index) { + return AppendExpr(MakeUnique<RefFuncExpr>(Var(func_index))); +} + Result BinaryReaderIR::OnRefNullExpr() { return AppendExpr(MakeUnique<RefNullExpr>()); } diff --git a/src/binary-reader-logging.cc b/src/binary-reader-logging.cc index 88ed41e6..16e7da41 100644 --- a/src/binary-reader-logging.cc +++ b/src/binary-reader-logging.cc @@ -731,6 +731,7 @@ DEFINE_INDEX(OnTableSetExpr) DEFINE_INDEX(OnTableGetExpr) DEFINE_INDEX(OnTableGrowExpr) DEFINE_INDEX(OnTableSizeExpr) +DEFINE_INDEX(OnRefFuncExpr) DEFINE0(OnRefNullExpr) DEFINE0(OnRefIsNullExpr) DEFINE0(OnNopExpr) diff --git a/src/binary-reader-logging.h b/src/binary-reader-logging.h index 568cd610..30353c8a 100644 --- a/src/binary-reader-logging.h +++ b/src/binary-reader-logging.h @@ -195,6 +195,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnTableSetExpr(Index table) override; Result OnTableGrowExpr(Index table) override; Result OnTableSizeExpr(Index table) override; + Result OnRefFuncExpr(Index index) override; Result OnRefNullExpr() override; Result OnRefIsNullExpr() override; Result OnNopExpr() override; diff --git a/src/binary-reader-nop.h b/src/binary-reader-nop.h index fe70a38a..79f31ea4 100644 --- a/src/binary-reader-nop.h +++ b/src/binary-reader-nop.h @@ -259,6 +259,7 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnTableSetExpr(Index table_index) override { return Result::Ok; } Result OnTableGrowExpr(Index table_index) override { return Result::Ok; } Result OnTableSizeExpr(Index table_index) override { return Result::Ok; } + Result OnRefFuncExpr(Index func_index) override { return Result::Ok; } Result OnRefNullExpr() override { return Result::Ok; } Result OnRefIsNullExpr() override { return Result::Ok; } Result OnNopExpr() override { return Result::Ok; } diff --git a/src/binary-reader.cc b/src/binary-reader.cc index 52e49000..cbc254a8 100644 --- a/src/binary-reader.cc +++ b/src/binary-reader.cc @@ -390,6 +390,9 @@ bool BinaryReader::IsConcreteType(Type type) { case Type::Anyref: return options_.features.reference_types_enabled(); + case Type::Funcref: + return options_.features.reference_types_enabled(); + default: return false; } @@ -1482,6 +1485,14 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { break; } + case Opcode::RefFunc: { + Index func; + CHECK_RESULT(ReadIndex(&func, "func index")); + CALLBACK(OnRefFuncExpr, func); + CALLBACK(OnOpcodeUint32, func); + break; + } + case Opcode::RefNull: { CALLBACK(OnRefNullExpr); CALLBACK0(OnOpcodeBare); diff --git a/src/binary-reader.h b/src/binary-reader.h index b9c4cba5..234e0493 100644 --- a/src/binary-reader.h +++ b/src/binary-reader.h @@ -251,6 +251,7 @@ class BinaryReaderDelegate { virtual Result OnTableSetExpr(Index table_index) = 0; virtual Result OnTableGrowExpr(Index table_index) = 0; virtual Result OnTableSizeExpr(Index table_index) = 0; + virtual Result OnRefFuncExpr(Index func_index) = 0; virtual Result OnRefNullExpr() = 0; virtual Result OnRefIsNullExpr() = 0; virtual Result OnNopExpr() = 0; diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 3610f2ee..8d63e28b 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -642,6 +642,12 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { WriteU32Leb128(stream_, index, "table.size table index"); break; } + case ExprType::RefFunc: { + WriteOpcode(stream_, Opcode::RefFunc); + Index index = module_->GetFuncIndex(cast<RefFuncExpr>(expr)->var); + WriteU32Leb128WithReloc(index, "function index", RelocType::FuncIndexLEB); + break; + } case ExprType::RefNull: { WriteOpcode(stream_, Opcode::RefNull); break; diff --git a/src/c-writer.cc b/src/c-writer.cc index 6584d6af..ac39dd3d 100644 --- a/src/c-writer.cc +++ b/src/c-writer.cc @@ -1592,6 +1592,7 @@ void CWriter::Write(const ExprList& exprs) { case ExprType::TableSet: case ExprType::TableGrow: case ExprType::TableSize: + case ExprType::RefFunc: case ExprType::RefNull: case ExprType::RefIsNull: UNIMPLEMENTED("..."); diff --git a/src/common.h b/src/common.h index b098f493..c4a9d144 100644 --- a/src/common.h +++ b/src/common.h @@ -389,6 +389,8 @@ static WABT_INLINE const char* GetTypeName(Type type) { return "any"; case Type::Anyref: return "anyref"; + case Type::Nullref: + return "nullref"; default: return "<type_index>"; } diff --git a/src/expr-visitor.cc b/src/expr-visitor.cc index 9547a432..4d38b508 100644 --- a/src/expr-visitor.cc +++ b/src/expr-visitor.cc @@ -305,6 +305,10 @@ Result ExprVisitor::HandleDefaultState(Expr* expr) { CHECK_RESULT(delegate_->OnTableSizeExpr(cast<TableSizeExpr>(expr))); break; + case ExprType::RefFunc: + CHECK_RESULT(delegate_->OnRefFuncExpr(cast<RefFuncExpr>(expr))); + break; + case ExprType::RefNull: CHECK_RESULT(delegate_->OnRefNullExpr(cast<RefNullExpr>(expr))); break; diff --git a/src/expr-visitor.h b/src/expr-visitor.h index 90ea4b25..6579b881 100644 --- a/src/expr-visitor.h +++ b/src/expr-visitor.h @@ -101,6 +101,7 @@ class ExprVisitor::Delegate { virtual Result OnTableSetExpr(TableSetExpr*) = 0; virtual Result OnTableGrowExpr(TableGrowExpr*) = 0; virtual Result OnTableSizeExpr(TableSizeExpr*) = 0; + virtual Result OnRefFuncExpr(RefFuncExpr*) = 0; virtual Result OnRefNullExpr(RefNullExpr*) = 0; virtual Result OnRefIsNullExpr(RefIsNullExpr*) = 0; virtual Result OnNopExpr(NopExpr*) = 0; @@ -167,6 +168,7 @@ class ExprVisitor::DelegateNop : public ExprVisitor::Delegate { Result OnTableSetExpr(TableSetExpr*) override { return Result::Ok; } Result OnTableGrowExpr(TableGrowExpr*) override { return Result::Ok; } Result OnTableSizeExpr(TableSizeExpr*) override { return Result::Ok; } + Result OnRefFuncExpr(RefFuncExpr*) override { return Result::Ok; } Result OnRefNullExpr(RefNullExpr*) override { return Result::Ok; } Result OnRefIsNullExpr(RefIsNullExpr*) override { return Result::Ok; } Result OnNopExpr(NopExpr*) override { return Result::Ok; } diff --git a/src/interp/binary-reader-interp.cc b/src/interp/binary-reader-interp.cc index 43ca9617..bcea26f7 100644 --- a/src/interp/binary-reader-interp.cc +++ b/src/interp/binary-reader-interp.cc @@ -55,7 +55,7 @@ struct ElemSegmentInfo { Table* table; Index dst; - std::vector<Index> src; + std::vector<Ref> src; }; struct DataSegmentInfo { @@ -198,6 +198,9 @@ class BinaryReaderInterp : public BinaryReaderNop { wabt::Result OnMemoryFillExpr() override; wabt::Result OnMemoryInitExpr(Index segment_index) override; wabt::Result OnMemorySizeExpr() override; + wabt::Result OnRefFuncExpr(Index func_index) override; + wabt::Result OnRefNullExpr() override; + wabt::Result OnRefIsNullExpr() override; wabt::Result OnNopExpr() override; wabt::Result OnReturnExpr() override; wabt::Result OnSelectExpr() override; @@ -206,6 +209,8 @@ class BinaryReaderInterp : public BinaryReaderNop { Address offset) override; wabt::Result OnUnaryExpr(wabt::Opcode opcode) override; wabt::Result OnTableCopyExpr() override; + wabt::Result OnTableGetExpr(Index table_index) override; + wabt::Result OnTableSetExpr(Index table_index) override; wabt::Result OnElemDropExpr(Index segment_index) override; wabt::Result OnTableInitExpr(Index segment_index) override; wabt::Result OnTernaryExpr(wabt::Opcode opcode) override; @@ -876,7 +881,7 @@ wabt::Result BinaryReaderInterp::OnImportGlobal(Index import_index, CHECK_RESULT(CheckImportKind(module_name, field_name, ExternalKind::Global, export_->kind)); Global* exported_global = env_->GetGlobal(export_->index); - if (exported_global->typed_value.type != type) { + if (Failed(typechecker_.CheckType(type, exported_global->typed_value.type))) { PrintError("type mismatch in imported global, expected %s but got %s.", GetTypeName(exported_global->typed_value.type), GetTypeName(type)); @@ -948,7 +953,7 @@ wabt::Result BinaryReaderInterp::BeginGlobal(Index index, wabt::Result BinaryReaderInterp::EndGlobalInitExpr(Index index) { Global* global = GetGlobalByModuleIndex(index); - if (init_expr_value_.type != global->typed_value.type) { + if (Failed(typechecker_.CheckType(init_expr_value_.type, global->typed_value.type))) { PrintError("type mismatch in global, expected %s but got %s.", GetTypeName(global->typed_value.type), GetTypeName(init_expr_value_.type)); @@ -1009,8 +1014,9 @@ wabt::Result BinaryReaderInterp::OnInitExprI64ConstExpr(Index index, } wabt::Result BinaryReaderInterp::OnInitExprRefNull(Index index) { - PrintError("ref.null global init expressions unimplemented by interpreter"); - return wabt::Result::Error; + init_expr_value_.type = Type::Nullref; + init_expr_value_.set_ref({RefType::Func, kInvalidIndex}); + return wabt::Result::Ok; } wabt::Result BinaryReaderInterp::OnExport(Index index, @@ -1121,7 +1127,7 @@ wabt::Result BinaryReaderInterp::OnElemSegmentElemExprCount(Index index, wabt::Result BinaryReaderInterp::OnElemSegmentElemExpr_RefNull( Index segment_index) { assert(segment_is_passive_); - elem_segment_->elems.push_back(kInvalidIndex); + elem_segment_->elems.push_back({RefType::Null, kInvalidIndex}); return wabt::Result::Ok; } @@ -1138,9 +1144,9 @@ wabt::Result BinaryReaderInterp::OnElemSegmentElemExpr_RefFunc( func_index = TranslateFuncIndexToEnv(func_index); if (segment_is_passive_) { - elem_segment_->elems.push_back(func_index); + elem_segment_->elems.push_back({RefType::Func, func_index}); } else { - elem_segment_info_->src.push_back(func_index); + elem_segment_info_->src.push_back({RefType::Func, func_index}); } return wabt::Result::Ok; } @@ -1732,6 +1738,25 @@ wabt::Result BinaryReaderInterp::OnMemorySizeExpr() { return wabt::Result::Ok; } +wabt::Result BinaryReaderInterp::OnRefFuncExpr(Index func_index) { + CHECK_RESULT(typechecker_.OnRefFuncExpr(func_index)); + CHECK_RESULT(EmitOpcode(Opcode::RefFunc)); + CHECK_RESULT(EmitI32(func_index)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnRefNullExpr() { + CHECK_RESULT(typechecker_.OnRefNullExpr()); + CHECK_RESULT(EmitOpcode(Opcode::RefNull)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnRefIsNullExpr() { + CHECK_RESULT(typechecker_.OnRefIsNullExpr()); + CHECK_RESULT(EmitOpcode(Opcode::RefIsNull)); + return wabt::Result::Ok; +} + wabt::Result BinaryReaderInterp::OnNopExpr() { return wabt::Result::Ok; } @@ -1815,6 +1840,20 @@ wabt::Result BinaryReaderInterp::OnMemoryInitExpr(Index segment_index) { return wabt::Result::Ok; } +wabt::Result BinaryReaderInterp::OnTableGetExpr(Index table_index) { + CHECK_RESULT(typechecker_.OnTableGet(table_index)); + CHECK_RESULT(EmitOpcode(Opcode::TableGet)); + CHECK_RESULT(EmitI32(table_index)); + return wabt::Result::Ok; +} + +wabt::Result BinaryReaderInterp::OnTableSetExpr(Index table_index) { + CHECK_RESULT(typechecker_.OnTableSet(table_index)); + CHECK_RESULT(EmitOpcode(Opcode::TableSet)); + CHECK_RESULT(EmitI32(table_index)); + return wabt::Result::Ok; +} + wabt::Result BinaryReaderInterp::OnTableCopyExpr() { CHECK_RESULT(CheckHasTable(Opcode::TableCopy)); CHECK_RESULT(typechecker_.OnTableCopy()); @@ -1851,14 +1890,14 @@ wabt::Result BinaryReaderInterp::InitializeSegments() { for (; pass <= Init; ++pass) { for (const ElemSegmentInfo& info : elem_segment_infos_) { - uint32_t table_size = info.table->func_indexes.size(); + uint32_t table_size = info.table->size(); uint32_t segment_size = info.src.size(); uint32_t copy_size = segment_size; bool ok = ClampToBounds(info.dst, ©_size, table_size); if (pass == Init && copy_size > 0) { std::copy(info.src.begin(), info.src.begin() + copy_size, - info.table->func_indexes.begin() + info.dst); + info.table->entries.begin() + info.dst); } if (!ok) { diff --git a/src/interp/interp.cc b/src/interp/interp.cc index 2e7883a1..4a207a0e 100644 --- a/src/interp/interp.cc +++ b/src/interp/interp.cc @@ -61,19 +61,30 @@ std::string TypedValueToString(const TypedValue& tv) { case Type::I64: return StringPrintf("i64:%" PRIu64, tv.get_i64()); - case Type::F32: { + case Type::F32: return StringPrintf("f32:%f", tv.get_f32()); - } - case Type::F64: { + case Type::F64: return StringPrintf("f64:%f", tv.get_f64()); - } case Type::V128: return StringPrintf("v128 i32x4:0x%08x 0x%08x 0x%08x 0x%08x", tv.value.v128_bits.v[0], tv.value.v128_bits.v[1], tv.value.v128_bits.v[2], tv.value.v128_bits.v[3]); + case Type::Nullref: + return StringPrintf("nullref"); + + case Type::Anyref: + if (tv.get_ref().index == kInvalidIndex) + return StringPrintf("anyref:nullref"); + return StringPrintf("anyref:%d(%" PRIindex ")", + static_cast<int>(tv.get_ref().kind), + tv.get_ref().index); + + case Type::Funcref: + return StringPrintf("funcref:%" PRIindex, tv.get_ref().index); + default: WABT_UNREACHABLE; } @@ -408,6 +419,7 @@ uint64_t ToRep(int64_t x) { return Bitcast<uint64_t>(x); } uint32_t ToRep(float x) { return Bitcast<uint32_t>(x); } uint64_t ToRep(double x) { return Bitcast<uint64_t>(x); } v128 ToRep(v128 x) { return Bitcast<v128>(x); } +Ref ToRep(Ref x) { return x; } template <typename Dst, typename Src> Dst FromRep(Src x); @@ -426,6 +438,8 @@ template <> double FromRep<double>(uint64_t x) { return Bitcast<double>(x); } template <> v128 FromRep<v128>(v128 x) { return Bitcast<v128>(x); } +template <> +Ref FromRep<Ref>(Ref x) { return x; } template <typename T> struct FloatTraits; @@ -717,6 +731,13 @@ Value MakeValue<v128>(v128 v) { return result; } +template <> +Value MakeValue<Ref>(Ref v) { + Value result; + result.ref = v; + return result; +} + template <typename T> ValueTypeRep<T> GetValue(Value); template<> uint32_t GetValue<int32_t>(Value v) { return v.i32; } template<> uint32_t GetValue<uint32_t>(Value v) { return v.i32; } @@ -725,6 +746,7 @@ template<> uint64_t GetValue<uint64_t>(Value v) { return v.i64; } template<> uint32_t GetValue<float>(Value v) { return v.f32_bits; } template<> uint64_t GetValue<double>(Value v) { return v.f64_bits; } template<> v128 GetValue<v128>(Value v) { return v.v128_bits; } +template<> Ref GetValue<Ref>(Value v) { return v.ref; } template <typename T> ValueTypeRep<T> CanonicalizeNan(ValueTypeRep<T> rep) { @@ -1032,21 +1054,40 @@ Result Thread::TableInit(const uint8_t** pc) { Table* table = ReadTable(pc); ElemSegment* segment = ReadElemSegment(pc); TRAP_IF(segment->dropped, ElemSegmentDropped); - uint32_t table_size = table->func_indexes.size(); uint32_t segment_size = segment->elems.size(); uint32_t size = Pop<uint32_t>(); uint32_t src = Pop<uint32_t>(); uint32_t dst = Pop<uint32_t>(); - bool ok = ClampToBounds(dst, &size, table_size); + bool ok = ClampToBounds(dst, &size, table->size()); ok &= ClampToBounds(src, &size, segment_size); if (size > 0) { - memcpy(table->func_indexes.data() + dst, segment->elems.data() + src, - size * sizeof(table->func_indexes[0])); + memcpy(table->entries.data() + dst, segment->elems.data() + src, + size * sizeof(table->entries[0])); } TRAP_IF(!ok, TableAccessOutOfBounds); return Result::Ok; } +Result Thread::TableSet(const uint8_t** pc) { + Table* table = ReadTable(pc); + // We currently only support tables of Funcref. + assert(table->elem_type == Type::Funcref); + Ref ref = Pop<Ref>(); + uint32_t index = Pop<uint32_t>(); + TRAP_IF(index >= table->size(), TableAccessOutOfBounds); + table->entries[index] = ref; + return Result::Ok; +} + +Result Thread::TableGet(const uint8_t** pc) { + Table* table = ReadTable(pc); + assert(table->elem_type == Type::Funcref); + uint32_t index = Pop<uint32_t>(); + TRAP_IF(index >= table->size(), TableAccessOutOfBounds); + Ref ref = static_cast<Ref>(table->entries[index]); + return Push(ref); +} + Result Thread::ElemDrop(const uint8_t** pc) { ElemSegment* segment = ReadElemSegment(pc); TRAP_IF(segment->dropped, ElemSegmentDropped); @@ -1056,25 +1097,30 @@ Result Thread::ElemDrop(const uint8_t** pc) { Result Thread::TableCopy(const uint8_t** pc) { Table* table = ReadTable(pc); - uint32_t table_size = table->func_indexes.size(); uint32_t size = Pop<uint32_t>(); uint32_t src = Pop<uint32_t>(); uint32_t dst = Pop<uint32_t>(); bool copy_backward = src < dst && dst - src < size; - bool ok = ClampToBounds(dst, &size, table_size); + bool ok = ClampToBounds(dst, &size, table->size()); // When copying backward, if the range is out-of-bounds, then no data will be // written. if (ok || !copy_backward) { - ok &= ClampToBounds(src, &size, table_size); + ok &= ClampToBounds(src, &size, table->size()); if (size > 0) { - Index* data = table->func_indexes.data(); - memmove(data + dst, data + src, size * sizeof(Index)); + Ref* data = table->entries.data(); + memmove(data + dst, data + src, size * sizeof(Ref)); } } TRAP_IF(!ok, TableAccessOutOfBounds); return Result::Ok; } +Result Thread::RefFunc(const uint8_t** pc) { + uint32_t index = ReadU32(pc); + assert(index < env_->GetFuncCount()); + return Push(Ref{RefType::Func, index}); +} + template <typename R, typename T> Result Thread::Unop(UnopFunc<R, T> func) { auto value = PopRep<T>(); @@ -1397,6 +1443,10 @@ ValueTypeRep<R> IntEqz(ValueTypeRep<T> v_rep) { return ToRep(v_rep == 0); } +ValueTypeRep<uint32_t> RefIsNull(ValueTypeRep<Ref> v_rep) { + return ToRep(v_rep.index == kInvalidIndex); +} + template <typename T> ValueTypeRep<T> IntNeg(ValueTypeRep<T> v_rep) { T tmp = static_cast<T>(v_rep); @@ -1800,10 +1850,11 @@ Result Thread::Run(int num_instructions) { Table* table = ReadTable(&pc); Index sig_index = ReadU32(&pc); Index entry_index = Pop<uint32_t>(); - TRAP_IF(entry_index >= table->func_indexes.size(), UndefinedTableIndex); - Index func_index = table->func_indexes[entry_index]; - TRAP_IF(func_index == kInvalidIndex, UninitializedTableElement); - Func* func = env_->funcs_[func_index].get(); + TRAP_IF(entry_index >= table->size(), UndefinedTableIndex); + Ref ref = table->entries[entry_index]; + TRAP_IF(ref.kind == RefType::Null, UninitializedTableElement); + assert(ref.kind == RefType::Func && ref.index != kInvalidIndex); + Func* func = env_->GetFunc(ref.index); TRAP_UNLESS(env_->FuncSignaturesAreEqual(func->sig_index, sig_index), IndirectCallSignatureMismatch); if (func->is_host) { @@ -1832,10 +1883,12 @@ Result Thread::Run(int num_instructions) { Table* table = ReadTable(&pc); Index sig_index = ReadU32(&pc); Index entry_index = Pop<uint32_t>(); - TRAP_IF(entry_index >= table->func_indexes.size(), UndefinedTableIndex); - Index func_index = table->func_indexes[entry_index]; - TRAP_IF(func_index == kInvalidIndex, UninitializedTableElement); - Func* func = env_->funcs_[func_index].get(); + TRAP_IF(entry_index >= table->size(), UndefinedTableIndex); + Ref ref = table->entries[entry_index]; + assert(ref.kind == RefType::Func); + TRAP_IF(ref.kind == RefType::Null, UninitializedTableElement); + assert(ref.kind == RefType::Func && ref.index != kInvalidIndex); + Func* func = env_->GetFunc(ref.index); TRAP_UNLESS(env_->FuncSignaturesAreEqual(func->sig_index, sig_index), IndirectCallSignatureMismatch); if (func->is_host) { // Emulate a call/return for imported functions @@ -3476,13 +3529,28 @@ Result Thread::Run(int num_instructions) { CHECK_TRAP(SimdUnop<v128, uint64_t>(IntTruncSat<uint64_t, double>)); break; + case Opcode::RefIsNull: + CHECK_TRAP(Unop(RefIsNull)); + break; + case Opcode::TableGet: + CHECK_TRAP(TableGet(&pc)); + break; + case Opcode::TableSet: + CHECK_TRAP(TableSet(&pc)); + break; + + case Opcode::RefFunc: + CHECK_TRAP(RefFunc(&pc)); + break; + + case Opcode::RefNull: + CHECK_TRAP(Push(Ref{RefType::Null, kInvalidIndex})); + break; + case Opcode::TableGrow: case Opcode::TableSize: - case Opcode::RefNull: - case Opcode::RefIsNull: - case Opcode::RefFunc: WABT_UNREACHABLE; break; diff --git a/src/interp/interp.h b/src/interp/interp.h index 7c0c7a30..1791084c 100644 --- a/src/interp/interp.h +++ b/src/interp/interp.h @@ -100,15 +100,27 @@ struct FuncSignature { std::vector<Type> result_types; }; +enum class RefType { + Func, + Null, + Host +}; + +struct Ref { + RefType kind; + Index index; // Only meaningful for RefType::FUNC +}; + struct Table { explicit Table(Type elem_type, const Limits& limits) : elem_type(elem_type), limits(limits), - func_indexes(limits.initial, kInvalidIndex) {} + entries(limits.initial, {RefType::Null, kInvalidIndex}) {} + size_t size() const { return entries.size(); } Type elem_type; Limits limits; - std::vector<Index> func_indexes; + std::vector<Ref> entries; }; struct Memory { @@ -130,7 +142,7 @@ struct DataSegment { struct ElemSegment { ElemSegment() = default; - std::vector<Index> elems; + std::vector<Ref> elems; bool dropped = false; }; @@ -139,6 +151,7 @@ struct ElemSegment { template <typename T> struct ValueTypeRepT; +template <> struct ValueTypeRepT<Ref> { typedef Ref type; }; template <> struct ValueTypeRepT<int32_t> { typedef uint32_t type; }; template <> struct ValueTypeRepT<uint32_t> { typedef uint32_t type; }; template <> struct ValueTypeRepT<int64_t> { typedef uint64_t type; }; @@ -156,6 +169,7 @@ union Value { ValueTypeRep<float> f32_bits; ValueTypeRep<double> f64_bits; ValueTypeRep<v128> v128_bits; + Ref ref; }; struct TypedValue { @@ -164,11 +178,13 @@ struct TypedValue { TypedValue(Type type, const Value& value) : type(type), value(value) {} void SetZero() { ZeroMemory(value); } + void set_ref(Ref x) { value.ref = x; } void set_i32(uint32_t x) { value.i32 = x; } void set_i64(uint64_t x) { value.i64 = x; } void set_f32(float x) { memcpy(&value.f32_bits, &x, sizeof(x)); } void set_f64(double x) { memcpy(&value.f64_bits, &x, sizeof(x)); } + Ref get_ref() const { return value.ref; } uint32_t get_i32() const { return value.i32; } uint64_t get_i64() const { return value.i64; } float get_f32() const { @@ -195,7 +211,7 @@ struct Global { TypedValue typed_value; bool mutable_; - Index import_index; /* or INVALID_INDEX if not imported */ + Index import_index; /* or kInvalidIndex if not imported */ }; struct Import { @@ -604,8 +620,11 @@ class Thread { Result MemoryCopy(const uint8_t** pc) WABT_WARN_UNUSED; Result MemoryFill(const uint8_t** pc) WABT_WARN_UNUSED; Result TableInit(const uint8_t** pc) WABT_WARN_UNUSED; + Result TableGet(const uint8_t** pc) WABT_WARN_UNUSED; + Result TableSet(const uint8_t** pc) WABT_WARN_UNUSED; Result ElemDrop(const uint8_t** pc) WABT_WARN_UNUSED; Result TableCopy(const uint8_t** pc) WABT_WARN_UNUSED; + Result RefFunc(const uint8_t** pc) WABT_WARN_UNUSED; template <typename R, typename T = R> Result Unop(UnopFunc<R, T> func) WABT_WARN_UNUSED; diff --git a/src/ir-util.cc b/src/ir-util.cc index c2cfd6d5..d1dc239f 100644 --- a/src/ir-util.cc +++ b/src/ir-util.cc @@ -155,6 +155,7 @@ ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const { case ExprType::MemorySize: case ExprType::TableSize: case ExprType::RefNull: + case ExprType::RefFunc: return { 0, 1 }; case ExprType::Unreachable: @@ -59,6 +59,7 @@ const char* ExprTypeName[] = { "MemorySize", "Nop", "RefIsNull", + "RefFunc", "RefNull", "Rethrow", "Return", @@ -193,6 +193,7 @@ enum class ExprType { MemorySize, Nop, RefIsNull, + RefFunc, RefNull, Rethrow, Return, @@ -323,6 +324,7 @@ class VarExpr : public ExprMixin<TypeEnum> { typedef VarExpr<ExprType::Br> BrExpr; typedef VarExpr<ExprType::BrIf> BrIfExpr; typedef VarExpr<ExprType::Call> CallExpr; +typedef VarExpr<ExprType::RefFunc> RefFuncExpr; typedef VarExpr<ExprType::GlobalGet> GlobalGetExpr; typedef VarExpr<ExprType::GlobalSet> GlobalSetExpr; typedef VarExpr<ExprType::LocalGet> LocalGetExpr; diff --git a/src/opcode.def b/src/opcode.def index fabb9550..79708415 100644 --- a/src/opcode.def +++ b/src/opcode.def @@ -255,8 +255,6 @@ WABT_OPCODE(___, ___, ___, ___, 0, 0xfc, 0x0f, TableGrow, "table.grow", "") WABT_OPCODE(___, ___, ___, ___, 0, 0xfc, 0x10, TableSize, "table.size", "") WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xd0, RefNull, "ref.null", "") WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xd1, RefIsNull, "ref.is_null", "") - -/* Not supported by any proposal currently; needed for passive element segments */ WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xd2, RefFunc, "ref.func", "") /* Simd opcodes (--enable-simd) */ diff --git a/src/resolve-names.cc b/src/resolve-names.cc index 0e3c70e1..6eef0685 100644 --- a/src/resolve-names.cc +++ b/src/resolve-names.cc @@ -63,6 +63,7 @@ class NameResolver : public ExprVisitor::DelegateNop { Result OnTableSetExpr(TableSetExpr*) override; Result OnTableGrowExpr(TableGrowExpr*) override; Result OnTableSizeExpr(TableSizeExpr*) override; + Result OnRefFuncExpr(RefFuncExpr*) override; Result BeginTryExpr(TryExpr*) override; Result EndTryExpr(TryExpr*) override; Result OnThrowExpr(ThrowExpr*) override; @@ -377,6 +378,11 @@ Result NameResolver::OnTableSizeExpr(TableSizeExpr* expr) { return Result::Ok; } +Result NameResolver::OnRefFuncExpr(RefFuncExpr* expr) { + ResolveFuncVar(&expr->var); + return Result::Ok; +} + Result NameResolver::BeginTryExpr(TryExpr* expr) { PushLabel(expr->block.label); ResolveBlockDeclarationVar(&expr->block.decl); diff --git a/src/type-checker.cc b/src/type-checker.cc index a5af56a9..f592c1db 100644 --- a/src/type-checker.cc +++ b/src/type-checker.cc @@ -658,6 +658,11 @@ Result TypeChecker::OnTableSize(Index segment) { return Result::Ok; } +Result TypeChecker::OnRefFuncExpr(Index) { + PushType(Type::Funcref); + return Result::Ok; +} + Result TypeChecker::OnRefNullExpr() { PushType(Type::Nullref); return Result::Ok; diff --git a/src/type-checker.h b/src/type-checker.h index dfaa9377..fe55768f 100644 --- a/src/type-checker.h +++ b/src/type-checker.h @@ -106,6 +106,7 @@ class TypeChecker { Result OnTableSet(Index); Result OnTableGrow(Index); Result OnTableSize(Index); + Result OnRefFuncExpr(Index); Result OnRefNullExpr(); Result OnRefIsNullExpr(); Result OnRethrow(); diff --git a/src/validator.cc b/src/validator.cc index 01bd6c8c..d3e9519a 100644 --- a/src/validator.cc +++ b/src/validator.cc @@ -80,6 +80,7 @@ class Validator : public ExprVisitor::Delegate { Result OnTableSetExpr(TableSetExpr*) override; Result OnTableGrowExpr(TableGrowExpr*) override; Result OnTableSizeExpr(TableSizeExpr*) override; + Result OnRefFuncExpr(RefFuncExpr*) override; Result OnRefNullExpr(RefNullExpr*) override; Result OnRefIsNullExpr(RefIsNullExpr*) override; Result OnNopExpr(NopExpr*) override; @@ -826,6 +827,15 @@ Result Validator::OnTableSizeExpr(TableSizeExpr* expr) { return Result::Ok; } +Result Validator::OnRefFuncExpr(RefFuncExpr* expr) { + expr_loc_ = &expr->loc; + const Func* callee; + if (Succeeded(CheckFuncVar(&expr->var, &callee))) { + typechecker_.OnRefFuncExpr(expr->var.index()); + } + return Result::Ok; +} + Result Validator::OnRefNullExpr(RefNullExpr* expr) { expr_loc_ = &expr->loc; typechecker_.OnRefNullExpr(); @@ -1069,10 +1079,14 @@ void Validator::CheckConstInitExpr(const Location* loc, break; } + case ExprType::RefFunc: + type = Type::Funcref; + break; + case ExprType::RefNull: type = Type::Nullref; break; - + default: PrintConstExprError(loc, desc); return; diff --git a/src/wast-parser.cc b/src/wast-parser.cc index ca21584f..8e85d830 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -145,6 +145,7 @@ bool IsPlainInstr(TokenType token_type) { case TokenType::TableSize: case TokenType::Throw: case TokenType::Rethrow: + case TokenType::RefFunc: case TokenType::RefNull: case TokenType::RefIsNull: case TokenType::AtomicLoad: @@ -1689,6 +1690,11 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) { CHECK_RESULT(ParsePlainInstrVar<TableSizeExpr>(loc, out_expr)); break; + case TokenType::RefFunc: + ErrorUnlessOpcodeEnabled(Consume()); + CHECK_RESULT(ParsePlainInstrVar<RefFuncExpr>(loc, out_expr)); + break; + case TokenType::RefNull: ErrorUnlessOpcodeEnabled(Consume()); out_expr->reset(new RefNullExpr(loc)); diff --git a/src/wat-writer.cc b/src/wat-writer.cc index 8402e9d7..e5cbe626 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -532,6 +532,7 @@ class WatWriter::ExprVisitorDelegate : public ExprVisitor::Delegate { Result OnTableSetExpr(TableSetExpr*) override; Result OnTableGrowExpr(TableGrowExpr*) override; Result OnTableSizeExpr(TableSizeExpr*) override; + Result OnRefFuncExpr(RefFuncExpr*) override; Result OnRefNullExpr(RefNullExpr*) override; Result OnRefIsNullExpr(RefIsNullExpr*) override; Result OnNopExpr(NopExpr*) override; @@ -787,6 +788,12 @@ Result WatWriter::ExprVisitorDelegate::OnTableSizeExpr(TableSizeExpr* expr) { return Result::Ok; } +Result WatWriter::ExprVisitorDelegate::OnRefFuncExpr(RefFuncExpr* expr) { + writer_->WritePutsNewline(Opcode::RefFunc_Opcode.GetName()); + writer_->WriteVar(expr->var, NextChar::Newline); + return Result::Ok; +} + Result WatWriter::ExprVisitorDelegate::OnRefNullExpr(RefNullExpr* expr) { writer_->WritePutsNewline(Opcode::RefNull_Opcode.GetName()); return Result::Ok; |