summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binary-reader-logging.cc1
-rw-r--r--src/binary-reader-logging.h1
-rw-r--r--src/binary-reader-nop.h3
-rw-r--r--src/binary-reader-objdump.cc26
-rw-r--r--src/binary-reader.cc7
-rw-r--r--src/binary-reader.h1
-rw-r--r--src/binary-writer-spec.cc22
-rw-r--r--src/common.h10
-rw-r--r--src/interp/binary-reader-interp.cc77
-rw-r--r--src/interp/interp-disassemble.cc20
-rw-r--r--src/interp/interp-trace.cc11
-rw-r--r--src/interp/interp.cc32
-rw-r--r--src/interp/interp.h47
-rw-r--r--src/type-checker.cc54
-rw-r--r--src/type-checker.h4
-rw-r--r--src/validator.cc51
-rw-r--r--src/wast-parser.cc36
17 files changed, 287 insertions, 116 deletions
diff --git a/src/binary-reader-logging.cc b/src/binary-reader-logging.cc
index 9a23337a..59421b75 100644
--- a/src/binary-reader-logging.cc
+++ b/src/binary-reader-logging.cc
@@ -783,6 +783,7 @@ DEFINE_END(EndRelocSection)
DEFINE_INDEX_INDEX(OnInitExprGlobalGetExpr, "index", "global_index")
DEFINE_INDEX(OnInitExprRefNull)
+DEFINE_INDEX_INDEX(OnInitExprRefFunc, "index", "func_index")
DEFINE_BEGIN(BeginDylinkSection)
DEFINE_INDEX(OnDylinkNeededCount)
diff --git a/src/binary-reader-logging.h b/src/binary-reader-logging.h
index 901ef79a..d8bea6c2 100644
--- a/src/binary-reader-logging.h
+++ b/src/binary-reader-logging.h
@@ -344,6 +344,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
Result OnInitExprI32ConstExpr(Index index, uint32_t value) override;
Result OnInitExprI64ConstExpr(Index index, uint64_t value) override;
Result OnInitExprRefNull(Index index) override;
+ Result OnInitExprRefFunc(Index index, Index func_index) override;
private:
void Indent();
diff --git a/src/binary-reader-nop.h b/src/binary-reader-nop.h
index eae1fc08..845411ac 100644
--- a/src/binary-reader-nop.h
+++ b/src/binary-reader-nop.h
@@ -497,6 +497,9 @@ class BinaryReaderNop : public BinaryReaderDelegate {
Result OnInitExprRefNull(Index index) override {
return Result::Ok;
}
+ Result OnInitExprRefFunc(Index index, Index func_index) override {
+ return Result::Ok;
+ }
};
} // namespace wabt
diff --git a/src/binary-reader-objdump.cc b/src/binary-reader-objdump.cc
index 69f3a2c9..25ce8b28 100644
--- a/src/binary-reader-objdump.cc
+++ b/src/binary-reader-objdump.cc
@@ -689,13 +689,14 @@ enum class InitExprType {
F64,
V128,
Global,
+ FuncRef,
NullRef,
};
struct InitExpr {
InitExprType type;
union {
- Index global;
+ Index index;
uint32_t i32;
uint32_t f32;
uint64_t i64;
@@ -829,6 +830,7 @@ class BinaryReaderObjdump : public BinaryReaderObjdumpBase {
Result OnInitExprI32ConstExpr(Index index, uint32_t value) override;
Result OnInitExprI64ConstExpr(Index index, uint64_t value) override;
Result OnInitExprRefNull(Index index) override;
+ Result OnInitExprRefFunc(Index index, Index func_index) override;
Result OnDylinkInfo(uint32_t mem_size,
uint32_t mem_align_log2,
@@ -1326,8 +1328,17 @@ void BinaryReaderObjdump::PrintInitExpr(const InitExpr& expr) {
break;
}
case InitExprType::Global: {
- PrintDetails(" - init global=%" PRIindex, expr.value.global);
- string_view name = GetGlobalName(expr.value.global);
+ PrintDetails(" - init global=%" PRIindex, expr.value.index);
+ string_view name = GetGlobalName(expr.value.index);
+ if (!name.empty()) {
+ PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
+ }
+ PrintDetails("\n");
+ break;
+ }
+ case InitExprType::FuncRef: {
+ PrintDetails(" - init ref.func:%" PRIindex, expr.value.index);
+ string_view name = GetFunctionName(expr.value.index);
if (!name.empty()) {
PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
}
@@ -1354,6 +1365,7 @@ static Result InitExprToConstOffset(const InitExpr& expr,
case InitExprType::F32:
case InitExprType::F64:
case InitExprType::V128:
+ case InitExprType::FuncRef:
case InitExprType::NullRef:
fprintf(stderr, "Segment/Elem offset must be an i32 init expr");
return Result::Error;
@@ -1405,7 +1417,7 @@ Result BinaryReaderObjdump::OnInitExprGlobalGetExpr(Index index,
Index global_index) {
InitExpr expr;
expr.type = InitExprType::Global;
- expr.value.global = global_index;
+ expr.value.index = global_index;
HandleInitExpr(expr);
return Result::Ok;
}
@@ -1435,6 +1447,12 @@ Result BinaryReaderObjdump::OnInitExprRefNull(Index index) {
return Result::Ok;
}
+Result BinaryReaderObjdump::OnInitExprRefFunc(Index index, Index func_index) {
+ InitExpr expr{InitExprType::FuncRef, {func_index}};
+ HandleInitExpr(expr);
+ return Result::Ok;
+}
+
Result BinaryReaderObjdump::OnModuleName(string_view name) {
PrintDetails(" - module <" PRIstringview ">\n",
WABT_PRINTF_STRING_VIEW_ARG(name));
diff --git a/src/binary-reader.cc b/src/binary-reader.cc
index 511f712c..bd2c039a 100644
--- a/src/binary-reader.cc
+++ b/src/binary-reader.cc
@@ -497,6 +497,13 @@ Result BinaryReader::ReadInitExpr(Index index, bool require_i32) {
CALLBACK(OnInitExprRefNull, index);
break;
+ case Opcode::RefFunc: {
+ Index func_index;
+ CHECK_RESULT(ReadIndex(&func_index, "init_expr ref.func index"));
+ CALLBACK(OnInitExprRefFunc, index, func_index);
+ break;
+ }
+
case Opcode::End:
return Result::Ok;
diff --git a/src/binary-reader.h b/src/binary-reader.h
index 59d10655..6ad979e4 100644
--- a/src/binary-reader.h
+++ b/src/binary-reader.h
@@ -413,6 +413,7 @@ class BinaryReaderDelegate {
virtual Result OnInitExprI32ConstExpr(Index index, uint32_t value) = 0;
virtual Result OnInitExprI64ConstExpr(Index index, uint64_t value) = 0;
virtual Result OnInitExprRefNull(Index index) = 0;
+ virtual Result OnInitExprRefFunc(Index index, Index func_index) = 0;
const State* state = nullptr;
};
diff --git a/src/binary-writer-spec.cc b/src/binary-writer-spec.cc
index 399d0e78..2c169426 100644
--- a/src/binary-writer-spec.cc
+++ b/src/binary-writer-spec.cc
@@ -203,9 +203,23 @@ void BinaryWriterSpec::WriteConst(const Const& const_) {
}
case Type::Nullref:
- case Type::Funcref:
- case Type::Anyref: {
- WriteString("ref");
+ WriteString("nullref");
+ WriteSeparator();
+ WriteKey("value");
+ json_stream_->Writef("\"0\"");
+ break;
+
+ case Type::Funcref: {
+ WriteString("funcref");
+ WriteSeparator();
+ WriteKey("value");
+ int64_t ref_bits = static_cast<int64_t>(const_.ref_bits);
+ json_stream_->Writef("\"%" PRIu64 "\"", ref_bits);
+ break;
+ }
+
+ case Type::Hostref: {
+ WriteString("hostref");
WriteSeparator();
WriteKey("value");
int64_t ref_bits = static_cast<int64_t>(const_.ref_bits);
@@ -224,7 +238,7 @@ void BinaryWriterSpec::WriteConst(const Const& const_) {
}
default:
- assert(0);
+ WABT_UNREACHABLE;
}
json_stream_->Writef("}");
diff --git a/src/common.h b/src/common.h
index 14db973f..bcd4c8d2 100644
--- a/src/common.h
+++ b/src/common.h
@@ -376,6 +376,16 @@ static WABT_INLINE const char* GetSymbolTypeName(SymbolType type) {
/* type */
+static WABT_INLINE bool IsRefType(Type t) {
+ return t == Type::Anyref || t == Type::Funcref || t == Type::Nullref ||
+ t == Type::Hostref;
+}
+
+static WABT_INLINE bool IsNullableRefType(Type t) {
+ /* Currently all reftypes are nullable */
+ return IsRefType(t);
+}
+
static WABT_INLINE const char* GetTypeName(Type type) {
switch (type) {
case Type::I32:
diff --git a/src/interp/binary-reader-interp.cc b/src/interp/binary-reader-interp.cc
index aea60c37..239e8b76 100644
--- a/src/interp/binary-reader-interp.cc
+++ b/src/interp/binary-reader-interp.cc
@@ -47,6 +47,11 @@ struct Label {
IstreamOffset fixup_offset;
};
+struct GlobalType {
+ Type type;
+ bool mutable_;
+};
+
Label::Label(IstreamOffset offset, IstreamOffset fixup_offset)
: offset(offset), fixup_offset(fixup_offset) {}
@@ -189,6 +194,8 @@ class BinaryReaderInterp : public BinaryReaderNop {
wabt::Result OnTableCopyExpr(Index dst_index, Index src_index) override;
wabt::Result OnTableGetExpr(Index table_index) override;
wabt::Result OnTableSetExpr(Index table_index) override;
+ wabt::Result OnTableGrowExpr(Index table_index) override;
+ wabt::Result OnTableSizeExpr(Index table_index) override;
wabt::Result OnElemDropExpr(Index segment_index) override;
wabt::Result OnTableInitExpr(Index segment_index, Index table_index) override;
wabt::Result OnTernaryExpr(wabt::Opcode opcode) override;
@@ -229,6 +236,7 @@ class BinaryReaderInterp : public BinaryReaderNop {
wabt::Result OnInitExprI32ConstExpr(Index index, uint32_t value) override;
wabt::Result OnInitExprI64ConstExpr(Index index, uint64_t value) override;
wabt::Result OnInitExprRefNull(Index index) override;
+ wabt::Result OnInitExprRefFunc(Index index, Index func_index) override;
private:
Label* GetLabel(Index depth);
@@ -291,6 +299,8 @@ class BinaryReaderInterp : public BinaryReaderNop {
wabt::Result CheckLocal(Index local_index);
wabt::Result CheckGlobal(Index global_index);
+ wabt::Result CheckGlobalType(GlobalType actual,
+ GlobalType expected);
wabt::Result CheckDataSegment(Index data_segment_index);
wabt::Result CheckElemSegment(Index elem_segment_index);
wabt::Result CheckImportKind(string_view module,
@@ -815,6 +825,12 @@ wabt::Result BinaryReaderInterp::OnImportTable(Index import_index,
CHECK_RESULT(CheckImportKind(module_name, field_name, ExternalKind::Table, export_->kind));
Table* table = env_->GetTable(export_->index);
+ if (elem_type != table->elem_type) {
+ PrintError("type mismatch in imported table, expected %s but got %s.",
+ GetTypeName(elem_type), GetTypeName(table->elem_type));
+ return wabt::Result::Error;
+ }
+
CHECK_RESULT(CheckImportLimits(elem_limits, &table->limits));
table_index_mapping_.push_back(export_->index);
@@ -845,6 +861,27 @@ wabt::Result BinaryReaderInterp::OnImportMemory(Index import_index,
return wabt::Result::Ok;
}
+wabt::Result BinaryReaderInterp::CheckGlobalType(GlobalType actual,
+ GlobalType expected) {
+ if (actual.mutable_ != expected.mutable_) {
+ const char* kMutableNames[] = {"immutable", "mutable"};
+ PrintError(
+ "mutability mismatch in imported global, expected %s but got %s.",
+ kMutableNames[actual.mutable_], kMutableNames[expected.mutable_]);
+ return wabt::Result::Error;
+ }
+
+ if (actual.type == expected.type ||
+ (!expected.mutable_ &&
+ Succeeded(typechecker_.CheckType(actual.type, expected.type)))) {
+ return wabt::Result::Ok;
+ }
+
+ PrintError("type mismatch in imported global, expected %s but got %s.",
+ GetTypeName(expected.type), GetTypeName(actual.type));
+ return wabt::Result::Error;
+}
+
wabt::Result BinaryReaderInterp::OnImportGlobal(Index import_index,
string_view module_name,
string_view field_name,
@@ -856,21 +893,14 @@ wabt::Result BinaryReaderInterp::OnImportGlobal(Index import_index,
Export* export_;
CHECK_RESULT(GetModuleExport(import_module, field_name, &export_));
- CHECK_RESULT(CheckImportKind(module_name, field_name, ExternalKind::Global, export_->kind));
+ CHECK_RESULT(CheckImportKind(module_name, field_name, ExternalKind::Global,
+ export_->kind));
Global* exported_global = env_->GetGlobal(export_->index);
- 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));
- return wabt::Result::Error;
- }
+ GlobalType expected = {type, mutable_};
+ GlobalType actual = {exported_global->type, exported_global->mutable_};
- if (exported_global->mutable_ != mutable_) {
- const char* kMutableNames[] = {"immutable", "mutable"};
- PrintError(
- "mutability mismatch in imported global, expected %s but got %s.",
- kMutableNames[exported_global->mutable_], kMutableNames[mutable_]);
+ if (Failed(CheckGlobalType(actual, expected))) {
return wabt::Result::Error;
}
@@ -999,6 +1029,12 @@ wabt::Result BinaryReaderInterp::OnInitExprRefNull(Index index) {
return wabt::Result::Ok;
}
+wabt::Result BinaryReaderInterp::OnInitExprRefFunc(Index index, Index func_index) {
+ init_expr_value_.type = Type::Funcref;
+ init_expr_value_.set_ref({RefType::Func, TranslateFuncIndexToEnv(func_index)});
+ return wabt::Result::Ok;
+}
+
wabt::Result BinaryReaderInterp::OnExport(Index index,
ExternalKind kind,
Index item_index,
@@ -1724,10 +1760,25 @@ wabt::Result BinaryReaderInterp::OnMemorySizeExpr() {
return wabt::Result::Ok;
}
+wabt::Result BinaryReaderInterp::OnTableGrowExpr(Index table_index) {
+ Table* table = GetTableByModuleIndex(table_index);
+ CHECK_RESULT(typechecker_.OnTableGrow(table->elem_type));
+ CHECK_RESULT(EmitOpcode(Opcode::TableGrow));
+ CHECK_RESULT(EmitI32(TranslateTableIndexToEnv(table_index)));
+ return wabt::Result::Ok;
+}
+
+wabt::Result BinaryReaderInterp::OnTableSizeExpr(Index table_index) {
+ CHECK_RESULT(typechecker_.OnTableSize());
+ CHECK_RESULT(EmitOpcode(Opcode::TableSize));
+ CHECK_RESULT(EmitI32(TranslateTableIndexToEnv(table_index)));
+ 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));
+ CHECK_RESULT(EmitI32(TranslateFuncIndexToEnv(func_index)));
return wabt::Result::Ok;
}
diff --git a/src/interp/interp-disassemble.cc b/src/interp/interp-disassemble.cc
index ba232e92..75ef8708 100644
--- a/src/interp/interp-disassemble.cc
+++ b/src/interp/interp-disassemble.cc
@@ -586,13 +586,28 @@ void Environment::Disassemble(Stream* stream,
}
case Opcode::TableGet:
+ stream->Writef("%s %u %%[-1]\n", opcode.GetName(), ReadU32(&pc));
+ break;
+
case Opcode::TableSet:
+ stream->Writef("%s $%u %%[-1] %%[-2]\n", opcode.GetName(), ReadU32(&pc));
+ break;
+
case Opcode::TableGrow:
case Opcode::TableSize:
+ stream->Writef("%s %u\n", opcode.GetName(), ReadU32(&pc));
+ break;
+
case Opcode::RefNull:
- case Opcode::RefIsNull:
+ stream->Writef("%s\n", opcode.GetName());
+ break;
+
case Opcode::RefFunc:
- WABT_UNREACHABLE;
+ stream->Writef("%s $%u\n", opcode.GetName(), ReadU32(&pc));
+ break;
+
+ case Opcode::RefIsNull:
+ stream->Writef("%s %%[-1]\n", opcode.GetName());
break;
case Opcode::MemoryInit:
@@ -634,6 +649,7 @@ void Environment::Disassemble(Stream* stream,
case Opcode::Rethrow:
case Opcode::Throw:
case Opcode::Try:
+ fprintf(stderr, "unknown opcode: %#x\n", static_cast<uint32_t>(opcode));
WABT_UNREACHABLE;
break;
}
diff --git a/src/interp/interp-trace.cc b/src/interp/interp-trace.cc
index 1d6bbb94..8acf0a1d 100644
--- a/src/interp/interp-trace.cc
+++ b/src/interp/interp-trace.cc
@@ -699,10 +699,19 @@ void Thread::Trace(Stream* stream) {
case Opcode::TableSet:
case Opcode::TableGrow:
case Opcode::TableSize:
+
case Opcode::RefNull:
+ stream->Writef("%s\n", opcode.GetName());
+ break;
+
case Opcode::RefIsNull:
+ stream->Writef("%s %s:%08x\n", opcode.GetName(),
+ RefTypeToString(Pick(1).ref.kind).c_str(),
+ Pick(1).ref.index);
+ break;
+
case Opcode::RefFunc:
- WABT_UNREACHABLE;
+ stream->Writef("%s $%u\n", opcode.GetName(), ReadU32At(pc));
break;
case Opcode::MemoryInit:
diff --git a/src/interp/interp.cc b/src/interp/interp.cc
index f23f687d..1cfa333f 100644
--- a/src/interp/interp.cc
+++ b/src/interp/interp.cc
@@ -1126,8 +1126,7 @@ Result Thread::TableGet(const uint8_t** pc) {
TRAP_MSG(TableAccessOutOfBounds, "table.get at %u >= max value %" PRIzx,
index, table->size());
}
- Ref ref = static_cast<Ref>(table->entries[index]);
- return Push(ref);
+ return Push(table->entries[index]);
}
Result Thread::ElemDrop(const uint8_t** pc) {
@@ -1486,7 +1485,7 @@ ValueTypeRep<R> IntEqz(ValueTypeRep<T> v_rep) {
}
ValueTypeRep<uint32_t> RefIsNull(ValueTypeRep<Ref> v_rep) {
- return ToRep(v_rep.index == kInvalidIndex);
+ return ToRep(v_rep.kind == RefType::Null);
}
template <typename T>
@@ -3596,10 +3595,24 @@ Result Thread::Run(int num_instructions) {
CHECK_TRAP(Push(Ref{RefType::Null, kInvalidIndex}));
break;
- case Opcode::TableGrow:
- case Opcode::TableSize:
- WABT_UNREACHABLE;
+ case Opcode::TableGrow: {
+ Table* table = ReadTable(&pc);
+ uint32_t increment = Pop<uint32_t>();
+ Ref ref = Pop<Ref>();
+ uint32_t old_size = table->size();
+ uint32_t max = table->limits.has_max ? table->limits.max : UINT32_MAX;
+ PUSH_NEG_1_AND_BREAK_IF(int64_t(old_size) + increment > max);
+ uint32_t new_size = old_size + increment;
+ table->resize(new_size, ref);
+ CHECK_TRAP(Push<uint32_t>(old_size));
break;
+ }
+
+ case Opcode::TableSize: {
+ Table* table = ReadTable(&pc);
+ CHECK_TRAP(Push<uint32_t>(table->entries.size()));
+ break;
+ }
case Opcode::MemoryInit:
CHECK_TRAP(MemoryInit(&pc));
@@ -3709,6 +3722,10 @@ Result Executor::InitializeSegments(DefinedModule* module) {
enum Pass { Check = 0, Init = 1 };
int pass = env_->features_.bulk_memory_enabled() ? Init : Check;
+ if (trace_stream_) {
+ trace_stream_->Writef(">>> initializing segments\n");
+ }
+
for (; pass <= Init; ++pass) {
for (const ElemSegmentInfo& info : module->active_elem_segments_) {
uint32_t table_size = info.table->size();
@@ -3823,8 +3840,9 @@ void Executor::CopyResults(const FuncSignature* sig, TypedValues* out_results) {
assert(expected_results == thread_.NumValues());
out_results->clear();
- for (size_t i = 0; i < expected_results; ++i)
+ for (size_t i = 0; i < expected_results; ++i) {
out_results->emplace_back(sig->result_types[i], thread_.ValueAt(i));
+ }
}
} // namespace interp
diff --git a/src/interp/interp.h b/src/interp/interp.h
index 0fdb812b..70f7b8c1 100644
--- a/src/interp/interp.h
+++ b/src/interp/interp.h
@@ -122,11 +122,16 @@ struct Ref {
struct Table {
explicit Table(Type elem_type, const Limits& limits)
- : elem_type(elem_type),
- limits(limits),
- entries(limits.initial, {RefType::Null, kInvalidIndex}) {}
+ : elem_type(elem_type), limits(limits) {
+ resize(limits.initial, {RefType::Null, kInvalidIndex});
+ }
+
size_t size() const { return entries.size(); }
+ void resize(size_t new_size, Ref init_elem) {
+ entries.resize(new_size, init_elem);
+ }
+
Type elem_type;
Limits limits;
std::vector<Ref> entries;
@@ -206,30 +211,34 @@ struct TypedValue {
TypedValue() {}
explicit TypedValue(Type type) : type(type) {}
TypedValue(Type basetype, const Value& value) : type(basetype), value(value) {
- SetConcreteType();
+ UpdateType();
}
- void SetConcreteType() {
- // Anyref is an abstract type. The actual type is stored in value.
- if (type == Type::Anyref) {
- switch (value.ref.kind) {
- case RefType::Func:
- type = Type::Funcref;
- break;
- case RefType::Null:
- type = Type::Nullref;
- break;
- case RefType::Host:
- type = Type::Hostref;
- break;
- }
+ void UpdateType() {
+ if (!IsRefType(type)) {
+ return;
+ }
+
+ // For references types, the concrete type of TypedValue can change as it
+ // gets its value changed. For example assigning a RefType::Func value to
+ // an Anyref will cause type of the TypedValue to be changed into a Funcref.
+ switch (value.ref.kind) {
+ case RefType::Func:
+ type = Type::Funcref;
+ break;
+ case RefType::Host:
+ type = Type::Hostref;
+ break;
+ case RefType::Null:
+ type = Type::Nullref;
+ break;
}
}
void SetZero() { ZeroMemory(value); }
void set_ref(Ref x) {
value.ref = x;
- SetConcreteType();
+ UpdateType();
}
void set_i32(uint32_t x) { value.i32 = x; }
void set_i64(uint64_t x) { value.i64 = x; }
diff --git a/src/type-checker.cc b/src/type-checker.cc
index cc7618d5..1fcd7f12 100644
--- a/src/type-checker.cc
+++ b/src/type-checker.cc
@@ -168,26 +168,32 @@ Result TypeChecker::CheckTypeStackEnd(const char* desc) {
return result;
}
-static bool IsRefType(Type t) {
- return t == Type::Anyref || t == Type::Funcref || t == Type::Nullref ||
- t == Type::Hostref;
-}
-
-static bool IsNullableRefType(Type t) {
- return t == Type::Anyref || t == Type::Funcref || t == Type::Hostref;
+static bool IsSubtype(Type sub, Type super) {
+ if (super == sub) {
+ return true;
+ }
+ if (IsRefType(super) != IsRefType(sub)) {
+ return false;
+ }
+ if (super == Type::Anyref) {
+ return IsRefType(sub);
+ }
+ if (IsNullableRefType(super)) {
+ return sub == Type::Nullref;
+ }
+ return false;
}
Result TypeChecker::CheckType(Type actual, Type expected) {
- if (expected == actual || expected == Type::Any || actual == Type::Any) {
+ if (expected == Type::Any || actual == Type::Any) {
return Result::Ok;
}
- if (expected == Type::Anyref && IsRefType(actual)) {
- return Result::Ok;
- }
- if (IsNullableRefType(expected) && actual == Type::Nullref) {
- return Result::Ok;
+
+ if (!IsSubtype(actual, expected)) {
+ return Result::Error;
}
- return Result::Error;
+
+ return Result::Ok;
}
Result TypeChecker::CheckTypes(const TypeVector& actual,
@@ -655,13 +661,13 @@ Result TypeChecker::OnTableSet(Type elem_type) {
return PopAndCheck2Types(Type::I32, elem_type, "table.set");
}
-Result TypeChecker::OnTableGrow(Index segment) {
- Result result = PopAndCheck2Types(Type::Anyref, Type::I32, "table.grow");
+Result TypeChecker::OnTableGrow(Type elem_type) {
+ Result result = PopAndCheck2Types(elem_type, Type::I32, "table.grow");
PushType(Type::I32);
return result;
}
-Result TypeChecker::OnTableSize(Index segment) {
+Result TypeChecker::OnTableSize() {
PushType(Type::I32);
return Result::Ok;
}
@@ -706,13 +712,17 @@ Result TypeChecker::OnReturn() {
Result TypeChecker::OnSelect() {
Result result = Result::Ok;
- Type type = Type::Any;
+ Type type1 = Type::Any;
+ Type type2 = Type::Any;
+ Type result_type = Type::Any;
result |= PeekAndCheckType(0, Type::I32);
- result |= PeekType(1, &type);
- result |= PeekAndCheckType(2, type);
- PrintStackIfFailed(result, "select", type, type, Type::I32);
+ result |= PeekType(1, &type1);
+ result |= PeekType(2, &type2);
+ result |= CheckType(type1, type2);
+ result_type = type1;
+ PrintStackIfFailed(result, "select", type1, type1, Type::I32);
result |= DropTypes(3);
- PushType(type);
+ PushType(result_type);
return result;
}
diff --git a/src/type-checker.h b/src/type-checker.h
index b345a2df..ae05b034 100644
--- a/src/type-checker.h
+++ b/src/type-checker.h
@@ -104,8 +104,8 @@ class TypeChecker {
Result OnTableInit(Index, Index);
Result OnTableGet(Type elem_type);
Result OnTableSet(Type elem_type);
- Result OnTableGrow(Index table_index);
- Result OnTableSize(Index table_index);
+ Result OnTableGrow(Type elem_type);
+ Result OnTableSize();
Result OnRefFuncExpr(Index func_index);
Result OnRefNullExpr();
Result OnRefIsNullExpr();
diff --git a/src/validator.cc b/src/validator.cc
index 940a811b..78293ded 100644
--- a/src/validator.cc
+++ b/src/validator.cc
@@ -161,14 +161,10 @@ class Validator : public ExprVisitor::Delegate {
const TypeVector& expected,
const char* desc,
const char* index_kind);
- void CheckConstTypes(const Location* loc,
- const TypeVector& actual,
- const ConstVector& expected,
- const char* desc);
- void CheckConstType(const Location* loc,
- Type actual,
- const ConstVector& expected,
- const char* desc);
+ void CheckResultTypes(const Location* loc,
+ const TypeVector& actual,
+ const TypeVector& expected,
+ const char* desc);
void CheckAssertReturnNanType(const Location* loc,
Type actual,
const char* desc);
@@ -448,13 +444,13 @@ void Validator::CheckTypes(const Location* loc,
}
}
-void Validator::CheckConstTypes(const Location* loc,
- const TypeVector& actual,
- const ConstVector& expected,
- const char* desc) {
+void Validator::CheckResultTypes(const Location* loc,
+ const TypeVector& actual,
+ const TypeVector& expected,
+ const char* desc) {
if (actual.size() == expected.size()) {
for (size_t i = 0; i < actual.size(); ++i) {
- CheckTypeIndex(loc, actual[i], expected[i].type, desc, i, "result");
+ CheckTypeIndex(loc, actual[i], expected[i], desc, i, "result");
}
} else {
PrintError(loc, "expected %" PRIzd " results, got %" PRIzd, expected.size(),
@@ -462,17 +458,6 @@ void Validator::CheckConstTypes(const Location* loc,
}
}
-void Validator::CheckConstType(const Location* loc,
- Type actual,
- const ConstVector& expected,
- const char* desc) {
- TypeVector actual_types;
- if (actual != Type::Void) {
- actual_types.push_back(actual);
- }
- CheckConstTypes(loc, actual_types, expected, desc);
-}
-
void Validator::CheckAssertReturnNanType(const Location* loc,
Type actual,
const char* desc) {
@@ -822,16 +807,18 @@ Result Validator::OnTableSetExpr(TableSetExpr* expr) {
}
Result Validator::OnTableGrowExpr(TableGrowExpr* expr) {
+ const Table* table;
+ CheckTableVar(&expr->var, &table);
expr_loc_ = &expr->loc;
CheckHasTable(&expr->loc, Opcode::TableGrow, expr->var.index());
- typechecker_.OnTableGrow(expr->var.index());
+ typechecker_.OnTableGrow(table->elem_type);
return Result::Ok;
}
Result Validator::OnTableSizeExpr(TableSizeExpr* expr) {
expr_loc_ = &expr->loc;
CheckHasTable(&expr->loc, Opcode::TableSize, expr->var.index());
- typechecker_.OnTableSize(expr->var.index());
+ typechecker_.OnTableSize();
return Result::Ok;
}
@@ -1523,15 +1510,19 @@ void Validator::CheckCommand(const Command* command) {
auto* assert_return_command = cast<AssertReturnCommand>(command);
const Action* action = assert_return_command->action.get();
ActionResult result = CheckAction(action);
+ // Here we take the concrete expected output types verify those actains
+ // the types that are the result of the action.
+ TypeVector actual_types;
+ for (auto ex : assert_return_command->expected) {
+ actual_types.push_back(ex.type);
+ }
switch (result.kind) {
case ActionResult::Kind::Types:
- CheckConstTypes(&action->loc, *result.types,
- assert_return_command->expected, "action");
+ CheckResultTypes(&action->loc, actual_types, *result.types, "action");
break;
case ActionResult::Kind::Type:
- CheckConstType(&action->loc, result.type,
- assert_return_command->expected, "action");
+ CheckResultTypes(&action->loc, actual_types, {result.type}, "action");
break;
case ActionResult::Kind::Error:
diff --git a/src/wast-parser.cc b/src/wast-parser.cc
index 02cc69ac..5d4f555f 100644
--- a/src/wast-parser.cc
+++ b/src/wast-parser.cc
@@ -672,6 +672,9 @@ Result WastParser::ParseValueType(Type* out_type) {
is_enabled = options_->features.simd_enabled();
break;
case Type::Anyref:
+ case Type::Funcref:
+ case Type::Hostref:
+ case Type::Exnref:
is_enabled = options_->features.reference_types_enabled();
break;
default:
@@ -949,24 +952,33 @@ Result WastParser::ParseElemModuleField(Module* module) {
// since there was only one table anyway.
// With bulk-memory enabled this introduces a new name for the particualr
// elem segment.
- std::string segment_name;
- ParseBindVarOpt(&segment_name);
+ std::string initial_name;
+ bool has_name = ParseBindVarOpt(&initial_name);
+
+ std::string segment_name = initial_name;
if (!options_->features.bulk_memory_enabled()) {
segment_name = "";
}
-
auto field = MakeUnique<ElemSegmentModuleField>(loc, segment_name);
// Optional table specifier
- if (options_->features.bulk_memory_enabled() &&
- PeekMatchLpar(TokenType::Table)) {
- field->elem_segment.flags |= SegExplicitIndex;
- EXPECT(Lpar);
- EXPECT(Table);
- CHECK_RESULT(ParseVar(&field->elem_segment.table_var));
- EXPECT(Rpar);
+ if (options_->features.bulk_memory_enabled()) {
+ if (PeekMatchLpar(TokenType::Table)) {
+ field->elem_segment.flags |= SegExplicitIndex;
+ EXPECT(Lpar);
+ EXPECT(Table);
+ CHECK_RESULT(ParseVar(&field->elem_segment.table_var));
+ EXPECT(Rpar);
+ } else {
+ ParseVarOpt(&field->elem_segment.table_var, Var(0, loc));
+ }
} else {
- ParseVarOpt(&field->elem_segment.table_var, Var(0, loc));
+ if (has_name) {
+ field->elem_segment.table_var = Var(initial_name, loc);
+ field->elem_segment.flags |= SegExplicitIndex;
+ } else {
+ ParseVarOpt(&field->elem_segment.table_var, Var(0, loc));
+ }
}
if (ParseRefTypeOpt(&field->elem_segment.elem_type)) {
@@ -2081,7 +2093,7 @@ Result WastParser::ParseHostRef(Const* const_) {
uint64_t ref_bits;
Result result = ParseInt64(s, end, &ref_bits, ParseIntType::UnsignedOnly);
- const_->type = ref_bits ? Type::Anyref : Type::Nullref;
+ const_->type = Type::Hostref;
const_->ref_bits = static_cast<uintptr_t>(ref_bits);
if (Failed(result)) {