summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/apply-names.cc6
-rw-r--r--src/binary-reader-ir.cc5
-rw-r--r--src/binary-reader-logging.cc1
-rw-r--r--src/binary-reader-logging.h1
-rw-r--r--src/binary-reader-nop.h1
-rw-r--r--src/binary-reader.cc11
-rw-r--r--src/binary-reader.h1
-rw-r--r--src/binary-writer.cc6
-rw-r--r--src/c-writer.cc1
-rw-r--r--src/common.h2
-rw-r--r--src/expr-visitor.cc4
-rw-r--r--src/expr-visitor.h2
-rw-r--r--src/interp/binary-reader-interp.cc59
-rw-r--r--src/interp/interp.cc116
-rw-r--r--src/interp/interp.h27
-rw-r--r--src/ir-util.cc1
-rw-r--r--src/ir.cc1
-rw-r--r--src/ir.h2
-rw-r--r--src/opcode.def2
-rw-r--r--src/resolve-names.cc6
-rw-r--r--src/type-checker.cc5
-rw-r--r--src/type-checker.h1
-rw-r--r--src/validator.cc16
-rw-r--r--src/wast-parser.cc6
-rw-r--r--src/wat-writer.cc7
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, &copy_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:
diff --git a/src/ir.cc b/src/ir.cc
index fb87b09b..69547bbc 100644
--- a/src/ir.cc
+++ b/src/ir.cc
@@ -59,6 +59,7 @@ const char* ExprTypeName[] = {
"MemorySize",
"Nop",
"RefIsNull",
+ "RefFunc",
"RefNull",
"Rethrow",
"Return",
diff --git a/src/ir.h b/src/ir.h
index 41bef666..01f9301b 100644
--- a/src/ir.h
+++ b/src/ir.h
@@ -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;