Index: llvm/trunk/include/llvm/BinaryFormat/Wasm.h =================================================================== --- llvm/trunk/include/llvm/BinaryFormat/Wasm.h +++ llvm/trunk/include/llvm/BinaryFormat/Wasm.h @@ -75,6 +75,18 @@ 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 @@ WasmGlobalType Global; WasmTable Table; WasmLimits Memory; + WasmEventType Event; }; }; @@ -178,7 +191,8 @@ 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 @@ 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 @@ 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; Index: llvm/trunk/include/llvm/BinaryFormat/WasmRelocs.def =================================================================== --- llvm/trunk/include/llvm/BinaryFormat/WasmRelocs.def +++ llvm/trunk/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_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) Index: llvm/trunk/include/llvm/CodeGen/WasmEHFuncInfo.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/WasmEHFuncInfo.h +++ llvm/trunk/include/llvm/CodeGen/WasmEHFuncInfo.h @@ -21,6 +21,8 @@ namespace llvm { +enum EventTag { CPP_EXCEPTION = 0, C_LONGJMP = 1 }; + using BBOrMBB = PointerUnion; struct WasmEHFuncInfo { Index: llvm/trunk/include/llvm/MC/MCExpr.h =================================================================== --- llvm/trunk/include/llvm/MC/MCExpr.h +++ llvm/trunk/include/llvm/MC/MCExpr.h @@ -288,6 +288,7 @@ 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 Index: llvm/trunk/include/llvm/MC/MCSymbolWasm.h =================================================================== --- llvm/trunk/include/llvm/MC/MCSymbolWasm.h +++ llvm/trunk/include/llvm/MC/MCSymbolWasm.h @@ -21,8 +21,8 @@ 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 @@ 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 @@ 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 Index: llvm/trunk/include/llvm/Object/RelocVisitor.h =================================================================== --- llvm/trunk/include/llvm/Object/RelocVisitor.h +++ llvm/trunk/include/llvm/Object/RelocVisitor.h @@ -333,6 +333,7 @@ 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; } Index: llvm/trunk/include/llvm/Object/Wasm.h =================================================================== --- llvm/trunk/include/llvm/Object/Wasm.h +++ llvm/trunk/include/llvm/Object/Wasm.h @@ -38,12 +38,15 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 Index: llvm/trunk/include/llvm/ObjectYAML/WasmYAML.h =================================================================== --- llvm/trunk/include/llvm/ObjectYAML/WasmYAML.h +++ llvm/trunk/include/llvm/ObjectYAML/WasmYAML.h @@ -74,6 +74,12 @@ wasm::WasmInitExpr InitExpr; }; +struct Event { + uint32_t Index; + uint32_t Attribute; + uint32_t SigIndex; +}; + struct Import { StringRef Module; StringRef Field; @@ -83,6 +89,7 @@ Global GlobalImport; Table TableImport; Limits Memory; + Event EventImport; }; }; @@ -262,6 +269,16 @@ 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::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 @@ 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 Index: llvm/trunk/lib/BinaryFormat/Wasm.cpp =================================================================== --- llvm/trunk/lib/BinaryFormat/Wasm.cpp +++ llvm/trunk/lib/BinaryFormat/Wasm.cpp @@ -19,6 +19,8 @@ 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"); } Index: llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.h @@ -24,7 +24,7 @@ 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; Index: llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.cpp +++ llvm/trunk/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()) { Index: llvm/trunk/lib/MC/MCExpr.cpp =================================================================== --- llvm/trunk/lib/MC/MCExpr.cpp +++ llvm/trunk/lib/MC/MCExpr.cpp @@ -306,6 +306,7 @@ 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 @@ .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) Index: llvm/trunk/lib/MC/WasmObjectWriter.cpp =================================================================== --- llvm/trunk/lib/MC/WasmObjectWriter.cpp +++ llvm/trunk/lib/MC/WasmObjectWriter.cpp @@ -56,10 +56,10 @@ 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 @@ // 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; - } - static WasmFunctionType getTombstoneKey() { - WasmFunctionType FuncTy; - FuncTy.State = WasmFunctionType::Tombstone; - return FuncTy; - } - static unsigned getHashValue(const WasmFunctionType &FuncTy) { - uintptr_t Value = FuncTy.State; - for (wasm::ValType Ret : FuncTy.Returns) +// Traits for using WasmSignature in a DenseMap. +struct WasmSignatureDenseMapInfo { + static WasmSignature getEmptyKey() { + WasmSignature Sig; + Sig.State = WasmSignature::Empty; + return Sig; + } + static WasmSignature getTombstoneKey() { + WasmSignature Sig; + Sig.State = WasmSignature::Tombstone; + return Sig; + } + 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 @@ // 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 @@ // 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 @@ // 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 @@ TableIndices.clear(); DataLocations.clear(); CustomSectionsRelocations.clear(); - FunctionTypeIndices.clear(); - FunctionTypes.clear(); + SignatureIndices.clear(); + Signatures.clear(); Globals.clear(); DataSegments.clear(); SectionFunctions.clear(); @@ -294,7 +294,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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::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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ SmallVector TableElems; SmallVector Imports; SmallVector Exports; + SmallVector Events; SmallVector SymbolInfos; SmallVector, 2> InitFuncs; std::map> Comdats; @@ -1128,7 +1181,7 @@ 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 @@ if (WS.isFunction()) registerFunctionType(WS); + if (WS.isEvent()) + registerEventType(WS); + if (WS.isTemporary()) continue; @@ -1163,6 +1219,18 @@ 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 @@ // 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 @@ } LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n"); + } else if (WS.isData()) { if (WS.isTemporary() && !WS.getSize()) continue; @@ -1299,6 +1368,7 @@ 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 @@ // 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 @@ 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 @@ // 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); Index: llvm/trunk/lib/Object/WasmObjectFile.cpp =================================================================== --- llvm/trunk/lib/Object/WasmObjectFile.cpp +++ llvm/trunk/lib/Object/WasmObjectFile.cpp @@ -295,6 +295,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ ECase(TABLE); ECase(MEMORY); ECase(GLOBAL); + ECase(EVENT); ECase(EXPORT); ECase(START); ECase(ELEM); Index: llvm/trunk/lib/ObjectYAML/WasmYAML.cpp =================================================================== --- llvm/trunk/lib/ObjectYAML/WasmYAML.cpp +++ llvm/trunk/lib/ObjectYAML/WasmYAML.cpp @@ -100,6 +100,11 @@ 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 @@ 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 @@ ECase(TABLE); ECase(MEMORY); ECase(GLOBAL); + ECase(EVENT); ECase(EXPORT); ECase(START); ECase(ELEM); @@ -307,6 +318,9 @@ } 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 @@ 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, 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 @@ ECase(DATA); ECase(GLOBAL); ECase(SECTION); + ECase(EVENT); #undef ECase } @@ -467,6 +490,7 @@ ECase(TABLE); ECase(MEMORY); ECase(GLOBAL); + ECase(EVENT); #undef ECase } Index: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp +++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp @@ -86,6 +86,7 @@ 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 @@ 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 @@ 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(), Index: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h =================================================================== --- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -77,6 +77,8 @@ OPERAND_SIGNATURE, /// type signature immediate for call_indirect. OPERAND_TYPEINDEX, + /// Event index. + OPERAND_EVENT, }; } // end namespace WebAssembly @@ -97,7 +99,8 @@ // 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 Index: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h =================================================================== --- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h +++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h @@ -45,6 +45,8 @@ 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 @@ 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 @@ 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; }; Index: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -100,12 +100,28 @@ } 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 @@ // Not needed. } +void WebAssemblyTargetWasmStreamer::emitEventType(MCSymbolWasm *Sym) { + // Not needed. +} void WebAssemblyTargetWasmStreamer::emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) { Sym->setModuleName(ModuleName); Index: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp +++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -86,6 +86,11 @@ 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 @@ 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) Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -79,11 +79,12 @@ 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) { Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISD.def =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISD.def +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISD.def @@ -25,5 +25,6 @@ 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... Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h @@ -98,6 +98,7 @@ 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; Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ llvm/trunk/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 @@ // Exception handling intrinsics setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); + setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); setMaxAtomicSizeInBitsSupported(64); } @@ -882,6 +884,8 @@ 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: @@ -1046,6 +1050,44 @@ } 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 { SDLoc DL(Op); Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -146,14 +146,16 @@ // 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>; Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -64,6 +64,7 @@ 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 @@ 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 @@ def P2Align : Operand { let PrintMethod = "printWebAssemblyP2AlignOperand"; } + +let OperandType = "OPERAND_EVENT" in +def event_op : Operand; + } // OperandType = "OPERAND_P2ALIGN" let OperandType = "OPERAND_SIGNATURE" in { Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.h =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.h +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.h @@ -34,7 +34,7 @@ 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) Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -75,10 +75,10 @@ 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 @@ 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 @@ 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 @@ "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 @@ 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; } Index: llvm/trunk/test/CodeGen/WebAssembly/exception.ll =================================================================== --- llvm/trunk/test/CodeGen/WebAssembly/exception.ll +++ llvm/trunk/test/CodeGen/WebAssembly/exception.ll @@ -13,7 +13,7 @@ ; 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 @__clang_call_terminate(i8*) declare void @_ZSt9terminatev() declare %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* returned) + +; CHECK: __cpp_exception: +; CHECK: .eventtype __cpp_exception, void, i32 Index: llvm/trunk/test/MC/WebAssembly/event-section.ll =================================================================== --- llvm/trunk/test/MC/WebAssembly/event-section.ll +++ llvm/trunk/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 Index: llvm/trunk/test/ObjectYAML/wasm/event_section.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/event_section.yaml +++ llvm/trunk/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 Index: llvm/trunk/tools/llvm-readobj/WasmDumper.cpp =================================================================== --- llvm/trunk/tools/llvm-readobj/WasmDumper.cpp +++ llvm/trunk/tools/llvm-readobj/WasmDumper.cpp @@ -25,20 +25,19 @@ 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 }; Index: llvm/trunk/tools/obj2yaml/wasm2yaml.cpp =================================================================== --- llvm/trunk/tools/obj2yaml/wasm2yaml.cpp +++ llvm/trunk/tools/obj2yaml/wasm2yaml.cpp @@ -107,6 +107,7 @@ 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 @@ 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 @@ 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(); Index: llvm/trunk/tools/yaml2obj/yaml2wasm.cpp =================================================================== --- llvm/trunk/tools/yaml2obj/yaml2wasm.cpp +++ llvm/trunk/tools/yaml2obj/yaml2wasm.cpp @@ -37,6 +37,7 @@ 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 @@ 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 @@ 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 @@ 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; @@ -370,6 +378,22 @@ } 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); for (auto &Segment : Section.Segments) { @@ -474,17 +498,7 @@ 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 @@ } 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;