diff options
-rw-r--r-- | src/apply-names.cc | 4 | ||||
-rw-r--r-- | src/binary-reader-ir.cc | 7 | ||||
-rw-r--r-- | src/binary-writer.cc | 45 | ||||
-rw-r--r-- | src/c-writer.cc | 6 | ||||
-rw-r--r-- | src/generate-names.cc | 4 | ||||
-rw-r--r-- | src/ir.cc | 43 | ||||
-rw-r--r-- | src/ir.h | 55 | ||||
-rw-r--r-- | src/wast-parser.cc | 4 | ||||
-rw-r--r-- | src/wat-writer.cc | 16 | ||||
-rw-r--r-- | test/regress/regress-20.txt | 19 |
10 files changed, 143 insertions, 60 deletions
diff --git a/src/apply-names.cc b/src/apply-names.cc index 4cabc13e..4b35d18e 100644 --- a/src/apply-names.cc +++ b/src/apply-names.cc @@ -328,10 +328,10 @@ Result NameApplier::VisitFunc(Index func_index, Func* func) { CHECK_RESULT(UseNameForFuncTypeVar(&func->decl.type_var)); } - MakeTypeBindingReverseMapping(func->decl.sig.param_types, + MakeTypeBindingReverseMapping(func->decl.sig.param_types.size(), func->param_bindings, ¶m_index_to_name_); - MakeTypeBindingReverseMapping(func->local_types, func->local_bindings, + MakeTypeBindingReverseMapping(func->local_types.size(), func->local_bindings, &local_index_to_name_); CHECK_RESULT(visitor_.VisitFunc(func)); diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index 448ac444..b90ed62c 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -541,12 +541,7 @@ Result BinaryReaderIR::BeginFunctionBody(Index index) { } Result BinaryReaderIR::OnLocalDecl(Index decl_index, Index count, Type type) { - TypeVector& types = current_func_->local_types; - WABT_TRY - types.reserve(types.size() + count); - WABT_CATCH_BAD_ALLOC - for (size_t i = 0; i < count; ++i) - types.push_back(type); + current_func_->local_types.decls.emplace_back(type, count); return Result::Ok; } diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 7f3d0f96..4c808359 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -139,7 +139,7 @@ class BinaryWriter { void WriteExpr(const Func* func, const Expr* expr); void WriteExprList(const Func* func, const ExprList& exprs); void WriteInitExpr(const ExprList& expr); - void WriteFuncLocals(const Func* func, const TypeVector& local_types); + void WriteFuncLocals(const Func* func, const LocalTypes& local_types); void WriteFunc(const Func* func); void WriteTable(const Table* table); void WriteMemory(const Memory* memory); @@ -622,44 +622,17 @@ void BinaryWriter::WriteInitExpr(const ExprList& expr) { } void BinaryWriter::WriteFuncLocals(const Func* func, - const TypeVector& local_types) { + const LocalTypes& local_types) { if (local_types.size() == 0) { WriteU32Leb128(stream_, 0, "local decl count"); return; } - Index num_params = func->GetNumParams(); - -#define FIRST_LOCAL_INDEX (num_params) -#define LAST_LOCAL_INDEX (num_params + local_types.size()) -#define GET_LOCAL_TYPE(x) (local_types[x - num_params]) - - /* loop through once to count the number of local declaration runs */ - Type current_type = GET_LOCAL_TYPE(FIRST_LOCAL_INDEX); - Index local_decl_count = 1; - for (Index i = FIRST_LOCAL_INDEX + 1; i < LAST_LOCAL_INDEX; ++i) { - Type type = GET_LOCAL_TYPE(i); - if (current_type != type) { - local_decl_count++; - current_type = type; - } - } - - /* loop through again to write everything out */ + Index local_decl_count = local_types.decls.size(); WriteU32Leb128(stream_, local_decl_count, "local decl count"); - current_type = GET_LOCAL_TYPE(FIRST_LOCAL_INDEX); - Index local_type_count = 1; - for (Index i = FIRST_LOCAL_INDEX + 1; i <= LAST_LOCAL_INDEX; ++i) { - /* loop through an extra time to catch the final type transition */ - Type type = i == LAST_LOCAL_INDEX ? Type::Void : GET_LOCAL_TYPE(i); - if (current_type == type) { - local_type_count++; - } else { - WriteU32Leb128(stream_, local_type_count, "local type count"); - WriteType(stream_, current_type); - local_type_count = 1; - current_type = type; - } + for (auto decl : local_types.decls) { + WriteU32Leb128(stream_, decl.second, "local type count"); + WriteType(stream_, decl.first); } } @@ -1034,7 +1007,7 @@ Result BinaryWriter::WriteModule() { WriteU32Leb128(stream_, i, "function index"); WriteU32Leb128(stream_, num_params_and_locals, "num locals"); - MakeTypeBindingReverseMapping(func->decl.sig.param_types, + MakeTypeBindingReverseMapping(func->decl.sig.param_types.size(), func->param_bindings, &index_to_name); for (size_t j = 0; j < num_params; ++j) { const std::string& name = index_to_name[j]; @@ -1043,8 +1016,8 @@ Result BinaryWriter::WriteModule() { WriteDebugName(stream_, name, desc); } - MakeTypeBindingReverseMapping(func->local_types, func->local_bindings, - &index_to_name); + MakeTypeBindingReverseMapping(func->local_types.size(), + func->local_bindings, &index_to_name); for (size_t j = 0; j < num_locals; ++j) { const std::string& name = index_to_name[j]; wabt_snprintf(desc, sizeof(desc), "local name %" PRIzd, num_params + j); diff --git a/src/c-writer.cc b/src/c-writer.cc index 43cf50d8..93dd9eb8 100644 --- a/src/c-writer.cc +++ b/src/c-writer.cc @@ -1314,7 +1314,7 @@ void CWriter::WriteParams() { Write("void"); } else { std::vector<std::string> index_to_name; - MakeTypeBindingReverseMapping(func_->decl.sig.param_types, + MakeTypeBindingReverseMapping(func_->decl.sig.param_types.size(), func_->param_bindings, &index_to_name); Indent(4); for (Index i = 0; i < func_->GetNumParams(); ++i) { @@ -1333,8 +1333,8 @@ void CWriter::WriteParams() { void CWriter::WriteLocals() { std::vector<std::string> index_to_name; - MakeTypeBindingReverseMapping(func_->local_types, func_->local_bindings, - &index_to_name); + MakeTypeBindingReverseMapping(func_->local_types.size(), + func_->local_bindings, &index_to_name); for (Type type : {Type::I32, Type::I64, Type::F32, Type::F64}) { Index local_index = 0; size_t count = 0; diff --git a/src/generate-names.cc b/src/generate-names.cc index a1b02fb4..ef2f8ab8 100644 --- a/src/generate-names.cc +++ b/src/generate-names.cc @@ -217,11 +217,11 @@ Result NameGenerator::VisitFunc(Index func_index, Func* func) { MaybeGenerateAndBindName(&module_->func_bindings, "$f", func_index, &func->name); - MakeTypeBindingReverseMapping(func->decl.sig.param_types, + MakeTypeBindingReverseMapping(func->decl.sig.param_types.size(), func->param_bindings, &index_to_name_); GenerateAndBindLocalNames(&func->param_bindings, "$p"); - MakeTypeBindingReverseMapping(func->local_types, func->local_bindings, + MakeTypeBindingReverseMapping(func->local_types.size(), func->local_bindings, &index_to_name_); GenerateAndBindLocalNames(&func->local_bindings, "$l"); @@ -18,6 +18,7 @@ #include <cassert> #include <cstddef> +#include <numeric> #include "src/cast.h" @@ -138,6 +139,44 @@ bool Module::IsImport(ExternalKind kind, const Var& var) const { } } +void LocalTypes::Set(const TypeVector& types) { + decls.clear(); + if (types.empty()) { + return; + } + + Type type = types[0]; + Index count = 1; + for (Index i = 1; i < types.size(); ++i) { + if (types[i] != type) { + decls.emplace_back(type, count); + type = types[i]; + count = 1; + } else { + ++count; + } + } + decls.emplace_back(type, count); +} + +Index LocalTypes::size() const { + return std::accumulate( + decls.begin(), decls.end(), 0, + [](Index sum, const Decl& decl) { return sum + decl.second; }); +} + +Type LocalTypes::operator[](Index i) const { + Index count = 0; + for (auto decl: decls) { + if (i < count + decl.second) { + return decl.first; + } + count += decl.second; + } + assert(i < count); + return Type::Any; +} + Type Func::GetLocalType(Index index) const { Index num_params = decl.GetNumParams(); if (index < num_params) { @@ -477,11 +516,11 @@ const Module* Script::GetModule(const Var& var) const { } void MakeTypeBindingReverseMapping( - const TypeVector& types, + size_t num_types, const BindingHash& bindings, std::vector<std::string>* out_reverse_mapping) { out_reverse_mapping->clear(); - out_reverse_mapping->resize(types.size()); + out_reverse_mapping->resize(num_types); for (const auto& pair : bindings) { assert(static_cast<size_t>(pair.second.index) < out_reverse_mapping->size()); @@ -404,6 +404,57 @@ struct Exception { TypeVector sig; }; +struct LocalTypes { + typedef std::pair<Type, Index> Decl; + typedef std::vector<Decl> Decls; + + struct const_iterator { + const_iterator(Decls::const_iterator decl, Index index) + : decl(decl), index(index) {} + Type operator*() const { return decl->first; } + const_iterator& operator++(); + const_iterator operator++(int); + + Decls::const_iterator decl; + Index index; + }; + + void Set(const TypeVector&); + + Index size() const; + Type operator[](Index) const; + + const_iterator begin() const { return {decls.begin(), 0}; } + const_iterator end() const { return {decls.end(), 0}; } + + Decls decls; +}; + +inline LocalTypes::const_iterator& LocalTypes::const_iterator::operator++() { + ++index; + if (index >= decl->second) { + ++decl; + index = 0; + } + return *this; +} + +inline LocalTypes::const_iterator LocalTypes::const_iterator::operator++(int) { + const_iterator result = *this; + operator++(); + return result; +} + +inline bool operator==(const LocalTypes::const_iterator& lhs, + const LocalTypes::const_iterator& rhs) { + return lhs.decl == rhs.decl && lhs.index == rhs.index; +} + +inline bool operator!=(const LocalTypes::const_iterator& lhs, + const LocalTypes::const_iterator& rhs) { + return !operator==(lhs, rhs); +} + struct Func { explicit Func(string_view name) : name(name.to_string()) {} @@ -421,7 +472,7 @@ struct Func { std::string name; FuncDeclaration decl; - TypeVector local_types; + LocalTypes local_types; BindingHash param_bindings; BindingHash local_bindings; ExprList exprs; @@ -969,7 +1020,7 @@ struct Script { }; void MakeTypeBindingReverseMapping( - const TypeVector& types, + size_t num_types, const BindingHash& bindings, std::vector<std::string>* out_reverse_mapping); diff --git a/src/wast-parser.cc b/src/wast-parser.cc index a86ab4e1..3381b65e 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -862,8 +862,10 @@ Result WastParser::ParseFuncModuleField(Module* module) { Func& func = field->func; CHECK_RESULT(ParseTypeUseOpt(&func.decl)); CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.param_bindings)); - CHECK_RESULT(ParseBoundValueTypeList(TokenType::Local, &func.local_types, + TypeVector local_types; + CHECK_RESULT(ParseBoundValueTypeList(TokenType::Local, &local_types, &func.local_bindings)); + func.local_types.Set(local_types); CHECK_RESULT(ParseTerminatingInstrList(&func.exprs)); module->AppendField(std::move(field)); } diff --git a/src/wat-writer.cc b/src/wat-writer.cc index c9db2f83..0f52e6a4 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -150,9 +150,10 @@ class WatWriter { void WriteLoadStoreExpr(const Expr* expr); void WriteExprList(const ExprList& exprs); void WriteInitExpr(const ExprList& expr); + template <typename T> void WriteTypeBindings(const char* prefix, const Func& func, - const TypeVector& types, + const T& types, const BindingHash& bindings); void WriteBeginFunc(const Func& func); void WriteFunc(const Func& func); @@ -1216,11 +1217,12 @@ void WatWriter::WriteInitExpr(const ExprList& expr) { } } +template <typename T> void WatWriter::WriteTypeBindings(const char* prefix, const Func& func, - const TypeVector& types, + const T& types, const BindingHash& bindings) { - MakeTypeBindingReverseMapping(types, bindings, &index_to_name_); + MakeTypeBindingReverseMapping(types.size(), bindings, &index_to_name_); /* named params/locals must be specified by themselves, but nameless * params/locals can be compressed, e.g.: @@ -1228,21 +1230,23 @@ void WatWriter::WriteTypeBindings(const char* prefix, * (param i32 i64 f32) */ bool is_open = false; - for (size_t i = 0; i < types.size(); ++i) { + size_t index = 0; + for (Type type : types) { if (!is_open) { WriteOpenSpace(prefix); is_open = true; } - const std::string& name = index_to_name_[i]; + const std::string& name = index_to_name_[index]; if (!name.empty()) { WriteString(name, NextChar::Space); } - WriteType(types[i], NextChar::Space); + WriteType(type, NextChar::Space); if (!name.empty()) { WriteCloseSpace(); is_open = false; } + ++index; } if (is_open) { WriteCloseSpace(); diff --git a/test/regress/regress-20.txt b/test/regress/regress-20.txt new file mode 100644 index 00000000..c1f409f8 --- /dev/null +++ b/test/regress/regress-20.txt @@ -0,0 +1,19 @@ +;;; TOOL: run-gen-wasm-bad +magic +version +section(TYPE) { count[1] function params[0] results[1] i32 } +section(FUNCTION) { count[1] type[0] } +section(CODE) { + count[1] + func { + locals[ + decl_count[1] + local_count[leb_i32(3334443763)] ;; <- huge number of locals + 42 ;; <- invalid type + ] + } +} +(;; STDERR ;;; +000001e: error: expected valid local type +000001e: error: expected valid local type +;;; STDERR ;;) |