From 8bcdd04bcefeaee0a928e62f60bb10ae2960f40d Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Wed, 14 Nov 2018 02:46:21 +0000 Subject: [PATCH] [WebAssembly] Add support for the event section Summary: This adds support for the 'event section' specified in the exception handling proposal. (This was named 'exception section' first, but later renamed to 'event section' to take possibilities of other kinds of events into consideration. But currently we only store exception info in this section.) The event section is added between the global section and the export section. This is for ease of validation per request of the V8 team. This patch: - Creates the event symbol type, which is a weak symbol - Makes 'throw' instruction take the event symbol '__cpp_exception' - Adds relocation support for events - Adds WasmObjectWriter / WasmObjectFile (Reader) support - Adds obj2yaml / yaml2obj support - Adds '.eventtype' printing support Reviewers: dschuff, sbc100, aardappel Subscribers: jgravelle-google, sunfish, llvm-commits Differential Revision: https://reviews.llvm.org/D54096 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@346825 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/BinaryFormat/Wasm.h | 23 ++- include/llvm/BinaryFormat/WasmRelocs.def | 2 +- include/llvm/CodeGen/WasmEHFuncInfo.h | 2 + include/llvm/MC/MCExpr.h | 1 + include/llvm/MC/MCSymbolWasm.h | 17 +- include/llvm/Object/RelocVisitor.h | 1 + include/llvm/Object/Wasm.h | 19 +- include/llvm/ObjectYAML/WasmYAML.h | 22 ++ lib/BinaryFormat/Wasm.cpp | 2 + lib/CodeGen/AsmPrinter/WasmException.cpp | 16 ++ lib/CodeGen/AsmPrinter/WasmException.h | 2 +- lib/MC/MCExpr.cpp | 2 + lib/MC/WasmObjectWriter.cpp | 191 +++++++++++++----- lib/Object/WasmObjectFile.cpp | 95 ++++++++- lib/ObjectYAML/WasmYAML.cpp | 24 +++ .../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 23 ++- .../MCTargetDesc/WebAssemblyMCTargetDesc.h | 5 +- .../WebAssemblyTargetStreamer.cpp | 19 ++ .../MCTargetDesc/WebAssemblyTargetStreamer.h | 4 + .../WebAssemblyWasmObjectWriter.cpp | 7 + .../WebAssembly/WebAssemblyAsmPrinter.cpp | 7 +- lib/Target/WebAssembly/WebAssemblyISD.def | 1 + .../WebAssembly/WebAssemblyISelLowering.cpp | 42 ++++ .../WebAssembly/WebAssemblyISelLowering.h | 1 + .../WebAssembly/WebAssemblyInstrControl.td | 14 +- .../WebAssembly/WebAssemblyInstrInfo.td | 7 + .../WebAssembly/WebAssemblyMCInstLower.cpp | 49 +++-- .../WebAssembly/WebAssemblyMCInstLower.h | 2 +- test/CodeGen/WebAssembly/exception.ll | 5 +- test/MC/WebAssembly/event-section.ll | 58 ++++++ test/ObjectYAML/wasm/event_section.yaml | 92 +++++++++ tools/llvm-readobj/WasmDumper.cpp | 15 +- tools/obj2yaml/wasm2yaml.cpp | 17 ++ tools/yaml2obj/yaml2wasm.cpp | 37 +++- 34 files changed, 708 insertions(+), 116 deletions(-) create mode 100644 test/MC/WebAssembly/event-section.ll create mode 100644 test/ObjectYAML/wasm/event_section.yaml diff --git a/include/llvm/BinaryFormat/Wasm.h b/include/llvm/BinaryFormat/Wasm.h index 3d25c9d15e4..fbca8df7382 100644 --- a/include/llvm/BinaryFormat/Wasm.h +++ b/include/llvm/BinaryFormat/Wasm.h @@ -75,6 +75,18 @@ struct WasmGlobal { StringRef SymbolName; // from the "linking" section }; +struct WasmEventType { + // Kind of event. Currently only WASM_EVENT_ATTRIBUTE_EXCEPTION is possible. + uint32_t Attribute; + uint32_t SigIndex; +}; + +struct WasmEvent { + uint32_t Index; + WasmEventType Type; + StringRef SymbolName; // from the "linking" section +}; + struct WasmImport { StringRef Module; StringRef Field; @@ -84,6 +96,7 @@ struct WasmImport { WasmGlobalType Global; WasmTable Table; WasmLimits Memory; + WasmEventType Event; }; }; @@ -178,7 +191,8 @@ enum : unsigned { WASM_SEC_START = 8, // Start function declaration WASM_SEC_ELEM = 9, // Elements section WASM_SEC_CODE = 10, // Function bodies (code) - WASM_SEC_DATA = 11 // Data segments + WASM_SEC_DATA = 11, // Data segments + WASM_SEC_EVENT = 12 // Event declarations }; // Type immediate encodings used in various contexts. @@ -200,6 +214,7 @@ enum : unsigned { WASM_EXTERNAL_TABLE = 0x1, WASM_EXTERNAL_MEMORY = 0x2, WASM_EXTERNAL_GLOBAL = 0x3, + WASM_EXTERNAL_EVENT = 0x4, }; // Opcodes used in initializer expressions. @@ -243,6 +258,12 @@ enum WasmSymbolType : unsigned { WASM_SYMBOL_TYPE_DATA = 0x1, WASM_SYMBOL_TYPE_GLOBAL = 0x2, WASM_SYMBOL_TYPE_SECTION = 0x3, + WASM_SYMBOL_TYPE_EVENT = 0x4, +}; + +// Kinds of event attributes. +enum WasmEventAttribute : unsigned { + WASM_EVENT_ATTRIBUTE_EXCEPTION = 0x0, }; const unsigned WASM_SYMBOL_BINDING_MASK = 0x3; diff --git a/include/llvm/BinaryFormat/WasmRelocs.def b/include/llvm/BinaryFormat/WasmRelocs.def index 8ffd51e483f..b3a08e70c1d 100644 --- a/include/llvm/BinaryFormat/WasmRelocs.def +++ b/include/llvm/BinaryFormat/WasmRelocs.def @@ -1,4 +1,3 @@ - #ifndef WASM_RELOC #error "WASM_RELOC must be defined" #endif @@ -13,3 +12,4 @@ WASM_RELOC(R_WEBASSEMBLY_TYPE_INDEX_LEB, 6) WASM_RELOC(R_WEBASSEMBLY_GLOBAL_INDEX_LEB, 7) WASM_RELOC(R_WEBASSEMBLY_FUNCTION_OFFSET_I32, 8) WASM_RELOC(R_WEBASSEMBLY_SECTION_OFFSET_I32, 9) +WASM_RELOC(R_WEBASSEMBLY_EVENT_INDEX_LEB, 10) diff --git a/include/llvm/CodeGen/WasmEHFuncInfo.h b/include/llvm/CodeGen/WasmEHFuncInfo.h index aa979349edf..219fff988f6 100644 --- a/include/llvm/CodeGen/WasmEHFuncInfo.h +++ b/include/llvm/CodeGen/WasmEHFuncInfo.h @@ -21,6 +21,8 @@ namespace llvm { +enum EventTag { CPP_EXCEPTION = 0, C_LONGJMP = 1 }; + using BBOrMBB = PointerUnion; struct WasmEHFuncInfo { diff --git a/include/llvm/MC/MCExpr.h b/include/llvm/MC/MCExpr.h index 23dde10e785..8cb6b86fd67 100644 --- a/include/llvm/MC/MCExpr.h +++ b/include/llvm/MC/MCExpr.h @@ -288,6 +288,7 @@ public: VK_WebAssembly_FUNCTION, // Function table index, rather than virtual addr VK_WebAssembly_GLOBAL, // Global object index VK_WebAssembly_TYPEINDEX,// Type table index + VK_WebAssembly_EVENT, // Event index VK_AMDGPU_GOTPCREL32_LO, // symbol@gotpcrel32@lo VK_AMDGPU_GOTPCREL32_HI, // symbol@gotpcrel32@hi diff --git a/include/llvm/MC/MCSymbolWasm.h b/include/llvm/MC/MCSymbolWasm.h index 281178aea61..8e66dc881d0 100644 --- a/include/llvm/MC/MCSymbolWasm.h +++ b/include/llvm/MC/MCSymbolWasm.h @@ -21,8 +21,8 @@ class MCSymbolWasm : public MCSymbol { bool IsComdat = false; std::string ModuleName; wasm::WasmSignature *Signature = nullptr; - wasm::WasmGlobalType GlobalType; - bool GlobalTypeSet = false; + Optional GlobalType; + Optional EventType; /// An expression describing how to calculate the size of a symbol. If a /// symbol has no size this field will be NULL. @@ -42,6 +42,7 @@ public: bool isData() const { return Type == wasm::WASM_SYMBOL_TYPE_DATA; } bool isGlobal() const { return Type == wasm::WASM_SYMBOL_TYPE_GLOBAL; } bool isSection() const { return Type == wasm::WASM_SYMBOL_TYPE_SECTION; } + bool isEvent() const { return Type == wasm::WASM_SYMBOL_TYPE_EVENT; } wasm::WasmSymbolType getType() const { return Type; } void setType(wasm::WasmSymbolType type) { Type = type; } @@ -61,14 +62,16 @@ public: void setSignature(wasm::WasmSignature *Sig) { Signature = Sig; } const wasm::WasmGlobalType &getGlobalType() const { - assert(GlobalTypeSet); - return GlobalType; + assert(GlobalType.hasValue()); + return GlobalType.getValue(); } + void setGlobalType(wasm::WasmGlobalType GT) { GlobalType = GT; } - void setGlobalType(wasm::WasmGlobalType GT) { - GlobalTypeSet = true; - GlobalType = GT; + const wasm::WasmEventType &getEventType() const { + assert(EventType.hasValue()); + return EventType.getValue(); } + void setEventType(wasm::WasmEventType ET) { EventType = ET; } }; } // end namespace llvm diff --git a/include/llvm/Object/RelocVisitor.h b/include/llvm/Object/RelocVisitor.h index 008e109f667..23e796c6ec4 100644 --- a/include/llvm/Object/RelocVisitor.h +++ b/include/llvm/Object/RelocVisitor.h @@ -333,6 +333,7 @@ private: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: + case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: // For wasm section, its offset at 0 -- ignoring Value return 0; } diff --git a/include/llvm/Object/Wasm.h b/include/llvm/Object/Wasm.h index 25903fc9945..03273a8bf44 100644 --- a/include/llvm/Object/Wasm.h +++ b/include/llvm/Object/Wasm.h @@ -38,12 +38,15 @@ class WasmSymbol { public: WasmSymbol(const wasm::WasmSymbolInfo &Info, const wasm::WasmSignature *FunctionType, - const wasm::WasmGlobalType *GlobalType) - : Info(Info), FunctionType(FunctionType), GlobalType(GlobalType) {} + const wasm::WasmGlobalType *GlobalType, + const wasm::WasmEventType *EventType) + : Info(Info), FunctionType(FunctionType), GlobalType(GlobalType), + EventType(EventType) {} const wasm::WasmSymbolInfo &Info; const wasm::WasmSignature *FunctionType; const wasm::WasmGlobalType *GlobalType; + const wasm::WasmEventType *EventType; bool isTypeFunction() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION; @@ -59,6 +62,8 @@ public: return Info.Kind == wasm::WASM_SYMBOL_TYPE_SECTION; } + bool isTypeEvent() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_EVENT; } + bool isDefined() const { return !isUndefined(); } bool isUndefined() const { @@ -130,6 +135,7 @@ public: ArrayRef tables() const { return Tables; } ArrayRef memories() const { return Memories; } ArrayRef globals() const { return Globals; } + ArrayRef events() const { return Events; } ArrayRef exports() const { return Exports; } ArrayRef syms() const { return Symbols; } const wasm::WasmLinkingData &linkingData() const { return LinkingData; } @@ -141,6 +147,7 @@ public: uint32_t startFunction() const { return StartFunction; } uint32_t getNumImportedGlobals() const { return NumImportedGlobals; } uint32_t getNumImportedFunctions() const { return NumImportedFunctions; } + uint32_t getNumImportedEvents() const { return NumImportedEvents; } void moveSymbolNext(DataRefImpl &Symb) const override; @@ -205,12 +212,16 @@ private: bool isDefinedFunctionIndex(uint32_t Index) const; bool isValidGlobalIndex(uint32_t Index) const; bool isDefinedGlobalIndex(uint32_t Index) const; + bool isValidEventIndex(uint32_t Index) const; + bool isDefinedEventIndex(uint32_t Index) const; bool isValidFunctionSymbol(uint32_t Index) const; bool isValidGlobalSymbol(uint32_t Index) const; + bool isValidEventSymbol(uint32_t Index) const; bool isValidDataSymbol(uint32_t Index) const; bool isValidSectionSymbol(uint32_t Index) const; wasm::WasmFunction &getDefinedFunction(uint32_t Index); wasm::WasmGlobal &getDefinedGlobal(uint32_t Index); + wasm::WasmEvent &getDefinedEvent(uint32_t Index); const WasmSection &getWasmSection(DataRefImpl Ref) const; const wasm::WasmRelocation &getWasmRelocation(DataRefImpl Ref) const; @@ -226,6 +237,7 @@ private: Error parseTableSection(ReadContext &Ctx); Error parseMemorySection(ReadContext &Ctx); Error parseGlobalSection(ReadContext &Ctx); + Error parseEventSection(ReadContext &Ctx); Error parseExportSection(ReadContext &Ctx); Error parseStartSection(ReadContext &Ctx); Error parseElemSection(ReadContext &Ctx); @@ -246,6 +258,7 @@ private: std::vector Tables; std::vector Memories; std::vector Globals; + std::vector Events; std::vector Imports; std::vector Exports; std::vector ElemSegments; @@ -258,9 +271,11 @@ private: wasm::WasmLinkingData LinkingData; uint32_t NumImportedGlobals = 0; uint32_t NumImportedFunctions = 0; + uint32_t NumImportedEvents = 0; uint32_t CodeSection = 0; uint32_t DataSection = 0; uint32_t GlobalSection = 0; + uint32_t EventSection = 0; }; } // end namespace object diff --git a/include/llvm/ObjectYAML/WasmYAML.h b/include/llvm/ObjectYAML/WasmYAML.h index 8cd08e52056..694fe9a7e14 100644 --- a/include/llvm/ObjectYAML/WasmYAML.h +++ b/include/llvm/ObjectYAML/WasmYAML.h @@ -74,6 +74,12 @@ struct Global { wasm::WasmInitExpr InitExpr; }; +struct Event { + uint32_t Index; + uint32_t Attribute; + uint32_t SigIndex; +}; + struct Import { StringRef Module; StringRef Field; @@ -83,6 +89,7 @@ struct Import { Global GlobalImport; Table TableImport; Limits Memory; + Event EventImport; }; }; @@ -262,6 +269,16 @@ struct GlobalSection : Section { std::vector Globals; }; +struct EventSection : Section { + EventSection() : Section(wasm::WASM_SEC_EVENT) {} + + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_EVENT; + } + + std::vector Events; +}; + struct ExportSection : Section { ExportSection() : Section(wasm::WASM_SEC_EXPORT) {} @@ -339,6 +356,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SymbolInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::InitFunction) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::ComdatEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Comdat) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Event) namespace llvm { namespace yaml { @@ -471,6 +489,10 @@ template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, WasmYAML::RelocType &Kind); }; +template <> struct MappingTraits { + static void mapping(IO &IO, WasmYAML::Event &Event); +}; + } // end namespace yaml } // end namespace llvm diff --git a/lib/BinaryFormat/Wasm.cpp b/lib/BinaryFormat/Wasm.cpp index ba8de34a6d2..94d40bf02a3 100644 --- a/lib/BinaryFormat/Wasm.cpp +++ b/lib/BinaryFormat/Wasm.cpp @@ -19,6 +19,8 @@ std::string llvm::wasm::toString(wasm::WasmSymbolType type) { return "WASM_SYMBOL_TYPE_DATA"; case wasm::WASM_SYMBOL_TYPE_SECTION: return "WASM_SYMBOL_TYPE_SECTION"; + case wasm::WASM_SYMBOL_TYPE_EVENT: + return "WASM_SYMBOL_TYPE_EVENT"; } llvm_unreachable("unknown symbol type"); } diff --git a/lib/CodeGen/AsmPrinter/WasmException.cpp b/lib/CodeGen/AsmPrinter/WasmException.cpp index 46745d08c9f..527e5ae5014 100644 --- a/lib/CodeGen/AsmPrinter/WasmException.cpp +++ b/lib/CodeGen/AsmPrinter/WasmException.cpp @@ -13,9 +13,25 @@ //===----------------------------------------------------------------------===// #include "WasmException.h" +#include "llvm/IR/Mangler.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" using namespace llvm; +void WasmException::endModule() { + // This is the symbol used in 'throw' and 'if_except' instruction to denote + // this is a C++ exception. This symbol has to be emitted somewhere once in + // the module. Check if the symbol has already been created, i.e., we have at + // least one 'throw' or 'if_except' instruction in the module, and emit the + // symbol only if so. + SmallString<60> NameStr; + Mangler::getNameWithPrefix(NameStr, "__cpp_exception", Asm->getDataLayout()); + if (Asm->OutContext.lookupSymbol(NameStr)) { + MCSymbol *ExceptionSym = Asm->GetExternalSymbolSymbol("__cpp_exception"); + Asm->OutStreamer->EmitLabel(ExceptionSym); + } +} + void WasmException::markFunctionEnd() { // Get rid of any dead landing pads. if (!Asm->MF->getLandingPads().empty()) { diff --git a/lib/CodeGen/AsmPrinter/WasmException.h b/lib/CodeGen/AsmPrinter/WasmException.h index 09a9a25ce8d..cbdb42457cf 100644 --- a/lib/CodeGen/AsmPrinter/WasmException.h +++ b/lib/CodeGen/AsmPrinter/WasmException.h @@ -24,7 +24,7 @@ class LLVM_LIBRARY_VISIBILITY WasmException : public EHStreamer { public: WasmException(AsmPrinter *A) : EHStreamer(A) {} - void endModule() override {} + void endModule() override; void beginFunction(const MachineFunction *MF) override {} virtual void markFunctionEnd() override; void endFunction(const MachineFunction *MF) override; diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index 38f311be7c6..3c022199145 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -306,6 +306,7 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { case VK_WebAssembly_FUNCTION: return "FUNCTION"; case VK_WebAssembly_GLOBAL: return "GLOBAL"; case VK_WebAssembly_TYPEINDEX: return "TYPEINDEX"; + case VK_WebAssembly_EVENT: return "EVENT"; case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo"; case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi"; case VK_AMDGPU_REL32_LO: return "rel32@lo"; @@ -421,6 +422,7 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) { .Case("function", VK_WebAssembly_FUNCTION) .Case("global", VK_WebAssembly_GLOBAL) .Case("typeindex", VK_WebAssembly_TYPEINDEX) + .Case("event", VK_WebAssembly_EVENT) .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI) .Case("rel32@lo", VK_AMDGPU_REL32_LO) diff --git a/lib/MC/WasmObjectWriter.cpp b/lib/MC/WasmObjectWriter.cpp index c1e0b7aa7ab..7e3949b26ef 100644 --- a/lib/MC/WasmObjectWriter.cpp +++ b/lib/MC/WasmObjectWriter.cpp @@ -56,10 +56,10 @@ struct SectionBookkeeping { uint32_t Index; }; -// The signature of a wasm function, in a struct capable of being used as a -// DenseMap key. -// TODO: Consider using WasmSignature directly instead. -struct WasmFunctionType { +// The signature of a wasm function or event, in a struct capable of being used +// as a DenseMap key. +// TODO: Consider using wasm::WasmSignature directly instead. +struct WasmSignature { // Support empty and tombstone instances, needed by DenseMap. enum { Plain, Empty, Tombstone } State; @@ -69,36 +69,35 @@ struct WasmFunctionType { // The parameter types of the function. SmallVector Params; - WasmFunctionType() : State(Plain) {} + WasmSignature() : State(Plain) {} - bool operator==(const WasmFunctionType &Other) const { + bool operator==(const WasmSignature &Other) const { return State == Other.State && Returns == Other.Returns && Params == Other.Params; } }; -// Traits for using WasmFunctionType in a DenseMap. -struct WasmFunctionTypeDenseMapInfo { - static WasmFunctionType getEmptyKey() { - WasmFunctionType FuncTy; - FuncTy.State = WasmFunctionType::Empty; - return FuncTy; +// Traits for using WasmSignature in a DenseMap. +struct WasmSignatureDenseMapInfo { + static WasmSignature getEmptyKey() { + WasmSignature Sig; + Sig.State = WasmSignature::Empty; + return Sig; } - static WasmFunctionType getTombstoneKey() { - WasmFunctionType FuncTy; - FuncTy.State = WasmFunctionType::Tombstone; - return FuncTy; + static WasmSignature getTombstoneKey() { + WasmSignature Sig; + Sig.State = WasmSignature::Tombstone; + return Sig; } - static unsigned getHashValue(const WasmFunctionType &FuncTy) { - uintptr_t Value = FuncTy.State; - for (wasm::ValType Ret : FuncTy.Returns) + static unsigned getHashValue(const WasmSignature &Sig) { + uintptr_t Value = Sig.State; + for (wasm::ValType Ret : Sig.Returns) Value += DenseMapInfo::getHashValue(uint32_t(Ret)); - for (wasm::ValType Param : FuncTy.Params) + for (wasm::ValType Param : Sig.Params) Value += DenseMapInfo::getHashValue(uint32_t(Param)); return Value; } - static bool isEqual(const WasmFunctionType &LHS, - const WasmFunctionType &RHS) { + static bool isEqual(const WasmSignature &LHS, const WasmSignature &RHS) { return LHS == RHS; } }; @@ -118,7 +117,7 @@ struct WasmDataSegment { // A wasm function to be written into the function section. struct WasmFunction { - uint32_t Type; + uint32_t SigIndex; const MCSymbolWasm *Sym; }; @@ -216,7 +215,8 @@ class WasmObjectWriter : public MCObjectWriter { // Maps function symbols to the table element index space. Used // for TABLE_INDEX relocation types (i.e. address taken functions). DenseMap TableIndices; - // Maps function/global symbols to the function/global/section index space. + // Maps function/global symbols to the function/global/event/section index + // space. DenseMap WasmIndices; // Maps data symbols to the Wasm segment and offset/size with the segment. DenseMap DataLocations; @@ -231,13 +231,13 @@ class WasmObjectWriter : public MCObjectWriter { // Map from section to defining function symbol. DenseMap SectionFunctions; - DenseMap - FunctionTypeIndices; - SmallVector FunctionTypes; + DenseMap SignatureIndices; + SmallVector Signatures; SmallVector Globals; SmallVector DataSegments; unsigned NumFunctionImports = 0; unsigned NumGlobalImports = 0; + unsigned NumEventImports = 0; uint32_t SectionCount = 0; // TargetObjectWriter wrappers. @@ -266,8 +266,8 @@ private: TableIndices.clear(); DataLocations.clear(); CustomSectionsRelocations.clear(); - FunctionTypeIndices.clear(); - FunctionTypes.clear(); + SignatureIndices.clear(); + Signatures.clear(); Globals.clear(); DataSegments.clear(); SectionFunctions.clear(); @@ -294,7 +294,7 @@ private: void writeValueType(wasm::ValType Ty) { W.OS << static_cast(Ty); } - void writeTypeSection(ArrayRef FunctionTypes); + void writeTypeSection(ArrayRef Signatures); void writeImportSection(ArrayRef Imports, uint32_t DataSize, uint32_t NumElements); void writeFunctionSection(ArrayRef Functions); @@ -304,6 +304,7 @@ private: void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, ArrayRef Functions); void writeDataSection(); + void writeEventSection(ArrayRef Events); void writeRelocSection(uint32_t SectionIndex, StringRef Name, std::vector &Relocations); void writeLinkingMetaDataSection( @@ -322,7 +323,9 @@ private: uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry); uint32_t getFunctionType(const MCSymbolWasm &Symbol); + uint32_t getEventType(const MCSymbolWasm &Symbol); uint32_t registerFunctionType(const MCSymbolWasm &Symbol); + uint32_t registerEventType(const MCSymbolWasm &Symbol); }; } // end anonymous namespace @@ -581,7 +584,8 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { return getRelocationIndexValue(RelEntry); case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - // Provisional value is function/global Wasm index + case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: + // Provisional value is function/global/event Wasm index if (!WasmIndices.count(RelEntry.Symbol)) report_fatal_error("symbol not found in wasm index space: " + RelEntry.Symbol->getName()); @@ -678,6 +682,7 @@ void WasmObjectWriter::applyRelocations( case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: WritePatchableLEB(Stream, Value, Offset); break; case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: @@ -696,23 +701,22 @@ void WasmObjectWriter::applyRelocations( } } -void WasmObjectWriter::writeTypeSection( - ArrayRef FunctionTypes) { - if (FunctionTypes.empty()) +void WasmObjectWriter::writeTypeSection(ArrayRef Signatures) { + if (Signatures.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_TYPE); - encodeULEB128(FunctionTypes.size(), W.OS); + encodeULEB128(Signatures.size(), W.OS); - for (const WasmFunctionType &FuncTy : FunctionTypes) { + for (const WasmSignature &Sig : Signatures) { W.OS << char(wasm::WASM_TYPE_FUNC); - encodeULEB128(FuncTy.Params.size(), W.OS); - for (wasm::ValType Ty : FuncTy.Params) + encodeULEB128(Sig.Params.size(), W.OS); + for (wasm::ValType Ty : Sig.Params) writeValueType(Ty); - encodeULEB128(FuncTy.Returns.size(), W.OS); - for (wasm::ValType Ty : FuncTy.Returns) + encodeULEB128(Sig.Returns.size(), W.OS); + for (wasm::ValType Ty : Sig.Returns) writeValueType(Ty); } @@ -753,6 +757,10 @@ void WasmObjectWriter::writeImportSection(ArrayRef Imports, encodeULEB128(0, W.OS); // flags encodeULEB128(NumElements, W.OS); // initial break; + case wasm::WASM_EXTERNAL_EVENT: + encodeULEB128(Import.Event.Attribute, W.OS); + encodeULEB128(Import.Event.SigIndex, W.OS); + break; default: llvm_unreachable("unsupported import kind"); } @@ -770,7 +778,7 @@ void WasmObjectWriter::writeFunctionSection(ArrayRef Functions) { encodeULEB128(Functions.size(), W.OS); for (const WasmFunction &Func : Functions) - encodeULEB128(Func.Type, W.OS); + encodeULEB128(Func.SigIndex, W.OS); endSection(Section); } @@ -795,6 +803,22 @@ void WasmObjectWriter::writeGlobalSection() { endSection(Section); } +void WasmObjectWriter::writeEventSection(ArrayRef Events) { + if (Events.empty()) + return; + + SectionBookkeeping Section; + startSection(Section, wasm::WASM_SEC_EVENT); + + encodeULEB128(Events.size(), W.OS); + for (const wasm::WasmEventType &Event : Events) { + encodeULEB128(Event.Attribute, W.OS); + encodeULEB128(Event.SigIndex, W.OS); + } + + endSection(Section); +} + void WasmObjectWriter::writeExportSection(ArrayRef Exports) { if (Exports.empty()) return; @@ -956,6 +980,7 @@ void WasmObjectWriter::writeLinkingMetaDataSection( switch (Sym.Kind) { case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_GLOBAL: + case wasm::WASM_SYMBOL_TYPE_EVENT: encodeULEB128(Sym.ElementIndex, W.OS); if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) writeString(Sym.Name); @@ -1047,20 +1072,25 @@ uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm &Symbol) { return TypeIndices[&Symbol]; } +uint32_t WasmObjectWriter::getEventType(const MCSymbolWasm &Symbol) { + assert(Symbol.isEvent()); + assert(TypeIndices.count(&Symbol)); + return TypeIndices[&Symbol]; +} + uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) { assert(Symbol.isFunction()); - WasmFunctionType F; + WasmSignature S; const MCSymbolWasm *ResolvedSym = ResolveSymbol(Symbol); if (auto *Sig = ResolvedSym->getSignature()) { - F.Returns = Sig->Returns; - F.Params = Sig->Params; + S.Returns = Sig->Returns; + S.Params = Sig->Params; } - auto Pair = - FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size())); + auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size())); if (Pair.second) - FunctionTypes.push_back(F); + Signatures.push_back(S); TypeIndices[&Symbol] = Pair.first->second; LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol @@ -1069,6 +1099,28 @@ uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) { return Pair.first->second; } +uint32_t WasmObjectWriter::registerEventType(const MCSymbolWasm &Symbol) { + assert(Symbol.isEvent()); + + // TODO Currently we don't generate imported exceptions, but if we do, we + // should have a way of infering types of imported exceptions. + WasmSignature S; + if (auto *Sig = Symbol.getSignature()) { + S.Returns = Sig->Returns; + S.Params = Sig->Params; + } + + auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size())); + if (Pair.second) + Signatures.push_back(S); + TypeIndices[&Symbol] = Pair.first->second; + + LLVM_DEBUG(dbgs() << "registerEventType: " << Symbol << " new:" << Pair.second + << "\n"); + LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n"); + return Pair.first->second; +} + static bool isInSymtab(const MCSymbolWasm &Sym) { if (Sym.isUsedInReloc()) return true; @@ -1100,6 +1152,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, SmallVector TableElems; SmallVector Imports; SmallVector Exports; + SmallVector Events; SmallVector SymbolInfos; SmallVector, 2> InitFuncs; std::map> Comdats; @@ -1128,7 +1181,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, TableImport.Table.ElemType = wasm::WASM_TYPE_ANYFUNC; Imports.push_back(TableImport); - // Populate FunctionTypeIndices, and Imports and WasmIndices for undefined + // Populate SignatureIndices, and Imports and WasmIndices for undefined // symbols. This must be done before populating WasmIndices for defined // symbols. for (const MCSymbol &S : Asm.symbols()) { @@ -1139,6 +1192,9 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, if (WS.isFunction()) registerFunctionType(WS); + if (WS.isEvent()) + registerEventType(WS); + if (WS.isTemporary()) continue; @@ -1163,6 +1219,18 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, Import.Global = WS.getGlobalType(); Imports.push_back(Import); WasmIndices[&WS] = NumGlobalImports++; + } else if (WS.isEvent()) { + if (WS.isWeak()) + report_fatal_error("undefined event symbol cannot be weak"); + + wasm::WasmImport Import; + Import.Module = WS.getModuleName(); + Import.Field = WS.getName(); + Import.Kind = wasm::WASM_EXTERNAL_EVENT; + Import.Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION; + Import.Event.SigIndex = getEventType(WS); + Imports.push_back(Import); + WasmIndices[&WS] = NumEventImports++; } } } @@ -1254,7 +1322,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // A definition. Write out the function body. Index = NumFunctionImports + Functions.size(); WasmFunction Func; - Func.Type = getFunctionType(WS); + Func.SigIndex = getFunctionType(WS); Func.Sym = &WS; WasmIndices[&WS] = Index; Functions.push_back(Func); @@ -1270,6 +1338,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, } LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n"); + } else if (WS.isData()) { if (WS.isTemporary() && !WS.getSize()) continue; @@ -1299,6 +1368,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, static_cast(Size)}; DataLocations[&WS] = Ref; LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n"); + } else if (WS.isGlobal()) { // A "true" Wasm global (currently just __stack_pointer) if (WS.isDefined()) @@ -1307,6 +1377,24 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // An import; the index was assigned above LLVM_DEBUG(dbgs() << " -> global index: " << WasmIndices.find(&WS)->second << "\n"); + + } else if (WS.isEvent()) { + // C++ exception symbol (__cpp_exception) + unsigned Index; + if (WS.isDefined()) { + Index = NumEventImports + Events.size(); + wasm::WasmEventType Event; + Event.SigIndex = getEventType(WS); + Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION; + WasmIndices[&WS] = Index; + Events.push_back(Event); + } else { + // An import; the index was assigned above. + Index = WasmIndices.find(&WS)->second; + } + LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices.find(&WS)->second + << "\n"); + } else { assert(WS.isSection()); } @@ -1340,7 +1428,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, DataLocations[&WS] = Ref; LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n"); } else { - report_fatal_error("don't yet support global aliases"); + report_fatal_error("don't yet support global/event aliases"); } } @@ -1473,12 +1561,13 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // Write out the Wasm header. writeHeader(Asm); - writeTypeSection(FunctionTypes); + writeTypeSection(Signatures); writeImportSection(Imports, DataSize, TableElems.size()); writeFunctionSection(Functions); // Skip the "table" section; we import the table instead. // Skip the "memory" section; we import the memory instead. writeGlobalSection(); + writeEventSection(Events); writeExportSection(Exports); writeElemSection(TableElems); writeCodeSection(Asm, Layout, Functions); diff --git a/lib/Object/WasmObjectFile.cpp b/lib/Object/WasmObjectFile.cpp index 3bd66f9375f..794f869d475 100644 --- a/lib/Object/WasmObjectFile.cpp +++ b/lib/Object/WasmObjectFile.cpp @@ -295,6 +295,8 @@ Error WasmObjectFile::parseSection(WasmSection &Sec) { return parseMemorySection(Ctx); case wasm::WASM_SEC_GLOBAL: return parseGlobalSection(Ctx); + case wasm::WASM_SEC_EVENT: + return parseEventSection(Ctx); case wasm::WASM_SEC_EXPORT: return parseExportSection(Ctx); case wasm::WASM_SEC_START: @@ -439,19 +441,24 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) { std::vector ImportedGlobals; std::vector ImportedFunctions; + std::vector ImportedEvents; ImportedGlobals.reserve(Imports.size()); ImportedFunctions.reserve(Imports.size()); + ImportedEvents.reserve(Imports.size()); for (auto &I : Imports) { if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION) ImportedFunctions.emplace_back(&I); else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL) ImportedGlobals.emplace_back(&I); + else if (I.Kind == wasm::WASM_EXTERNAL_EVENT) + ImportedEvents.emplace_back(&I); } while (Count--) { wasm::WasmSymbolInfo Info; const wasm::WasmSignature *FunctionType = nullptr; const wasm::WasmGlobalType *GlobalType = nullptr; + const wasm::WasmEventType *EventType = nullptr; Info.Kind = readUint8(Ctx); Info.Flags = readVaruint32(Ctx); @@ -532,6 +539,32 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) { break; } + case wasm::WASM_SYMBOL_TYPE_EVENT: { + Info.ElementIndex = readVaruint32(Ctx); + if (!isValidEventIndex(Info.ElementIndex) || + IsDefined != isDefinedEventIndex(Info.ElementIndex)) + return make_error("invalid event symbol index", + object_error::parse_failed); + if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) == + wasm::WASM_SYMBOL_BINDING_WEAK) + return make_error("undefined weak global symbol", + object_error::parse_failed); + if (IsDefined) { + Info.Name = readString(Ctx); + unsigned EventIndex = Info.ElementIndex - NumImportedEvents; + wasm::WasmEvent &Event = Events[EventIndex]; + EventType = &Event.Type; + if (Event.SymbolName.empty()) + Event.SymbolName = Info.Name; + + } else { + wasm::WasmImport &Import = *ImportedEvents[Info.ElementIndex]; + EventType = &Import.Event; + Info.Name = Import.Field; + } + break; + } + default: return make_error("Invalid symbol type", object_error::parse_failed); @@ -545,7 +578,7 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) { object_error::parse_failed); LinkingData.SymbolTable.emplace_back(Info); Symbols.emplace_back(LinkingData.SymbolTable.back(), FunctionType, - GlobalType); + GlobalType, EventType); LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n"); } @@ -635,6 +668,11 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { return make_error("Bad relocation global index", object_error::parse_failed); break; + case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: + if (!isValidEventSymbol(Reloc.Index)) + return make_error("Bad relocation event index", + object_error::parse_failed); + break; case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: @@ -755,6 +793,11 @@ Error WasmObjectFile::parseImportSection(ReadContext &Ctx) { return make_error("Invalid table element type", object_error::parse_failed); break; + case wasm::WASM_EXTERNAL_EVENT: + NumImportedEvents++; + Im.Event.Attribute = readVarint32(Ctx); + Im.Event.SigIndex = readVarint32(Ctx); + break; default: return make_error("Unexpected import kind", object_error::parse_failed); @@ -831,6 +874,24 @@ Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) { return Error::success(); } +Error WasmObjectFile::parseEventSection(ReadContext &Ctx) { + EventSection = Sections.size(); + uint32_t Count = readVarint32(Ctx); + Events.reserve(Count); + while (Count--) { + wasm::WasmEvent Event; + Event.Index = NumImportedEvents + Events.size(); + Event.Type.Attribute = readVaruint32(Ctx); + Event.Type.SigIndex = readVarint32(Ctx); + Events.push_back(Event); + } + + if (Ctx.Ptr != Ctx.End) + return make_error("Event section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + Error WasmObjectFile::parseExportSection(ReadContext &Ctx) { uint32_t Count = readVaruint32(Ctx); Exports.reserve(Count); @@ -850,6 +911,11 @@ Error WasmObjectFile::parseExportSection(ReadContext &Ctx) { return make_error("Invalid global export", object_error::parse_failed); break; + case wasm::WASM_EXTERNAL_EVENT: + if (!isValidEventIndex(Ex.Index)) + return make_error("Invalid event export", + object_error::parse_failed); + break; case wasm::WASM_EXTERNAL_MEMORY: case wasm::WASM_EXTERNAL_TABLE: break; @@ -881,6 +947,14 @@ bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const { return Index >= NumImportedGlobals && isValidGlobalIndex(Index); } +bool WasmObjectFile::isValidEventIndex(uint32_t Index) const { + return Index < NumImportedEvents + Events.size(); +} + +bool WasmObjectFile::isDefinedEventIndex(uint32_t Index) const { + return Index >= NumImportedEvents && isValidEventIndex(Index); +} + bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const { return Index < Symbols.size() && Symbols[Index].isTypeFunction(); } @@ -889,6 +963,10 @@ bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const { return Index < Symbols.size() && Symbols[Index].isTypeGlobal(); } +bool WasmObjectFile::isValidEventSymbol(uint32_t Index) const { + return Index < Symbols.size() && Symbols[Index].isTypeEvent(); +} + bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const { return Index < Symbols.size() && Symbols[Index].isTypeData(); } @@ -907,6 +985,11 @@ wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) { return Globals[Index - NumImportedGlobals]; } +wasm::WasmEvent &WasmObjectFile::getDefinedEvent(uint32_t Index) { + assert(isDefinedEventIndex(Index)); + return Events[Index - NumImportedEvents]; +} + Error WasmObjectFile::parseStartSection(ReadContext &Ctx) { StartFunction = readVaruint32(Ctx); if (!isValidFunctionIndex(StartFunction)) @@ -1070,6 +1153,7 @@ uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const { switch (Sym.Info.Kind) { case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_GLOBAL: + case wasm::WASM_SYMBOL_TYPE_EVENT: return Sym.Info.ElementIndex; case wasm::WASM_SYMBOL_TYPE_DATA: { // The value of a data symbol is the segment offset, plus the symbol @@ -1112,6 +1196,8 @@ WasmObjectFile::getSymbolType(DataRefImpl Symb) const { return SymbolRef::ST_Data; case wasm::WASM_SYMBOL_TYPE_SECTION: return SymbolRef::ST_Debug; + case wasm::WASM_SYMBOL_TYPE_EVENT: + return SymbolRef::ST_Other; } llvm_unreachable("Unknown WasmSymbol::SymbolType"); @@ -1135,10 +1221,12 @@ WasmObjectFile::getSymbolSection(DataRefImpl Symb) const { case wasm::WASM_SYMBOL_TYPE_DATA: Ref.d.a = DataSection; break; - case wasm::WASM_SYMBOL_TYPE_SECTION: { + case wasm::WASM_SYMBOL_TYPE_SECTION: Ref.d.a = Sym.Info.ElementIndex; break; - } + case wasm::WASM_SYMBOL_TYPE_EVENT: + Ref.d.a = EventSection; + break; default: llvm_unreachable("Unknown WasmSymbol::SymbolType"); } @@ -1161,6 +1249,7 @@ std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec, ECase(TABLE); ECase(MEMORY); ECase(GLOBAL); + ECase(EVENT); ECase(EXPORT); ECase(START); ECase(ELEM); diff --git a/lib/ObjectYAML/WasmYAML.cpp b/lib/ObjectYAML/WasmYAML.cpp index dba950af589..610507cf7f0 100644 --- a/lib/ObjectYAML/WasmYAML.cpp +++ b/lib/ObjectYAML/WasmYAML.cpp @@ -100,6 +100,11 @@ static void sectionMapping(IO &IO, WasmYAML::GlobalSection &Section) { IO.mapOptional("Globals", Section.Globals); } +static void sectionMapping(IO &IO, WasmYAML::EventSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Events", Section.Events); +} + static void sectionMapping(IO &IO, WasmYAML::ExportSection &Section) { commonSectionMapping(IO, Section); IO.mapOptional("Exports", Section.Exports); @@ -187,6 +192,11 @@ void MappingTraits>::mapping( Section.reset(new WasmYAML::GlobalSection()); sectionMapping(IO, *cast(Section.get())); break; + case wasm::WASM_SEC_EVENT: + if (!IO.outputting()) + Section.reset(new WasmYAML::EventSection()); + sectionMapping(IO, *cast(Section.get())); + break; case wasm::WASM_SEC_EXPORT: if (!IO.outputting()) Section.reset(new WasmYAML::ExportSection()); @@ -227,6 +237,7 @@ void ScalarEnumerationTraits::enumeration( ECase(TABLE); ECase(MEMORY); ECase(GLOBAL); + ECase(EVENT); ECase(EXPORT); ECase(START); ECase(ELEM); @@ -307,6 +318,9 @@ void MappingTraits::mapping(IO &IO, } else if (Import.Kind == wasm::WASM_EXTERNAL_GLOBAL) { IO.mapRequired("GlobalType", Import.GlobalImport.Type); IO.mapRequired("GlobalMutable", Import.GlobalImport.Mutable); + } else if (Import.Kind == wasm::WASM_EXTERNAL_EVENT) { + IO.mapRequired("EventAttribute", Import.EventImport.Attribute); + IO.mapRequired("EventSigIndex", Import.EventImport.SigIndex); } else if (Import.Kind == wasm::WASM_EXTERNAL_TABLE) { IO.mapRequired("Table", Import.TableImport); } else if (Import.Kind == wasm::WASM_EXTERNAL_MEMORY) { @@ -399,6 +413,8 @@ void MappingTraits::mapping(IO &IO, IO.mapRequired("Function", Info.ElementIndex); } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL) { IO.mapRequired("Global", Info.ElementIndex); + } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_EVENT) { + IO.mapRequired("Event", Info.ElementIndex); } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_DATA) { if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) { IO.mapRequired("Segment", Info.DataRef.Segment); @@ -412,6 +428,12 @@ void MappingTraits::mapping(IO &IO, } } +void MappingTraits::mapping(IO &IO, WasmYAML::Event &Event) { + IO.mapRequired("Index", Event.Index); + IO.mapRequired("Attribute", Event.Attribute); + IO.mapRequired("SigIndex", Event.SigIndex); +} + void ScalarBitSetTraits::bitset( IO &IO, WasmYAML::LimitFlags &Value) { #define BCase(X) IO.bitSetCase(Value, #X, wasm::WASM_LIMITS_FLAG_##X) @@ -443,6 +465,7 @@ void ScalarEnumerationTraits::enumeration( ECase(DATA); ECase(GLOBAL); ECase(SECTION); + ECase(EVENT); #undef ECase } @@ -467,6 +490,7 @@ void ScalarEnumerationTraits::enumeration( ECase(TABLE); ECase(MEMORY); ECase(GLOBAL); + ECase(EVENT); #undef ECase } diff --git a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp index 53b69eaf005..490c00aa9ec 100644 --- a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp +++ b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp @@ -86,6 +86,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction( const MCOperand &MO = MI.getOperand(i); if (MO.isReg()) { /* nothing to encode */ + } else if (MO.isImm()) { if (i < Desc.getNumOperands()) { assert(Desc.TSFlags == 0 && @@ -128,6 +129,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction( WebAssemblyII::VariableOpImmediateIsLabel)); encodeULEB128(uint64_t(MO.getImm()), OS); } + } else if (MO.isFPImm()) { assert(i < Desc.getNumOperands() && "Unexpected floating-point immediate as a non-fixed operand"); @@ -144,22 +146,27 @@ void WebAssemblyMCCodeEmitter::encodeInstruction( double d = MO.getFPImm(); support::endian::write(OS, d, support::little); } + } else if (MO.isExpr()) { const MCOperandInfo &Info = Desc.OpInfo[i]; llvm::MCFixupKind FixupKind; size_t PaddedSize = 5; - if (Info.OperandType == WebAssembly::OPERAND_I32IMM) { + switch (Info.OperandType) { + case WebAssembly::OPERAND_I32IMM: FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i32); - } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) { + break; + case WebAssembly::OPERAND_I64IMM: FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i64); PaddedSize = 10; - } else if (Info.OperandType == WebAssembly::OPERAND_FUNCTION32 || - Info.OperandType == WebAssembly::OPERAND_OFFSET32 || - Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) { + break; + case WebAssembly::OPERAND_FUNCTION32: + case WebAssembly::OPERAND_OFFSET32: + case WebAssembly::OPERAND_TYPEINDEX: + case WebAssembly::OPERAND_GLOBAL: + case WebAssembly::OPERAND_EVENT: FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32); - } else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) { - FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32); - } else { + break; + default: llvm_unreachable("unexpected symbolic operand kind"); } Fixups.push_back(MCFixup::create(OS.tell() - Start, MO.getExpr(), diff --git a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index 730bb8d6c79..69d4db96323 100644 --- a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -77,6 +77,8 @@ enum OperandType { OPERAND_SIGNATURE, /// type signature immediate for call_indirect. OPERAND_TYPEINDEX, + /// Event index. + OPERAND_EVENT, }; } // end namespace WebAssembly @@ -97,7 +99,8 @@ enum TOF { // Flags to indicate the type of the symbol being referenced MO_SYMBOL_FUNCTION = 0x1, MO_SYMBOL_GLOBAL = 0x2, - MO_SYMBOL_MASK = 0x3, + MO_SYMBOL_EVENT = 0x4, + MO_SYMBOL_MASK = 0x7, }; } // end namespace WebAssemblyII diff --git a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp index 4c4ca4e599c..ada687e20e1 100644 --- a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -100,12 +100,28 @@ void WebAssemblyTargetAsmStreamer::emitIndirectFunctionType( } void WebAssemblyTargetAsmStreamer::emitGlobalType(MCSymbolWasm *Sym) { + assert(Sym->isGlobal()); OS << "\t.globaltype\t" << Sym->getName() << ", " << WebAssembly::TypeToString( static_cast(Sym->getGlobalType().Type)) << '\n'; } +void WebAssemblyTargetAsmStreamer::emitEventType(MCSymbolWasm *Sym) { + assert(Sym->isEvent()); + OS << "\t.eventtype\t" << Sym->getName(); + if (Sym->getSignature()->Returns.empty()) + OS << ", void"; + else { + assert(Sym->getSignature()->Returns.size() == 1); + OS << ", " + << WebAssembly::TypeToString(Sym->getSignature()->Returns.front()); + } + for (auto Ty : Sym->getSignature()->Params) + OS << ", " << WebAssembly::TypeToString(Ty); + OS << '\n'; +} + void WebAssemblyTargetAsmStreamer::emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) { OS << "\t.import_module\t" << Sym->getName() << ", " << ModuleName << '\n'; @@ -159,6 +175,9 @@ void WebAssemblyTargetWasmStreamer::emitGlobalType(MCSymbolWasm *Sym) { // Not needed. } +void WebAssemblyTargetWasmStreamer::emitEventType(MCSymbolWasm *Sym) { + // Not needed. +} void WebAssemblyTargetWasmStreamer::emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) { Sym->setModuleName(ModuleName); diff --git a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h index e60158b5def..68527542e3e 100644 --- a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h +++ b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h @@ -45,6 +45,8 @@ public: virtual void emitIndIdx(const MCExpr *Value) = 0; /// .globaltype virtual void emitGlobalType(MCSymbolWasm *Sym) = 0; + /// .eventtype + virtual void emitEventType(MCSymbolWasm *Sym) = 0; /// .import_module virtual void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) = 0; @@ -66,6 +68,7 @@ public: void emitIndirectFunctionType(MCSymbolWasm *Symbol) override; void emitIndIdx(const MCExpr *Value) override; void emitGlobalType(MCSymbolWasm *Sym) override; + void emitEventType(MCSymbolWasm *Sym) override; void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) override; }; @@ -81,6 +84,7 @@ public: void emitIndirectFunctionType(MCSymbolWasm *Symbol) override; void emitIndIdx(const MCExpr *Value) override; void emitGlobalType(MCSymbolWasm *Sym) override; + void emitEventType(MCSymbolWasm *Sym) override; void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) override; }; diff --git a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp index d9ed146ede7..763e30be8e0 100644 --- a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp +++ b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -86,6 +86,11 @@ static bool IsGlobalType(const MCValue &Target) { return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_GLOBAL; } +static bool IsEventType(const MCValue &Target) { + const MCSymbolRefExpr *RefA = Target.getSymA(); + return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_EVENT; +} + unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target, const MCFixup &Fixup) const { // WebAssembly functions are not allocated in the data address space. To @@ -106,6 +111,8 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target, return wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB; if (IsFunction) return wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB; + if (IsEventType(Target)) + return wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB; return wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB; case FK_Data_4: if (IsFunction) diff --git a/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 1e21ab92b62..66fa91bd4d9 100644 --- a/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -79,11 +79,12 @@ WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() { void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { for (auto &It : OutContext.getSymbols()) { - // Emit a .globaltype declaration. + // Emit a .globaltype and .eventtype declaration. auto Sym = cast(It.getValue()); - if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL) { + if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL) getTargetStreamer()->emitGlobalType(Sym); - } + else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_EVENT) + getTargetStreamer()->emitEventType(Sym); } for (const auto &F : M) { diff --git a/lib/Target/WebAssembly/WebAssemblyISD.def b/lib/Target/WebAssembly/WebAssemblyISD.def index 444a087605e..e987d7f7f43 100644 --- a/lib/Target/WebAssembly/WebAssemblyISD.def +++ b/lib/Target/WebAssembly/WebAssemblyISD.def @@ -25,5 +25,6 @@ HANDLE_NODETYPE(SHUFFLE) HANDLE_NODETYPE(VEC_SHL) HANDLE_NODETYPE(VEC_SHR_S) HANDLE_NODETYPE(VEC_SHR_U) +HANDLE_NODETYPE(THROW) // add memory opcodes starting at ISD::FIRST_TARGET_MEMORY_OPCODE here... diff --git a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index 46f8877198c..418ceca5713 100644 --- a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -24,6 +24,7 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/WasmEHFuncInfo.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/Function.h" @@ -234,6 +235,7 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering( // Exception handling intrinsics setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); + setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); setMaxAtomicSizeInBitsSupported(64); } @@ -882,6 +884,8 @@ SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op, case ISD::EXTRACT_VECTOR_ELT: case ISD::INSERT_VECTOR_ELT: return LowerAccessVectorElement(Op, DAG); + case ISD::INTRINSIC_VOID: + return LowerINTRINSIC_VOID(Op, DAG); case ISD::VECTOR_SHUFFLE: return LowerVECTOR_SHUFFLE(Op, DAG); case ISD::SHL: @@ -1045,6 +1049,44 @@ WebAssemblyTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, } } +SDValue +WebAssemblyTargetLowering::LowerINTRINSIC_VOID(SDValue Op, + SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + unsigned IntNo = cast(Op.getOperand(1))->getZExtValue(); + SDLoc DL(Op); + + switch (IntNo) { + default: + return {}; // Don't custom lower most intrinsics. + + case Intrinsic::wasm_throw: { + int Tag = cast(Op.getOperand(2).getNode())->getZExtValue(); + switch (Tag) { + case CPP_EXCEPTION: { + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); + const char *SymName = MF.createExternalSymbolName("__cpp_exception"); + SDValue SymNode = + DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, + DAG.getTargetExternalSymbol( + SymName, PtrVT, WebAssemblyII::MO_SYMBOL_EVENT)); + return DAG.getNode(WebAssemblyISD::THROW, DL, + MVT::Other, // outchain type + { + Op.getOperand(0), // inchain + SymNode, // exception symbol + Op.getOperand(3) // thrown value + }); + } + default: + llvm_unreachable("Invalid tag!"); + } + break; + } + } +} + SDValue WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const { diff --git a/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/lib/Target/WebAssembly/WebAssemblyISelLowering.h index 5182a58efc7..80076818de7 100644 --- a/lib/Target/WebAssembly/WebAssemblyISelLowering.h +++ b/lib/Target/WebAssembly/WebAssemblyISelLowering.h @@ -98,6 +98,7 @@ private: SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const; SDValue LowerCopyToReg(SDValue Op, SelectionDAG &DAG) const; SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerAccessVectorElement(SDValue Op, SelectionDAG &DAG) const; SDValue LowerShift(SDValue Op, SelectionDAG &DAG) const; diff --git a/lib/Target/WebAssembly/WebAssemblyInstrControl.td b/lib/Target/WebAssembly/WebAssemblyInstrControl.td index 0af94ef8755..718bbfa54b9 100644 --- a/lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ b/lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -146,14 +146,16 @@ let Predicates = [HasExceptionHandling] in { // Throwing an exception: throw / rethrow let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in { -defm THROW_I32 : I<(outs), (ins i32imm:$tag, I32:$val), - (outs), (ins i32imm:$tag), - [(int_wasm_throw imm:$tag, I32:$val)], +defm THROW_I32 : I<(outs), (ins event_op:$tag, I32:$val), + (outs), (ins event_op:$tag), + [(WebAssemblythrow (WebAssemblywrapper texternalsym:$tag), + I32:$val)], "throw \t$tag, $val", "throw \t$tag", 0x08>; -defm THROW_I64 : I<(outs), (ins i32imm:$tag, I64:$val), - (outs), (ins i32imm:$tag), - [(int_wasm_throw imm:$tag, I64:$val)], +defm THROW_I64 : I<(outs), (ins event_op:$tag, I64:$val), + (outs), (ins event_op:$tag), + [(WebAssemblythrow (WebAssemblywrapper texternalsym:$tag), + I64:$val)], "throw \t$tag, $val", "throw \t$tag", 0x08>; defm RETHROW : NRI<(outs), (ins bb_op:$dst), [], "rethrow \t$dst", 0x09>; diff --git a/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/lib/Target/WebAssembly/WebAssemblyInstrInfo.td index 8fff924265f..085c5a77e68 100644 --- a/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -64,6 +64,7 @@ def SDT_WebAssemblyArgument : SDTypeProfile<1, 1, [SDTCisVT<1, i32>]>; def SDT_WebAssemblyReturn : SDTypeProfile<0, -1, []>; def SDT_WebAssemblyWrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>; +def SDT_WebAssemblyThrow : SDTypeProfile<0, 2, [SDTCisPtrTy<0>]>; //===----------------------------------------------------------------------===// // WebAssembly-specific DAG Nodes. @@ -90,6 +91,8 @@ def WebAssemblyreturn : SDNode<"WebAssemblyISD::RETURN", SDT_WebAssemblyReturn, [SDNPHasChain]>; def WebAssemblywrapper : SDNode<"WebAssemblyISD::Wrapper", SDT_WebAssemblyWrapper>; +def WebAssemblythrow : SDNode<"WebAssemblyISD::THROW", SDT_WebAssemblyThrow, + [SDNPHasChain]>; //===----------------------------------------------------------------------===// // WebAssembly-specific Operands. @@ -140,6 +143,10 @@ let OperandType = "OPERAND_P2ALIGN" in { def P2Align : Operand { let PrintMethod = "printWebAssemblyP2AlignOperand"; } + +let OperandType = "OPERAND_EVENT" in +def event_op : Operand; + } // OperandType = "OPERAND_P2ALIGN" let OperandType = "OPERAND_SIGNATURE" in { diff --git a/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp index 1dad7b8a289..fa862fbaa63 100644 --- a/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -75,10 +75,10 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol( cast(Printer.GetExternalSymbolSymbol(Name)); const WebAssemblySubtarget &Subtarget = Printer.getSubtarget(); - // __stack_pointer is a global variable; all other external symbols used by - // CodeGen are functions. It's OK to hardcode knowledge of specific symbols - // here; this method is precisely there for fetching the signatures of known - // Clang-provided symbols. + // Except for the two exceptions (__stack_pointer and __cpp_exception), all + // other external symbols used by CodeGen are functions. It's OK to hardcode + // knowledge of specific symbols here; this method is precisely there for + // fetching the signatures of known Clang-provided symbols. if (strcmp(Name, "__stack_pointer") == 0) { WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); WasmSym->setGlobalType(wasm::WasmGlobalType{ @@ -90,24 +90,45 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol( SmallVector Returns; SmallVector Params; - GetLibcallSignature(Subtarget, Name, Returns, Params); + if (strcmp(Name, "__cpp_exception") == 0) { + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT); + // We can't confirm its signature index for now because there can be + // imported exceptions. Set it to be 0 for now. + WasmSym->setEventType( + {wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION, /* SigIndex */ 0}); + // We may have multiple C++ compilation units to be linked together, each of + // which defines the exception symbol. To resolve them, we declare them as + // weak. + WasmSym->setWeak(true); + WasmSym->setExternal(true); + + // All C++ exceptions are assumed to have a single i32 (for wasm32) or i64 + // (for wasm64) param type and void return type. The reaon is, all C++ + // exception values are pointers, and to share the type section with + // functions, exceptions are assumed to have void return type. + Params.push_back(Subtarget.hasAddr64() ? wasm::ValType::I64 + : wasm::ValType::I32); + } else { // Function symbols + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); + GetLibcallSignature(Subtarget, Name, Returns, Params); + } auto Signature = make_unique(std::move(Returns), std::move(Params)); WasmSym->setSignature(Signature.get()); Printer.addSignature(std::move(Signature)); - WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); return WasmSym; } MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym, int64_t Offset, - bool IsFunc, - bool IsGlob) const { + bool IsFunc, bool IsGlob, + bool IsEvent) const { MCSymbolRefExpr::VariantKind VK = IsFunc ? MCSymbolRefExpr::VK_WebAssembly_FUNCTION : IsGlob ? MCSymbolRefExpr::VK_WebAssembly_GLOBAL - : MCSymbolRefExpr::VK_None; + : IsEvent ? MCSymbolRefExpr::VK_WebAssembly_EVENT + : MCSymbolRefExpr::VK_None; const MCExpr *Expr = MCSymbolRefExpr::create(Sym, VK, Ctx); @@ -116,6 +137,8 @@ MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym, report_fatal_error("Function addresses with offsets not supported"); if (IsGlob) report_fatal_error("Global indexes with offsets not supported"); + if (IsEvent) + report_fatal_error("Event indexes with offsets not supported"); Expr = MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, Ctx), Ctx); } @@ -218,7 +241,7 @@ void WebAssemblyMCInstLower::Lower(const MachineInstr *MI, "WebAssembly does not use target flags on GlobalAddresses"); MCOp = LowerSymbolOperand(GetGlobalAddressSymbol(MO), MO.getOffset(), MO.getGlobal()->getValueType()->isFunctionTy(), - false); + false, false); break; case MachineOperand::MO_ExternalSymbol: // The target flag indicates whether this is a symbol for a @@ -228,14 +251,16 @@ void WebAssemblyMCInstLower::Lower(const MachineInstr *MI, MCOp = LowerSymbolOperand( GetExternalSymbolSymbol(MO), /*Offset=*/0, (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_FUNCTION) != 0, - (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_GLOBAL) != 0); + (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_GLOBAL) != 0, + (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_EVENT) != 0); break; case MachineOperand::MO_MCSymbol: // This is currently used only for LSDA symbols (GCC_except_table), // because global addresses or other external symbols are handled above. assert(MO.getTargetFlags() == 0 && "WebAssembly does not use target flags on MCSymbol"); - MCOp = LowerSymbolOperand(MO.getMCSymbol(), /*Offset=*/0, false, false); + MCOp = LowerSymbolOperand(MO.getMCSymbol(), /*Offset=*/0, false, false, + false); break; } diff --git a/lib/Target/WebAssembly/WebAssemblyMCInstLower.h b/lib/Target/WebAssembly/WebAssemblyMCInstLower.h index 54a55796415..fa7a0ea61b3 100644 --- a/lib/Target/WebAssembly/WebAssemblyMCInstLower.h +++ b/lib/Target/WebAssembly/WebAssemblyMCInstLower.h @@ -34,7 +34,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyMCInstLower { MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; MCOperand LowerSymbolOperand(MCSymbol *Sym, int64_t Offset, bool IsFunc, - bool IsGlob) const; + bool IsGlob, bool IsEvent) const; public: WebAssemblyMCInstLower(MCContext &ctx, WebAssemblyAsmPrinter &printer) diff --git a/test/CodeGen/WebAssembly/exception.ll b/test/CodeGen/WebAssembly/exception.ll index bd7935c3684..0577cd43b97 100644 --- a/test/CodeGen/WebAssembly/exception.ll +++ b/test/CodeGen/WebAssembly/exception.ll @@ -13,7 +13,7 @@ declare void @llvm.wasm.throw(i32, i8*) ; CHECK-LABEL: test_throw: ; CHECK-NEXT: i32.const $push0=, 0 -; CHECK-NEXT: throw 0, $pop0 +; CHECK-NEXT: throw __cpp_exception@EVENT, $pop0 define void @test_throw() { call void @llvm.wasm.throw(i32 0, i8* null) ret void @@ -259,3 +259,6 @@ declare void @__cxa_rethrow() declare void @__clang_call_terminate(i8*) declare void @_ZSt9terminatev() declare %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* returned) + +; CHECK: __cpp_exception: +; CHECK: .eventtype __cpp_exception, void, i32 diff --git a/test/MC/WebAssembly/event-section.ll b/test/MC/WebAssembly/event-section.ll new file mode 100644 index 00000000000..2a6f66cd971 --- /dev/null +++ b/test/MC/WebAssembly/event-section.ll @@ -0,0 +1,58 @@ +; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling %s -o - | obj2yaml | FileCheck %s +; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling %s -o - | llvm-readobj -s | FileCheck -check-prefix=SEC %s + +target triple = "wasm32-unknown-unknown" + +declare void @llvm.wasm.throw(i32, i8*) + +define i32 @test_throw0(i8* %p) { + call void @llvm.wasm.throw(i32 0, i8* %p) + ret i32 0 +} + +define i32 @test_throw1(i8* %p) { + call void @llvm.wasm.throw(i32 0, i8* %p) + ret i32 1 +} + +; CHECK: Sections: +; CHECK-NEXT: - Type: TYPE +; CHECK-NEXT: Signatures: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ReturnType: I32 +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - I32 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - I32 + +; CHECK: - Type: EVENT +; CHECK-NEXT: Events: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Attribute: 0 +; CHECK-NEXT: SigIndex: 1 + +; CHECK-NEXT: - Type: CODE +; CHECK-NEXT: Relocations: +; CHECK-NEXT: - Type: R_WEBASSEMBLY_EVENT_INDEX_LEB +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Offset: 0x00000006 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_EVENT_INDEX_LEB +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Offset: 0x00000013 + +; CHECK: - Type: CUSTOM +; CHECK-NEXT: Name: linking +; CHECK-NEXT: Version: 1 +; CHECK-NEXT: SymbolTable: + +; CHECK: - Index: 1 +; CHECK-NEXT: Kind: EVENT +; CHECK-NEXT: Name: __cpp_exception +; CHECK-NEXT: Flags: [ BINDING_WEAK ] +; CHECK-NEXT: Event: 0 + +; SEC: Type: EVENT (0xC) +; SEC-NEXT: Size: 3 +; SEC-NEXT: Offset: 97 diff --git a/test/ObjectYAML/wasm/event_section.yaml b/test/ObjectYAML/wasm/event_section.yaml new file mode 100644 index 00000000000..017efda056c --- /dev/null +++ b/test/ObjectYAML/wasm/event_section.yaml @@ -0,0 +1,92 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s + +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - Index: 0 + ReturnType: I32 + ParamTypes: + - I32 + - Index: 1 + ReturnType: NORESULT + ParamTypes: + - I32 + - Type: FUNCTION + FunctionTypes: [ 0 ] + - Type: EVENT + Events: + - Index: 0 + Attribute: 0 + SigIndex: 1 + - Type: CODE + Relocations: + - Type: R_WEBASSEMBLY_EVENT_INDEX_LEB + Index: 1 + Offset: 0x00000006 + Functions: + - Index: 0 + Locals: + Body: 200008808080800041000B + - Type: CUSTOM + Name: linking + Version: 1 + SymbolTable: + - Index: 0 + Kind: FUNCTION + Name: test_throw0 + Flags: [ ] + Function: 0 + - Index: 1 + Kind: EVENT + Name: __cpp_exception + Flags: [ BINDING_WEAK ] + Event: 0 +... + +# CHECK: --- !WASM +# CHECK-NEXT: FileHeader: +# CHECK-NEXT: Version: 0x00000001 +# CHECK-NEXT: Sections: +# CHECK-NEXT: - Type: TYPE +# CHECK-NEXT: Signatures: +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: ReturnType: I32 +# CHECK-NEXT: ParamTypes: +# CHECK-NEXT: - I32 +# CHECK-NEXT: - Index: 1 +# CHECK-NEXT: ReturnType: NORESULT +# CHECK-NEXT: ParamTypes: +# CHECK-NEXT: - I32 +# CHECK-NEXT: - Type: FUNCTION +# CHECK-NEXT: FunctionTypes: [ 0 ] +# CHECK-NEXT: - Type: EVENT +# CHECK-NEXT: Events: +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: Attribute: 0 +# CHECK-NEXT: SigIndex: 1 +# CHECK-NEXT: - Type: CODE +# CHECK-NEXT: Relocations: +# CHECK-NEXT: - Type: R_WEBASSEMBLY_EVENT_INDEX_LEB +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Offset: 0x00000006 +# CHECK-NEXT: Functions: +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: Locals: +# CHECK-NEXT: Body: 200008808080800041000B +# CHECK-NEXT: - Type: CUSTOM +# CHECK-NEXT: Name: linking +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: SymbolTable: +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: Kind: FUNCTION +# CHECK-NEXT: Name: test_throw0 +# CHECK-NEXT: Flags: [ ] +# CHECK-NEXT: Function: 0 +# CHECK-NEXT: - Index: 1 +# CHECK-NEXT: Kind: EVENT +# CHECK-NEXT: Name: __cpp_exception +# CHECK-NEXT: Flags: [ BINDING_WEAK ] +# CHECK-NEXT: Event: 0 diff --git a/tools/llvm-readobj/WasmDumper.cpp b/tools/llvm-readobj/WasmDumper.cpp index 2d979958983..79d3db4e2d2 100644 --- a/tools/llvm-readobj/WasmDumper.cpp +++ b/tools/llvm-readobj/WasmDumper.cpp @@ -25,20 +25,19 @@ namespace { static const EnumEntry WasmSymbolTypes[] = { #define ENUM_ENTRY(X) \ { #X, wasm::WASM_SYMBOL_TYPE_##X } - ENUM_ENTRY(FUNCTION), - ENUM_ENTRY(DATA), - ENUM_ENTRY(GLOBAL), - ENUM_ENTRY(SECTION), + ENUM_ENTRY(FUNCTION), ENUM_ENTRY(DATA), ENUM_ENTRY(GLOBAL), + ENUM_ENTRY(SECTION), ENUM_ENTRY(EVENT), #undef ENUM_ENTRY }; static const EnumEntry WasmSectionTypes[] = { #define ENUM_ENTRY(X) \ { #X, wasm::WASM_SEC_##X } - ENUM_ENTRY(CUSTOM), ENUM_ENTRY(TYPE), ENUM_ENTRY(IMPORT), - ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE), ENUM_ENTRY(MEMORY), - ENUM_ENTRY(GLOBAL), ENUM_ENTRY(EXPORT), ENUM_ENTRY(START), - ENUM_ENTRY(ELEM), ENUM_ENTRY(CODE), ENUM_ENTRY(DATA), + ENUM_ENTRY(CUSTOM), ENUM_ENTRY(TYPE), ENUM_ENTRY(IMPORT), + ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE), ENUM_ENTRY(MEMORY), + ENUM_ENTRY(GLOBAL), ENUM_ENTRY(EVENT), ENUM_ENTRY(EXPORT), + ENUM_ENTRY(START), ENUM_ENTRY(ELEM), ENUM_ENTRY(CODE), + ENUM_ENTRY(DATA), #undef ENUM_ENTRY }; diff --git a/tools/obj2yaml/wasm2yaml.cpp b/tools/obj2yaml/wasm2yaml.cpp index a1120a96571..8bbc9fb468c 100644 --- a/tools/obj2yaml/wasm2yaml.cpp +++ b/tools/obj2yaml/wasm2yaml.cpp @@ -107,6 +107,7 @@ WasmDumper::dumpCustomSection(const WasmSection &WasmSec) { break; case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_GLOBAL: + case wasm::WASM_SYMBOL_TYPE_EVENT: Info.ElementIndex = Symbol.ElementIndex; break; case wasm::WASM_SYMBOL_TYPE_SECTION: @@ -182,6 +183,10 @@ ErrorOr WasmDumper::dump() { Im.GlobalImport.Type = Import.Global.Type; Im.GlobalImport.Mutable = Import.Global.Mutable; break; + case wasm::WASM_EXTERNAL_EVENT: + Im.EventImport.Attribute = Import.Event.Attribute; + Im.EventImport.SigIndex = Import.Event.SigIndex; + break; case wasm::WASM_EXTERNAL_TABLE: Im.TableImport = make_table(Import.Table); break; @@ -231,6 +236,18 @@ ErrorOr WasmDumper::dump() { S = std::move(GlobalSec); break; } + case wasm::WASM_SEC_EVENT: { + auto EventSec = make_unique(); + for (auto &Event : Obj.events()) { + WasmYAML::Event E; + E.Index = Event.Index; + E.Attribute = Event.Type.Attribute; + E.SigIndex = Event.Type.SigIndex; + EventSec->Events.push_back(E); + } + S = std::move(EventSec); + break; + } case wasm::WASM_SEC_START: { auto StartSec = make_unique(); StartSec->StartFunction = Obj.startFunction(); diff --git a/tools/yaml2obj/yaml2wasm.cpp b/tools/yaml2obj/yaml2wasm.cpp index 2b1e256f8f6..4a9269d96a1 100644 --- a/tools/yaml2obj/yaml2wasm.cpp +++ b/tools/yaml2obj/yaml2wasm.cpp @@ -37,6 +37,7 @@ private: int writeSectionContent(raw_ostream &OS, WasmYAML::TableSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::MemorySection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::GlobalSection &Section); + int writeSectionContent(raw_ostream &OS, WasmYAML::EventSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::ExportSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::StartSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::ElemSection &Section); @@ -49,6 +50,7 @@ private: WasmYAML::Object &Obj; uint32_t NumImportedFunctions = 0; uint32_t NumImportedGlobals = 0; + uint32_t NumImportedEvents = 0; }; static int writeUint64(raw_ostream &OS, uint64_t Value) { @@ -152,6 +154,7 @@ int WasmWriter::writeSectionContent(raw_ostream &OS, switch (Info.Kind) { case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_GLOBAL: + case wasm::WASM_SYMBOL_TYPE_EVENT: encodeULEB128(Info.ElementIndex, SubSection.GetStream()); if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) writeStringRef(Info.Name, SubSection.GetStream()); @@ -292,6 +295,11 @@ int WasmWriter::writeSectionContent(raw_ostream &OS, writeUint8(OS, Import.GlobalImport.Mutable); NumImportedGlobals++; break; + case wasm::WASM_EXTERNAL_EVENT: + writeUint32(OS, Import.EventImport.Attribute); + writeUint32(OS, Import.EventImport.SigIndex); + NumImportedGlobals++; + break; case wasm::WASM_EXTERNAL_MEMORY: writeLimits(Import.Memory, OS); break; @@ -369,6 +377,22 @@ int WasmWriter::writeSectionContent(raw_ostream &OS, return 0; } +int WasmWriter::writeSectionContent(raw_ostream &OS, + WasmYAML::EventSection &Section) { + encodeULEB128(Section.Events.size(), OS); + uint32_t ExpectedIndex = NumImportedEvents; + for (auto &Event : Section.Events) { + if (Event.Index != ExpectedIndex) { + errs() << "Unexpected event index: " << Event.Index << "\n"; + return 1; + } + ++ExpectedIndex; + encodeULEB128(Event.Attribute, OS); + encodeULEB128(Event.SigIndex, OS); + } + return 0; +} + int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::ElemSection &Section) { encodeULEB128(Section.Segments.size(), OS); @@ -474,17 +498,7 @@ int WasmWriter::writeWasm(raw_ostream &OS) { writeUint32(OS, Obj.Header.Version); // Write each section - uint32_t LastType = 0; for (const std::unique_ptr &Sec : Obj.Sections) { - uint32_t Type = Sec->Type; - if (Type != wasm::WASM_SEC_CUSTOM) { - if (Type < LastType) { - errs() << "Out of order section type: " << Type << "\n"; - return 1; - } - LastType = Type; - } - encodeULEB128(Sec->Type, OS); std::string OutString; raw_string_ostream StringStream(OutString); @@ -509,6 +523,9 @@ int WasmWriter::writeWasm(raw_ostream &OS) { } else if (auto S = dyn_cast(Sec.get())) { if (auto Err = writeSectionContent(StringStream, *S)) return Err; + } else if (auto S = dyn_cast(Sec.get())) { + if (auto Err = writeSectionContent(StringStream, *S)) + return Err; } else if (auto S = dyn_cast(Sec.get())) { if (auto Err = writeSectionContent(StringStream, *S)) return Err;