diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/wasm2c/src/ir.cc | |
parent | Initial commit. (diff) | |
download | firefox-upstream/124.0.1.tar.xz firefox-upstream/124.0.1.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/wasm2c/src/ir.cc')
-rw-r--r-- | third_party/wasm2c/src/ir.cc | 701 |
1 files changed, 701 insertions, 0 deletions
diff --git a/third_party/wasm2c/src/ir.cc b/third_party/wasm2c/src/ir.cc new file mode 100644 index 0000000000..88db7d5f46 --- /dev/null +++ b/third_party/wasm2c/src/ir.cc @@ -0,0 +1,701 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wabt/ir.h" + +#include <cassert> +#include <cstddef> +#include <numeric> + +#include "wabt/cast.h" + +namespace { + +const char* ExprTypeName[] = { + "AtomicFence", + "AtomicLoad", + "AtomicRmw", + "AtomicRmwCmpxchg", + "AtomicStore", + "AtomicNotify", + "AtomicWait", + "Binary", + "Block", + "Br", + "BrIf", + "BrTable", + "Call", + "CallIndirect", + "CallRef", + "CodeMetadata", + "Compare", + "Const", + "Convert", + "Drop", + "GlobalGet", + "GlobalSet", + "If", + "Load", + "LocalGet", + "LocalSet", + "LocalTee", + "Loop", + "MemoryCopy", + "DataDrop", + "MemoryFill", + "MemoryGrow", + "MemoryInit", + "MemorySize", + "Nop", + "RefIsNull", + "RefFunc", + "RefNull", + "Rethrow", + "Return", + "ReturnCall", + "ReturnCallIndirect", + "Select", + "SimdLaneOp", + "SimdLoadLane", + "SimdStoreLane", + "SimdShuffleOp", + "LoadSplat", + "LoadZero", + "Store", + "TableCopy", + "ElemDrop", + "TableInit", + "TableGet", + "TableGrow", + "TableSize", + "TableSet", + "TableFill", + "Ternary", + "Throw", + "Try", + "Unary", + "Unreachable", +}; + +} // end of anonymous namespace + +namespace wabt { + +const char* GetExprTypeName(ExprType type) { + static_assert(WABT_ENUM_COUNT(ExprType) == WABT_ARRAY_SIZE(ExprTypeName), + "Malformed ExprTypeName array"); + return ExprTypeName[size_t(type)]; +} + +const char* GetExprTypeName(const Expr& expr) { + return GetExprTypeName(expr.type()); +} + +bool FuncSignature::operator==(const FuncSignature& rhs) const { + return param_types == rhs.param_types && result_types == rhs.result_types; +} + +const Export* Module::GetExport(std::string_view name) const { + Index index = export_bindings.FindIndex(name); + if (index >= exports.size()) { + return nullptr; + } + return exports[index]; +} + +Index Module::GetFuncIndex(const Var& var) const { + return func_bindings.FindIndex(var); +} + +Index Module::GetGlobalIndex(const Var& var) const { + return global_bindings.FindIndex(var); +} + +Index Module::GetTableIndex(const Var& var) const { + return table_bindings.FindIndex(var); +} + +Index Module::GetMemoryIndex(const Var& var) const { + return memory_bindings.FindIndex(var); +} + +Index Module::GetFuncTypeIndex(const Var& var) const { + return type_bindings.FindIndex(var); +} + +Index Module::GetTagIndex(const Var& var) const { + return tag_bindings.FindIndex(var); +} + +Index Module::GetDataSegmentIndex(const Var& var) const { + return data_segment_bindings.FindIndex(var); +} + +Index Module::GetElemSegmentIndex(const Var& var) const { + return elem_segment_bindings.FindIndex(var); +} + +bool Module::IsImport(ExternalKind kind, const Var& var) const { + switch (kind) { + case ExternalKind::Func: + return GetFuncIndex(var) < num_func_imports; + + case ExternalKind::Global: + return GetGlobalIndex(var) < num_global_imports; + + case ExternalKind::Memory: + return GetMemoryIndex(var) < num_memory_imports; + + case ExternalKind::Table: + return GetTableIndex(var) < num_table_imports; + + case ExternalKind::Tag: + return GetTagIndex(var) < num_tag_imports; + + default: + return false; + } +} + +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) { + return GetParamType(index); + } else { + index -= num_params; + assert(index < local_types.size()); + return local_types[index]; + } +} + +Type Func::GetLocalType(const Var& var) const { + return GetLocalType(GetLocalIndex(var)); +} + +Index Func::GetLocalIndex(const Var& var) const { + if (var.is_index()) { + return var.index(); + } + return bindings.FindIndex(var); +} + +const Func* Module::GetFunc(const Var& var) const { + return const_cast<Module*>(this)->GetFunc(var); +} + +Func* Module::GetFunc(const Var& var) { + Index index = func_bindings.FindIndex(var); + if (index >= funcs.size()) { + return nullptr; + } + return funcs[index]; +} + +const Global* Module::GetGlobal(const Var& var) const { + return const_cast<Module*>(this)->GetGlobal(var); +} + +Global* Module::GetGlobal(const Var& var) { + Index index = global_bindings.FindIndex(var); + if (index >= globals.size()) { + return nullptr; + } + return globals[index]; +} + +const Table* Module::GetTable(const Var& var) const { + return const_cast<Module*>(this)->GetTable(var); +} + +Table* Module::GetTable(const Var& var) { + Index index = table_bindings.FindIndex(var); + if (index >= tables.size()) { + return nullptr; + } + return tables[index]; +} + +const Memory* Module::GetMemory(const Var& var) const { + return const_cast<Module*>(this)->GetMemory(var); +} + +Memory* Module::GetMemory(const Var& var) { + Index index = memory_bindings.FindIndex(var); + if (index >= memories.size()) { + return nullptr; + } + return memories[index]; +} + +Tag* Module::GetTag(const Var& var) const { + Index index = GetTagIndex(var); + if (index >= tags.size()) { + return nullptr; + } + return tags[index]; +} + +const DataSegment* Module::GetDataSegment(const Var& var) const { + return const_cast<Module*>(this)->GetDataSegment(var); +} + +DataSegment* Module::GetDataSegment(const Var& var) { + Index index = data_segment_bindings.FindIndex(var); + if (index >= data_segments.size()) { + return nullptr; + } + return data_segments[index]; +} + +const ElemSegment* Module::GetElemSegment(const Var& var) const { + return const_cast<Module*>(this)->GetElemSegment(var); +} + +ElemSegment* Module::GetElemSegment(const Var& var) { + Index index = elem_segment_bindings.FindIndex(var); + if (index >= elem_segments.size()) { + return nullptr; + } + return elem_segments[index]; +} + +const FuncType* Module::GetFuncType(const Var& var) const { + return const_cast<Module*>(this)->GetFuncType(var); +} + +FuncType* Module::GetFuncType(const Var& var) { + Index index = type_bindings.FindIndex(var); + if (index >= types.size()) { + return nullptr; + } + return dyn_cast<FuncType>(types[index]); +} + +Index Module::GetFuncTypeIndex(const FuncSignature& sig) const { + for (size_t i = 0; i < types.size(); ++i) { + if (auto* func_type = dyn_cast<FuncType>(types[i])) { + if (func_type->sig == sig) { + return i; + } + } + } + return kInvalidIndex; +} + +Index Module::GetFuncTypeIndex(const FuncDeclaration& decl) const { + if (decl.has_func_type) { + return GetFuncTypeIndex(decl.type_var); + } else { + return GetFuncTypeIndex(decl.sig); + } +} + +void Module::AppendField(std::unique_ptr<DataSegmentModuleField> field) { + DataSegment& data_segment = field->data_segment; + if (!data_segment.name.empty()) { + data_segment_bindings.emplace(data_segment.name, + Binding(field->loc, data_segments.size())); + } + data_segments.push_back(&data_segment); + fields.push_back(std::move(field)); +} + +void Module::AppendField(std::unique_ptr<ElemSegmentModuleField> field) { + ElemSegment& elem_segment = field->elem_segment; + if (!elem_segment.name.empty()) { + elem_segment_bindings.emplace(elem_segment.name, + Binding(field->loc, elem_segments.size())); + } + elem_segments.push_back(&elem_segment); + fields.push_back(std::move(field)); +} + +void Module::AppendField(std::unique_ptr<TagModuleField> field) { + Tag& tag = field->tag; + if (!tag.name.empty()) { + tag_bindings.emplace(tag.name, Binding(field->loc, tags.size())); + } + tags.push_back(&tag); + fields.push_back(std::move(field)); +} + +void Module::AppendField(std::unique_ptr<ExportModuleField> field) { + // Exported names are allowed to be empty. + Export& export_ = field->export_; + export_bindings.emplace(export_.name, Binding(field->loc, exports.size())); + exports.push_back(&export_); + fields.push_back(std::move(field)); +} + +void Module::AppendField(std::unique_ptr<FuncModuleField> field) { + Func& func = field->func; + if (!func.name.empty()) { + func_bindings.emplace(func.name, Binding(field->loc, funcs.size())); + } + funcs.push_back(&func); + fields.push_back(std::move(field)); +} + +void Module::AppendField(std::unique_ptr<TypeModuleField> field) { + TypeEntry& type = *field->type; + if (!type.name.empty()) { + type_bindings.emplace(type.name, Binding(field->loc, types.size())); + } + types.push_back(&type); + fields.push_back(std::move(field)); +} + +void Module::AppendField(std::unique_ptr<GlobalModuleField> field) { + Global& global = field->global; + if (!global.name.empty()) { + global_bindings.emplace(global.name, Binding(field->loc, globals.size())); + } + globals.push_back(&global); + fields.push_back(std::move(field)); +} + +void Module::AppendField(std::unique_ptr<ImportModuleField> field) { + Import* import = field->import.get(); + const std::string* name = nullptr; + BindingHash* bindings = nullptr; + Index index = kInvalidIndex; + + switch (import->kind()) { + case ExternalKind::Func: { + Func& func = cast<FuncImport>(import)->func; + name = &func.name; + bindings = &func_bindings; + index = funcs.size(); + funcs.push_back(&func); + ++num_func_imports; + break; + } + + case ExternalKind::Table: { + Table& table = cast<TableImport>(import)->table; + name = &table.name; + bindings = &table_bindings; + index = tables.size(); + tables.push_back(&table); + ++num_table_imports; + break; + } + + case ExternalKind::Memory: { + Memory& memory = cast<MemoryImport>(import)->memory; + name = &memory.name; + bindings = &memory_bindings; + index = memories.size(); + memories.push_back(&memory); + ++num_memory_imports; + break; + } + + case ExternalKind::Global: { + Global& global = cast<GlobalImport>(import)->global; + name = &global.name; + bindings = &global_bindings; + index = globals.size(); + globals.push_back(&global); + ++num_global_imports; + break; + } + + case ExternalKind::Tag: { + Tag& tag = cast<TagImport>(import)->tag; + name = &tag.name; + bindings = &tag_bindings; + index = tags.size(); + tags.push_back(&tag); + ++num_tag_imports; + break; + } + } + + assert(name && bindings && index != kInvalidIndex); + if (!name->empty()) { + bindings->emplace(*name, Binding(field->loc, index)); + } + imports.push_back(import); + fields.push_back(std::move(field)); +} + +void Module::AppendField(std::unique_ptr<MemoryModuleField> field) { + Memory& memory = field->memory; + if (!memory.name.empty()) { + memory_bindings.emplace(memory.name, Binding(field->loc, memories.size())); + } + memories.push_back(&memory); + fields.push_back(std::move(field)); +} + +void Module::AppendField(std::unique_ptr<StartModuleField> field) { + starts.push_back(&field->start); + fields.push_back(std::move(field)); +} + +void Module::AppendField(std::unique_ptr<TableModuleField> field) { + Table& table = field->table; + if (!table.name.empty()) { + table_bindings.emplace(table.name, Binding(field->loc, tables.size())); + } + tables.push_back(&table); + fields.push_back(std::move(field)); +} + +void Module::AppendField(std::unique_ptr<ModuleField> field) { + switch (field->type()) { + case ModuleFieldType::Func: + AppendField(cast<FuncModuleField>(std::move(field))); + break; + + case ModuleFieldType::Global: + AppendField(cast<GlobalModuleField>(std::move(field))); + break; + + case ModuleFieldType::Import: + AppendField(cast<ImportModuleField>(std::move(field))); + break; + + case ModuleFieldType::Export: + AppendField(cast<ExportModuleField>(std::move(field))); + break; + + case ModuleFieldType::Type: + AppendField(cast<TypeModuleField>(std::move(field))); + break; + + case ModuleFieldType::Table: + AppendField(cast<TableModuleField>(std::move(field))); + break; + + case ModuleFieldType::ElemSegment: + AppendField(cast<ElemSegmentModuleField>(std::move(field))); + break; + + case ModuleFieldType::Memory: + AppendField(cast<MemoryModuleField>(std::move(field))); + break; + + case ModuleFieldType::DataSegment: + AppendField(cast<DataSegmentModuleField>(std::move(field))); + break; + + case ModuleFieldType::Start: + AppendField(cast<StartModuleField>(std::move(field))); + break; + + case ModuleFieldType::Tag: + AppendField(cast<TagModuleField>(std::move(field))); + break; + } +} + +void Module::AppendFields(ModuleFieldList* fields) { + while (!fields->empty()) + AppendField(std::unique_ptr<ModuleField>(fields->extract_front())); +} + +const Module* Script::GetFirstModule() const { + return const_cast<Script*>(this)->GetFirstModule(); +} + +Module* Script::GetFirstModule() { + for (const std::unique_ptr<Command>& command : commands) { + if (auto* module_command = dyn_cast<ModuleCommand>(command.get())) { + return &module_command->module; + } + } + return nullptr; +} + +const Module* Script::GetModule(const Var& var) const { + Index index = module_bindings.FindIndex(var); + if (index >= commands.size()) { + return nullptr; + } + auto* command = commands[index].get(); + if (isa<ModuleCommand>(command)) { + return &cast<ModuleCommand>(command)->module; + } else if (isa<ScriptModuleCommand>(command)) { + return &cast<ScriptModuleCommand>(command)->module; + } + return nullptr; +} + +void MakeTypeBindingReverseMapping( + size_t num_types, + const BindingHash& bindings, + std::vector<std::string>* out_reverse_mapping) { + out_reverse_mapping->clear(); + out_reverse_mapping->resize(num_types); + for (const auto& [name, binding] : bindings) { + assert(static_cast<size_t>(binding.index) < out_reverse_mapping->size()); + (*out_reverse_mapping)[binding.index] = name; + } +} + +Var::Var() : Var(kInvalidIndex, Location()) {} + +Var::Var(Index index, const Location& loc) + : loc(loc), type_(VarType::Index), index_(index) {} + +Var::Var(std::string_view name, const Location& loc) + : loc(loc), type_(VarType::Name), name_(name) {} + +Var::Var(Var&& rhs) : Var() { + *this = std::move(rhs); +} + +Var::Var(const Var& rhs) : Var() { + *this = rhs; +} + +Var& Var::operator=(Var&& rhs) { + loc = rhs.loc; + if (rhs.is_index()) { + set_index(rhs.index_); + } else { + set_name(rhs.name_); + } + return *this; +} + +Var& Var::operator=(const Var& rhs) { + loc = rhs.loc; + if (rhs.is_index()) { + set_index(rhs.index_); + } else { + set_name(rhs.name_); + } + return *this; +} + +Var::~Var() { + Destroy(); +} + +void Var::set_index(Index index) { + Destroy(); + type_ = VarType::Index; + index_ = index; +} + +void Var::set_name(std::string&& name) { + Destroy(); + type_ = VarType::Name; + Construct(name_, std::move(name)); +} + +void Var::set_name(std::string_view name) { + set_name(std::string(name)); +} + +void Var::Destroy() { + if (is_name()) { + Destruct(name_); + } +} + +uint8_t ElemSegment::GetFlags(const Module* module) const { + uint8_t flags = 0; + + switch (kind) { + case SegmentKind::Active: { + Index table_index = module->GetTableIndex(table_var); + if (elem_type != Type::FuncRef || table_index != 0) { + flags |= SegExplicitIndex; + } + break; + } + + case SegmentKind::Passive: + flags |= SegPassive; + break; + + case SegmentKind::Declared: + flags |= SegDeclared; + break; + } + + bool all_ref_func = + elem_type == Type::FuncRef && + std::all_of(elem_exprs.begin(), elem_exprs.end(), + [](const ExprList& elem_expr) { + return elem_expr.front().type() == ExprType::RefFunc; + }); + + if (!all_ref_func) { + flags |= SegUseElemExprs; + } + + return flags; +} + +uint8_t DataSegment::GetFlags(const Module* module) const { + uint8_t flags = 0; + + if (kind == SegmentKind::Passive) { + flags |= SegPassive; + } + + Index memory_index = module->GetMemoryIndex(memory_var); + if (memory_index != 0) { + flags |= SegExplicitIndex; + } + + return flags; +} + +} // namespace wabt |