Index: test/wasm/Inputs/event-section1.ll =================================================================== --- /dev/null +++ test/wasm/Inputs/event-section1.ll @@ -0,0 +1,10 @@ +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: test/wasm/Inputs/event-section2.ll =================================================================== --- /dev/null +++ test/wasm/Inputs/event-section2.ll @@ -0,0 +1,10 @@ +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: test/wasm/event-section.ll =================================================================== --- /dev/null +++ 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: EventTypes: [ 1 ] +; CHECK-NEXT: Events: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Attribute: 0 Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -10,7 +10,7 @@ #include "lld/Common/Driver.h" #include "Config.h" #include "InputChunks.h" -#include "InputGlobal.h" +#include "InputEntity.h" #include "MarkLive.h" #include "SymbolTable.h" #include "Writer.h" Index: wasm/InputChunks.cpp =================================================================== --- wasm/InputChunks.cpp +++ 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: wasm/InputEntity.h =================================================================== --- /dev/null +++ wasm/InputEntity.h @@ -0,0 +1,95 @@ +//===- InputEntity.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Unlike InputChunk, which is a contiguous sequence of input bytes that are +// copied into the output, InputEntity represents an entity for which we create +// output sections from scratch. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_WASM_INPUT_ENTITY_H +#define LLD_WASM_INPUT_ENTITY_H + +#include "Config.h" +#include "InputFiles.h" +#include "WriterUtils.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/Object/Wasm.h" + +using llvm::wasm::WasmEvent; +using llvm::wasm::WasmGlobal; + +namespace lld { +namespace wasm { + +class InputEntity { +public: + InputEntity(ObjFile *F) : File(F), Live(!Config->GcSections) {} + virtual ~InputEntity() {} + virtual StringRef getName() const = 0; + + ObjFile *File; + bool Live = false; +}; + +// Represents a single Wasm Global Variable within an input file. These are +// combined to form the final GLOBALS section. +class InputGlobal : public InputEntity { +public: + InputGlobal(const WasmGlobal &G, ObjFile *F) : InputEntity(F), Global(G) {} + + StringRef getName() const override { return Global.SymbolName; } + const WasmGlobalType &getType() const { return Global.Type; } + + uint32_t getGlobalIndex() const { return GlobalIndex.getValue(); } + bool hasGlobalIndex() const { return GlobalIndex.hasValue(); } + void setGlobalIndex(uint32_t Index) { + assert(!hasGlobalIndex()); + GlobalIndex = Index; + } + + WasmGlobal Global; + +protected: + llvm::Optional GlobalIndex; +}; + +// Represents a single Wasm Event within an input file. These are combined to +// form the final EVENTS section. +class InputEvent : public InputEntity { +public: + InputEvent(const WasmSignature &S, const WasmEvent &E, ObjFile *F) + : InputEntity(F), Signature(S), Event(E) {} + + StringRef getName() const override { 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; + } + + const WasmSignature &Signature; + WasmEvent Event; + +protected: + llvm::Optional EventIndex; +}; + +} // namespace wasm + +inline std::string toString(const wasm::InputEntity *E) { + return (toString(E->File) + ":(" + E->getName() + ")").str(); +} + +} // namespace lld + +#endif // LLD_WASM_INPUT_ENTITY_H Index: wasm/InputFiles.h =================================================================== --- wasm/InputFiles.h +++ wasm/InputFiles.h @@ -39,6 +39,7 @@ class InputFunction; class InputSegment; class InputGlobal; +class InputEvent; class InputSection; class InputFile { @@ -120,6 +121,7 @@ std::vector Segments; std::vector Functions; std::vector Globals; + std::vector Events; std::vector CustomSections; llvm::DenseMap CustomSectionsByIndex; @@ -128,6 +130,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: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -10,7 +10,7 @@ #include "InputFiles.h" #include "Config.h" #include "InputChunks.h" -#include "InputGlobal.h" +#include "InputEntity.h" #include "SymbolTable.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" @@ -57,7 +57,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 +120,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 +149,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 +271,15 @@ for (const WasmGlobal &G : WasmObj->globals()) Globals.emplace_back(make(G, this)); + // Populate `Events`. + ArrayRef EventTypes = WasmObj->eventTypes(); + assert(EventTypes.size() == WasmObj->events().size() && + "EventType size and Event size differ"); + for (unsigned I = 0; I < WasmObj->events().size(); ++I) { + const WasmEvent &E = WasmObj->events()[I]; + Events.emplace_back(make(Types[EventTypes[I]], E, this)); + } + // Populate `Symbols` based on the WasmSymbols in the object. Symbols.reserve(WasmObj->getNumberOfSymbols()); for (const SymbolRef &Sym : WasmObj->symbols()) { @@ -293,6 +306,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 +364,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"); } @@ -362,6 +386,9 @@ return Symtab->addUndefinedData(Name, Flags, this); case WASM_SYMBOL_TYPE_GLOBAL: return Symtab->addUndefinedGlobal(Name, Flags, this, Sym.GlobalType); + case WASM_SYMBOL_TYPE_EVENT: + return Symtab->addUndefinedEvent(Name, Flags, this, Sym.EventType, + Sym.Signature); case WASM_SYMBOL_TYPE_SECTION: llvm_unreachable("section symbols cannot be undefined"); } Index: wasm/InputGlobal.h =================================================================== --- wasm/InputGlobal.h +++ /dev/null @@ -1,58 +0,0 @@ -//===- InputGlobal.h --------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_WASM_INPUT_GLOBAL_H -#define LLD_WASM_INPUT_GLOBAL_H - -#include "Config.h" -#include "InputFiles.h" -#include "WriterUtils.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Object/Wasm.h" - -using llvm::wasm::WasmGlobal; - -namespace lld { -namespace wasm { - -// Represents a single Wasm Global Variable within an input file. These are -// combined to form the final GLOBALS section. -class InputGlobal { -public: - InputGlobal(const WasmGlobal &G, ObjFile *F) - : File(F), Global(G), Live(!Config->GcSections) {} - - StringRef getName() const { return Global.SymbolName; } - const WasmGlobalType &getType() const { return Global.Type; } - - uint32_t getGlobalIndex() const { return GlobalIndex.getValue(); } - bool hasGlobalIndex() const { return GlobalIndex.hasValue(); } - void setGlobalIndex(uint32_t Index) { - assert(!hasGlobalIndex()); - GlobalIndex = Index; - } - - ObjFile *File; - WasmGlobal Global; - - bool Live = false; - -protected: - llvm::Optional GlobalIndex; -}; - -} // namespace wasm - -inline std::string toString(const wasm::InputGlobal *G) { - return (toString(G->File) + ":(" + G->getName() + ")").str(); -} - -} // namespace lld - -#endif // LLD_WASM_INPUT_GLOBAL_H Index: wasm/MarkLive.cpp =================================================================== --- wasm/MarkLive.cpp +++ wasm/MarkLive.cpp @@ -22,7 +22,7 @@ #include "MarkLive.h" #include "Config.h" #include "InputChunks.h" -#include "InputGlobal.h" +#include "InputEntity.h" #include "SymbolTable.h" #include "Symbols.h" @@ -102,15 +102,21 @@ for (InputChunk *C : Obj->Segments) if (!C->Live) message("removing unused section " + toString(C)); - for (InputGlobal *G : Obj->Globals) - if (!G->Live) - message("removing unused section " + toString(G)); + for (InputEntity *E : Obj->Globals) + if (!E->Live) + message("removing unused section " + toString(E)); + for (InputEntity *E : Obj->Events) + if (!E->Live) + message("removing unused section " + toString(E)); } for (InputChunk *C : Symtab->SyntheticFunctions) if (!C->Live) message("removing unused section " + toString(C)); - for (InputGlobal *G : Symtab->SyntheticGlobals) - if (!G->Live) - message("removing unused section " + toString(G)); + for (InputEntity *E : Symtab->SyntheticGlobals) + if (!E->Live) + message("removing unused section " + toString(E)); + for (InputEntity *E : Symtab->SyntheticEvents) + if (!E->Live) + message("removing unused section " + toString(E)); } } Index: wasm/OutputSections.cpp =================================================================== --- wasm/OutputSections.cpp +++ 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: wasm/SymbolTable.h =================================================================== --- wasm/SymbolTable.h +++ wasm/SymbolTable.h @@ -18,6 +18,7 @@ #include "llvm/Support/raw_ostream.h" using llvm::wasm::WasmGlobalType; +using llvm::wasm::WasmEventType; using llvm::wasm::WasmSignature; namespace lld { @@ -46,6 +47,7 @@ std::vector BitcodeFiles; std::vector SyntheticFunctions; std::vector SyntheticGlobals; + std::vector SyntheticEvents; void reportRemainingUndefines(); @@ -59,12 +61,17 @@ 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); Symbol *addUndefinedData(StringRef Name, uint32_t Flags, InputFile *File); Symbol *addUndefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, const WasmGlobalType *Type); + Symbol *addUndefinedEvent(StringRef Name, uint32_t Flags, InputFile *File, + const WasmEventType *Type, + const WasmSignature *Signature); void addLazy(ArchiveFile *F, const Archive::Symbol *Sym); @@ -75,6 +82,8 @@ InputGlobal *Global); DefinedFunction *addSyntheticFunction(StringRef Name, uint32_t Flags, InputFunction *Function); + DefinedEvent *addSyntheticEvent(StringRef Name, uint32_t Flags, + InputEvent *Event); private: std::pair insert(StringRef Name, InputFile *File); Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -10,7 +10,7 @@ #include "SymbolTable.h" #include "Config.h" #include "InputChunks.h" -#include "InputGlobal.h" +#include "InputEntity.h" #include "WriterUtils.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" @@ -138,6 +138,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_GLOBAL); + 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); @@ -170,6 +192,16 @@ nullptr, Global); } +DefinedEvent *SymbolTable::addSyntheticEvent(StringRef Name, uint32_t Flags, + InputEvent *Event) { + LLVM_DEBUG(dbgs() << "addSyntheticEvent: " << Name << " -> " << Event + << "\n"); + assert(!find(Name)); + SyntheticEvents.emplace_back(Event); + return replaceSymbol(insert(Name, nullptr).first, Name, Flags, + nullptr, Event); +} + static bool shouldReplace(const Symbol *Existing, InputFile *NewFile, uint32_t NewFlags) { // If existing symbol is undefined, replace it. @@ -270,6 +302,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) { @@ -325,6 +377,25 @@ return S; } +Symbol *SymbolTable::addUndefinedEvent(StringRef Name, uint32_t Flags, + InputFile *File, + const WasmEventType *Type, + const WasmSignature *Sig) { + LLVM_DEBUG(dbgs() << "addUndefinedEvent: " << Name << "\n"); + + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name, File); + + if (WasInserted) + replaceSymbol(S, Name, Flags, File, Type, Sig); + else if (auto *Lazy = dyn_cast(S)) + Lazy->fetch(); + else if (S->isDefined()) + checkEventType(S, File, Type, Sig); + return S; +} + void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) { LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n"); StringRef Name = Sym->getName(); Index: wasm/Symbols.h =================================================================== --- wasm/Symbols.h +++ wasm/Symbols.h @@ -16,6 +16,7 @@ #include "llvm/Object/Wasm.h" using llvm::object::Archive; +using llvm::wasm::WasmEventType; using llvm::wasm::WasmGlobalType; using llvm::wasm::WasmSignature; using llvm::wasm::WasmSymbolType; @@ -25,9 +26,11 @@ class InputFile; class InputChunk; +class InputEntity; class InputSegment; class InputFunction; class InputGlobal; +class InputEvent; class InputSection; #define INVALID_INDEX UINT32_MAX @@ -39,10 +42,12 @@ DefinedFunctionKind, DefinedDataKind, DefinedGlobalKind, + DefinedEventKind, SectionKind, UndefinedFunctionKind, UndefinedDataKind, UndefinedGlobalKind, + UndefinedEventKind, LazyKind, }; @@ -50,12 +55,15 @@ bool isDefined() const { return SymbolKind == DefinedFunctionKind || SymbolKind == DefinedDataKind || - SymbolKind == DefinedGlobalKind || SymbolKind == SectionKind; + SymbolKind == DefinedGlobalKind || SymbolKind == DefinedEventKind || + SymbolKind == SectionKind; } bool isUndefined() const { return SymbolKind == UndefinedFunctionKind || - SymbolKind == UndefinedDataKind || SymbolKind == UndefinedGlobalKind; + SymbolKind == UndefinedDataKind || + SymbolKind == UndefinedGlobalKind || + SymbolKind == UndefinedEventKind; } bool isLazy() const { return SymbolKind == LazyKind; } @@ -71,6 +79,7 @@ InputFile *getFile() const { return File; } InputChunk *getChunk() const; + InputEntity *getEntity() const; // Indicates that the section or import for this symbol will be included in // the final image. @@ -272,6 +281,52 @@ } }; +class EventSymbol : public Symbol { +public: + static bool classof(const Symbol *S) { + return S->kind() == DefinedEventKind || S->kind() == UndefinedEventKind; + } + + 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 UndefinedEvent : public EventSymbol { +public: + UndefinedEvent(StringRef Name, uint32_t Flags, InputFile *File = nullptr, + const WasmEventType *Type = nullptr, + const WasmSignature *Sig = nullptr) + : EventSymbol(Name, UndefinedEventKind, Flags, File, Type, Sig) {} + + static bool classof(const Symbol *S) { + return S->kind() == UndefinedEventKind; + } +}; + class LazySymbol : public Symbol { public: LazySymbol(StringRef Name, InputFile *File, const Archive::Symbol &Sym) @@ -325,11 +380,13 @@ 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(SectionSymbol) char I[sizeof(SectionSymbol)]; + 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(UndefinedEvent) char I[sizeof(UndefinedEvent)]; + alignas(SectionSymbol) char J[sizeof(SectionSymbol)]; }; template Index: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -10,8 +10,8 @@ #include "Symbols.h" #include "Config.h" #include "InputChunks.h" +#include "InputEntity.h" #include "InputFiles.h" -#include "InputGlobal.h" #include "OutputSegment.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Strings.h" @@ -38,6 +38,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"); @@ -51,17 +53,25 @@ return nullptr; } -bool Symbol::isLive() const { +InputEntity *Symbol::getEntity() const { if (auto *G = dyn_cast(this)) - return G->Global->Live; + return G->Global; + if (auto *E = dyn_cast(this)) + return E->Event; + return nullptr; +} + +bool Symbol::isLive() const { + if (InputEntity *E = getEntity()) + return E->Live; if (InputChunk *C = getChunk()) return C->Live; return Referenced; } void Symbol::markLive() { - if (auto *G = dyn_cast(this)) - G->Global->Live = true; + if (InputEntity *E = getEntity()) + E->Live = true; if (InputChunk *C = getChunk()) C->Live = true; Referenced = true; @@ -212,6 +222,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,12 +282,16 @@ return "DefinedData"; case wasm::Symbol::DefinedGlobalKind: return "DefinedGlobal"; + case wasm::Symbol::DefinedEventKind: + return "DefinedEvent"; case wasm::Symbol::UndefinedFunctionKind: return "UndefinedFunction"; case wasm::Symbol::UndefinedDataKind: return "UndefinedData"; case wasm::Symbol::UndefinedGlobalKind: return "UndefinedGlobal"; + case wasm::Symbol::UndefinedEventKind: + return "UndefinedEvent"; case wasm::Symbol::LazyKind: return "LazyKind"; case wasm::Symbol::SectionKind: Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -10,7 +10,7 @@ #include "Writer.h" #include "Config.h" #include "InputChunks.h" -#include "InputGlobal.h" +#include "InputEntity.h" #include "OutputSections.h" #include "OutputSegment.h" #include "SymbolTable.h" @@ -80,6 +80,7 @@ void createFunctionSection(); void createTableSection(); void createGlobalSection(); + void createEventSection(); void createExportSection(); void createImportSection(); void createMemorySection(); @@ -111,10 +112,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; @@ -183,10 +186,16 @@ if (auto *FunctionSym = dyn_cast(Sym)) { Import.Kind = WASM_EXTERNAL_FUNCTION; Import.SigIndex = lookupType(*FunctionSym->Signature); - } else { - auto *GlobalSym = cast(Sym); + } else if (auto *GlobalSym = dyn_cast(Sym)) { Import.Kind = WASM_EXTERNAL_GLOBAL; Import.Global = *GlobalSym->getGlobalType(); + } else if (auto *EventSym = dyn_cast(Sym)) { + Import.Kind = WASM_EXTERNAL_EVENT; + Import.Event = *EventSym->getEventType(); + // Reassign the new signature after merging all object files + Import.SigIndex = lookupType(*EventSym->Signature); + } else { + assert(false && "Invalid symbol"); } writeImport(OS, Import); } @@ -252,6 +261,21 @@ } } +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) { + writeEvent(OS, E->Event); + writeUleb128(OS, lookupType(E->Signature), "sig index"); + } +} + void Writer::createTableSection() { if (Config->ImportTable) return; @@ -478,6 +502,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 +750,7 @@ createTableSection(); createMemorySection(); createGlobalSection(); + createEventSection(); createExportSection(); createElemSection(); createCodeSection(); @@ -760,8 +789,12 @@ ImportedSymbols.emplace_back(Sym); if (auto *F = dyn_cast(Sym)) F->setFunctionIndex(NumImportedFunctions++); + else if (auto *G = dyn_cast(Sym)) + G->setGlobalIndex(NumImportedGlobals++); + else if (auto *E = dyn_cast(Sym)) + E->setEventIndex(NumImportedEvents++); else - cast(Sym)->setGlobalIndex(NumImportedGlobals++); + assert(false && "Invalid symbol for imports"); } } @@ -797,6 +830,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 +909,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 +919,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->Signature); + else if (auto *E = dyn_cast(Sym)) + registerType(*F->Signature); + } for (const InputFunction *F : InputFunctions) registerType(F->Signature); + + for (const InputEvent *E : InputEvents) + registerType(E->Signature); } void Writer::assignIndexes() { @@ -959,6 +1002,25 @@ 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 (InputEvent *Event : Symtab->SyntheticEvents) + AddDefinedEvent(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) { @@ -1080,8 +1142,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: wasm/WriterUtils.h =================================================================== --- wasm/WriterUtils.h +++ wasm/WriterUtils.h @@ -48,6 +48,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); @@ -58,7 +62,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: wasm/WriterUtils.cpp =================================================================== --- wasm/WriterUtils.cpp +++ wasm/WriterUtils.cpp @@ -110,6 +110,14 @@ writeInitExpr(OS, Global.InitExpr); } +void wasm::writeEventType(raw_ostream &OS, const WasmEventType &Type) { + writeUleb128(OS, Type.Attribute, "event attribute"); +} + +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 +134,10 @@ case WASM_EXTERNAL_GLOBAL: writeGlobalType(OS, Import.Global); break; + case WASM_EXTERNAL_EVENT: + writeEventType(OS, Import.Event); + writeUleb128(OS, Import.SigIndex, "import sig index"); + break; case WASM_EXTERNAL_MEMORY: writeLimits(OS, Import.Memory); break; @@ -192,7 +204,12 @@ 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) { + return (Type.Attribute == WASM_EVENT_ATTRIBUTE_EXCEPTION ? "exception" + : "unknown"); }