forked from OSchip/llvm-project
[WebAssembly] Add support for the event section
Summary: This adds support for the 'event section' specified in the exception handling proposal. Wasm exception handling binary model spec: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md#changes-to-the-binary-model Reviewers: sbc100, ruiu Subscribers: dschuff, jgravelle-google, sunfish, llvm-commits Differential Revision: https://reviews.llvm.org/D54875 llvm-svn: 348703
This commit is contained in:
parent
a2125b8d99
commit
e915a71f18
|
@ -43,6 +43,8 @@ class WasmSymbol;
|
|||
} // namespace object
|
||||
|
||||
namespace wasm {
|
||||
struct WasmEvent;
|
||||
struct WasmEventType;
|
||||
struct WasmFunction;
|
||||
struct WasmGlobal;
|
||||
struct WasmGlobalType;
|
||||
|
@ -76,6 +78,8 @@ using llvm::object::WasmObjectFile;
|
|||
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;
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -306,8 +306,8 @@ static void handleWeakUndefines() {
|
|||
|
||||
// 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.
|
||||
|
|
|
@ -55,6 +55,7 @@ void InputChunk::verifyRelocTargets() const {
|
|||
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 @@ void InputChunk::writeTo(uint8_t *Buf) const {
|
|||
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 @@ static unsigned writeCompressedReloc(uint8_t *Buf, const WasmRelocation &Rel,
|
|||
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 @@ static unsigned getRelocWidthPadded(const WasmRelocation &Rel) {
|
|||
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:
|
||||
|
|
|
@ -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<uint32_t> 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
|
|
@ -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 @@ void ObjFile::dumpInfo() const {
|
|||
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 @@ uint32_t ObjFile::calcExpectedValue(const WasmRelocation &Reloc) const {
|
|||
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 @@ uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const {
|
|||
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<DefinedFunction>(getFunctionSymbol(Reloc.Index))) {
|
||||
if (Sym->isLive())
|
||||
|
@ -267,6 +272,10 @@ void ObjFile::parse() {
|
|||
for (const WasmGlobal &G : WasmObj->globals())
|
||||
Globals.emplace_back(make<InputGlobal>(G, this));
|
||||
|
||||
// Populate `Events`.
|
||||
for (const WasmEvent &E : WasmObj->events())
|
||||
Events.emplace_back(make<InputEvent>(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 @@ GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t Index) const {
|
|||
return cast<GlobalSymbol>(Symbols[Index]);
|
||||
}
|
||||
|
||||
EventSymbol *ObjFile::getEventSymbol(uint32_t Index) const {
|
||||
return cast<EventSymbol>(Symbols[Index]);
|
||||
}
|
||||
|
||||
SectionSymbol *ObjFile::getSectionSymbol(uint32_t Index) const {
|
||||
return cast<SectionSymbol>(Symbols[Index]);
|
||||
}
|
||||
|
@ -347,6 +360,13 @@ Symbol *ObjFile::createDefined(const WasmSymbol &Sym) {
|
|||
assert(Sym.isBindingLocal());
|
||||
return make<SectionSymbol>(Name, Flags, Section, this);
|
||||
}
|
||||
case WASM_SYMBOL_TYPE_EVENT: {
|
||||
InputEvent *Event =
|
||||
Events[Sym.Info.ElementIndex - WasmObj->getNumImportedEvents()];
|
||||
if (Sym.isBindingLocal())
|
||||
return make<DefinedEvent>(Name, Flags, this, Event);
|
||||
return Symtab->addDefinedEvent(Name, Flags, this, Event);
|
||||
}
|
||||
}
|
||||
llvm_unreachable("unknown symbol kind");
|
||||
}
|
||||
|
@ -357,7 +377,7 @@ Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) {
|
|||
|
||||
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:
|
||||
|
|
|
@ -27,6 +27,7 @@ class InputChunk;
|
|||
class InputFunction;
|
||||
class InputSegment;
|
||||
class InputGlobal;
|
||||
class InputEvent;
|
||||
class InputSection;
|
||||
|
||||
class InputFile {
|
||||
|
@ -108,6 +109,7 @@ public:
|
|||
std::vector<InputSegment *> Segments;
|
||||
std::vector<InputFunction *> Functions;
|
||||
std::vector<InputGlobal *> Globals;
|
||||
std::vector<InputEvent *> Events;
|
||||
std::vector<InputSection *> CustomSections;
|
||||
llvm::DenseMap<uint32_t, InputSection *> CustomSectionsByIndex;
|
||||
|
||||
|
@ -116,6 +118,7 @@ public:
|
|||
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);
|
||||
|
|
|
@ -80,7 +80,7 @@ BitcodeCompiler::~BitcodeCompiler() = default;
|
|||
static void undefine(Symbol *S) {
|
||||
if (auto F = dyn_cast<DefinedFunction>(S))
|
||||
replaceSymbol<UndefinedFunction>(F, F->getName(), 0, F->getFile(),
|
||||
F->FunctionType);
|
||||
F->Signature);
|
||||
else if (isa<DefinedData>(S))
|
||||
replaceSymbol<UndefinedData>(S, S->getName(), 0, S->getFile());
|
||||
else
|
||||
|
|
|
@ -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 @@ void lld::wasm::markLive() {
|
|||
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)
|
||||
|
|
|
@ -40,6 +40,8 @@ static StringRef sectionTypeToString(uint32_t SectionType) {
|
|||
return "MEMORY";
|
||||
case WASM_SEC_GLOBAL:
|
||||
return "GLOBAL";
|
||||
case WASM_SEC_EVENT:
|
||||
return "EVENT";
|
||||
case WASM_SEC_EXPORT:
|
||||
return "EXPORT";
|
||||
case WASM_SEC_START:
|
||||
|
|
|
@ -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 @@ static void checkFunctionType(Symbol *Existing, const InputFile *File,
|
|||
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 checkGlobalType(const Symbol *Existing, const InputFile *File,
|
|||
}
|
||||
}
|
||||
|
||||
static void checkEventType(const Symbol *Existing, const InputFile *File,
|
||||
const WasmEventType *NewType,
|
||||
const WasmSignature *NewSig) {
|
||||
auto ExistingEvent = dyn_cast<EventSymbol>(Existing);
|
||||
if (!isa<EventSymbol>(Existing)) {
|
||||
reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT);
|
||||
return;
|
||||
}
|
||||
|
||||
const WasmEventType *OldType = cast<EventSymbol>(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<DataSymbol>(Existing))
|
||||
reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
|
||||
|
@ -222,10 +245,10 @@ Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
|
|||
// functions) but the old symbols does then preserve the old signature
|
||||
const WasmSignature *OldSig = nullptr;
|
||||
if (auto* F = dyn_cast<FunctionSymbol>(S))
|
||||
OldSig = F->FunctionType;
|
||||
OldSig = F->Signature;
|
||||
auto NewSym = replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
|
||||
if (!NewSym->FunctionType)
|
||||
NewSym->FunctionType = OldSig;
|
||||
if (!NewSym->Signature)
|
||||
NewSym->Signature = OldSig;
|
||||
}
|
||||
return S;
|
||||
}
|
||||
|
@ -271,6 +294,26 @@ Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
|
|||
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<DefinedEvent>(S, Name, Flags, File, Event);
|
||||
return S;
|
||||
}
|
||||
|
||||
checkEventType(S, File, &Event->getType(), &Event->Signature);
|
||||
|
||||
if (shouldReplace(S, File, Flags))
|
||||
replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
|
||||
return S;
|
||||
}
|
||||
|
||||
Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
|
||||
InputFile *File,
|
||||
const WasmSignature *Sig) {
|
||||
|
|
|
@ -56,6 +56,8 @@ public:
|
|||
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);
|
||||
|
|
|
@ -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 @@ WasmSymbolType Symbol::getWasmType() const {
|
|||
return WASM_SYMBOL_TYPE_DATA;
|
||||
if (isa<GlobalSymbol>(this))
|
||||
return WASM_SYMBOL_TYPE_GLOBAL;
|
||||
if (isa<EventSymbol>(this))
|
||||
return WASM_SYMBOL_TYPE_EVENT;
|
||||
if (isa<SectionSymbol>(this))
|
||||
return WASM_SYMBOL_TYPE_SECTION;
|
||||
llvm_unreachable("invalid symbol kind");
|
||||
|
@ -54,6 +57,8 @@ InputChunk *Symbol::getChunk() const {
|
|||
bool Symbol::isLive() const {
|
||||
if (auto *G = dyn_cast<DefinedGlobal>(this))
|
||||
return G->Global->Live;
|
||||
if (auto *E = dyn_cast<DefinedEvent>(this))
|
||||
return E->Event->Live;
|
||||
if (InputChunk *C = getChunk())
|
||||
return C->Live;
|
||||
return Referenced;
|
||||
|
@ -62,6 +67,8 @@ bool Symbol::isLive() const {
|
|||
void Symbol::markLive() {
|
||||
if (auto *G = dyn_cast<DefinedGlobal>(this))
|
||||
G->Global->Live = true;
|
||||
if (auto *E = dyn_cast<DefinedEvent>(this))
|
||||
E->Event->Live = true;
|
||||
if (InputChunk *C = getChunk())
|
||||
C->Live = true;
|
||||
Referenced = true;
|
||||
|
@ -212,6 +219,32 @@ DefinedGlobal::DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
|
|||
Global ? &Global->getType() : nullptr),
|
||||
Global(Global) {}
|
||||
|
||||
uint32_t EventSymbol::getEventIndex() const {
|
||||
if (auto *F = dyn_cast<DefinedEvent>(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<DefinedEvent>(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 @@ std::string lld::toString(wasm::Symbol::Kind Kind) {
|
|||
return "DefinedData";
|
||||
case wasm::Symbol::DefinedGlobalKind:
|
||||
return "DefinedGlobal";
|
||||
case wasm::Symbol::DefinedEventKind:
|
||||
return "DefinedEvent";
|
||||
case wasm::Symbol::UndefinedFunctionKind:
|
||||
return "UndefinedFunction";
|
||||
case wasm::Symbol::UndefinedDataKind:
|
||||
|
|
|
@ -25,6 +25,7 @@ class InputChunk;
|
|||
class InputSegment;
|
||||
class InputFunction;
|
||||
class InputGlobal;
|
||||
class InputEvent;
|
||||
class InputSection;
|
||||
|
||||
#define INVALID_INDEX UINT32_MAX
|
||||
|
@ -36,6 +37,7 @@ public:
|
|||
DefinedFunctionKind,
|
||||
DefinedDataKind,
|
||||
DefinedGlobalKind,
|
||||
DefinedEventKind,
|
||||
SectionKind,
|
||||
UndefinedFunctionKind,
|
||||
UndefinedDataKind,
|
||||
|
@ -47,7 +49,8 @@ public:
|
|||
|
||||
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 @@ public:
|
|||
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 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// 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 @@ union SymbolUnion {
|
|||
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)];
|
||||
};
|
||||
|
||||
|
|
|
@ -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 @@ private:
|
|||
void createFunctionSection();
|
||||
void createTableSection();
|
||||
void createGlobalSection();
|
||||
void createEventSection();
|
||||
void createExportSection();
|
||||
void createImportSection();
|
||||
void createMemorySection();
|
||||
|
@ -111,10 +113,12 @@ private:
|
|||
std::vector<const Symbol *> ImportedSymbols;
|
||||
unsigned NumImportedFunctions = 0;
|
||||
unsigned NumImportedGlobals = 0;
|
||||
unsigned NumImportedEvents = 0;
|
||||
std::vector<WasmExport> Exports;
|
||||
std::vector<const DefinedData *> DefinedFakeGlobals;
|
||||
std::vector<InputGlobal *> InputGlobals;
|
||||
std::vector<InputFunction *> InputFunctions;
|
||||
std::vector<InputEvent *> InputEvents;
|
||||
std::vector<const FunctionSymbol *> IndirectFunctions;
|
||||
std::vector<const Symbol *> SymtabEntries;
|
||||
std::vector<WasmInitEntry> InitFunctions;
|
||||
|
@ -182,11 +186,15 @@ void Writer::createImportSection() {
|
|||
Import.Field = Sym->getName();
|
||||
if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) {
|
||||
Import.Kind = WASM_EXTERNAL_FUNCTION;
|
||||
Import.SigIndex = lookupType(*FunctionSym->FunctionType);
|
||||
} else {
|
||||
auto *GlobalSym = cast<GlobalSymbol>(Sym);
|
||||
Import.SigIndex = lookupType(*FunctionSym->Signature);
|
||||
} else if (auto *GlobalSym = dyn_cast<GlobalSymbol>(Sym)) {
|
||||
Import.Kind = WASM_EXTERNAL_GLOBAL;
|
||||
Import.Global = *GlobalSym->getGlobalType();
|
||||
} else {
|
||||
auto *EventSym = cast<EventSymbol>(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 @@ void Writer::createGlobalSection() {
|
|||
}
|
||||
}
|
||||
|
||||
// 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 @@ void Writer::createLinkingSection() {
|
|||
writeUleb128(Sub.OS, G->getGlobalIndex(), "index");
|
||||
if (Sym->isDefined())
|
||||
writeStr(Sub.OS, Sym->getName(), "sym name");
|
||||
} else if (auto *E = dyn_cast<EventSymbol>(Sym)) {
|
||||
writeUleb128(Sub.OS, E->getEventIndex(), "index");
|
||||
if (Sym->isDefined())
|
||||
writeStr(Sub.OS, Sym->getName(), "sym name");
|
||||
} else if (isa<DataSymbol>(Sym)) {
|
||||
writeStr(Sub.OS, Sym->getName(), "sym name");
|
||||
if (auto *DataSym = dyn_cast<DefinedData>(Sym)) {
|
||||
|
@ -722,6 +759,7 @@ void Writer::createSections() {
|
|||
createTableSection();
|
||||
createMemorySection();
|
||||
createGlobalSection();
|
||||
createEventSection();
|
||||
createExportSection();
|
||||
createElemSection();
|
||||
createCodeSection();
|
||||
|
@ -760,8 +798,10 @@ void Writer::calculateImports() {
|
|||
ImportedSymbols.emplace_back(Sym);
|
||||
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
|
||||
F->setFunctionIndex(NumImportedFunctions++);
|
||||
else if (auto *G = dyn_cast<GlobalSymbol>(Sym))
|
||||
G->setGlobalIndex(NumImportedGlobals++);
|
||||
else
|
||||
cast<GlobalSymbol>(Sym)->setGlobalIndex(NumImportedGlobals++);
|
||||
cast<EventSymbol>(Sym)->setEventIndex(NumImportedEvents++);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -797,6 +837,8 @@ void Writer::calculateExports() {
|
|||
continue;
|
||||
}
|
||||
Export = {Name, WASM_EXTERNAL_GLOBAL, G->getGlobalIndex()};
|
||||
} else if (auto *E = dyn_cast<DefinedEvent>(Sym)) {
|
||||
Export = {Name, WASM_EXTERNAL_EVENT, E->getEventIndex()};
|
||||
} else {
|
||||
auto *D = cast<DefinedData>(Sym);
|
||||
DefinedFakeGlobals.emplace_back(D);
|
||||
|
@ -874,6 +916,8 @@ void Writer::calculateTypes() {
|
|||
// 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<WasmSignature> Types = File->getWasmObj()->types();
|
||||
|
@ -882,12 +926,18 @@ void Writer::calculateTypes() {
|
|||
File->TypeMap[I] = registerType(Types[I]);
|
||||
}
|
||||
|
||||
for (const Symbol *Sym : ImportedSymbols)
|
||||
for (const Symbol *Sym : ImportedSymbols) {
|
||||
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
|
||||
registerType(*F->FunctionType);
|
||||
registerType(*F->Signature);
|
||||
else if (auto *E = dyn_cast<EventSymbol>(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 @@ void Writer::assignIndexes() {
|
|||
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 @@ void Writer::calculateInitFunctions() {
|
|||
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 @@ void Writer::run() {
|
|||
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();
|
||||
}
|
||||
|
|
|
@ -110,6 +110,15 @@ void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) {
|
|||
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 @@ void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) {
|
|||
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 @@ std::string lld::toString(const WasmSignature &Sig) {
|
|||
return S.str();
|
||||
}
|
||||
|
||||
std::string lld::toString(const WasmGlobalType &Sig) {
|
||||
return (Sig.Mutable ? "var " : "const ") +
|
||||
toString(static_cast<ValType>(Sig.Type));
|
||||
std::string lld::toString(const WasmGlobalType &Type) {
|
||||
return (Type.Mutable ? "var " : "const ") +
|
||||
toString(static_cast<ValType>(Type.Type));
|
||||
}
|
||||
|
||||
std::string lld::toString(const WasmEventType &Type) {
|
||||
if (Type.Attribute == WASM_EVENT_ATTRIBUTE_EXCEPTION)
|
||||
return "exception";
|
||||
return "unknown";
|
||||
}
|
||||
|
|
|
@ -45,6 +45,10 @@ void writeGlobalType(raw_ostream &OS, const llvm::wasm::WasmGlobalType &Type);
|
|||
|
||||
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 @@ void writeExport(raw_ostream &OS, const llvm::wasm::WasmExport &Export);
|
|||
|
||||
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
|
||||
|
||||
|
|
Loading…
Reference in New Issue