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 object
|
||||||
|
|
||||||
namespace wasm {
|
namespace wasm {
|
||||||
|
struct WasmEvent;
|
||||||
|
struct WasmEventType;
|
||||||
struct WasmFunction;
|
struct WasmFunction;
|
||||||
struct WasmGlobal;
|
struct WasmGlobal;
|
||||||
struct WasmGlobalType;
|
struct WasmGlobalType;
|
||||||
|
@ -76,6 +78,8 @@ using llvm::object::WasmObjectFile;
|
||||||
using llvm::object::WasmSection;
|
using llvm::object::WasmSection;
|
||||||
using llvm::object::WasmSegment;
|
using llvm::object::WasmSegment;
|
||||||
using llvm::object::WasmSymbol;
|
using llvm::object::WasmSymbol;
|
||||||
|
using llvm::wasm::WasmEvent;
|
||||||
|
using llvm::wasm::WasmEventType;
|
||||||
using llvm::wasm::WasmFunction;
|
using llvm::wasm::WasmFunction;
|
||||||
using llvm::wasm::WasmGlobal;
|
using llvm::wasm::WasmGlobal;
|
||||||
using llvm::wasm::WasmGlobalType;
|
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
|
// It is possible for undefined functions not to have a signature (eg. if
|
||||||
// added via "--undefined"), but weak undefined ones do have a signature.
|
// added via "--undefined"), but weak undefined ones do have a signature.
|
||||||
assert(FuncSym->FunctionType);
|
assert(FuncSym->Signature);
|
||||||
const WasmSignature &Sig = *FuncSym->FunctionType;
|
const WasmSignature &Sig = *FuncSym->Signature;
|
||||||
|
|
||||||
// Add a synthetic dummy for weak undefined functions. These dummies will
|
// Add a synthetic dummy for weak undefined functions. These dummies will
|
||||||
// be GC'd if not used as the target of any "call" instructions.
|
// 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_TYPE_INDEX_LEB:
|
||||||
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
|
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
|
||||||
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
|
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
|
||||||
|
case R_WEBASSEMBLY_EVENT_INDEX_LEB:
|
||||||
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
|
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
|
||||||
ExistingValue = decodeULEB128(Loc, &BytesRead);
|
ExistingValue = decodeULEB128(Loc, &BytesRead);
|
||||||
break;
|
break;
|
||||||
|
@ -111,6 +112,7 @@ void InputChunk::writeTo(uint8_t *Buf) const {
|
||||||
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
|
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
|
||||||
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
|
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
|
||||||
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
|
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
|
||||||
|
case R_WEBASSEMBLY_EVENT_INDEX_LEB:
|
||||||
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
|
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
|
||||||
encodeULEB128(Value, Loc, 5);
|
encodeULEB128(Value, Loc, 5);
|
||||||
break;
|
break;
|
||||||
|
@ -180,6 +182,7 @@ static unsigned writeCompressedReloc(uint8_t *Buf, const WasmRelocation &Rel,
|
||||||
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
|
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
|
||||||
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
|
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
|
||||||
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
|
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
|
||||||
|
case R_WEBASSEMBLY_EVENT_INDEX_LEB:
|
||||||
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
|
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
|
||||||
return encodeULEB128(Value, Buf);
|
return encodeULEB128(Value, Buf);
|
||||||
case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
|
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_TYPE_INDEX_LEB:
|
||||||
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
|
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
|
||||||
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
|
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
|
||||||
|
case R_WEBASSEMBLY_EVENT_INDEX_LEB:
|
||||||
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
|
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
|
||||||
case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
|
case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
|
||||||
case R_WEBASSEMBLY_MEMORY_ADDR_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 "InputFiles.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "InputChunks.h"
|
#include "InputChunks.h"
|
||||||
|
#include "InputEvent.h"
|
||||||
#include "InputGlobal.h"
|
#include "InputGlobal.h"
|
||||||
#include "SymbolTable.h"
|
#include "SymbolTable.h"
|
||||||
#include "lld/Common/ErrorHandler.h"
|
#include "lld/Common/ErrorHandler.h"
|
||||||
|
@ -57,7 +58,8 @@ void ObjFile::dumpInfo() const {
|
||||||
log("info for: " + getName() +
|
log("info for: " + getName() +
|
||||||
"\n Symbols : " + Twine(Symbols.size()) +
|
"\n Symbols : " + Twine(Symbols.size()) +
|
||||||
"\n Function Imports : " + Twine(WasmObj->getNumImportedFunctions()) +
|
"\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
|
// 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:
|
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
|
||||||
return Reloc.Index;
|
return Reloc.Index;
|
||||||
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
|
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];
|
const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index];
|
||||||
return Sym.Info.ElementIndex;
|
return Sym.Info.ElementIndex;
|
||||||
}
|
}
|
||||||
|
@ -147,6 +150,8 @@ uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const {
|
||||||
return getFunctionSymbol(Reloc.Index)->getFunctionIndex();
|
return getFunctionSymbol(Reloc.Index)->getFunctionIndex();
|
||||||
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
|
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
|
||||||
return getGlobalSymbol(Reloc.Index)->getGlobalIndex();
|
return getGlobalSymbol(Reloc.Index)->getGlobalIndex();
|
||||||
|
case R_WEBASSEMBLY_EVENT_INDEX_LEB:
|
||||||
|
return getEventSymbol(Reloc.Index)->getEventIndex();
|
||||||
case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
|
case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
|
||||||
if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) {
|
if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) {
|
||||||
if (Sym->isLive())
|
if (Sym->isLive())
|
||||||
|
@ -267,6 +272,10 @@ void ObjFile::parse() {
|
||||||
for (const WasmGlobal &G : WasmObj->globals())
|
for (const WasmGlobal &G : WasmObj->globals())
|
||||||
Globals.emplace_back(make<InputGlobal>(G, this));
|
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.
|
// Populate `Symbols` based on the WasmSymbols in the object.
|
||||||
Symbols.reserve(WasmObj->getNumberOfSymbols());
|
Symbols.reserve(WasmObj->getNumberOfSymbols());
|
||||||
for (const SymbolRef &Sym : WasmObj->symbols()) {
|
for (const SymbolRef &Sym : WasmObj->symbols()) {
|
||||||
|
@ -293,6 +302,10 @@ GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t Index) const {
|
||||||
return cast<GlobalSymbol>(Symbols[Index]);
|
return cast<GlobalSymbol>(Symbols[Index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EventSymbol *ObjFile::getEventSymbol(uint32_t Index) const {
|
||||||
|
return cast<EventSymbol>(Symbols[Index]);
|
||||||
|
}
|
||||||
|
|
||||||
SectionSymbol *ObjFile::getSectionSymbol(uint32_t Index) const {
|
SectionSymbol *ObjFile::getSectionSymbol(uint32_t Index) const {
|
||||||
return cast<SectionSymbol>(Symbols[Index]);
|
return cast<SectionSymbol>(Symbols[Index]);
|
||||||
}
|
}
|
||||||
|
@ -347,6 +360,13 @@ Symbol *ObjFile::createDefined(const WasmSymbol &Sym) {
|
||||||
assert(Sym.isBindingLocal());
|
assert(Sym.isBindingLocal());
|
||||||
return make<SectionSymbol>(Name, Flags, Section, this);
|
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");
|
llvm_unreachable("unknown symbol kind");
|
||||||
}
|
}
|
||||||
|
@ -357,7 +377,7 @@ Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) {
|
||||||
|
|
||||||
switch (Sym.Info.Kind) {
|
switch (Sym.Info.Kind) {
|
||||||
case WASM_SYMBOL_TYPE_FUNCTION:
|
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:
|
case WASM_SYMBOL_TYPE_DATA:
|
||||||
return Symtab->addUndefinedData(Name, Flags, this);
|
return Symtab->addUndefinedData(Name, Flags, this);
|
||||||
case WASM_SYMBOL_TYPE_GLOBAL:
|
case WASM_SYMBOL_TYPE_GLOBAL:
|
||||||
|
|
|
@ -27,6 +27,7 @@ class InputChunk;
|
||||||
class InputFunction;
|
class InputFunction;
|
||||||
class InputSegment;
|
class InputSegment;
|
||||||
class InputGlobal;
|
class InputGlobal;
|
||||||
|
class InputEvent;
|
||||||
class InputSection;
|
class InputSection;
|
||||||
|
|
||||||
class InputFile {
|
class InputFile {
|
||||||
|
@ -108,6 +109,7 @@ public:
|
||||||
std::vector<InputSegment *> Segments;
|
std::vector<InputSegment *> Segments;
|
||||||
std::vector<InputFunction *> Functions;
|
std::vector<InputFunction *> Functions;
|
||||||
std::vector<InputGlobal *> Globals;
|
std::vector<InputGlobal *> Globals;
|
||||||
|
std::vector<InputEvent *> Events;
|
||||||
std::vector<InputSection *> CustomSections;
|
std::vector<InputSection *> CustomSections;
|
||||||
llvm::DenseMap<uint32_t, InputSection *> CustomSectionsByIndex;
|
llvm::DenseMap<uint32_t, InputSection *> CustomSectionsByIndex;
|
||||||
|
|
||||||
|
@ -116,6 +118,7 @@ public:
|
||||||
DataSymbol *getDataSymbol(uint32_t Index) const;
|
DataSymbol *getDataSymbol(uint32_t Index) const;
|
||||||
GlobalSymbol *getGlobalSymbol(uint32_t Index) const;
|
GlobalSymbol *getGlobalSymbol(uint32_t Index) const;
|
||||||
SectionSymbol *getSectionSymbol(uint32_t Index) const;
|
SectionSymbol *getSectionSymbol(uint32_t Index) const;
|
||||||
|
EventSymbol *getEventSymbol(uint32_t Index) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Symbol *createDefined(const WasmSymbol &Sym);
|
Symbol *createDefined(const WasmSymbol &Sym);
|
||||||
|
|
|
@ -80,7 +80,7 @@ BitcodeCompiler::~BitcodeCompiler() = default;
|
||||||
static void undefine(Symbol *S) {
|
static void undefine(Symbol *S) {
|
||||||
if (auto F = dyn_cast<DefinedFunction>(S))
|
if (auto F = dyn_cast<DefinedFunction>(S))
|
||||||
replaceSymbol<UndefinedFunction>(F, F->getName(), 0, F->getFile(),
|
replaceSymbol<UndefinedFunction>(F, F->getName(), 0, F->getFile(),
|
||||||
F->FunctionType);
|
F->Signature);
|
||||||
else if (isa<DefinedData>(S))
|
else if (isa<DefinedData>(S))
|
||||||
replaceSymbol<UndefinedData>(S, S->getName(), 0, S->getFile());
|
replaceSymbol<UndefinedData>(S, S->getName(), 0, S->getFile());
|
||||||
else
|
else
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "MarkLive.h"
|
#include "MarkLive.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "InputChunks.h"
|
#include "InputChunks.h"
|
||||||
|
#include "InputEvent.h"
|
||||||
#include "InputGlobal.h"
|
#include "InputGlobal.h"
|
||||||
#include "SymbolTable.h"
|
#include "SymbolTable.h"
|
||||||
#include "Symbols.h"
|
#include "Symbols.h"
|
||||||
|
@ -105,6 +106,9 @@ void lld::wasm::markLive() {
|
||||||
for (InputGlobal *G : Obj->Globals)
|
for (InputGlobal *G : Obj->Globals)
|
||||||
if (!G->Live)
|
if (!G->Live)
|
||||||
message("removing unused section " + toString(G));
|
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)
|
for (InputChunk *C : Symtab->SyntheticFunctions)
|
||||||
if (!C->Live)
|
if (!C->Live)
|
||||||
|
|
|
@ -40,6 +40,8 @@ static StringRef sectionTypeToString(uint32_t SectionType) {
|
||||||
return "MEMORY";
|
return "MEMORY";
|
||||||
case WASM_SEC_GLOBAL:
|
case WASM_SEC_GLOBAL:
|
||||||
return "GLOBAL";
|
return "GLOBAL";
|
||||||
|
case WASM_SEC_EVENT:
|
||||||
|
return "EVENT";
|
||||||
case WASM_SEC_EXPORT:
|
case WASM_SEC_EXPORT:
|
||||||
return "EXPORT";
|
return "EXPORT";
|
||||||
case WASM_SEC_START:
|
case WASM_SEC_START:
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "SymbolTable.h"
|
#include "SymbolTable.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "InputChunks.h"
|
#include "InputChunks.h"
|
||||||
|
#include "InputEvent.h"
|
||||||
#include "InputGlobal.h"
|
#include "InputGlobal.h"
|
||||||
#include "WriterUtils.h"
|
#include "WriterUtils.h"
|
||||||
#include "lld/Common/ErrorHandler.h"
|
#include "lld/Common/ErrorHandler.h"
|
||||||
|
@ -111,9 +112,9 @@ static void checkFunctionType(Symbol *Existing, const InputFile *File,
|
||||||
if (!NewSig)
|
if (!NewSig)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const WasmSignature *OldSig = ExistingFunction->FunctionType;
|
const WasmSignature *OldSig = ExistingFunction->Signature;
|
||||||
if (!OldSig) {
|
if (!OldSig) {
|
||||||
ExistingFunction->FunctionType = NewSig;
|
ExistingFunction->Signature = NewSig;
|
||||||
return;
|
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) {
|
static void checkDataType(const Symbol *Existing, const InputFile *File) {
|
||||||
if (!isa<DataSymbol>(Existing))
|
if (!isa<DataSymbol>(Existing))
|
||||||
reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
|
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
|
// functions) but the old symbols does then preserve the old signature
|
||||||
const WasmSignature *OldSig = nullptr;
|
const WasmSignature *OldSig = nullptr;
|
||||||
if (auto* F = dyn_cast<FunctionSymbol>(S))
|
if (auto* F = dyn_cast<FunctionSymbol>(S))
|
||||||
OldSig = F->FunctionType;
|
OldSig = F->Signature;
|
||||||
auto NewSym = replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
|
auto NewSym = replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
|
||||||
if (!NewSym->FunctionType)
|
if (!NewSym->Signature)
|
||||||
NewSym->FunctionType = OldSig;
|
NewSym->Signature = OldSig;
|
||||||
}
|
}
|
||||||
return S;
|
return S;
|
||||||
}
|
}
|
||||||
|
@ -271,6 +294,26 @@ Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
|
||||||
return S;
|
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,
|
Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
|
||||||
InputFile *File,
|
InputFile *File,
|
||||||
const WasmSignature *Sig) {
|
const WasmSignature *Sig) {
|
||||||
|
|
|
@ -56,6 +56,8 @@ public:
|
||||||
uint32_t Size);
|
uint32_t Size);
|
||||||
Symbol *addDefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
|
Symbol *addDefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
|
||||||
InputGlobal *G);
|
InputGlobal *G);
|
||||||
|
Symbol *addDefinedEvent(StringRef Name, uint32_t Flags, InputFile *File,
|
||||||
|
InputEvent *E);
|
||||||
|
|
||||||
Symbol *addUndefinedFunction(StringRef Name, uint32_t Flags, InputFile *File,
|
Symbol *addUndefinedFunction(StringRef Name, uint32_t Flags, InputFile *File,
|
||||||
const WasmSignature *Signature);
|
const WasmSignature *Signature);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "Symbols.h"
|
#include "Symbols.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "InputChunks.h"
|
#include "InputChunks.h"
|
||||||
|
#include "InputEvent.h"
|
||||||
#include "InputFiles.h"
|
#include "InputFiles.h"
|
||||||
#include "InputGlobal.h"
|
#include "InputGlobal.h"
|
||||||
#include "OutputSegment.h"
|
#include "OutputSegment.h"
|
||||||
|
@ -38,6 +39,8 @@ WasmSymbolType Symbol::getWasmType() const {
|
||||||
return WASM_SYMBOL_TYPE_DATA;
|
return WASM_SYMBOL_TYPE_DATA;
|
||||||
if (isa<GlobalSymbol>(this))
|
if (isa<GlobalSymbol>(this))
|
||||||
return WASM_SYMBOL_TYPE_GLOBAL;
|
return WASM_SYMBOL_TYPE_GLOBAL;
|
||||||
|
if (isa<EventSymbol>(this))
|
||||||
|
return WASM_SYMBOL_TYPE_EVENT;
|
||||||
if (isa<SectionSymbol>(this))
|
if (isa<SectionSymbol>(this))
|
||||||
return WASM_SYMBOL_TYPE_SECTION;
|
return WASM_SYMBOL_TYPE_SECTION;
|
||||||
llvm_unreachable("invalid symbol kind");
|
llvm_unreachable("invalid symbol kind");
|
||||||
|
@ -54,6 +57,8 @@ InputChunk *Symbol::getChunk() const {
|
||||||
bool Symbol::isLive() const {
|
bool Symbol::isLive() const {
|
||||||
if (auto *G = dyn_cast<DefinedGlobal>(this))
|
if (auto *G = dyn_cast<DefinedGlobal>(this))
|
||||||
return G->Global->Live;
|
return G->Global->Live;
|
||||||
|
if (auto *E = dyn_cast<DefinedEvent>(this))
|
||||||
|
return E->Event->Live;
|
||||||
if (InputChunk *C = getChunk())
|
if (InputChunk *C = getChunk())
|
||||||
return C->Live;
|
return C->Live;
|
||||||
return Referenced;
|
return Referenced;
|
||||||
|
@ -62,6 +67,8 @@ bool Symbol::isLive() const {
|
||||||
void Symbol::markLive() {
|
void Symbol::markLive() {
|
||||||
if (auto *G = dyn_cast<DefinedGlobal>(this))
|
if (auto *G = dyn_cast<DefinedGlobal>(this))
|
||||||
G->Global->Live = true;
|
G->Global->Live = true;
|
||||||
|
if (auto *E = dyn_cast<DefinedEvent>(this))
|
||||||
|
E->Event->Live = true;
|
||||||
if (InputChunk *C = getChunk())
|
if (InputChunk *C = getChunk())
|
||||||
C->Live = true;
|
C->Live = true;
|
||||||
Referenced = true;
|
Referenced = true;
|
||||||
|
@ -212,6 +219,32 @@ DefinedGlobal::DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
|
||||||
Global ? &Global->getType() : nullptr),
|
Global ? &Global->getType() : nullptr),
|
||||||
Global(Global) {}
|
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 {
|
uint32_t SectionSymbol::getOutputSectionIndex() const {
|
||||||
LLVM_DEBUG(dbgs() << "getOutputSectionIndex: " << getName() << "\n");
|
LLVM_DEBUG(dbgs() << "getOutputSectionIndex: " << getName() << "\n");
|
||||||
assert(OutputSectionIndex != INVALID_INDEX);
|
assert(OutputSectionIndex != INVALID_INDEX);
|
||||||
|
@ -246,6 +279,8 @@ std::string lld::toString(wasm::Symbol::Kind Kind) {
|
||||||
return "DefinedData";
|
return "DefinedData";
|
||||||
case wasm::Symbol::DefinedGlobalKind:
|
case wasm::Symbol::DefinedGlobalKind:
|
||||||
return "DefinedGlobal";
|
return "DefinedGlobal";
|
||||||
|
case wasm::Symbol::DefinedEventKind:
|
||||||
|
return "DefinedEvent";
|
||||||
case wasm::Symbol::UndefinedFunctionKind:
|
case wasm::Symbol::UndefinedFunctionKind:
|
||||||
return "UndefinedFunction";
|
return "UndefinedFunction";
|
||||||
case wasm::Symbol::UndefinedDataKind:
|
case wasm::Symbol::UndefinedDataKind:
|
||||||
|
|
|
@ -25,6 +25,7 @@ class InputChunk;
|
||||||
class InputSegment;
|
class InputSegment;
|
||||||
class InputFunction;
|
class InputFunction;
|
||||||
class InputGlobal;
|
class InputGlobal;
|
||||||
|
class InputEvent;
|
||||||
class InputSection;
|
class InputSection;
|
||||||
|
|
||||||
#define INVALID_INDEX UINT32_MAX
|
#define INVALID_INDEX UINT32_MAX
|
||||||
|
@ -36,6 +37,7 @@ public:
|
||||||
DefinedFunctionKind,
|
DefinedFunctionKind,
|
||||||
DefinedDataKind,
|
DefinedDataKind,
|
||||||
DefinedGlobalKind,
|
DefinedGlobalKind,
|
||||||
|
DefinedEventKind,
|
||||||
SectionKind,
|
SectionKind,
|
||||||
UndefinedFunctionKind,
|
UndefinedFunctionKind,
|
||||||
UndefinedDataKind,
|
UndefinedDataKind,
|
||||||
|
@ -47,7 +49,8 @@ public:
|
||||||
|
|
||||||
bool isDefined() const {
|
bool isDefined() const {
|
||||||
return SymbolKind == DefinedFunctionKind || SymbolKind == DefinedDataKind ||
|
return SymbolKind == DefinedFunctionKind || SymbolKind == DefinedDataKind ||
|
||||||
SymbolKind == DefinedGlobalKind || SymbolKind == SectionKind;
|
SymbolKind == DefinedGlobalKind || SymbolKind == DefinedEventKind ||
|
||||||
|
SymbolKind == SectionKind;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isUndefined() const {
|
bool isUndefined() const {
|
||||||
|
@ -121,12 +124,12 @@ public:
|
||||||
void setFunctionIndex(uint32_t Index);
|
void setFunctionIndex(uint32_t Index);
|
||||||
bool hasFunctionIndex() const;
|
bool hasFunctionIndex() const;
|
||||||
|
|
||||||
const WasmSignature *FunctionType;
|
const WasmSignature *Signature;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
|
FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
|
||||||
const WasmSignature *Type)
|
const WasmSignature *Sig)
|
||||||
: Symbol(Name, K, Flags, F), FunctionType(Type) {}
|
: Symbol(Name, K, Flags, F), Signature(Sig) {}
|
||||||
|
|
||||||
uint32_t TableIndex = INVALID_INDEX;
|
uint32_t TableIndex = INVALID_INDEX;
|
||||||
uint32_t FunctionIndex = 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 {
|
class LazySymbol : public Symbol {
|
||||||
public:
|
public:
|
||||||
LazySymbol(StringRef Name, InputFile *File,
|
LazySymbol(StringRef Name, InputFile *File,
|
||||||
|
@ -321,10 +368,11 @@ union SymbolUnion {
|
||||||
alignas(DefinedFunction) char A[sizeof(DefinedFunction)];
|
alignas(DefinedFunction) char A[sizeof(DefinedFunction)];
|
||||||
alignas(DefinedData) char B[sizeof(DefinedData)];
|
alignas(DefinedData) char B[sizeof(DefinedData)];
|
||||||
alignas(DefinedGlobal) char C[sizeof(DefinedGlobal)];
|
alignas(DefinedGlobal) char C[sizeof(DefinedGlobal)];
|
||||||
alignas(LazySymbol) char D[sizeof(LazySymbol)];
|
alignas(DefinedEvent) char D[sizeof(DefinedEvent)];
|
||||||
alignas(UndefinedFunction) char E[sizeof(UndefinedFunction)];
|
alignas(LazySymbol) char E[sizeof(LazySymbol)];
|
||||||
alignas(UndefinedData) char F[sizeof(UndefinedData)];
|
alignas(UndefinedFunction) char F[sizeof(UndefinedFunction)];
|
||||||
alignas(UndefinedGlobal) char G[sizeof(UndefinedGlobal)];
|
alignas(UndefinedData) char G[sizeof(UndefinedData)];
|
||||||
|
alignas(UndefinedGlobal) char H[sizeof(UndefinedGlobal)];
|
||||||
alignas(SectionSymbol) char I[sizeof(SectionSymbol)];
|
alignas(SectionSymbol) char I[sizeof(SectionSymbol)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "Writer.h"
|
#include "Writer.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "InputChunks.h"
|
#include "InputChunks.h"
|
||||||
|
#include "InputEvent.h"
|
||||||
#include "InputGlobal.h"
|
#include "InputGlobal.h"
|
||||||
#include "OutputSections.h"
|
#include "OutputSections.h"
|
||||||
#include "OutputSegment.h"
|
#include "OutputSegment.h"
|
||||||
|
@ -80,6 +81,7 @@ private:
|
||||||
void createFunctionSection();
|
void createFunctionSection();
|
||||||
void createTableSection();
|
void createTableSection();
|
||||||
void createGlobalSection();
|
void createGlobalSection();
|
||||||
|
void createEventSection();
|
||||||
void createExportSection();
|
void createExportSection();
|
||||||
void createImportSection();
|
void createImportSection();
|
||||||
void createMemorySection();
|
void createMemorySection();
|
||||||
|
@ -111,10 +113,12 @@ private:
|
||||||
std::vector<const Symbol *> ImportedSymbols;
|
std::vector<const Symbol *> ImportedSymbols;
|
||||||
unsigned NumImportedFunctions = 0;
|
unsigned NumImportedFunctions = 0;
|
||||||
unsigned NumImportedGlobals = 0;
|
unsigned NumImportedGlobals = 0;
|
||||||
|
unsigned NumImportedEvents = 0;
|
||||||
std::vector<WasmExport> Exports;
|
std::vector<WasmExport> Exports;
|
||||||
std::vector<const DefinedData *> DefinedFakeGlobals;
|
std::vector<const DefinedData *> DefinedFakeGlobals;
|
||||||
std::vector<InputGlobal *> InputGlobals;
|
std::vector<InputGlobal *> InputGlobals;
|
||||||
std::vector<InputFunction *> InputFunctions;
|
std::vector<InputFunction *> InputFunctions;
|
||||||
|
std::vector<InputEvent *> InputEvents;
|
||||||
std::vector<const FunctionSymbol *> IndirectFunctions;
|
std::vector<const FunctionSymbol *> IndirectFunctions;
|
||||||
std::vector<const Symbol *> SymtabEntries;
|
std::vector<const Symbol *> SymtabEntries;
|
||||||
std::vector<WasmInitEntry> InitFunctions;
|
std::vector<WasmInitEntry> InitFunctions;
|
||||||
|
@ -182,11 +186,15 @@ void Writer::createImportSection() {
|
||||||
Import.Field = Sym->getName();
|
Import.Field = Sym->getName();
|
||||||
if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) {
|
if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) {
|
||||||
Import.Kind = WASM_EXTERNAL_FUNCTION;
|
Import.Kind = WASM_EXTERNAL_FUNCTION;
|
||||||
Import.SigIndex = lookupType(*FunctionSym->FunctionType);
|
Import.SigIndex = lookupType(*FunctionSym->Signature);
|
||||||
} else {
|
} else if (auto *GlobalSym = dyn_cast<GlobalSymbol>(Sym)) {
|
||||||
auto *GlobalSym = cast<GlobalSymbol>(Sym);
|
|
||||||
Import.Kind = WASM_EXTERNAL_GLOBAL;
|
Import.Kind = WASM_EXTERNAL_GLOBAL;
|
||||||
Import.Global = *GlobalSym->getGlobalType();
|
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);
|
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() {
|
void Writer::createTableSection() {
|
||||||
if (Config->ImportTable)
|
if (Config->ImportTable)
|
||||||
return;
|
return;
|
||||||
|
@ -478,6 +511,10 @@ void Writer::createLinkingSection() {
|
||||||
writeUleb128(Sub.OS, G->getGlobalIndex(), "index");
|
writeUleb128(Sub.OS, G->getGlobalIndex(), "index");
|
||||||
if (Sym->isDefined())
|
if (Sym->isDefined())
|
||||||
writeStr(Sub.OS, Sym->getName(), "sym name");
|
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)) {
|
} else if (isa<DataSymbol>(Sym)) {
|
||||||
writeStr(Sub.OS, Sym->getName(), "sym name");
|
writeStr(Sub.OS, Sym->getName(), "sym name");
|
||||||
if (auto *DataSym = dyn_cast<DefinedData>(Sym)) {
|
if (auto *DataSym = dyn_cast<DefinedData>(Sym)) {
|
||||||
|
@ -722,6 +759,7 @@ void Writer::createSections() {
|
||||||
createTableSection();
|
createTableSection();
|
||||||
createMemorySection();
|
createMemorySection();
|
||||||
createGlobalSection();
|
createGlobalSection();
|
||||||
|
createEventSection();
|
||||||
createExportSection();
|
createExportSection();
|
||||||
createElemSection();
|
createElemSection();
|
||||||
createCodeSection();
|
createCodeSection();
|
||||||
|
@ -760,8 +798,10 @@ void Writer::calculateImports() {
|
||||||
ImportedSymbols.emplace_back(Sym);
|
ImportedSymbols.emplace_back(Sym);
|
||||||
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
|
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
|
||||||
F->setFunctionIndex(NumImportedFunctions++);
|
F->setFunctionIndex(NumImportedFunctions++);
|
||||||
|
else if (auto *G = dyn_cast<GlobalSymbol>(Sym))
|
||||||
|
G->setGlobalIndex(NumImportedGlobals++);
|
||||||
else
|
else
|
||||||
cast<GlobalSymbol>(Sym)->setGlobalIndex(NumImportedGlobals++);
|
cast<EventSymbol>(Sym)->setEventIndex(NumImportedEvents++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -797,6 +837,8 @@ void Writer::calculateExports() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Export = {Name, WASM_EXTERNAL_GLOBAL, G->getGlobalIndex()};
|
Export = {Name, WASM_EXTERNAL_GLOBAL, G->getGlobalIndex()};
|
||||||
|
} else if (auto *E = dyn_cast<DefinedEvent>(Sym)) {
|
||||||
|
Export = {Name, WASM_EXTERNAL_EVENT, E->getEventIndex()};
|
||||||
} else {
|
} else {
|
||||||
auto *D = cast<DefinedData>(Sym);
|
auto *D = cast<DefinedData>(Sym);
|
||||||
DefinedFakeGlobals.emplace_back(D);
|
DefinedFakeGlobals.emplace_back(D);
|
||||||
|
@ -874,6 +916,8 @@ void Writer::calculateTypes() {
|
||||||
// 1. Any signature used in the TYPE relocation
|
// 1. Any signature used in the TYPE relocation
|
||||||
// 2. The signatures of all imported functions
|
// 2. The signatures of all imported functions
|
||||||
// 3. The signatures of all defined 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) {
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
||||||
ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
|
ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
|
||||||
|
@ -882,12 +926,18 @@ void Writer::calculateTypes() {
|
||||||
File->TypeMap[I] = registerType(Types[I]);
|
File->TypeMap[I] = registerType(Types[I]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const Symbol *Sym : ImportedSymbols)
|
for (const Symbol *Sym : ImportedSymbols) {
|
||||||
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
|
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)
|
for (const InputFunction *F : InputFunctions)
|
||||||
registerType(F->Signature);
|
registerType(F->Signature);
|
||||||
|
|
||||||
|
for (const InputEvent *E : InputEvents)
|
||||||
|
registerType(E->Signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Writer::assignIndexes() {
|
void Writer::assignIndexes() {
|
||||||
|
@ -959,6 +1009,22 @@ void Writer::assignIndexes() {
|
||||||
for (InputGlobal *Global : File->Globals)
|
for (InputGlobal *Global : File->Globals)
|
||||||
AddDefinedGlobal(Global);
|
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) {
|
static StringRef getOutputDataSegmentName(StringRef Name) {
|
||||||
|
@ -1035,7 +1101,7 @@ void Writer::calculateInitFunctions() {
|
||||||
const WasmLinkingData &L = File->getWasmObj()->linkingData();
|
const WasmLinkingData &L = File->getWasmObj()->linkingData();
|
||||||
for (const WasmInitFunc &F : L.InitFunctions) {
|
for (const WasmInitFunc &F : L.InitFunctions) {
|
||||||
FunctionSymbol *Sym = File->getFunctionSymbol(F.Symbol);
|
FunctionSymbol *Sym = File->getFunctionSymbol(F.Symbol);
|
||||||
if (*Sym->FunctionType != WasmSignature{{}, {}})
|
if (*Sym->Signature != WasmSignature{{}, {}})
|
||||||
error("invalid signature for init func: " + toString(*Sym));
|
error("invalid signature for init func: " + toString(*Sym));
|
||||||
InitFunctions.emplace_back(WasmInitEntry{Sym, F.Priority});
|
InitFunctions.emplace_back(WasmInitEntry{Sym, F.Priority});
|
||||||
}
|
}
|
||||||
|
@ -1080,8 +1146,10 @@ void Writer::run() {
|
||||||
if (errorHandler().Verbose) {
|
if (errorHandler().Verbose) {
|
||||||
log("Defined Functions: " + Twine(InputFunctions.size()));
|
log("Defined Functions: " + Twine(InputFunctions.size()));
|
||||||
log("Defined Globals : " + Twine(InputGlobals.size()));
|
log("Defined Globals : " + Twine(InputGlobals.size()));
|
||||||
|
log("Defined Events : " + Twine(InputEvents.size()));
|
||||||
log("Function Imports : " + Twine(NumImportedFunctions));
|
log("Function Imports : " + Twine(NumImportedFunctions));
|
||||||
log("Global Imports : " + Twine(NumImportedGlobals));
|
log("Global Imports : " + Twine(NumImportedGlobals));
|
||||||
|
log("Event Imports : " + Twine(NumImportedEvents));
|
||||||
for (ObjFile *File : Symtab->ObjectFiles)
|
for (ObjFile *File : Symtab->ObjectFiles)
|
||||||
File->dumpInfo();
|
File->dumpInfo();
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,15 @@ void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) {
|
||||||
writeInitExpr(OS, Global.InitExpr);
|
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) {
|
void wasm::writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type) {
|
||||||
writeU8(OS, WASM_TYPE_ANYFUNC, "table type");
|
writeU8(OS, WASM_TYPE_ANYFUNC, "table type");
|
||||||
writeLimits(OS, Type.Limits);
|
writeLimits(OS, Type.Limits);
|
||||||
|
@ -126,6 +135,9 @@ void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) {
|
||||||
case WASM_EXTERNAL_GLOBAL:
|
case WASM_EXTERNAL_GLOBAL:
|
||||||
writeGlobalType(OS, Import.Global);
|
writeGlobalType(OS, Import.Global);
|
||||||
break;
|
break;
|
||||||
|
case WASM_EXTERNAL_EVENT:
|
||||||
|
writeEventType(OS, Import.Event);
|
||||||
|
break;
|
||||||
case WASM_EXTERNAL_MEMORY:
|
case WASM_EXTERNAL_MEMORY:
|
||||||
writeLimits(OS, Import.Memory);
|
writeLimits(OS, Import.Memory);
|
||||||
break;
|
break;
|
||||||
|
@ -192,7 +204,13 @@ std::string lld::toString(const WasmSignature &Sig) {
|
||||||
return S.str();
|
return S.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string lld::toString(const WasmGlobalType &Sig) {
|
std::string lld::toString(const WasmGlobalType &Type) {
|
||||||
return (Sig.Mutable ? "var " : "const ") +
|
return (Type.Mutable ? "var " : "const ") +
|
||||||
toString(static_cast<ValType>(Sig.Type));
|
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 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 writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type);
|
||||||
|
|
||||||
void writeImport(raw_ostream &OS, const llvm::wasm::WasmImport &Import);
|
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(llvm::wasm::ValType Type);
|
||||||
std::string toString(const llvm::wasm::WasmSignature &Sig);
|
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
|
} // namespace lld
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue