Index: lld/trunk/include/lld/Common/LLVM.h =================================================================== --- lld/trunk/include/lld/Common/LLVM.h +++ lld/trunk/include/lld/Common/LLVM.h @@ -43,6 +43,8 @@ } // namespace object namespace wasm { +struct WasmEvent; +struct WasmEventType; struct WasmFunction; struct WasmGlobal; struct WasmGlobalType; @@ -76,6 +78,8 @@ using llvm::object::WasmSection; using llvm::object::WasmSegment; using llvm::object::WasmSymbol; +using llvm::wasm::WasmEvent; +using llvm::wasm::WasmEventType; using llvm::wasm::WasmFunction; using llvm::wasm::WasmGlobal; using llvm::wasm::WasmGlobalType; Index: lld/trunk/test/wasm/Inputs/event-section1.ll =================================================================== --- lld/trunk/test/wasm/Inputs/event-section1.ll +++ lld/trunk/test/wasm/Inputs/event-section1.ll @@ -0,0 +1,9 @@ +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +declare void @llvm.wasm.throw(i32, i8*) + +define void @foo(i8* %p) { + call void @llvm.wasm.throw(i32 0, i8* %p) + ret void +} Index: lld/trunk/test/wasm/Inputs/event-section2.ll =================================================================== --- lld/trunk/test/wasm/Inputs/event-section2.ll +++ lld/trunk/test/wasm/Inputs/event-section2.ll @@ -0,0 +1,9 @@ +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +declare void @llvm.wasm.throw(i32, i8*) + +define void @bar(i8* %p) { + call void @llvm.wasm.throw(i32 0, i8* %p) + ret void +} Index: lld/trunk/test/wasm/event-section.ll =================================================================== --- lld/trunk/test/wasm/event-section.ll +++ lld/trunk/test/wasm/event-section.ll @@ -0,0 +1,34 @@ +; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling %p/Inputs/event-section1.ll -o %t1.o +; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling %p/Inputs/event-section2.ll -o %t2.o +; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling %s -o %t.o +; RUN: wasm-ld -o %t.wasm %t.o %t1.o %t2.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +declare void @foo(i8*) +declare void @bar(i8*) + +define void @_start() { + call void @foo(i8* null) + call void @bar(i8* null) + ret void +} + +; CHECK: Sections: +; CHECK-NEXT: - Type: TYPE +; CHECK-NEXT: Signatures: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: [] +; 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 Index: lld/trunk/wasm/Driver.cpp =================================================================== --- lld/trunk/wasm/Driver.cpp +++ lld/trunk/wasm/Driver.cpp @@ -306,8 +306,8 @@ // It is possible for undefined functions not to have a signature (eg. if // added via "--undefined"), but weak undefined ones do have a signature. - assert(FuncSym->FunctionType); - const WasmSignature &Sig = *FuncSym->FunctionType; + assert(FuncSym->Signature); + const WasmSignature &Sig = *FuncSym->Signature; // Add a synthetic dummy for weak undefined functions. These dummies will // be GC'd if not used as the target of any "call" instructions. Index: lld/trunk/wasm/InputChunks.cpp =================================================================== --- lld/trunk/wasm/InputChunks.cpp +++ lld/trunk/wasm/InputChunks.cpp @@ -55,6 +55,7 @@ case R_WEBASSEMBLY_TYPE_INDEX_LEB: case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case R_WEBASSEMBLY_EVENT_INDEX_LEB: case R_WEBASSEMBLY_MEMORY_ADDR_LEB: ExistingValue = decodeULEB128(Loc, &BytesRead); break; @@ -111,6 +112,7 @@ case R_WEBASSEMBLY_TYPE_INDEX_LEB: case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case R_WEBASSEMBLY_EVENT_INDEX_LEB: case R_WEBASSEMBLY_MEMORY_ADDR_LEB: encodeULEB128(Value, Loc, 5); break; @@ -180,6 +182,7 @@ case R_WEBASSEMBLY_TYPE_INDEX_LEB: case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case R_WEBASSEMBLY_EVENT_INDEX_LEB: case R_WEBASSEMBLY_MEMORY_ADDR_LEB: return encodeULEB128(Value, Buf); case R_WEBASSEMBLY_TABLE_INDEX_SLEB: @@ -195,6 +198,7 @@ case R_WEBASSEMBLY_TYPE_INDEX_LEB: case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case R_WEBASSEMBLY_EVENT_INDEX_LEB: case R_WEBASSEMBLY_MEMORY_ADDR_LEB: case R_WEBASSEMBLY_TABLE_INDEX_SLEB: case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: Index: lld/trunk/wasm/InputEvent.h =================================================================== --- lld/trunk/wasm/InputEvent.h +++ lld/trunk/wasm/InputEvent.h @@ -0,0 +1,63 @@ +//===- InputEvent.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Wasm events are features that suspend the current execution and transfer the +// control flow to a corresponding handler. Currently the only supported event +// kind is exceptions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_WASM_INPUT_EVENT_H +#define LLD_WASM_INPUT_EVENT_H + +#include "Config.h" +#include "InputFiles.h" +#include "WriterUtils.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/Object/Wasm.h" + +namespace lld { +namespace wasm { + +// Represents a single Wasm Event within an input file. These are combined to +// form the final EVENTS section. +class InputEvent { +public: + InputEvent(const WasmSignature &S, const WasmEvent &E, ObjFile *F) + : File(F), Event(E), Signature(S), Live(!Config->GcSections) {} + + StringRef getName() const { return Event.SymbolName; } + const WasmEventType &getType() const { return Event.Type; } + + uint32_t getEventIndex() const { return EventIndex.getValue(); } + bool hasEventIndex() const { return EventIndex.hasValue(); } + void setEventIndex(uint32_t Index) { + assert(!hasEventIndex()); + EventIndex = Index; + } + + ObjFile *File; + WasmEvent Event; + const WasmSignature &Signature; + + bool Live = false; + +protected: + llvm::Optional EventIndex; +}; + +} // namespace wasm + +inline std::string toString(const wasm::InputEvent *E) { + return (toString(E->File) + ":(" + E->getName() + ")").str(); +} + +} // namespace lld + +#endif // LLD_WASM_INPUT_EVENT_H Index: lld/trunk/wasm/InputFiles.h =================================================================== --- lld/trunk/wasm/InputFiles.h +++ lld/trunk/wasm/InputFiles.h @@ -27,6 +27,7 @@ class InputFunction; class InputSegment; class InputGlobal; +class InputEvent; class InputSection; class InputFile { @@ -108,6 +109,7 @@ std::vector Segments; std::vector Functions; std::vector Globals; + std::vector Events; std::vector CustomSections; llvm::DenseMap CustomSectionsByIndex; @@ -116,6 +118,7 @@ DataSymbol *getDataSymbol(uint32_t Index) const; GlobalSymbol *getGlobalSymbol(uint32_t Index) const; SectionSymbol *getSectionSymbol(uint32_t Index) const; + EventSymbol *getEventSymbol(uint32_t Index) const; private: Symbol *createDefined(const WasmSymbol &Sym); Index: lld/trunk/wasm/InputFiles.cpp =================================================================== --- lld/trunk/wasm/InputFiles.cpp +++ lld/trunk/wasm/InputFiles.cpp @@ -10,6 +10,7 @@ #include "InputFiles.h" #include "Config.h" #include "InputChunks.h" +#include "InputEvent.h" #include "InputGlobal.h" #include "SymbolTable.h" #include "lld/Common/ErrorHandler.h" @@ -57,7 +58,8 @@ log("info for: " + getName() + "\n Symbols : " + Twine(Symbols.size()) + "\n Function Imports : " + Twine(WasmObj->getNumImportedFunctions()) + - "\n Global Imports : " + Twine(WasmObj->getNumImportedGlobals())); + "\n Global Imports : " + Twine(WasmObj->getNumImportedGlobals()) + + "\n Event Imports : " + Twine(WasmObj->getNumImportedEvents())); } // Relocations contain either symbol or type indices. This function takes a @@ -119,7 +121,8 @@ case R_WEBASSEMBLY_TYPE_INDEX_LEB: return Reloc.Index; case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: - case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: { + case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case R_WEBASSEMBLY_EVENT_INDEX_LEB: { const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index]; return Sym.Info.ElementIndex; } @@ -147,6 +150,8 @@ return getFunctionSymbol(Reloc.Index)->getFunctionIndex(); case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: return getGlobalSymbol(Reloc.Index)->getGlobalIndex(); + case R_WEBASSEMBLY_EVENT_INDEX_LEB: + return getEventSymbol(Reloc.Index)->getEventIndex(); case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: if (auto *Sym = dyn_cast(getFunctionSymbol(Reloc.Index))) { if (Sym->isLive()) @@ -267,6 +272,10 @@ for (const WasmGlobal &G : WasmObj->globals()) Globals.emplace_back(make(G, this)); + // Populate `Events`. + for (const WasmEvent &E : WasmObj->events()) + Events.emplace_back(make(Types[E.Type.SigIndex], E, this)); + // Populate `Symbols` based on the WasmSymbols in the object. Symbols.reserve(WasmObj->getNumberOfSymbols()); for (const SymbolRef &Sym : WasmObj->symbols()) { @@ -293,6 +302,10 @@ return cast(Symbols[Index]); } +EventSymbol *ObjFile::getEventSymbol(uint32_t Index) const { + return cast(Symbols[Index]); +} + SectionSymbol *ObjFile::getSectionSymbol(uint32_t Index) const { return cast(Symbols[Index]); } @@ -347,6 +360,13 @@ assert(Sym.isBindingLocal()); return make(Name, Flags, Section, this); } + case WASM_SYMBOL_TYPE_EVENT: { + InputEvent *Event = + Events[Sym.Info.ElementIndex - WasmObj->getNumImportedEvents()]; + if (Sym.isBindingLocal()) + return make(Name, Flags, this, Event); + return Symtab->addDefinedEvent(Name, Flags, this, Event); + } } llvm_unreachable("unknown symbol kind"); } @@ -357,7 +377,7 @@ switch (Sym.Info.Kind) { case WASM_SYMBOL_TYPE_FUNCTION: - return Symtab->addUndefinedFunction(Name, Flags, this, Sym.FunctionType); + return Symtab->addUndefinedFunction(Name, Flags, this, Sym.Signature); case WASM_SYMBOL_TYPE_DATA: return Symtab->addUndefinedData(Name, Flags, this); case WASM_SYMBOL_TYPE_GLOBAL: Index: lld/trunk/wasm/LTO.cpp =================================================================== --- lld/trunk/wasm/LTO.cpp +++ lld/trunk/wasm/LTO.cpp @@ -80,7 +80,7 @@ static void undefine(Symbol *S) { if (auto F = dyn_cast(S)) replaceSymbol(F, F->getName(), 0, F->getFile(), - F->FunctionType); + F->Signature); else if (isa(S)) replaceSymbol(S, S->getName(), 0, S->getFile()); else Index: lld/trunk/wasm/MarkLive.cpp =================================================================== --- lld/trunk/wasm/MarkLive.cpp +++ lld/trunk/wasm/MarkLive.cpp @@ -22,6 +22,7 @@ #include "MarkLive.h" #include "Config.h" #include "InputChunks.h" +#include "InputEvent.h" #include "InputGlobal.h" #include "SymbolTable.h" #include "Symbols.h" @@ -105,6 +106,9 @@ for (InputGlobal *G : Obj->Globals) if (!G->Live) message("removing unused section " + toString(G)); + for (InputEvent *E : Obj->Events) + if (!E->Live) + message("removing unused section " + toString(E)); } for (InputChunk *C : Symtab->SyntheticFunctions) if (!C->Live) Index: lld/trunk/wasm/OutputSections.cpp =================================================================== --- lld/trunk/wasm/OutputSections.cpp +++ lld/trunk/wasm/OutputSections.cpp @@ -40,6 +40,8 @@ return "MEMORY"; case WASM_SEC_GLOBAL: return "GLOBAL"; + case WASM_SEC_EVENT: + return "EVENT"; case WASM_SEC_EXPORT: return "EXPORT"; case WASM_SEC_START: Index: lld/trunk/wasm/SymbolTable.h =================================================================== --- lld/trunk/wasm/SymbolTable.h +++ lld/trunk/wasm/SymbolTable.h @@ -56,6 +56,8 @@ uint32_t Size); Symbol *addDefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, InputGlobal *G); + Symbol *addDefinedEvent(StringRef Name, uint32_t Flags, InputFile *File, + InputEvent *E); Symbol *addUndefinedFunction(StringRef Name, uint32_t Flags, InputFile *File, const WasmSignature *Signature); Index: lld/trunk/wasm/SymbolTable.cpp =================================================================== --- lld/trunk/wasm/SymbolTable.cpp +++ lld/trunk/wasm/SymbolTable.cpp @@ -10,6 +10,7 @@ #include "SymbolTable.h" #include "Config.h" #include "InputChunks.h" +#include "InputEvent.h" #include "InputGlobal.h" #include "WriterUtils.h" #include "lld/Common/ErrorHandler.h" @@ -111,9 +112,9 @@ if (!NewSig) return; - const WasmSignature *OldSig = ExistingFunction->FunctionType; + const WasmSignature *OldSig = ExistingFunction->Signature; if (!OldSig) { - ExistingFunction->FunctionType = NewSig; + ExistingFunction->Signature = NewSig; return; } @@ -139,6 +140,28 @@ } } +static void checkEventType(const Symbol *Existing, const InputFile *File, + const WasmEventType *NewType, + const WasmSignature *NewSig) { + auto ExistingEvent = dyn_cast(Existing); + if (!isa(Existing)) { + reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT); + return; + } + + const WasmEventType *OldType = cast(Existing)->getEventType(); + const WasmSignature *OldSig = ExistingEvent->Signature; + if (NewType->Attribute != OldType->Attribute) + error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " + + toString(*OldType) + " in " + toString(Existing->getFile()) + + "\n>>> defined as " + toString(*NewType) + " in " + toString(File)); + if (*NewSig != *OldSig) + warn("Event signature mismatch: " + Existing->getName() + + "\n>>> defined as " + toString(*OldSig) + " in " + + toString(Existing->getFile()) + "\n>>> defined as " + + toString(*NewSig) + " in " + toString(File)); +} + static void checkDataType(const Symbol *Existing, const InputFile *File) { if (!isa(Existing)) reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA); @@ -222,10 +245,10 @@ // functions) but the old symbols does then preserve the old signature const WasmSignature *OldSig = nullptr; if (auto* F = dyn_cast(S)) - OldSig = F->FunctionType; + OldSig = F->Signature; auto NewSym = replaceSymbol(S, Name, Flags, File, Function); - if (!NewSym->FunctionType) - NewSym->FunctionType = OldSig; + if (!NewSym->Signature) + NewSym->Signature = OldSig; } return S; } @@ -271,6 +294,26 @@ return S; } +Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags, + InputFile *File, InputEvent *Event) { + LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n"); + + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name, File); + + if (WasInserted || S->isLazy()) { + replaceSymbol(S, Name, Flags, File, Event); + return S; + } + + checkEventType(S, File, &Event->getType(), &Event->Signature); + + if (shouldReplace(S, File, Flags)) + replaceSymbol(S, Name, Flags, File, Event); + return S; +} + Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags, InputFile *File, const WasmSignature *Sig) { Index: lld/trunk/wasm/Symbols.h =================================================================== --- lld/trunk/wasm/Symbols.h +++ lld/trunk/wasm/Symbols.h @@ -25,6 +25,7 @@ class InputSegment; class InputFunction; class InputGlobal; +class InputEvent; class InputSection; #define INVALID_INDEX UINT32_MAX @@ -36,6 +37,7 @@ DefinedFunctionKind, DefinedDataKind, DefinedGlobalKind, + DefinedEventKind, SectionKind, UndefinedFunctionKind, UndefinedDataKind, @@ -47,7 +49,8 @@ bool isDefined() const { return SymbolKind == DefinedFunctionKind || SymbolKind == DefinedDataKind || - SymbolKind == DefinedGlobalKind || SymbolKind == SectionKind; + SymbolKind == DefinedGlobalKind || SymbolKind == DefinedEventKind || + SymbolKind == SectionKind; } bool isUndefined() const { @@ -121,12 +124,12 @@ void setFunctionIndex(uint32_t Index); bool hasFunctionIndex() const; - const WasmSignature *FunctionType; + const WasmSignature *Signature; protected: FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, - const WasmSignature *Type) - : Symbol(Name, K, Flags, F), FunctionType(Type) {} + const WasmSignature *Sig) + : Symbol(Name, K, Flags, F), Signature(Sig) {} uint32_t TableIndex = INVALID_INDEX; uint32_t FunctionIndex = INVALID_INDEX; @@ -267,6 +270,50 @@ } }; +// Wasm events are features that suspend the current execution and transfer the +// control flow to a corresponding handler. Currently the only supported event +// kind is exceptions. +// +// Event tags are values to distinguish different events. For exceptions, they +// can be used to distinguish different language's exceptions, i.e., all C++ +// exceptions have the same tag. Wasm can generate code capable of doing +// different handling actions based on the tag of caught exceptions. +// +// A single EventSymbol object represents a single tag. C++ exception event +// symbol is a weak symbol generated in every object file in which exceptions +// are used, and has name '__cpp_exception' for linking. +class EventSymbol : public Symbol { +public: + static bool classof(const Symbol *S) { return S->kind() == DefinedEventKind; } + + const WasmEventType *getEventType() const { return EventType; } + + // Get/set the event index + uint32_t getEventIndex() const; + void setEventIndex(uint32_t Index); + bool hasEventIndex() const; + + const WasmSignature *Signature; + +protected: + EventSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, + const WasmEventType *EventType, const WasmSignature *Sig) + : Symbol(Name, K, Flags, F), Signature(Sig), EventType(EventType) {} + + const WasmEventType *EventType; + uint32_t EventIndex = INVALID_INDEX; +}; + +class DefinedEvent : public EventSymbol { +public: + DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File, + InputEvent *Event); + + static bool classof(const Symbol *S) { return S->kind() == DefinedEventKind; } + + InputEvent *Event; +}; + class LazySymbol : public Symbol { public: LazySymbol(StringRef Name, InputFile *File, @@ -321,10 +368,11 @@ alignas(DefinedFunction) char A[sizeof(DefinedFunction)]; alignas(DefinedData) char B[sizeof(DefinedData)]; alignas(DefinedGlobal) char C[sizeof(DefinedGlobal)]; - alignas(LazySymbol) char D[sizeof(LazySymbol)]; - alignas(UndefinedFunction) char E[sizeof(UndefinedFunction)]; - alignas(UndefinedData) char F[sizeof(UndefinedData)]; - alignas(UndefinedGlobal) char G[sizeof(UndefinedGlobal)]; + alignas(DefinedEvent) char D[sizeof(DefinedEvent)]; + alignas(LazySymbol) char E[sizeof(LazySymbol)]; + alignas(UndefinedFunction) char F[sizeof(UndefinedFunction)]; + alignas(UndefinedData) char G[sizeof(UndefinedData)]; + alignas(UndefinedGlobal) char H[sizeof(UndefinedGlobal)]; alignas(SectionSymbol) char I[sizeof(SectionSymbol)]; }; Index: lld/trunk/wasm/Symbols.cpp =================================================================== --- lld/trunk/wasm/Symbols.cpp +++ lld/trunk/wasm/Symbols.cpp @@ -10,6 +10,7 @@ #include "Symbols.h" #include "Config.h" #include "InputChunks.h" +#include "InputEvent.h" #include "InputFiles.h" #include "InputGlobal.h" #include "OutputSegment.h" @@ -38,6 +39,8 @@ return WASM_SYMBOL_TYPE_DATA; if (isa(this)) return WASM_SYMBOL_TYPE_GLOBAL; + if (isa(this)) + return WASM_SYMBOL_TYPE_EVENT; if (isa(this)) return WASM_SYMBOL_TYPE_SECTION; llvm_unreachable("invalid symbol kind"); @@ -54,6 +57,8 @@ bool Symbol::isLive() const { if (auto *G = dyn_cast(this)) return G->Global->Live; + if (auto *E = dyn_cast(this)) + return E->Event->Live; if (InputChunk *C = getChunk()) return C->Live; return Referenced; @@ -62,6 +67,8 @@ void Symbol::markLive() { if (auto *G = dyn_cast(this)) G->Global->Live = true; + if (auto *E = dyn_cast(this)) + E->Event->Live = true; if (InputChunk *C = getChunk()) C->Live = true; Referenced = true; @@ -212,6 +219,32 @@ Global ? &Global->getType() : nullptr), Global(Global) {} +uint32_t EventSymbol::getEventIndex() const { + if (auto *F = dyn_cast(this)) + return F->Event->getEventIndex(); + assert(EventIndex != INVALID_INDEX); + return EventIndex; +} + +void EventSymbol::setEventIndex(uint32_t Index) { + LLVM_DEBUG(dbgs() << "setEventIndex " << Name << " -> " << Index << "\n"); + assert(EventIndex == INVALID_INDEX); + EventIndex = Index; +} + +bool EventSymbol::hasEventIndex() const { + if (auto *F = dyn_cast(this)) + return F->Event->hasEventIndex(); + return EventIndex != INVALID_INDEX; +} + +DefinedEvent::DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File, + InputEvent *Event) + : EventSymbol(Name, DefinedEventKind, Flags, File, + Event ? &Event->getType() : nullptr, + Event ? &Event->Signature : nullptr), + Event(Event) {} + uint32_t SectionSymbol::getOutputSectionIndex() const { LLVM_DEBUG(dbgs() << "getOutputSectionIndex: " << getName() << "\n"); assert(OutputSectionIndex != INVALID_INDEX); @@ -246,6 +279,8 @@ return "DefinedData"; case wasm::Symbol::DefinedGlobalKind: return "DefinedGlobal"; + case wasm::Symbol::DefinedEventKind: + return "DefinedEvent"; case wasm::Symbol::UndefinedFunctionKind: return "UndefinedFunction"; case wasm::Symbol::UndefinedDataKind: Index: lld/trunk/wasm/Writer.cpp =================================================================== --- lld/trunk/wasm/Writer.cpp +++ lld/trunk/wasm/Writer.cpp @@ -10,6 +10,7 @@ #include "Writer.h" #include "Config.h" #include "InputChunks.h" +#include "InputEvent.h" #include "InputGlobal.h" #include "OutputSections.h" #include "OutputSegment.h" @@ -80,6 +81,7 @@ void createFunctionSection(); void createTableSection(); void createGlobalSection(); + void createEventSection(); void createExportSection(); void createImportSection(); void createMemorySection(); @@ -111,10 +113,12 @@ std::vector ImportedSymbols; unsigned NumImportedFunctions = 0; unsigned NumImportedGlobals = 0; + unsigned NumImportedEvents = 0; std::vector Exports; std::vector DefinedFakeGlobals; std::vector InputGlobals; std::vector InputFunctions; + std::vector InputEvents; std::vector IndirectFunctions; std::vector SymtabEntries; std::vector InitFunctions; @@ -182,11 +186,15 @@ Import.Field = Sym->getName(); if (auto *FunctionSym = dyn_cast(Sym)) { Import.Kind = WASM_EXTERNAL_FUNCTION; - Import.SigIndex = lookupType(*FunctionSym->FunctionType); - } else { - auto *GlobalSym = cast(Sym); + Import.SigIndex = lookupType(*FunctionSym->Signature); + } else if (auto *GlobalSym = dyn_cast(Sym)) { Import.Kind = WASM_EXTERNAL_GLOBAL; Import.Global = *GlobalSym->getGlobalType(); + } else { + auto *EventSym = cast(Sym); + Import.Kind = WASM_EXTERNAL_EVENT; + Import.Event.Attribute = EventSym->getEventType()->Attribute; + Import.Event.SigIndex = lookupType(*EventSym->Signature); } writeImport(OS, Import); } @@ -252,6 +260,31 @@ } } +// The event section contains a list of declared wasm events associated with the +// module. Currently the only supported event kind is exceptions. A single event +// entry represents a single event with an event tag. All C++ exceptions are +// represented by a single event. An event entry in this section contains +// information on what kind of event it is (e.g. exception) and the type of +// values contained in a single event object. (In wasm, an event can contain +// multiple values of primitive types. But for C++ exceptions, we just throw a +// pointer which is an i32 value (for wasm32 architecture), so the signature of +// C++ exception is (i32)->(void), because all event types are assumed to have +// void return type to share WasmSignature with functions.) +void Writer::createEventSection() { + unsigned NumEvents = InputEvents.size(); + if (NumEvents == 0) + return; + + SyntheticSection *Section = createSyntheticSection(WASM_SEC_EVENT); + raw_ostream &OS = Section->getStream(); + + writeUleb128(OS, NumEvents, "event count"); + for (InputEvent *E : InputEvents) { + E->Event.Type.SigIndex = lookupType(E->Signature); + writeEvent(OS, E->Event); + } +} + void Writer::createTableSection() { if (Config->ImportTable) return; @@ -478,6 +511,10 @@ writeUleb128(Sub.OS, G->getGlobalIndex(), "index"); if (Sym->isDefined()) writeStr(Sub.OS, Sym->getName(), "sym name"); + } else if (auto *E = dyn_cast(Sym)) { + writeUleb128(Sub.OS, E->getEventIndex(), "index"); + if (Sym->isDefined()) + writeStr(Sub.OS, Sym->getName(), "sym name"); } else if (isa(Sym)) { writeStr(Sub.OS, Sym->getName(), "sym name"); if (auto *DataSym = dyn_cast(Sym)) { @@ -722,6 +759,7 @@ createTableSection(); createMemorySection(); createGlobalSection(); + createEventSection(); createExportSection(); createElemSection(); createCodeSection(); @@ -760,8 +798,10 @@ ImportedSymbols.emplace_back(Sym); if (auto *F = dyn_cast(Sym)) F->setFunctionIndex(NumImportedFunctions++); + else if (auto *G = dyn_cast(Sym)) + G->setGlobalIndex(NumImportedGlobals++); else - cast(Sym)->setGlobalIndex(NumImportedGlobals++); + cast(Sym)->setEventIndex(NumImportedEvents++); } } @@ -797,6 +837,8 @@ continue; } Export = {Name, WASM_EXTERNAL_GLOBAL, G->getGlobalIndex()}; + } else if (auto *E = dyn_cast(Sym)) { + Export = {Name, WASM_EXTERNAL_EVENT, E->getEventIndex()}; } else { auto *D = cast(Sym); DefinedFakeGlobals.emplace_back(D); @@ -874,6 +916,8 @@ // 1. Any signature used in the TYPE relocation // 2. The signatures of all imported functions // 3. The signatures of all defined functions + // 4. The signatures of all imported events + // 5. The signatures of all defined events for (ObjFile *File : Symtab->ObjectFiles) { ArrayRef Types = File->getWasmObj()->types(); @@ -882,12 +926,18 @@ File->TypeMap[I] = registerType(Types[I]); } - for (const Symbol *Sym : ImportedSymbols) + for (const Symbol *Sym : ImportedSymbols) { if (auto *F = dyn_cast(Sym)) - registerType(*F->FunctionType); + registerType(*F->Signature); + else if (auto *E = dyn_cast(Sym)) + registerType(*E->Signature); + } for (const InputFunction *F : InputFunctions) registerType(F->Signature); + + for (const InputEvent *E : InputEvents) + registerType(E->Signature); } void Writer::assignIndexes() { @@ -959,6 +1009,22 @@ for (InputGlobal *Global : File->Globals) AddDefinedGlobal(Global); } + + assert(InputEvents.empty()); + uint32_t EventIndex = NumImportedEvents; + auto AddDefinedEvent = [&](InputEvent *Event) { + if (Event->Live) { + LLVM_DEBUG(dbgs() << "AddDefinedEvent: " << EventIndex << "\n"); + Event->setEventIndex(EventIndex++); + InputEvents.push_back(Event); + } + }; + + for (ObjFile *File : Symtab->ObjectFiles) { + LLVM_DEBUG(dbgs() << "Events: " << File->getName() << "\n"); + for (InputEvent *Event : File->Events) + AddDefinedEvent(Event); + } } static StringRef getOutputDataSegmentName(StringRef Name) { @@ -1035,7 +1101,7 @@ const WasmLinkingData &L = File->getWasmObj()->linkingData(); for (const WasmInitFunc &F : L.InitFunctions) { FunctionSymbol *Sym = File->getFunctionSymbol(F.Symbol); - if (*Sym->FunctionType != WasmSignature{{}, {}}) + if (*Sym->Signature != WasmSignature{{}, {}}) error("invalid signature for init func: " + toString(*Sym)); InitFunctions.emplace_back(WasmInitEntry{Sym, F.Priority}); } @@ -1080,8 +1146,10 @@ if (errorHandler().Verbose) { log("Defined Functions: " + Twine(InputFunctions.size())); log("Defined Globals : " + Twine(InputGlobals.size())); + log("Defined Events : " + Twine(InputEvents.size())); log("Function Imports : " + Twine(NumImportedFunctions)); log("Global Imports : " + Twine(NumImportedGlobals)); + log("Event Imports : " + Twine(NumImportedEvents)); for (ObjFile *File : Symtab->ObjectFiles) File->dumpInfo(); } Index: lld/trunk/wasm/WriterUtils.h =================================================================== --- lld/trunk/wasm/WriterUtils.h +++ lld/trunk/wasm/WriterUtils.h @@ -45,6 +45,10 @@ void writeGlobal(raw_ostream &OS, const llvm::wasm::WasmGlobal &Global); +void writeEventType(raw_ostream &OS, const llvm::wasm::WasmEventType &Type); + +void writeEvent(raw_ostream &OS, const llvm::wasm::WasmEvent &Event); + void writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type); void writeImport(raw_ostream &OS, const llvm::wasm::WasmImport &Import); @@ -55,7 +59,8 @@ std::string toString(llvm::wasm::ValType Type); std::string toString(const llvm::wasm::WasmSignature &Sig); -std::string toString(const llvm::wasm::WasmGlobalType &Sig); +std::string toString(const llvm::wasm::WasmGlobalType &Type); +std::string toString(const llvm::wasm::WasmEventType &Type); } // namespace lld Index: lld/trunk/wasm/WriterUtils.cpp =================================================================== --- lld/trunk/wasm/WriterUtils.cpp +++ lld/trunk/wasm/WriterUtils.cpp @@ -110,6 +110,15 @@ writeInitExpr(OS, Global.InitExpr); } +void wasm::writeEventType(raw_ostream &OS, const WasmEventType &Type) { + writeUleb128(OS, Type.Attribute, "event attribute"); + writeUleb128(OS, Type.SigIndex, "sig index"); +} + +void wasm::writeEvent(raw_ostream &OS, const WasmEvent &Event) { + writeEventType(OS, Event.Type); +} + void wasm::writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type) { writeU8(OS, WASM_TYPE_ANYFUNC, "table type"); writeLimits(OS, Type.Limits); @@ -126,6 +135,9 @@ case WASM_EXTERNAL_GLOBAL: writeGlobalType(OS, Import.Global); break; + case WASM_EXTERNAL_EVENT: + writeEventType(OS, Import.Event); + break; case WASM_EXTERNAL_MEMORY: writeLimits(OS, Import.Memory); break; @@ -192,7 +204,13 @@ return S.str(); } -std::string lld::toString(const WasmGlobalType &Sig) { - return (Sig.Mutable ? "var " : "const ") + - toString(static_cast(Sig.Type)); +std::string lld::toString(const WasmGlobalType &Type) { + return (Type.Mutable ? "var " : "const ") + + toString(static_cast(Type.Type)); +} + +std::string lld::toString(const WasmEventType &Type) { + if (Type.Attribute == WASM_EVENT_ATTRIBUTE_EXCEPTION) + return "exception"; + return "unknown"; }