/* * Copyright 2017 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/c-writer.h" #include #include #include #include #include #include #include #include #include "wabt/cast.h" #include "wabt/common.h" #include "wabt/ir.h" #include "wabt/literal.h" #include "wabt/sha256.h" #include "wabt/stream.h" #include "wabt/string-util.h" #define INDENT_SIZE 2 #define UNIMPLEMENTED(x) printf("unimplemented: %s\n", (x)), abort() // code to be inserted into the generated output extern const char* s_header_top; extern const char* s_header_bottom; extern const char* s_source_includes; extern const char* s_source_declarations; namespace wabt { namespace { struct Label { Label(LabelType label_type, const std::string& name, const TypeVector& sig, size_t type_stack_size, size_t try_catch_stack_size, bool used = false) : label_type(label_type), name(name), sig(sig), type_stack_size(type_stack_size), try_catch_stack_size(try_catch_stack_size), used(used) {} bool HasValue() const { return !sig.empty(); } LabelType label_type; const std::string& name; const TypeVector& sig; size_t type_stack_size; size_t try_catch_stack_size; bool used = false; }; struct LocalName { explicit LocalName(const std::string& name) : name(name) {} const std::string& name; }; struct ParamName : LocalName { using LocalName::LocalName; ParamName(const Var& var) : LocalName(var.name()) {} }; struct LabelName : LocalName { using LocalName::LocalName; }; struct GlobalName { GlobalName(ModuleFieldType type, const std::string& name) : type(type), name(name) {} ModuleFieldType type; const std::string& name; }; struct ExternalPtr : GlobalName { using GlobalName::GlobalName; }; struct ExternalRef : GlobalName { using GlobalName::GlobalName; }; struct ExternalInstancePtr : GlobalName { using GlobalName::GlobalName; }; struct ExternalInstanceRef : GlobalName { using GlobalName::GlobalName; }; struct GotoLabel { explicit GotoLabel(const Var& var) : var(var) {} const Var& var; }; struct LabelDecl { explicit LabelDecl(const std::string& name) : name(name) {} std::string name; }; struct GlobalInstanceVar { explicit GlobalInstanceVar(const Var& var) : var(var) {} const Var& var; }; struct StackVar { explicit StackVar(Index index, Type type = Type::Any) : index(index), type(type) {} Index index; Type type; }; struct TypeEnum { explicit TypeEnum(Type type) : type(type) {} Type type; }; struct SignedType { explicit SignedType(Type type) : type(type) {} Type type; }; struct ResultType { explicit ResultType(const TypeVector& types) : types(types) {} const TypeVector& types; }; struct TryCatchLabel { TryCatchLabel(const std::string& name, size_t try_catch_stack_size) : name(name), try_catch_stack_size(try_catch_stack_size), used(false) {} std::string name; size_t try_catch_stack_size; bool used; }; struct FuncTypeExpr { const FuncType* func_type; FuncTypeExpr(const FuncType* f) : func_type(f) {} }; struct Newline {}; struct OpenBrace {}; struct CloseBrace {}; int GetShiftMask(Type type) { // clang-format off switch (type) { case Type::I32: return 31; case Type::I64: return 63; default: WABT_UNREACHABLE; return 0; } // clang-format on } /* * This function is the default behavior for name_to_output_file_index_. For * single .c output, this function returns a vector filled with 0. For multiple * .c outputs, this function sorts all non-imported functions in the module by * their names, and then divides all non-imported functions into equal-sized * buckets (# of non-imported functions / # of .c outputs) based on the sorting. */ static std::vector default_name_to_output_file_index( std::vector::const_iterator func_begin, std::vector::const_iterator func_end, size_t num_imports, size_t num_streams) { std::vector result; result.resize(std::distance(func_begin, func_end)); if (num_streams == 1) { return result; } std::map sorted_functions; size_t non_imported_funcs = result.size() - num_imports; size_t bucket_size = non_imported_funcs / num_streams + (non_imported_funcs % num_streams ? 1 : 0); Index func_index = 0; for (auto func = func_begin; func != func_end; func++) { sorted_functions.insert({(*func)->name, func_index}); ++func_index; } Index sorted_func_index = 0; for (const auto& [func_name, index] : sorted_functions) { bool is_import = index < num_imports; if (!is_import) { result.at(index) = sorted_func_index / bucket_size; ++sorted_func_index; } } return result; } class CWriter { public: CWriter(std::vector&& c_streams, Stream* h_stream, Stream* h_impl_stream, const char* header_name, const char* header_impl_name, const WriteCOptions& options) : options_(options), c_streams_(std::move(c_streams)), h_stream_(h_stream), h_impl_stream_(h_impl_stream), header_name_(header_name), header_impl_name_(header_impl_name) { module_prefix_ = MangleModuleName(options_.module_name); if (c_streams_.size() != 1 && options.name_to_output_file_index) { name_to_output_file_index_ = options.name_to_output_file_index; } else { name_to_output_file_index_ = default_name_to_output_file_index; } } Result WriteModule(const Module&); private: using SymbolSet = std::set; using SymbolMap = std::map; using StackTypePair = std::pair; using StackVarSymbolMap = std::map; void WriteCHeader(); void WriteCSource(); size_t MarkTypeStack() const; void ResetTypeStack(size_t mark); Type StackType(Index) const; void PushType(Type); void PushTypes(const TypeVector&); void DropTypes(size_t count); void PushLabel(LabelType, const std::string& name, const FuncSignature&, bool used = false); const Label* FindLabel(const Var& var, bool mark_used = true); bool IsTopLabelUsed() const; void PopLabel(); static constexpr char MangleType(Type); static constexpr char MangleField(ModuleFieldType); static std::string MangleMultivalueTypes(const TypeVector&); static std::string MangleTagTypes(const TypeVector&); static std::string Mangle(std::string_view name, bool double_underscores); static std::string MangleName(std::string_view); static std::string MangleModuleName(std::string_view); std::string ExportName(std::string_view module_name, std::string_view export_name); std::string ExportName(std::string_view export_name); std::string ModuleInstanceTypeName() const; static std::string ModuleInstanceTypeName(std::string_view module_name); void ClaimName(SymbolSet& set, SymbolMap& map, char type_suffix, std::string_view wasm_name, const std::string& c_name); std::string FindUniqueName(SymbolSet& set, std::string_view proposed_name); std::string ClaimUniqueName(SymbolSet& set, SymbolMap& map, char type_suffix, std::string_view wasm_name, const std::string& proposed_c_name); void DefineImportName(const Import* import, std::string_view module_name, std::string_view field_name); void ReserveExportNames(); void ReserveExportName(std::string_view); std::string DefineImportedModuleInstanceName(std::string_view name); std::string DefineInstanceMemberName(ModuleFieldType, std::string_view); std::string DefineGlobalScopeName(ModuleFieldType, std::string_view); std::string DefineLocalScopeName(std::string_view name, bool is_label); std::string DefineParamName(std::string_view); std::string DefineLabelName(std::string_view); std::string DefineStackVarName(Index, Type, std::string_view); static void SerializeFuncType(const FuncType&, std::string&); std::string GetGlobalName(ModuleFieldType, const std::string&) const; std::string GetLocalName(const std::string&, bool is_label) const; void Indent(int size = INDENT_SIZE); void Dedent(int size = INDENT_SIZE); void WriteIndent(); void WriteData(const char* src, size_t size); void Writef(const char* format, ...); template void Write(T&& t, U&& u, Args&&... args) { Write(std::forward(t)); Write(std::forward(u)); Write(std::forward(args)...); } static const char* GetReferenceTypeName(const Type& type); static const char* GetReferenceNullValue(const Type& type); static const char* GetCTypeName(const Type& type); const char* InternalSymbolScope() const; enum class CWriterPhase { Declarations, Definitions, }; void Write() {} void Write(Newline); void Write(OpenBrace); void Write(CloseBrace); void Write(uint64_t); void Write(std::string_view); void Write(const ParamName&); void Write(const LabelName&); void Write(const GlobalName&); void Write(const ExternalPtr&); void Write(const ExternalRef&); void Write(const ExternalInstancePtr&); void Write(const ExternalInstanceRef&); void Write(Type); void Write(SignedType); void Write(TypeEnum); void Write(const GotoLabel&); void Write(const LabelDecl&); void Write(const GlobalInstanceVar&); void Write(const StackVar&); void Write(const ResultType&); void Write(const Const&); void WriteInitExpr(const ExprList&); void WriteInitExprTerminal(const Expr*); std::string GenerateHeaderGuard() const; void WriteSourceTop(); void WriteMultiCTop(); void WriteMultiCTopEmpty(); void WriteMultivalueTypes(); void WriteTagTypes(); void WriteFuncTypeDecls(); void WriteFuncTypes(); void Write(const FuncTypeExpr&); void WriteTagDecls(); void WriteTags(); void ComputeUniqueImports(); void BeginInstance(); void WriteImports(); void WriteFuncDeclarations(); void WriteFuncDeclaration(const FuncDeclaration&, const std::string&); void WriteImportFuncDeclaration(const FuncDeclaration&, const std::string& module_name, const std::string&); void WriteCallIndirectFuncDeclaration(const FuncDeclaration&, const std::string&); void WriteFeatureMacros(); void WriteModuleInstance(); void WriteGlobals(); void WriteGlobal(const Global&, const std::string&); void WriteGlobalPtr(const Global&, const std::string&); void WriteMemories(); void WriteMemory(const std::string&); void WriteMemoryPtr(const std::string&); void WriteTables(); void WriteTable(const std::string&, const wabt::Type&); void WriteTablePtr(const std::string&, const Table&); void WriteTableType(const wabt::Type&); void WriteDataInstances(); void WriteElemInstances(); void WriteGlobalInitializers(); void WriteDataInitializerDecls(); void WriteDataInitializers(); void WriteElemInitializerDecls(); void WriteElemInitializers(); void WriteElemTableInit(bool, const ElemSegment*, const Table*); void WriteExports(CWriterPhase); void WriteInitDecl(); void WriteFreeDecl(); void WriteGetFuncTypeDecl(); void WriteInit(); void WriteFree(); void WriteGetFuncType(); void WriteInitInstanceImport(); void WriteImportProperties(CWriterPhase); void WriteFuncs(); void Write(const Func&); void WriteParamsAndLocals(); void WriteParams(const std::vector& index_to_name); void WriteParamSymbols(const std::vector& index_to_name); void WriteParamTypes(const FuncDeclaration& decl); void WriteLocals(const std::vector& index_to_name); void WriteStackVarDeclarations(); void Write(const ExprList&); enum class AssignOp { Disallowed, Allowed, }; void WriteSimpleUnaryExpr(Opcode, const char* op); void WriteInfixBinaryExpr(Opcode, const char* op, AssignOp = AssignOp::Allowed); void WritePrefixBinaryExpr(Opcode, const char* op); void WriteSignedBinaryExpr(Opcode, const char* op); void Write(const BinaryExpr&); void Write(const CompareExpr&); void Write(const ConvertExpr&); void Write(const LoadExpr&); void Write(const StoreExpr&); void Write(const UnaryExpr&); void Write(const TernaryExpr&); void Write(const SimdLaneOpExpr&); void Write(const SimdLoadLaneExpr&); void Write(const SimdStoreLaneExpr&); void Write(const SimdShuffleOpExpr&); void Write(const LoadSplatExpr&); void Write(const LoadZeroExpr&); void Write(const Block&); size_t BeginTry(const TryExpr& tryexpr); void WriteTryCatch(const TryExpr& tryexpr); void WriteTryDelegate(const TryExpr& tryexpr); void Write(const Catch& c); void WriteThrow(); void PushTryCatch(const std::string& name); void PopTryCatch(); void PushFuncSection(std::string_view include_condition = ""); const WriteCOptions& options_; const Module* module_ = nullptr; const Func* func_ = nullptr; Stream* stream_ = nullptr; std::vector c_streams_; Stream* h_stream_ = nullptr; Stream* h_impl_stream_ = nullptr; std::string header_name_; std::string header_impl_name_; Result result_ = Result::Ok; int indent_ = 0; bool should_write_indent_next_ = false; int consecutive_newline_count_ = 0; SymbolMap global_sym_map_; SymbolMap local_sym_map_; SymbolMap import_module_sym_map_; StackVarSymbolMap stack_var_sym_map_; SymbolSet global_syms_; SymbolSet local_syms_; SymbolSet import_syms_; TypeVector type_stack_; std::vector