[WebAssembly] Add support for the event section

Summary:
This adds support for the 'event section' specified in the exception
handling proposal. (This was named 'exception section' first, but later
renamed to 'event section' to take possibilities of other kinds of
events into consideration. But currently we only store exception info in
this section.)

The event section is added between the global section and the export
section. This is for ease of validation per request of the V8 team.

This patch:
- Creates the event symbol type, which is a weak symbol
- Makes 'throw' instruction take the event symbol '__cpp_exception'
- Adds relocation support for events
- Adds WasmObjectWriter / WasmObjectFile (Reader) support
- Adds obj2yaml / yaml2obj support
- Adds '.eventtype' printing support

Reviewers: dschuff, sbc100, aardappel

Subscribers: jgravelle-google, sunfish, llvm-commits

Differential Revision: https://reviews.llvm.org/D54096

llvm-svn: 346825
This commit is contained in:
Heejin Ahn 2018-11-14 02:46:21 +00:00
parent 6a3c279d1c
commit da419bdb5e
34 changed files with 708 additions and 116 deletions

View File

@ -75,6 +75,18 @@ struct WasmGlobal {
StringRef SymbolName; // from the "linking" section StringRef SymbolName; // from the "linking" section
}; };
struct WasmEventType {
// Kind of event. Currently only WASM_EVENT_ATTRIBUTE_EXCEPTION is possible.
uint32_t Attribute;
uint32_t SigIndex;
};
struct WasmEvent {
uint32_t Index;
WasmEventType Type;
StringRef SymbolName; // from the "linking" section
};
struct WasmImport { struct WasmImport {
StringRef Module; StringRef Module;
StringRef Field; StringRef Field;
@ -84,6 +96,7 @@ struct WasmImport {
WasmGlobalType Global; WasmGlobalType Global;
WasmTable Table; WasmTable Table;
WasmLimits Memory; WasmLimits Memory;
WasmEventType Event;
}; };
}; };
@ -178,7 +191,8 @@ enum : unsigned {
WASM_SEC_START = 8, // Start function declaration WASM_SEC_START = 8, // Start function declaration
WASM_SEC_ELEM = 9, // Elements section WASM_SEC_ELEM = 9, // Elements section
WASM_SEC_CODE = 10, // Function bodies (code) WASM_SEC_CODE = 10, // Function bodies (code)
WASM_SEC_DATA = 11 // Data segments WASM_SEC_DATA = 11, // Data segments
WASM_SEC_EVENT = 12 // Event declarations
}; };
// Type immediate encodings used in various contexts. // Type immediate encodings used in various contexts.
@ -200,6 +214,7 @@ enum : unsigned {
WASM_EXTERNAL_TABLE = 0x1, WASM_EXTERNAL_TABLE = 0x1,
WASM_EXTERNAL_MEMORY = 0x2, WASM_EXTERNAL_MEMORY = 0x2,
WASM_EXTERNAL_GLOBAL = 0x3, WASM_EXTERNAL_GLOBAL = 0x3,
WASM_EXTERNAL_EVENT = 0x4,
}; };
// Opcodes used in initializer expressions. // Opcodes used in initializer expressions.
@ -243,6 +258,12 @@ enum WasmSymbolType : unsigned {
WASM_SYMBOL_TYPE_DATA = 0x1, WASM_SYMBOL_TYPE_DATA = 0x1,
WASM_SYMBOL_TYPE_GLOBAL = 0x2, WASM_SYMBOL_TYPE_GLOBAL = 0x2,
WASM_SYMBOL_TYPE_SECTION = 0x3, WASM_SYMBOL_TYPE_SECTION = 0x3,
WASM_SYMBOL_TYPE_EVENT = 0x4,
};
// Kinds of event attributes.
enum WasmEventAttribute : unsigned {
WASM_EVENT_ATTRIBUTE_EXCEPTION = 0x0,
}; };
const unsigned WASM_SYMBOL_BINDING_MASK = 0x3; const unsigned WASM_SYMBOL_BINDING_MASK = 0x3;

View File

@ -1,4 +1,3 @@
#ifndef WASM_RELOC #ifndef WASM_RELOC
#error "WASM_RELOC must be defined" #error "WASM_RELOC must be defined"
#endif #endif
@ -13,3 +12,4 @@ WASM_RELOC(R_WEBASSEMBLY_TYPE_INDEX_LEB, 6)
WASM_RELOC(R_WEBASSEMBLY_GLOBAL_INDEX_LEB, 7) WASM_RELOC(R_WEBASSEMBLY_GLOBAL_INDEX_LEB, 7)
WASM_RELOC(R_WEBASSEMBLY_FUNCTION_OFFSET_I32, 8) WASM_RELOC(R_WEBASSEMBLY_FUNCTION_OFFSET_I32, 8)
WASM_RELOC(R_WEBASSEMBLY_SECTION_OFFSET_I32, 9) WASM_RELOC(R_WEBASSEMBLY_SECTION_OFFSET_I32, 9)
WASM_RELOC(R_WEBASSEMBLY_EVENT_INDEX_LEB, 10)

View File

@ -21,6 +21,8 @@
namespace llvm { namespace llvm {
enum EventTag { CPP_EXCEPTION = 0, C_LONGJMP = 1 };
using BBOrMBB = PointerUnion<const BasicBlock *, MachineBasicBlock *>; using BBOrMBB = PointerUnion<const BasicBlock *, MachineBasicBlock *>;
struct WasmEHFuncInfo { struct WasmEHFuncInfo {

View File

@ -288,6 +288,7 @@ public:
VK_WebAssembly_FUNCTION, // Function table index, rather than virtual addr VK_WebAssembly_FUNCTION, // Function table index, rather than virtual addr
VK_WebAssembly_GLOBAL, // Global object index VK_WebAssembly_GLOBAL, // Global object index
VK_WebAssembly_TYPEINDEX,// Type table index VK_WebAssembly_TYPEINDEX,// Type table index
VK_WebAssembly_EVENT, // Event index
VK_AMDGPU_GOTPCREL32_LO, // symbol@gotpcrel32@lo VK_AMDGPU_GOTPCREL32_LO, // symbol@gotpcrel32@lo
VK_AMDGPU_GOTPCREL32_HI, // symbol@gotpcrel32@hi VK_AMDGPU_GOTPCREL32_HI, // symbol@gotpcrel32@hi

View File

@ -21,8 +21,8 @@ class MCSymbolWasm : public MCSymbol {
bool IsComdat = false; bool IsComdat = false;
std::string ModuleName; std::string ModuleName;
wasm::WasmSignature *Signature = nullptr; wasm::WasmSignature *Signature = nullptr;
wasm::WasmGlobalType GlobalType; Optional<wasm::WasmGlobalType> GlobalType;
bool GlobalTypeSet = false; Optional<wasm::WasmEventType> EventType;
/// An expression describing how to calculate the size of a symbol. If a /// An expression describing how to calculate the size of a symbol. If a
/// symbol has no size this field will be NULL. /// symbol has no size this field will be NULL.
@ -42,6 +42,7 @@ public:
bool isData() const { return Type == wasm::WASM_SYMBOL_TYPE_DATA; } bool isData() const { return Type == wasm::WASM_SYMBOL_TYPE_DATA; }
bool isGlobal() const { return Type == wasm::WASM_SYMBOL_TYPE_GLOBAL; } bool isGlobal() const { return Type == wasm::WASM_SYMBOL_TYPE_GLOBAL; }
bool isSection() const { return Type == wasm::WASM_SYMBOL_TYPE_SECTION; } bool isSection() const { return Type == wasm::WASM_SYMBOL_TYPE_SECTION; }
bool isEvent() const { return Type == wasm::WASM_SYMBOL_TYPE_EVENT; }
wasm::WasmSymbolType getType() const { return Type; } wasm::WasmSymbolType getType() const { return Type; }
void setType(wasm::WasmSymbolType type) { Type = type; } void setType(wasm::WasmSymbolType type) { Type = type; }
@ -61,14 +62,16 @@ public:
void setSignature(wasm::WasmSignature *Sig) { Signature = Sig; } void setSignature(wasm::WasmSignature *Sig) { Signature = Sig; }
const wasm::WasmGlobalType &getGlobalType() const { const wasm::WasmGlobalType &getGlobalType() const {
assert(GlobalTypeSet); assert(GlobalType.hasValue());
return GlobalType; return GlobalType.getValue();
} }
void setGlobalType(wasm::WasmGlobalType GT) { GlobalType = GT; }
void setGlobalType(wasm::WasmGlobalType GT) { const wasm::WasmEventType &getEventType() const {
GlobalTypeSet = true; assert(EventType.hasValue());
GlobalType = GT; return EventType.getValue();
} }
void setEventType(wasm::WasmEventType ET) { EventType = ET; }
}; };
} // end namespace llvm } // end namespace llvm

View File

@ -333,6 +333,7 @@ private:
case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB:
// For wasm section, its offset at 0 -- ignoring Value // For wasm section, its offset at 0 -- ignoring Value
return 0; return 0;
} }

View File

@ -38,12 +38,15 @@ class WasmSymbol {
public: public:
WasmSymbol(const wasm::WasmSymbolInfo &Info, WasmSymbol(const wasm::WasmSymbolInfo &Info,
const wasm::WasmSignature *FunctionType, const wasm::WasmSignature *FunctionType,
const wasm::WasmGlobalType *GlobalType) const wasm::WasmGlobalType *GlobalType,
: Info(Info), FunctionType(FunctionType), GlobalType(GlobalType) {} const wasm::WasmEventType *EventType)
: Info(Info), FunctionType(FunctionType), GlobalType(GlobalType),
EventType(EventType) {}
const wasm::WasmSymbolInfo &Info; const wasm::WasmSymbolInfo &Info;
const wasm::WasmSignature *FunctionType; const wasm::WasmSignature *FunctionType;
const wasm::WasmGlobalType *GlobalType; const wasm::WasmGlobalType *GlobalType;
const wasm::WasmEventType *EventType;
bool isTypeFunction() const { bool isTypeFunction() const {
return Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION; return Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION;
@ -59,6 +62,8 @@ public:
return Info.Kind == wasm::WASM_SYMBOL_TYPE_SECTION; return Info.Kind == wasm::WASM_SYMBOL_TYPE_SECTION;
} }
bool isTypeEvent() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_EVENT; }
bool isDefined() const { return !isUndefined(); } bool isDefined() const { return !isUndefined(); }
bool isUndefined() const { bool isUndefined() const {
@ -130,6 +135,7 @@ public:
ArrayRef<wasm::WasmTable> tables() const { return Tables; } ArrayRef<wasm::WasmTable> tables() const { return Tables; }
ArrayRef<wasm::WasmLimits> memories() const { return Memories; } ArrayRef<wasm::WasmLimits> memories() const { return Memories; }
ArrayRef<wasm::WasmGlobal> globals() const { return Globals; } ArrayRef<wasm::WasmGlobal> globals() const { return Globals; }
ArrayRef<wasm::WasmEvent> events() const { return Events; }
ArrayRef<wasm::WasmExport> exports() const { return Exports; } ArrayRef<wasm::WasmExport> exports() const { return Exports; }
ArrayRef<WasmSymbol> syms() const { return Symbols; } ArrayRef<WasmSymbol> syms() const { return Symbols; }
const wasm::WasmLinkingData &linkingData() const { return LinkingData; } const wasm::WasmLinkingData &linkingData() const { return LinkingData; }
@ -141,6 +147,7 @@ public:
uint32_t startFunction() const { return StartFunction; } uint32_t startFunction() const { return StartFunction; }
uint32_t getNumImportedGlobals() const { return NumImportedGlobals; } uint32_t getNumImportedGlobals() const { return NumImportedGlobals; }
uint32_t getNumImportedFunctions() const { return NumImportedFunctions; } uint32_t getNumImportedFunctions() const { return NumImportedFunctions; }
uint32_t getNumImportedEvents() const { return NumImportedEvents; }
void moveSymbolNext(DataRefImpl &Symb) const override; void moveSymbolNext(DataRefImpl &Symb) const override;
@ -205,12 +212,16 @@ private:
bool isDefinedFunctionIndex(uint32_t Index) const; bool isDefinedFunctionIndex(uint32_t Index) const;
bool isValidGlobalIndex(uint32_t Index) const; bool isValidGlobalIndex(uint32_t Index) const;
bool isDefinedGlobalIndex(uint32_t Index) const; bool isDefinedGlobalIndex(uint32_t Index) const;
bool isValidEventIndex(uint32_t Index) const;
bool isDefinedEventIndex(uint32_t Index) const;
bool isValidFunctionSymbol(uint32_t Index) const; bool isValidFunctionSymbol(uint32_t Index) const;
bool isValidGlobalSymbol(uint32_t Index) const; bool isValidGlobalSymbol(uint32_t Index) const;
bool isValidEventSymbol(uint32_t Index) const;
bool isValidDataSymbol(uint32_t Index) const; bool isValidDataSymbol(uint32_t Index) const;
bool isValidSectionSymbol(uint32_t Index) const; bool isValidSectionSymbol(uint32_t Index) const;
wasm::WasmFunction &getDefinedFunction(uint32_t Index); wasm::WasmFunction &getDefinedFunction(uint32_t Index);
wasm::WasmGlobal &getDefinedGlobal(uint32_t Index); wasm::WasmGlobal &getDefinedGlobal(uint32_t Index);
wasm::WasmEvent &getDefinedEvent(uint32_t Index);
const WasmSection &getWasmSection(DataRefImpl Ref) const; const WasmSection &getWasmSection(DataRefImpl Ref) const;
const wasm::WasmRelocation &getWasmRelocation(DataRefImpl Ref) const; const wasm::WasmRelocation &getWasmRelocation(DataRefImpl Ref) const;
@ -226,6 +237,7 @@ private:
Error parseTableSection(ReadContext &Ctx); Error parseTableSection(ReadContext &Ctx);
Error parseMemorySection(ReadContext &Ctx); Error parseMemorySection(ReadContext &Ctx);
Error parseGlobalSection(ReadContext &Ctx); Error parseGlobalSection(ReadContext &Ctx);
Error parseEventSection(ReadContext &Ctx);
Error parseExportSection(ReadContext &Ctx); Error parseExportSection(ReadContext &Ctx);
Error parseStartSection(ReadContext &Ctx); Error parseStartSection(ReadContext &Ctx);
Error parseElemSection(ReadContext &Ctx); Error parseElemSection(ReadContext &Ctx);
@ -246,6 +258,7 @@ private:
std::vector<wasm::WasmTable> Tables; std::vector<wasm::WasmTable> Tables;
std::vector<wasm::WasmLimits> Memories; std::vector<wasm::WasmLimits> Memories;
std::vector<wasm::WasmGlobal> Globals; std::vector<wasm::WasmGlobal> Globals;
std::vector<wasm::WasmEvent> Events;
std::vector<wasm::WasmImport> Imports; std::vector<wasm::WasmImport> Imports;
std::vector<wasm::WasmExport> Exports; std::vector<wasm::WasmExport> Exports;
std::vector<wasm::WasmElemSegment> ElemSegments; std::vector<wasm::WasmElemSegment> ElemSegments;
@ -258,9 +271,11 @@ private:
wasm::WasmLinkingData LinkingData; wasm::WasmLinkingData LinkingData;
uint32_t NumImportedGlobals = 0; uint32_t NumImportedGlobals = 0;
uint32_t NumImportedFunctions = 0; uint32_t NumImportedFunctions = 0;
uint32_t NumImportedEvents = 0;
uint32_t CodeSection = 0; uint32_t CodeSection = 0;
uint32_t DataSection = 0; uint32_t DataSection = 0;
uint32_t GlobalSection = 0; uint32_t GlobalSection = 0;
uint32_t EventSection = 0;
}; };
} // end namespace object } // end namespace object

View File

@ -74,6 +74,12 @@ struct Global {
wasm::WasmInitExpr InitExpr; wasm::WasmInitExpr InitExpr;
}; };
struct Event {
uint32_t Index;
uint32_t Attribute;
uint32_t SigIndex;
};
struct Import { struct Import {
StringRef Module; StringRef Module;
StringRef Field; StringRef Field;
@ -83,6 +89,7 @@ struct Import {
Global GlobalImport; Global GlobalImport;
Table TableImport; Table TableImport;
Limits Memory; Limits Memory;
Event EventImport;
}; };
}; };
@ -262,6 +269,16 @@ struct GlobalSection : Section {
std::vector<Global> Globals; std::vector<Global> Globals;
}; };
struct EventSection : Section {
EventSection() : Section(wasm::WASM_SEC_EVENT) {}
static bool classof(const Section *S) {
return S->Type == wasm::WASM_SEC_EVENT;
}
std::vector<Event> Events;
};
struct ExportSection : Section { struct ExportSection : Section {
ExportSection() : Section(wasm::WASM_SEC_EXPORT) {} ExportSection() : Section(wasm::WASM_SEC_EXPORT) {}
@ -339,6 +356,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SymbolInfo)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::InitFunction) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::InitFunction)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::ComdatEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::ComdatEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Comdat) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Comdat)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Event)
namespace llvm { namespace llvm {
namespace yaml { namespace yaml {
@ -471,6 +489,10 @@ template <> struct ScalarEnumerationTraits<WasmYAML::RelocType> {
static void enumeration(IO &IO, WasmYAML::RelocType &Kind); static void enumeration(IO &IO, WasmYAML::RelocType &Kind);
}; };
template <> struct MappingTraits<WasmYAML::Event> {
static void mapping(IO &IO, WasmYAML::Event &Event);
};
} // end namespace yaml } // end namespace yaml
} // end namespace llvm } // end namespace llvm

View File

@ -19,6 +19,8 @@ std::string llvm::wasm::toString(wasm::WasmSymbolType type) {
return "WASM_SYMBOL_TYPE_DATA"; return "WASM_SYMBOL_TYPE_DATA";
case wasm::WASM_SYMBOL_TYPE_SECTION: case wasm::WASM_SYMBOL_TYPE_SECTION:
return "WASM_SYMBOL_TYPE_SECTION"; return "WASM_SYMBOL_TYPE_SECTION";
case wasm::WASM_SYMBOL_TYPE_EVENT:
return "WASM_SYMBOL_TYPE_EVENT";
} }
llvm_unreachable("unknown symbol type"); llvm_unreachable("unknown symbol type");
} }

View File

@ -13,9 +13,25 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "WasmException.h" #include "WasmException.h"
#include "llvm/IR/Mangler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCStreamer.h"
using namespace llvm; using namespace llvm;
void WasmException::endModule() {
// This is the symbol used in 'throw' and 'if_except' instruction to denote
// this is a C++ exception. This symbol has to be emitted somewhere once in
// the module. Check if the symbol has already been created, i.e., we have at
// least one 'throw' or 'if_except' instruction in the module, and emit the
// symbol only if so.
SmallString<60> NameStr;
Mangler::getNameWithPrefix(NameStr, "__cpp_exception", Asm->getDataLayout());
if (Asm->OutContext.lookupSymbol(NameStr)) {
MCSymbol *ExceptionSym = Asm->GetExternalSymbolSymbol("__cpp_exception");
Asm->OutStreamer->EmitLabel(ExceptionSym);
}
}
void WasmException::markFunctionEnd() { void WasmException::markFunctionEnd() {
// Get rid of any dead landing pads. // Get rid of any dead landing pads.
if (!Asm->MF->getLandingPads().empty()) { if (!Asm->MF->getLandingPads().empty()) {

View File

@ -24,7 +24,7 @@ class LLVM_LIBRARY_VISIBILITY WasmException : public EHStreamer {
public: public:
WasmException(AsmPrinter *A) : EHStreamer(A) {} WasmException(AsmPrinter *A) : EHStreamer(A) {}
void endModule() override {} void endModule() override;
void beginFunction(const MachineFunction *MF) override {} void beginFunction(const MachineFunction *MF) override {}
virtual void markFunctionEnd() override; virtual void markFunctionEnd() override;
void endFunction(const MachineFunction *MF) override; void endFunction(const MachineFunction *MF) override;

View File

@ -306,6 +306,7 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
case VK_WebAssembly_FUNCTION: return "FUNCTION"; case VK_WebAssembly_FUNCTION: return "FUNCTION";
case VK_WebAssembly_GLOBAL: return "GLOBAL"; case VK_WebAssembly_GLOBAL: return "GLOBAL";
case VK_WebAssembly_TYPEINDEX: return "TYPEINDEX"; case VK_WebAssembly_TYPEINDEX: return "TYPEINDEX";
case VK_WebAssembly_EVENT: return "EVENT";
case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo"; case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo";
case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi"; case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi";
case VK_AMDGPU_REL32_LO: return "rel32@lo"; case VK_AMDGPU_REL32_LO: return "rel32@lo";
@ -421,6 +422,7 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) {
.Case("function", VK_WebAssembly_FUNCTION) .Case("function", VK_WebAssembly_FUNCTION)
.Case("global", VK_WebAssembly_GLOBAL) .Case("global", VK_WebAssembly_GLOBAL)
.Case("typeindex", VK_WebAssembly_TYPEINDEX) .Case("typeindex", VK_WebAssembly_TYPEINDEX)
.Case("event", VK_WebAssembly_EVENT)
.Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO)
.Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI) .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI)
.Case("rel32@lo", VK_AMDGPU_REL32_LO) .Case("rel32@lo", VK_AMDGPU_REL32_LO)

View File

@ -56,10 +56,10 @@ struct SectionBookkeeping {
uint32_t Index; uint32_t Index;
}; };
// The signature of a wasm function, in a struct capable of being used as a // The signature of a wasm function or event, in a struct capable of being used
// DenseMap key. // as a DenseMap key.
// TODO: Consider using WasmSignature directly instead. // TODO: Consider using wasm::WasmSignature directly instead.
struct WasmFunctionType { struct WasmSignature {
// Support empty and tombstone instances, needed by DenseMap. // Support empty and tombstone instances, needed by DenseMap.
enum { Plain, Empty, Tombstone } State; enum { Plain, Empty, Tombstone } State;
@ -69,36 +69,35 @@ struct WasmFunctionType {
// The parameter types of the function. // The parameter types of the function.
SmallVector<wasm::ValType, 4> Params; SmallVector<wasm::ValType, 4> Params;
WasmFunctionType() : State(Plain) {} WasmSignature() : State(Plain) {}
bool operator==(const WasmFunctionType &Other) const { bool operator==(const WasmSignature &Other) const {
return State == Other.State && Returns == Other.Returns && return State == Other.State && Returns == Other.Returns &&
Params == Other.Params; Params == Other.Params;
} }
}; };
// Traits for using WasmFunctionType in a DenseMap. // Traits for using WasmSignature in a DenseMap.
struct WasmFunctionTypeDenseMapInfo { struct WasmSignatureDenseMapInfo {
static WasmFunctionType getEmptyKey() { static WasmSignature getEmptyKey() {
WasmFunctionType FuncTy; WasmSignature Sig;
FuncTy.State = WasmFunctionType::Empty; Sig.State = WasmSignature::Empty;
return FuncTy; return Sig;
} }
static WasmFunctionType getTombstoneKey() { static WasmSignature getTombstoneKey() {
WasmFunctionType FuncTy; WasmSignature Sig;
FuncTy.State = WasmFunctionType::Tombstone; Sig.State = WasmSignature::Tombstone;
return FuncTy; return Sig;
} }
static unsigned getHashValue(const WasmFunctionType &FuncTy) { static unsigned getHashValue(const WasmSignature &Sig) {
uintptr_t Value = FuncTy.State; uintptr_t Value = Sig.State;
for (wasm::ValType Ret : FuncTy.Returns) for (wasm::ValType Ret : Sig.Returns)
Value += DenseMapInfo<uint32_t>::getHashValue(uint32_t(Ret)); Value += DenseMapInfo<uint32_t>::getHashValue(uint32_t(Ret));
for (wasm::ValType Param : FuncTy.Params) for (wasm::ValType Param : Sig.Params)
Value += DenseMapInfo<uint32_t>::getHashValue(uint32_t(Param)); Value += DenseMapInfo<uint32_t>::getHashValue(uint32_t(Param));
return Value; return Value;
} }
static bool isEqual(const WasmFunctionType &LHS, static bool isEqual(const WasmSignature &LHS, const WasmSignature &RHS) {
const WasmFunctionType &RHS) {
return LHS == RHS; return LHS == RHS;
} }
}; };
@ -118,7 +117,7 @@ struct WasmDataSegment {
// A wasm function to be written into the function section. // A wasm function to be written into the function section.
struct WasmFunction { struct WasmFunction {
uint32_t Type; uint32_t SigIndex;
const MCSymbolWasm *Sym; const MCSymbolWasm *Sym;
}; };
@ -216,7 +215,8 @@ class WasmObjectWriter : public MCObjectWriter {
// Maps function symbols to the table element index space. Used // Maps function symbols to the table element index space. Used
// for TABLE_INDEX relocation types (i.e. address taken functions). // for TABLE_INDEX relocation types (i.e. address taken functions).
DenseMap<const MCSymbolWasm *, uint32_t> TableIndices; DenseMap<const MCSymbolWasm *, uint32_t> TableIndices;
// Maps function/global symbols to the function/global/section index space. // Maps function/global symbols to the function/global/event/section index
// space.
DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices; DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices;
// Maps data symbols to the Wasm segment and offset/size with the segment. // Maps data symbols to the Wasm segment and offset/size with the segment.
DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations; DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations;
@ -231,13 +231,13 @@ class WasmObjectWriter : public MCObjectWriter {
// Map from section to defining function symbol. // Map from section to defining function symbol.
DenseMap<const MCSection *, const MCSymbol *> SectionFunctions; DenseMap<const MCSection *, const MCSymbol *> SectionFunctions;
DenseMap<WasmFunctionType, uint32_t, WasmFunctionTypeDenseMapInfo> DenseMap<WasmSignature, uint32_t, WasmSignatureDenseMapInfo> SignatureIndices;
FunctionTypeIndices; SmallVector<WasmSignature, 4> Signatures;
SmallVector<WasmFunctionType, 4> FunctionTypes;
SmallVector<WasmGlobal, 4> Globals; SmallVector<WasmGlobal, 4> Globals;
SmallVector<WasmDataSegment, 4> DataSegments; SmallVector<WasmDataSegment, 4> DataSegments;
unsigned NumFunctionImports = 0; unsigned NumFunctionImports = 0;
unsigned NumGlobalImports = 0; unsigned NumGlobalImports = 0;
unsigned NumEventImports = 0;
uint32_t SectionCount = 0; uint32_t SectionCount = 0;
// TargetObjectWriter wrappers. // TargetObjectWriter wrappers.
@ -266,8 +266,8 @@ private:
TableIndices.clear(); TableIndices.clear();
DataLocations.clear(); DataLocations.clear();
CustomSectionsRelocations.clear(); CustomSectionsRelocations.clear();
FunctionTypeIndices.clear(); SignatureIndices.clear();
FunctionTypes.clear(); Signatures.clear();
Globals.clear(); Globals.clear();
DataSegments.clear(); DataSegments.clear();
SectionFunctions.clear(); SectionFunctions.clear();
@ -294,7 +294,7 @@ private:
void writeValueType(wasm::ValType Ty) { W.OS << static_cast<char>(Ty); } void writeValueType(wasm::ValType Ty) { W.OS << static_cast<char>(Ty); }
void writeTypeSection(ArrayRef<WasmFunctionType> FunctionTypes); void writeTypeSection(ArrayRef<WasmSignature> Signatures);
void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize, void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize,
uint32_t NumElements); uint32_t NumElements);
void writeFunctionSection(ArrayRef<WasmFunction> Functions); void writeFunctionSection(ArrayRef<WasmFunction> Functions);
@ -304,6 +304,7 @@ private:
void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
ArrayRef<WasmFunction> Functions); ArrayRef<WasmFunction> Functions);
void writeDataSection(); void writeDataSection();
void writeEventSection(ArrayRef<wasm::WasmEventType> Events);
void writeRelocSection(uint32_t SectionIndex, StringRef Name, void writeRelocSection(uint32_t SectionIndex, StringRef Name,
std::vector<WasmRelocationEntry> &Relocations); std::vector<WasmRelocationEntry> &Relocations);
void writeLinkingMetaDataSection( void writeLinkingMetaDataSection(
@ -322,7 +323,9 @@ private:
uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry); uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry);
uint32_t getFunctionType(const MCSymbolWasm &Symbol); uint32_t getFunctionType(const MCSymbolWasm &Symbol);
uint32_t getEventType(const MCSymbolWasm &Symbol);
uint32_t registerFunctionType(const MCSymbolWasm &Symbol); uint32_t registerFunctionType(const MCSymbolWasm &Symbol);
uint32_t registerEventType(const MCSymbolWasm &Symbol);
}; };
} // end anonymous namespace } // end anonymous namespace
@ -581,7 +584,8 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
return getRelocationIndexValue(RelEntry); return getRelocationIndexValue(RelEntry);
case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
// Provisional value is function/global Wasm index case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB:
// Provisional value is function/global/event Wasm index
if (!WasmIndices.count(RelEntry.Symbol)) if (!WasmIndices.count(RelEntry.Symbol))
report_fatal_error("symbol not found in wasm index space: " + report_fatal_error("symbol not found in wasm index space: " +
RelEntry.Symbol->getName()); RelEntry.Symbol->getName());
@ -678,6 +682,7 @@ void WasmObjectWriter::applyRelocations(
case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB:
WritePatchableLEB(Stream, Value, Offset); WritePatchableLEB(Stream, Value, Offset);
break; break;
case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
@ -696,23 +701,22 @@ void WasmObjectWriter::applyRelocations(
} }
} }
void WasmObjectWriter::writeTypeSection( void WasmObjectWriter::writeTypeSection(ArrayRef<WasmSignature> Signatures) {
ArrayRef<WasmFunctionType> FunctionTypes) { if (Signatures.empty())
if (FunctionTypes.empty())
return; return;
SectionBookkeeping Section; SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_TYPE); startSection(Section, wasm::WASM_SEC_TYPE);
encodeULEB128(FunctionTypes.size(), W.OS); encodeULEB128(Signatures.size(), W.OS);
for (const WasmFunctionType &FuncTy : FunctionTypes) { for (const WasmSignature &Sig : Signatures) {
W.OS << char(wasm::WASM_TYPE_FUNC); W.OS << char(wasm::WASM_TYPE_FUNC);
encodeULEB128(FuncTy.Params.size(), W.OS); encodeULEB128(Sig.Params.size(), W.OS);
for (wasm::ValType Ty : FuncTy.Params) for (wasm::ValType Ty : Sig.Params)
writeValueType(Ty); writeValueType(Ty);
encodeULEB128(FuncTy.Returns.size(), W.OS); encodeULEB128(Sig.Returns.size(), W.OS);
for (wasm::ValType Ty : FuncTy.Returns) for (wasm::ValType Ty : Sig.Returns)
writeValueType(Ty); writeValueType(Ty);
} }
@ -753,6 +757,10 @@ void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports,
encodeULEB128(0, W.OS); // flags encodeULEB128(0, W.OS); // flags
encodeULEB128(NumElements, W.OS); // initial encodeULEB128(NumElements, W.OS); // initial
break; break;
case wasm::WASM_EXTERNAL_EVENT:
encodeULEB128(Import.Event.Attribute, W.OS);
encodeULEB128(Import.Event.SigIndex, W.OS);
break;
default: default:
llvm_unreachable("unsupported import kind"); llvm_unreachable("unsupported import kind");
} }
@ -770,7 +778,7 @@ void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) {
encodeULEB128(Functions.size(), W.OS); encodeULEB128(Functions.size(), W.OS);
for (const WasmFunction &Func : Functions) for (const WasmFunction &Func : Functions)
encodeULEB128(Func.Type, W.OS); encodeULEB128(Func.SigIndex, W.OS);
endSection(Section); endSection(Section);
} }
@ -795,6 +803,22 @@ void WasmObjectWriter::writeGlobalSection() {
endSection(Section); endSection(Section);
} }
void WasmObjectWriter::writeEventSection(ArrayRef<wasm::WasmEventType> Events) {
if (Events.empty())
return;
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_EVENT);
encodeULEB128(Events.size(), W.OS);
for (const wasm::WasmEventType &Event : Events) {
encodeULEB128(Event.Attribute, W.OS);
encodeULEB128(Event.SigIndex, W.OS);
}
endSection(Section);
}
void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) { void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) {
if (Exports.empty()) if (Exports.empty())
return; return;
@ -956,6 +980,7 @@ void WasmObjectWriter::writeLinkingMetaDataSection(
switch (Sym.Kind) { switch (Sym.Kind) {
case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_FUNCTION:
case wasm::WASM_SYMBOL_TYPE_GLOBAL: case wasm::WASM_SYMBOL_TYPE_GLOBAL:
case wasm::WASM_SYMBOL_TYPE_EVENT:
encodeULEB128(Sym.ElementIndex, W.OS); encodeULEB128(Sym.ElementIndex, W.OS);
if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0)
writeString(Sym.Name); writeString(Sym.Name);
@ -1047,20 +1072,25 @@ uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm &Symbol) {
return TypeIndices[&Symbol]; return TypeIndices[&Symbol];
} }
uint32_t WasmObjectWriter::getEventType(const MCSymbolWasm &Symbol) {
assert(Symbol.isEvent());
assert(TypeIndices.count(&Symbol));
return TypeIndices[&Symbol];
}
uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) { uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) {
assert(Symbol.isFunction()); assert(Symbol.isFunction());
WasmFunctionType F; WasmSignature S;
const MCSymbolWasm *ResolvedSym = ResolveSymbol(Symbol); const MCSymbolWasm *ResolvedSym = ResolveSymbol(Symbol);
if (auto *Sig = ResolvedSym->getSignature()) { if (auto *Sig = ResolvedSym->getSignature()) {
F.Returns = Sig->Returns; S.Returns = Sig->Returns;
F.Params = Sig->Params; S.Params = Sig->Params;
} }
auto Pair = auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size()));
FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
if (Pair.second) if (Pair.second)
FunctionTypes.push_back(F); Signatures.push_back(S);
TypeIndices[&Symbol] = Pair.first->second; TypeIndices[&Symbol] = Pair.first->second;
LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol
@ -1069,6 +1099,28 @@ uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) {
return Pair.first->second; return Pair.first->second;
} }
uint32_t WasmObjectWriter::registerEventType(const MCSymbolWasm &Symbol) {
assert(Symbol.isEvent());
// TODO Currently we don't generate imported exceptions, but if we do, we
// should have a way of infering types of imported exceptions.
WasmSignature S;
if (auto *Sig = Symbol.getSignature()) {
S.Returns = Sig->Returns;
S.Params = Sig->Params;
}
auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size()));
if (Pair.second)
Signatures.push_back(S);
TypeIndices[&Symbol] = Pair.first->second;
LLVM_DEBUG(dbgs() << "registerEventType: " << Symbol << " new:" << Pair.second
<< "\n");
LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n");
return Pair.first->second;
}
static bool isInSymtab(const MCSymbolWasm &Sym) { static bool isInSymtab(const MCSymbolWasm &Sym) {
if (Sym.isUsedInReloc()) if (Sym.isUsedInReloc())
return true; return true;
@ -1100,6 +1152,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
SmallVector<uint32_t, 4> TableElems; SmallVector<uint32_t, 4> TableElems;
SmallVector<wasm::WasmImport, 4> Imports; SmallVector<wasm::WasmImport, 4> Imports;
SmallVector<wasm::WasmExport, 4> Exports; SmallVector<wasm::WasmExport, 4> Exports;
SmallVector<wasm::WasmEventType, 1> Events;
SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos; SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos;
SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs; SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
std::map<StringRef, std::vector<WasmComdatEntry>> Comdats; std::map<StringRef, std::vector<WasmComdatEntry>> Comdats;
@ -1128,7 +1181,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
TableImport.Table.ElemType = wasm::WASM_TYPE_ANYFUNC; TableImport.Table.ElemType = wasm::WASM_TYPE_ANYFUNC;
Imports.push_back(TableImport); Imports.push_back(TableImport);
// Populate FunctionTypeIndices, and Imports and WasmIndices for undefined // Populate SignatureIndices, and Imports and WasmIndices for undefined
// symbols. This must be done before populating WasmIndices for defined // symbols. This must be done before populating WasmIndices for defined
// symbols. // symbols.
for (const MCSymbol &S : Asm.symbols()) { for (const MCSymbol &S : Asm.symbols()) {
@ -1139,6 +1192,9 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
if (WS.isFunction()) if (WS.isFunction())
registerFunctionType(WS); registerFunctionType(WS);
if (WS.isEvent())
registerEventType(WS);
if (WS.isTemporary()) if (WS.isTemporary())
continue; continue;
@ -1163,6 +1219,18 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
Import.Global = WS.getGlobalType(); Import.Global = WS.getGlobalType();
Imports.push_back(Import); Imports.push_back(Import);
WasmIndices[&WS] = NumGlobalImports++; WasmIndices[&WS] = NumGlobalImports++;
} else if (WS.isEvent()) {
if (WS.isWeak())
report_fatal_error("undefined event symbol cannot be weak");
wasm::WasmImport Import;
Import.Module = WS.getModuleName();
Import.Field = WS.getName();
Import.Kind = wasm::WASM_EXTERNAL_EVENT;
Import.Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION;
Import.Event.SigIndex = getEventType(WS);
Imports.push_back(Import);
WasmIndices[&WS] = NumEventImports++;
} }
} }
} }
@ -1254,7 +1322,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
// A definition. Write out the function body. // A definition. Write out the function body.
Index = NumFunctionImports + Functions.size(); Index = NumFunctionImports + Functions.size();
WasmFunction Func; WasmFunction Func;
Func.Type = getFunctionType(WS); Func.SigIndex = getFunctionType(WS);
Func.Sym = &WS; Func.Sym = &WS;
WasmIndices[&WS] = Index; WasmIndices[&WS] = Index;
Functions.push_back(Func); Functions.push_back(Func);
@ -1270,6 +1338,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
} }
LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n"); LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n");
} else if (WS.isData()) { } else if (WS.isData()) {
if (WS.isTemporary() && !WS.getSize()) if (WS.isTemporary() && !WS.getSize())
continue; continue;
@ -1299,6 +1368,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
static_cast<uint32_t>(Size)}; static_cast<uint32_t>(Size)};
DataLocations[&WS] = Ref; DataLocations[&WS] = Ref;
LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n"); LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n");
} else if (WS.isGlobal()) { } else if (WS.isGlobal()) {
// A "true" Wasm global (currently just __stack_pointer) // A "true" Wasm global (currently just __stack_pointer)
if (WS.isDefined()) if (WS.isDefined())
@ -1307,6 +1377,24 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
// An import; the index was assigned above // An import; the index was assigned above
LLVM_DEBUG(dbgs() << " -> global index: " LLVM_DEBUG(dbgs() << " -> global index: "
<< WasmIndices.find(&WS)->second << "\n"); << WasmIndices.find(&WS)->second << "\n");
} else if (WS.isEvent()) {
// C++ exception symbol (__cpp_exception)
unsigned Index;
if (WS.isDefined()) {
Index = NumEventImports + Events.size();
wasm::WasmEventType Event;
Event.SigIndex = getEventType(WS);
Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION;
WasmIndices[&WS] = Index;
Events.push_back(Event);
} else {
// An import; the index was assigned above.
Index = WasmIndices.find(&WS)->second;
}
LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices.find(&WS)->second
<< "\n");
} else { } else {
assert(WS.isSection()); assert(WS.isSection());
} }
@ -1340,7 +1428,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
DataLocations[&WS] = Ref; DataLocations[&WS] = Ref;
LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n"); LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n");
} else { } else {
report_fatal_error("don't yet support global aliases"); report_fatal_error("don't yet support global/event aliases");
} }
} }
@ -1473,12 +1561,13 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
// Write out the Wasm header. // Write out the Wasm header.
writeHeader(Asm); writeHeader(Asm);
writeTypeSection(FunctionTypes); writeTypeSection(Signatures);
writeImportSection(Imports, DataSize, TableElems.size()); writeImportSection(Imports, DataSize, TableElems.size());
writeFunctionSection(Functions); writeFunctionSection(Functions);
// Skip the "table" section; we import the table instead. // Skip the "table" section; we import the table instead.
// Skip the "memory" section; we import the memory instead. // Skip the "memory" section; we import the memory instead.
writeGlobalSection(); writeGlobalSection();
writeEventSection(Events);
writeExportSection(Exports); writeExportSection(Exports);
writeElemSection(TableElems); writeElemSection(TableElems);
writeCodeSection(Asm, Layout, Functions); writeCodeSection(Asm, Layout, Functions);

View File

@ -295,6 +295,8 @@ Error WasmObjectFile::parseSection(WasmSection &Sec) {
return parseMemorySection(Ctx); return parseMemorySection(Ctx);
case wasm::WASM_SEC_GLOBAL: case wasm::WASM_SEC_GLOBAL:
return parseGlobalSection(Ctx); return parseGlobalSection(Ctx);
case wasm::WASM_SEC_EVENT:
return parseEventSection(Ctx);
case wasm::WASM_SEC_EXPORT: case wasm::WASM_SEC_EXPORT:
return parseExportSection(Ctx); return parseExportSection(Ctx);
case wasm::WASM_SEC_START: case wasm::WASM_SEC_START:
@ -439,19 +441,24 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
std::vector<wasm::WasmImport *> ImportedGlobals; std::vector<wasm::WasmImport *> ImportedGlobals;
std::vector<wasm::WasmImport *> ImportedFunctions; std::vector<wasm::WasmImport *> ImportedFunctions;
std::vector<wasm::WasmImport *> ImportedEvents;
ImportedGlobals.reserve(Imports.size()); ImportedGlobals.reserve(Imports.size());
ImportedFunctions.reserve(Imports.size()); ImportedFunctions.reserve(Imports.size());
ImportedEvents.reserve(Imports.size());
for (auto &I : Imports) { for (auto &I : Imports) {
if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION) if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
ImportedFunctions.emplace_back(&I); ImportedFunctions.emplace_back(&I);
else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL) else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
ImportedGlobals.emplace_back(&I); ImportedGlobals.emplace_back(&I);
else if (I.Kind == wasm::WASM_EXTERNAL_EVENT)
ImportedEvents.emplace_back(&I);
} }
while (Count--) { while (Count--) {
wasm::WasmSymbolInfo Info; wasm::WasmSymbolInfo Info;
const wasm::WasmSignature *FunctionType = nullptr; const wasm::WasmSignature *FunctionType = nullptr;
const wasm::WasmGlobalType *GlobalType = nullptr; const wasm::WasmGlobalType *GlobalType = nullptr;
const wasm::WasmEventType *EventType = nullptr;
Info.Kind = readUint8(Ctx); Info.Kind = readUint8(Ctx);
Info.Flags = readVaruint32(Ctx); Info.Flags = readVaruint32(Ctx);
@ -532,6 +539,32 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
break; break;
} }
case wasm::WASM_SYMBOL_TYPE_EVENT: {
Info.ElementIndex = readVaruint32(Ctx);
if (!isValidEventIndex(Info.ElementIndex) ||
IsDefined != isDefinedEventIndex(Info.ElementIndex))
return make_error<GenericBinaryError>("invalid event symbol index",
object_error::parse_failed);
if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
wasm::WASM_SYMBOL_BINDING_WEAK)
return make_error<GenericBinaryError>("undefined weak global symbol",
object_error::parse_failed);
if (IsDefined) {
Info.Name = readString(Ctx);
unsigned EventIndex = Info.ElementIndex - NumImportedEvents;
wasm::WasmEvent &Event = Events[EventIndex];
EventType = &Event.Type;
if (Event.SymbolName.empty())
Event.SymbolName = Info.Name;
} else {
wasm::WasmImport &Import = *ImportedEvents[Info.ElementIndex];
EventType = &Import.Event;
Info.Name = Import.Field;
}
break;
}
default: default:
return make_error<GenericBinaryError>("Invalid symbol type", return make_error<GenericBinaryError>("Invalid symbol type",
object_error::parse_failed); object_error::parse_failed);
@ -545,7 +578,7 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
object_error::parse_failed); object_error::parse_failed);
LinkingData.SymbolTable.emplace_back(Info); LinkingData.SymbolTable.emplace_back(Info);
Symbols.emplace_back(LinkingData.SymbolTable.back(), FunctionType, Symbols.emplace_back(LinkingData.SymbolTable.back(), FunctionType,
GlobalType); GlobalType, EventType);
LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n"); LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
} }
@ -635,6 +668,11 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
return make_error<GenericBinaryError>("Bad relocation global index", return make_error<GenericBinaryError>("Bad relocation global index",
object_error::parse_failed); object_error::parse_failed);
break; break;
case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB:
if (!isValidEventSymbol(Reloc.Index))
return make_error<GenericBinaryError>("Bad relocation event index",
object_error::parse_failed);
break;
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
@ -755,6 +793,11 @@ Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
return make_error<GenericBinaryError>("Invalid table element type", return make_error<GenericBinaryError>("Invalid table element type",
object_error::parse_failed); object_error::parse_failed);
break; break;
case wasm::WASM_EXTERNAL_EVENT:
NumImportedEvents++;
Im.Event.Attribute = readVarint32(Ctx);
Im.Event.SigIndex = readVarint32(Ctx);
break;
default: default:
return make_error<GenericBinaryError>("Unexpected import kind", return make_error<GenericBinaryError>("Unexpected import kind",
object_error::parse_failed); object_error::parse_failed);
@ -831,6 +874,24 @@ Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
return Error::success(); return Error::success();
} }
Error WasmObjectFile::parseEventSection(ReadContext &Ctx) {
EventSection = Sections.size();
uint32_t Count = readVarint32(Ctx);
Events.reserve(Count);
while (Count--) {
wasm::WasmEvent Event;
Event.Index = NumImportedEvents + Events.size();
Event.Type.Attribute = readVaruint32(Ctx);
Event.Type.SigIndex = readVarint32(Ctx);
Events.push_back(Event);
}
if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("Event section ended prematurely",
object_error::parse_failed);
return Error::success();
}
Error WasmObjectFile::parseExportSection(ReadContext &Ctx) { Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
uint32_t Count = readVaruint32(Ctx); uint32_t Count = readVaruint32(Ctx);
Exports.reserve(Count); Exports.reserve(Count);
@ -850,6 +911,11 @@ Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
return make_error<GenericBinaryError>("Invalid global export", return make_error<GenericBinaryError>("Invalid global export",
object_error::parse_failed); object_error::parse_failed);
break; break;
case wasm::WASM_EXTERNAL_EVENT:
if (!isValidEventIndex(Ex.Index))
return make_error<GenericBinaryError>("Invalid event export",
object_error::parse_failed);
break;
case wasm::WASM_EXTERNAL_MEMORY: case wasm::WASM_EXTERNAL_MEMORY:
case wasm::WASM_EXTERNAL_TABLE: case wasm::WASM_EXTERNAL_TABLE:
break; break;
@ -881,6 +947,14 @@ bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
return Index >= NumImportedGlobals && isValidGlobalIndex(Index); return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
} }
bool WasmObjectFile::isValidEventIndex(uint32_t Index) const {
return Index < NumImportedEvents + Events.size();
}
bool WasmObjectFile::isDefinedEventIndex(uint32_t Index) const {
return Index >= NumImportedEvents && isValidEventIndex(Index);
}
bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const { bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
return Index < Symbols.size() && Symbols[Index].isTypeFunction(); return Index < Symbols.size() && Symbols[Index].isTypeFunction();
} }
@ -889,6 +963,10 @@ bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
return Index < Symbols.size() && Symbols[Index].isTypeGlobal(); return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
} }
bool WasmObjectFile::isValidEventSymbol(uint32_t Index) const {
return Index < Symbols.size() && Symbols[Index].isTypeEvent();
}
bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const { bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
return Index < Symbols.size() && Symbols[Index].isTypeData(); return Index < Symbols.size() && Symbols[Index].isTypeData();
} }
@ -907,6 +985,11 @@ wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) {
return Globals[Index - NumImportedGlobals]; return Globals[Index - NumImportedGlobals];
} }
wasm::WasmEvent &WasmObjectFile::getDefinedEvent(uint32_t Index) {
assert(isDefinedEventIndex(Index));
return Events[Index - NumImportedEvents];
}
Error WasmObjectFile::parseStartSection(ReadContext &Ctx) { Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
StartFunction = readVaruint32(Ctx); StartFunction = readVaruint32(Ctx);
if (!isValidFunctionIndex(StartFunction)) if (!isValidFunctionIndex(StartFunction))
@ -1070,6 +1153,7 @@ uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
switch (Sym.Info.Kind) { switch (Sym.Info.Kind) {
case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_FUNCTION:
case wasm::WASM_SYMBOL_TYPE_GLOBAL: case wasm::WASM_SYMBOL_TYPE_GLOBAL:
case wasm::WASM_SYMBOL_TYPE_EVENT:
return Sym.Info.ElementIndex; return Sym.Info.ElementIndex;
case wasm::WASM_SYMBOL_TYPE_DATA: { case wasm::WASM_SYMBOL_TYPE_DATA: {
// The value of a data symbol is the segment offset, plus the symbol // The value of a data symbol is the segment offset, plus the symbol
@ -1112,6 +1196,8 @@ WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
return SymbolRef::ST_Data; return SymbolRef::ST_Data;
case wasm::WASM_SYMBOL_TYPE_SECTION: case wasm::WASM_SYMBOL_TYPE_SECTION:
return SymbolRef::ST_Debug; return SymbolRef::ST_Debug;
case wasm::WASM_SYMBOL_TYPE_EVENT:
return SymbolRef::ST_Other;
} }
llvm_unreachable("Unknown WasmSymbol::SymbolType"); llvm_unreachable("Unknown WasmSymbol::SymbolType");
@ -1135,10 +1221,12 @@ WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
case wasm::WASM_SYMBOL_TYPE_DATA: case wasm::WASM_SYMBOL_TYPE_DATA:
Ref.d.a = DataSection; Ref.d.a = DataSection;
break; break;
case wasm::WASM_SYMBOL_TYPE_SECTION: { case wasm::WASM_SYMBOL_TYPE_SECTION:
Ref.d.a = Sym.Info.ElementIndex; Ref.d.a = Sym.Info.ElementIndex;
break; break;
} case wasm::WASM_SYMBOL_TYPE_EVENT:
Ref.d.a = EventSection;
break;
default: default:
llvm_unreachable("Unknown WasmSymbol::SymbolType"); llvm_unreachable("Unknown WasmSymbol::SymbolType");
} }
@ -1161,6 +1249,7 @@ std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec,
ECase(TABLE); ECase(TABLE);
ECase(MEMORY); ECase(MEMORY);
ECase(GLOBAL); ECase(GLOBAL);
ECase(EVENT);
ECase(EXPORT); ECase(EXPORT);
ECase(START); ECase(START);
ECase(ELEM); ECase(ELEM);

View File

@ -100,6 +100,11 @@ static void sectionMapping(IO &IO, WasmYAML::GlobalSection &Section) {
IO.mapOptional("Globals", Section.Globals); IO.mapOptional("Globals", Section.Globals);
} }
static void sectionMapping(IO &IO, WasmYAML::EventSection &Section) {
commonSectionMapping(IO, Section);
IO.mapOptional("Events", Section.Events);
}
static void sectionMapping(IO &IO, WasmYAML::ExportSection &Section) { static void sectionMapping(IO &IO, WasmYAML::ExportSection &Section) {
commonSectionMapping(IO, Section); commonSectionMapping(IO, Section);
IO.mapOptional("Exports", Section.Exports); IO.mapOptional("Exports", Section.Exports);
@ -187,6 +192,11 @@ void MappingTraits<std::unique_ptr<WasmYAML::Section>>::mapping(
Section.reset(new WasmYAML::GlobalSection()); Section.reset(new WasmYAML::GlobalSection());
sectionMapping(IO, *cast<WasmYAML::GlobalSection>(Section.get())); sectionMapping(IO, *cast<WasmYAML::GlobalSection>(Section.get()));
break; break;
case wasm::WASM_SEC_EVENT:
if (!IO.outputting())
Section.reset(new WasmYAML::EventSection());
sectionMapping(IO, *cast<WasmYAML::EventSection>(Section.get()));
break;
case wasm::WASM_SEC_EXPORT: case wasm::WASM_SEC_EXPORT:
if (!IO.outputting()) if (!IO.outputting())
Section.reset(new WasmYAML::ExportSection()); Section.reset(new WasmYAML::ExportSection());
@ -227,6 +237,7 @@ void ScalarEnumerationTraits<WasmYAML::SectionType>::enumeration(
ECase(TABLE); ECase(TABLE);
ECase(MEMORY); ECase(MEMORY);
ECase(GLOBAL); ECase(GLOBAL);
ECase(EVENT);
ECase(EXPORT); ECase(EXPORT);
ECase(START); ECase(START);
ECase(ELEM); ECase(ELEM);
@ -307,6 +318,9 @@ void MappingTraits<WasmYAML::Import>::mapping(IO &IO,
} else if (Import.Kind == wasm::WASM_EXTERNAL_GLOBAL) { } else if (Import.Kind == wasm::WASM_EXTERNAL_GLOBAL) {
IO.mapRequired("GlobalType", Import.GlobalImport.Type); IO.mapRequired("GlobalType", Import.GlobalImport.Type);
IO.mapRequired("GlobalMutable", Import.GlobalImport.Mutable); IO.mapRequired("GlobalMutable", Import.GlobalImport.Mutable);
} else if (Import.Kind == wasm::WASM_EXTERNAL_EVENT) {
IO.mapRequired("EventAttribute", Import.EventImport.Attribute);
IO.mapRequired("EventSigIndex", Import.EventImport.SigIndex);
} else if (Import.Kind == wasm::WASM_EXTERNAL_TABLE) { } else if (Import.Kind == wasm::WASM_EXTERNAL_TABLE) {
IO.mapRequired("Table", Import.TableImport); IO.mapRequired("Table", Import.TableImport);
} else if (Import.Kind == wasm::WASM_EXTERNAL_MEMORY) { } else if (Import.Kind == wasm::WASM_EXTERNAL_MEMORY) {
@ -399,6 +413,8 @@ void MappingTraits<WasmYAML::SymbolInfo>::mapping(IO &IO,
IO.mapRequired("Function", Info.ElementIndex); IO.mapRequired("Function", Info.ElementIndex);
} else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL) { } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL) {
IO.mapRequired("Global", Info.ElementIndex); IO.mapRequired("Global", Info.ElementIndex);
} else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_EVENT) {
IO.mapRequired("Event", Info.ElementIndex);
} else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_DATA) { } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_DATA) {
if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) { if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) {
IO.mapRequired("Segment", Info.DataRef.Segment); IO.mapRequired("Segment", Info.DataRef.Segment);
@ -412,6 +428,12 @@ void MappingTraits<WasmYAML::SymbolInfo>::mapping(IO &IO,
} }
} }
void MappingTraits<WasmYAML::Event>::mapping(IO &IO, WasmYAML::Event &Event) {
IO.mapRequired("Index", Event.Index);
IO.mapRequired("Attribute", Event.Attribute);
IO.mapRequired("SigIndex", Event.SigIndex);
}
void ScalarBitSetTraits<WasmYAML::LimitFlags>::bitset( void ScalarBitSetTraits<WasmYAML::LimitFlags>::bitset(
IO &IO, WasmYAML::LimitFlags &Value) { IO &IO, WasmYAML::LimitFlags &Value) {
#define BCase(X) IO.bitSetCase(Value, #X, wasm::WASM_LIMITS_FLAG_##X) #define BCase(X) IO.bitSetCase(Value, #X, wasm::WASM_LIMITS_FLAG_##X)
@ -443,6 +465,7 @@ void ScalarEnumerationTraits<WasmYAML::SymbolKind>::enumeration(
ECase(DATA); ECase(DATA);
ECase(GLOBAL); ECase(GLOBAL);
ECase(SECTION); ECase(SECTION);
ECase(EVENT);
#undef ECase #undef ECase
} }
@ -467,6 +490,7 @@ void ScalarEnumerationTraits<WasmYAML::ExportKind>::enumeration(
ECase(TABLE); ECase(TABLE);
ECase(MEMORY); ECase(MEMORY);
ECase(GLOBAL); ECase(GLOBAL);
ECase(EVENT);
#undef ECase #undef ECase
} }

View File

@ -86,6 +86,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
const MCOperand &MO = MI.getOperand(i); const MCOperand &MO = MI.getOperand(i);
if (MO.isReg()) { if (MO.isReg()) {
/* nothing to encode */ /* nothing to encode */
} else if (MO.isImm()) { } else if (MO.isImm()) {
if (i < Desc.getNumOperands()) { if (i < Desc.getNumOperands()) {
assert(Desc.TSFlags == 0 && assert(Desc.TSFlags == 0 &&
@ -128,6 +129,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
WebAssemblyII::VariableOpImmediateIsLabel)); WebAssemblyII::VariableOpImmediateIsLabel));
encodeULEB128(uint64_t(MO.getImm()), OS); encodeULEB128(uint64_t(MO.getImm()), OS);
} }
} else if (MO.isFPImm()) { } else if (MO.isFPImm()) {
assert(i < Desc.getNumOperands() && assert(i < Desc.getNumOperands() &&
"Unexpected floating-point immediate as a non-fixed operand"); "Unexpected floating-point immediate as a non-fixed operand");
@ -144,22 +146,27 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
double d = MO.getFPImm(); double d = MO.getFPImm();
support::endian::write<double>(OS, d, support::little); support::endian::write<double>(OS, d, support::little);
} }
} else if (MO.isExpr()) { } else if (MO.isExpr()) {
const MCOperandInfo &Info = Desc.OpInfo[i]; const MCOperandInfo &Info = Desc.OpInfo[i];
llvm::MCFixupKind FixupKind; llvm::MCFixupKind FixupKind;
size_t PaddedSize = 5; size_t PaddedSize = 5;
if (Info.OperandType == WebAssembly::OPERAND_I32IMM) { switch (Info.OperandType) {
case WebAssembly::OPERAND_I32IMM:
FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i32); FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i32);
} else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) { break;
case WebAssembly::OPERAND_I64IMM:
FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i64); FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i64);
PaddedSize = 10; PaddedSize = 10;
} else if (Info.OperandType == WebAssembly::OPERAND_FUNCTION32 || break;
Info.OperandType == WebAssembly::OPERAND_OFFSET32 || case WebAssembly::OPERAND_FUNCTION32:
Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) { case WebAssembly::OPERAND_OFFSET32:
case WebAssembly::OPERAND_TYPEINDEX:
case WebAssembly::OPERAND_GLOBAL:
case WebAssembly::OPERAND_EVENT:
FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32); FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32);
} else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) { break;
FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32); default:
} else {
llvm_unreachable("unexpected symbolic operand kind"); llvm_unreachable("unexpected symbolic operand kind");
} }
Fixups.push_back(MCFixup::create(OS.tell() - Start, MO.getExpr(), Fixups.push_back(MCFixup::create(OS.tell() - Start, MO.getExpr(),

View File

@ -77,6 +77,8 @@ enum OperandType {
OPERAND_SIGNATURE, OPERAND_SIGNATURE,
/// type signature immediate for call_indirect. /// type signature immediate for call_indirect.
OPERAND_TYPEINDEX, OPERAND_TYPEINDEX,
/// Event index.
OPERAND_EVENT,
}; };
} // end namespace WebAssembly } // end namespace WebAssembly
@ -97,7 +99,8 @@ enum TOF {
// Flags to indicate the type of the symbol being referenced // Flags to indicate the type of the symbol being referenced
MO_SYMBOL_FUNCTION = 0x1, MO_SYMBOL_FUNCTION = 0x1,
MO_SYMBOL_GLOBAL = 0x2, MO_SYMBOL_GLOBAL = 0x2,
MO_SYMBOL_MASK = 0x3, MO_SYMBOL_EVENT = 0x4,
MO_SYMBOL_MASK = 0x7,
}; };
} // end namespace WebAssemblyII } // end namespace WebAssemblyII

View File

@ -100,12 +100,28 @@ void WebAssemblyTargetAsmStreamer::emitIndirectFunctionType(
} }
void WebAssemblyTargetAsmStreamer::emitGlobalType(MCSymbolWasm *Sym) { void WebAssemblyTargetAsmStreamer::emitGlobalType(MCSymbolWasm *Sym) {
assert(Sym->isGlobal());
OS << "\t.globaltype\t" << Sym->getName() << ", " << OS << "\t.globaltype\t" << Sym->getName() << ", " <<
WebAssembly::TypeToString( WebAssembly::TypeToString(
static_cast<wasm::ValType>(Sym->getGlobalType().Type)) << static_cast<wasm::ValType>(Sym->getGlobalType().Type)) <<
'\n'; '\n';
} }
void WebAssemblyTargetAsmStreamer::emitEventType(MCSymbolWasm *Sym) {
assert(Sym->isEvent());
OS << "\t.eventtype\t" << Sym->getName();
if (Sym->getSignature()->Returns.empty())
OS << ", void";
else {
assert(Sym->getSignature()->Returns.size() == 1);
OS << ", "
<< WebAssembly::TypeToString(Sym->getSignature()->Returns.front());
}
for (auto Ty : Sym->getSignature()->Params)
OS << ", " << WebAssembly::TypeToString(Ty);
OS << '\n';
}
void WebAssemblyTargetAsmStreamer::emitImportModule(MCSymbolWasm *Sym, void WebAssemblyTargetAsmStreamer::emitImportModule(MCSymbolWasm *Sym,
StringRef ModuleName) { StringRef ModuleName) {
OS << "\t.import_module\t" << Sym->getName() << ", " << ModuleName << '\n'; OS << "\t.import_module\t" << Sym->getName() << ", " << ModuleName << '\n';
@ -159,6 +175,9 @@ void WebAssemblyTargetWasmStreamer::emitGlobalType(MCSymbolWasm *Sym) {
// Not needed. // Not needed.
} }
void WebAssemblyTargetWasmStreamer::emitEventType(MCSymbolWasm *Sym) {
// Not needed.
}
void WebAssemblyTargetWasmStreamer::emitImportModule(MCSymbolWasm *Sym, void WebAssemblyTargetWasmStreamer::emitImportModule(MCSymbolWasm *Sym,
StringRef ModuleName) { StringRef ModuleName) {
Sym->setModuleName(ModuleName); Sym->setModuleName(ModuleName);

View File

@ -45,6 +45,8 @@ public:
virtual void emitIndIdx(const MCExpr *Value) = 0; virtual void emitIndIdx(const MCExpr *Value) = 0;
/// .globaltype /// .globaltype
virtual void emitGlobalType(MCSymbolWasm *Sym) = 0; virtual void emitGlobalType(MCSymbolWasm *Sym) = 0;
/// .eventtype
virtual void emitEventType(MCSymbolWasm *Sym) = 0;
/// .import_module /// .import_module
virtual void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) = 0; virtual void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) = 0;
@ -66,6 +68,7 @@ public:
void emitIndirectFunctionType(MCSymbolWasm *Symbol) override; void emitIndirectFunctionType(MCSymbolWasm *Symbol) override;
void emitIndIdx(const MCExpr *Value) override; void emitIndIdx(const MCExpr *Value) override;
void emitGlobalType(MCSymbolWasm *Sym) override; void emitGlobalType(MCSymbolWasm *Sym) override;
void emitEventType(MCSymbolWasm *Sym) override;
void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) override; void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) override;
}; };
@ -81,6 +84,7 @@ public:
void emitIndirectFunctionType(MCSymbolWasm *Symbol) override; void emitIndirectFunctionType(MCSymbolWasm *Symbol) override;
void emitIndIdx(const MCExpr *Value) override; void emitIndIdx(const MCExpr *Value) override;
void emitGlobalType(MCSymbolWasm *Sym) override; void emitGlobalType(MCSymbolWasm *Sym) override;
void emitEventType(MCSymbolWasm *Sym) override;
void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) override; void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) override;
}; };

View File

@ -86,6 +86,11 @@ static bool IsGlobalType(const MCValue &Target) {
return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_GLOBAL; return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_GLOBAL;
} }
static bool IsEventType(const MCValue &Target) {
const MCSymbolRefExpr *RefA = Target.getSymA();
return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_EVENT;
}
unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target, unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
const MCFixup &Fixup) const { const MCFixup &Fixup) const {
// WebAssembly functions are not allocated in the data address space. To // WebAssembly functions are not allocated in the data address space. To
@ -106,6 +111,8 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
return wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB; return wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB;
if (IsFunction) if (IsFunction)
return wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB; return wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB;
if (IsEventType(Target))
return wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB;
return wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB; return wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB;
case FK_Data_4: case FK_Data_4:
if (IsFunction) if (IsFunction)

View File

@ -79,11 +79,12 @@ WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() {
void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
for (auto &It : OutContext.getSymbols()) { for (auto &It : OutContext.getSymbols()) {
// Emit a .globaltype declaration. // Emit a .globaltype and .eventtype declaration.
auto Sym = cast<MCSymbolWasm>(It.getValue()); auto Sym = cast<MCSymbolWasm>(It.getValue());
if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL) { if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL)
getTargetStreamer()->emitGlobalType(Sym); getTargetStreamer()->emitGlobalType(Sym);
} else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_EVENT)
getTargetStreamer()->emitEventType(Sym);
} }
for (const auto &F : M) { for (const auto &F : M) {

View File

@ -25,5 +25,6 @@ HANDLE_NODETYPE(SHUFFLE)
HANDLE_NODETYPE(VEC_SHL) HANDLE_NODETYPE(VEC_SHL)
HANDLE_NODETYPE(VEC_SHR_S) HANDLE_NODETYPE(VEC_SHR_S)
HANDLE_NODETYPE(VEC_SHR_U) HANDLE_NODETYPE(VEC_SHR_U)
HANDLE_NODETYPE(THROW)
// add memory opcodes starting at ISD::FIRST_TARGET_MEMORY_OPCODE here... // add memory opcodes starting at ISD::FIRST_TARGET_MEMORY_OPCODE here...

View File

@ -24,6 +24,7 @@
#include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/WasmEHFuncInfo.h"
#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/Function.h" #include "llvm/IR/Function.h"
@ -234,6 +235,7 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
// Exception handling intrinsics // Exception handling intrinsics
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
setMaxAtomicSizeInBitsSupported(64); setMaxAtomicSizeInBitsSupported(64);
} }
@ -882,6 +884,8 @@ SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
case ISD::EXTRACT_VECTOR_ELT: case ISD::EXTRACT_VECTOR_ELT:
case ISD::INSERT_VECTOR_ELT: case ISD::INSERT_VECTOR_ELT:
return LowerAccessVectorElement(Op, DAG); return LowerAccessVectorElement(Op, DAG);
case ISD::INTRINSIC_VOID:
return LowerINTRINSIC_VOID(Op, DAG);
case ISD::VECTOR_SHUFFLE: case ISD::VECTOR_SHUFFLE:
return LowerVECTOR_SHUFFLE(Op, DAG); return LowerVECTOR_SHUFFLE(Op, DAG);
case ISD::SHL: case ISD::SHL:
@ -1045,6 +1049,44 @@ WebAssemblyTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
} }
} }
SDValue
WebAssemblyTargetLowering::LowerINTRINSIC_VOID(SDValue Op,
SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
SDLoc DL(Op);
switch (IntNo) {
default:
return {}; // Don't custom lower most intrinsics.
case Intrinsic::wasm_throw: {
int Tag = cast<ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue();
switch (Tag) {
case CPP_EXCEPTION: {
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
const char *SymName = MF.createExternalSymbolName("__cpp_exception");
SDValue SymNode =
DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
DAG.getTargetExternalSymbol(
SymName, PtrVT, WebAssemblyII::MO_SYMBOL_EVENT));
return DAG.getNode(WebAssemblyISD::THROW, DL,
MVT::Other, // outchain type
{
Op.getOperand(0), // inchain
SymNode, // exception symbol
Op.getOperand(3) // thrown value
});
}
default:
llvm_unreachable("Invalid tag!");
}
break;
}
}
}
SDValue SDValue
WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
SelectionDAG &DAG) const { SelectionDAG &DAG) const {

View File

@ -98,6 +98,7 @@ private:
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerCopyToReg(SDValue Op, SelectionDAG &DAG) const; SDValue LowerCopyToReg(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerAccessVectorElement(SDValue Op, SelectionDAG &DAG) const; SDValue LowerAccessVectorElement(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerShift(SDValue Op, SelectionDAG &DAG) const; SDValue LowerShift(SDValue Op, SelectionDAG &DAG) const;

View File

@ -146,14 +146,16 @@ let Predicates = [HasExceptionHandling] in {
// Throwing an exception: throw / rethrow // Throwing an exception: throw / rethrow
let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in { let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
defm THROW_I32 : I<(outs), (ins i32imm:$tag, I32:$val), defm THROW_I32 : I<(outs), (ins event_op:$tag, I32:$val),
(outs), (ins i32imm:$tag), (outs), (ins event_op:$tag),
[(int_wasm_throw imm:$tag, I32:$val)], [(WebAssemblythrow (WebAssemblywrapper texternalsym:$tag),
I32:$val)],
"throw \t$tag, $val", "throw \t$tag", "throw \t$tag, $val", "throw \t$tag",
0x08>; 0x08>;
defm THROW_I64 : I<(outs), (ins i32imm:$tag, I64:$val), defm THROW_I64 : I<(outs), (ins event_op:$tag, I64:$val),
(outs), (ins i32imm:$tag), (outs), (ins event_op:$tag),
[(int_wasm_throw imm:$tag, I64:$val)], [(WebAssemblythrow (WebAssemblywrapper texternalsym:$tag),
I64:$val)],
"throw \t$tag, $val", "throw \t$tag", "throw \t$tag, $val", "throw \t$tag",
0x08>; 0x08>;
defm RETHROW : NRI<(outs), (ins bb_op:$dst), [], "rethrow \t$dst", 0x09>; defm RETHROW : NRI<(outs), (ins bb_op:$dst), [], "rethrow \t$dst", 0x09>;

View File

@ -64,6 +64,7 @@ def SDT_WebAssemblyArgument : SDTypeProfile<1, 1, [SDTCisVT<1, i32>]>;
def SDT_WebAssemblyReturn : SDTypeProfile<0, -1, []>; def SDT_WebAssemblyReturn : SDTypeProfile<0, -1, []>;
def SDT_WebAssemblyWrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, def SDT_WebAssemblyWrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>,
SDTCisPtrTy<0>]>; SDTCisPtrTy<0>]>;
def SDT_WebAssemblyThrow : SDTypeProfile<0, 2, [SDTCisPtrTy<0>]>;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// WebAssembly-specific DAG Nodes. // WebAssembly-specific DAG Nodes.
@ -90,6 +91,8 @@ def WebAssemblyreturn : SDNode<"WebAssemblyISD::RETURN",
SDT_WebAssemblyReturn, [SDNPHasChain]>; SDT_WebAssemblyReturn, [SDNPHasChain]>;
def WebAssemblywrapper : SDNode<"WebAssemblyISD::Wrapper", def WebAssemblywrapper : SDNode<"WebAssemblyISD::Wrapper",
SDT_WebAssemblyWrapper>; SDT_WebAssemblyWrapper>;
def WebAssemblythrow : SDNode<"WebAssemblyISD::THROW", SDT_WebAssemblyThrow,
[SDNPHasChain]>;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// WebAssembly-specific Operands. // WebAssembly-specific Operands.
@ -140,6 +143,10 @@ let OperandType = "OPERAND_P2ALIGN" in {
def P2Align : Operand<i32> { def P2Align : Operand<i32> {
let PrintMethod = "printWebAssemblyP2AlignOperand"; let PrintMethod = "printWebAssemblyP2AlignOperand";
} }
let OperandType = "OPERAND_EVENT" in
def event_op : Operand<i32>;
} // OperandType = "OPERAND_P2ALIGN" } // OperandType = "OPERAND_P2ALIGN"
let OperandType = "OPERAND_SIGNATURE" in { let OperandType = "OPERAND_SIGNATURE" in {

View File

@ -75,10 +75,10 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
cast<MCSymbolWasm>(Printer.GetExternalSymbolSymbol(Name)); cast<MCSymbolWasm>(Printer.GetExternalSymbolSymbol(Name));
const WebAssemblySubtarget &Subtarget = Printer.getSubtarget(); const WebAssemblySubtarget &Subtarget = Printer.getSubtarget();
// __stack_pointer is a global variable; all other external symbols used by // Except for the two exceptions (__stack_pointer and __cpp_exception), all
// CodeGen are functions. It's OK to hardcode knowledge of specific symbols // other external symbols used by CodeGen are functions. It's OK to hardcode
// here; this method is precisely there for fetching the signatures of known // knowledge of specific symbols here; this method is precisely there for
// Clang-provided symbols. // fetching the signatures of known Clang-provided symbols.
if (strcmp(Name, "__stack_pointer") == 0) { if (strcmp(Name, "__stack_pointer") == 0) {
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
WasmSym->setGlobalType(wasm::WasmGlobalType{ WasmSym->setGlobalType(wasm::WasmGlobalType{
@ -90,23 +90,44 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
SmallVector<wasm::ValType, 4> Returns; SmallVector<wasm::ValType, 4> Returns;
SmallVector<wasm::ValType, 4> Params; SmallVector<wasm::ValType, 4> Params;
if (strcmp(Name, "__cpp_exception") == 0) {
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT);
// We can't confirm its signature index for now because there can be
// imported exceptions. Set it to be 0 for now.
WasmSym->setEventType(
{wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION, /* SigIndex */ 0});
// We may have multiple C++ compilation units to be linked together, each of
// which defines the exception symbol. To resolve them, we declare them as
// weak.
WasmSym->setWeak(true);
WasmSym->setExternal(true);
// All C++ exceptions are assumed to have a single i32 (for wasm32) or i64
// (for wasm64) param type and void return type. The reaon is, all C++
// exception values are pointers, and to share the type section with
// functions, exceptions are assumed to have void return type.
Params.push_back(Subtarget.hasAddr64() ? wasm::ValType::I64
: wasm::ValType::I32);
} else { // Function symbols
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
GetLibcallSignature(Subtarget, Name, Returns, Params); GetLibcallSignature(Subtarget, Name, Returns, Params);
}
auto Signature = auto Signature =
make_unique<wasm::WasmSignature>(std::move(Returns), std::move(Params)); make_unique<wasm::WasmSignature>(std::move(Returns), std::move(Params));
WasmSym->setSignature(Signature.get()); WasmSym->setSignature(Signature.get());
Printer.addSignature(std::move(Signature)); Printer.addSignature(std::move(Signature));
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
return WasmSym; return WasmSym;
} }
MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym, MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym,
int64_t Offset, int64_t Offset,
bool IsFunc, bool IsFunc, bool IsGlob,
bool IsGlob) const { bool IsEvent) const {
MCSymbolRefExpr::VariantKind VK = MCSymbolRefExpr::VariantKind VK =
IsFunc ? MCSymbolRefExpr::VK_WebAssembly_FUNCTION IsFunc ? MCSymbolRefExpr::VK_WebAssembly_FUNCTION
: IsGlob ? MCSymbolRefExpr::VK_WebAssembly_GLOBAL : IsGlob ? MCSymbolRefExpr::VK_WebAssembly_GLOBAL
: IsEvent ? MCSymbolRefExpr::VK_WebAssembly_EVENT
: MCSymbolRefExpr::VK_None; : MCSymbolRefExpr::VK_None;
const MCExpr *Expr = MCSymbolRefExpr::create(Sym, VK, Ctx); const MCExpr *Expr = MCSymbolRefExpr::create(Sym, VK, Ctx);
@ -116,6 +137,8 @@ MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym,
report_fatal_error("Function addresses with offsets not supported"); report_fatal_error("Function addresses with offsets not supported");
if (IsGlob) if (IsGlob)
report_fatal_error("Global indexes with offsets not supported"); report_fatal_error("Global indexes with offsets not supported");
if (IsEvent)
report_fatal_error("Event indexes with offsets not supported");
Expr = Expr =
MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, Ctx), Ctx); MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, Ctx), Ctx);
} }
@ -218,7 +241,7 @@ void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
"WebAssembly does not use target flags on GlobalAddresses"); "WebAssembly does not use target flags on GlobalAddresses");
MCOp = LowerSymbolOperand(GetGlobalAddressSymbol(MO), MO.getOffset(), MCOp = LowerSymbolOperand(GetGlobalAddressSymbol(MO), MO.getOffset(),
MO.getGlobal()->getValueType()->isFunctionTy(), MO.getGlobal()->getValueType()->isFunctionTy(),
false); false, false);
break; break;
case MachineOperand::MO_ExternalSymbol: case MachineOperand::MO_ExternalSymbol:
// The target flag indicates whether this is a symbol for a // The target flag indicates whether this is a symbol for a
@ -228,14 +251,16 @@ void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
MCOp = LowerSymbolOperand( MCOp = LowerSymbolOperand(
GetExternalSymbolSymbol(MO), /*Offset=*/0, GetExternalSymbolSymbol(MO), /*Offset=*/0,
(MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_FUNCTION) != 0, (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_FUNCTION) != 0,
(MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_GLOBAL) != 0); (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_GLOBAL) != 0,
(MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_EVENT) != 0);
break; break;
case MachineOperand::MO_MCSymbol: case MachineOperand::MO_MCSymbol:
// This is currently used only for LSDA symbols (GCC_except_table), // This is currently used only for LSDA symbols (GCC_except_table),
// because global addresses or other external symbols are handled above. // because global addresses or other external symbols are handled above.
assert(MO.getTargetFlags() == 0 && assert(MO.getTargetFlags() == 0 &&
"WebAssembly does not use target flags on MCSymbol"); "WebAssembly does not use target flags on MCSymbol");
MCOp = LowerSymbolOperand(MO.getMCSymbol(), /*Offset=*/0, false, false); MCOp = LowerSymbolOperand(MO.getMCSymbol(), /*Offset=*/0, false, false,
false);
break; break;
} }

View File

@ -34,7 +34,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyMCInstLower {
MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const;
MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const;
MCOperand LowerSymbolOperand(MCSymbol *Sym, int64_t Offset, bool IsFunc, MCOperand LowerSymbolOperand(MCSymbol *Sym, int64_t Offset, bool IsFunc,
bool IsGlob) const; bool IsGlob, bool IsEvent) const;
public: public:
WebAssemblyMCInstLower(MCContext &ctx, WebAssemblyAsmPrinter &printer) WebAssemblyMCInstLower(MCContext &ctx, WebAssemblyAsmPrinter &printer)

View File

@ -13,7 +13,7 @@ declare void @llvm.wasm.throw(i32, i8*)
; CHECK-LABEL: test_throw: ; CHECK-LABEL: test_throw:
; CHECK-NEXT: i32.const $push0=, 0 ; CHECK-NEXT: i32.const $push0=, 0
; CHECK-NEXT: throw 0, $pop0 ; CHECK-NEXT: throw __cpp_exception@EVENT, $pop0
define void @test_throw() { define void @test_throw() {
call void @llvm.wasm.throw(i32 0, i8* null) call void @llvm.wasm.throw(i32 0, i8* null)
ret void ret void
@ -259,3 +259,6 @@ declare void @__cxa_rethrow()
declare void @__clang_call_terminate(i8*) declare void @__clang_call_terminate(i8*)
declare void @_ZSt9terminatev() declare void @_ZSt9terminatev()
declare %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* returned) declare %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* returned)
; CHECK: __cpp_exception:
; CHECK: .eventtype __cpp_exception, void, i32

View File

@ -0,0 +1,58 @@
; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling %s -o - | obj2yaml | FileCheck %s
; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling %s -o - | llvm-readobj -s | FileCheck -check-prefix=SEC %s
target triple = "wasm32-unknown-unknown"
declare void @llvm.wasm.throw(i32, i8*)
define i32 @test_throw0(i8* %p) {
call void @llvm.wasm.throw(i32 0, i8* %p)
ret i32 0
}
define i32 @test_throw1(i8* %p) {
call void @llvm.wasm.throw(i32 0, i8* %p)
ret i32 1
}
; CHECK: Sections:
; CHECK-NEXT: - Type: TYPE
; CHECK-NEXT: Signatures:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - I32
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - I32
; CHECK: - Type: EVENT
; CHECK-NEXT: Events:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Attribute: 0
; CHECK-NEXT: SigIndex: 1
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Relocations:
; CHECK-NEXT: - Type: R_WEBASSEMBLY_EVENT_INDEX_LEB
; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000006
; CHECK-NEXT: - Type: R_WEBASSEMBLY_EVENT_INDEX_LEB
; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x00000013
; CHECK: - Type: CUSTOM
; CHECK-NEXT: Name: linking
; CHECK-NEXT: Version: 1
; CHECK-NEXT: SymbolTable:
; CHECK: - Index: 1
; CHECK-NEXT: Kind: EVENT
; CHECK-NEXT: Name: __cpp_exception
; CHECK-NEXT: Flags: [ BINDING_WEAK ]
; CHECK-NEXT: Event: 0
; SEC: Type: EVENT (0xC)
; SEC-NEXT: Size: 3
; SEC-NEXT: Offset: 97

View File

@ -0,0 +1,92 @@
# RUN: yaml2obj %s | obj2yaml | FileCheck %s
--- !WASM
FileHeader:
Version: 0x00000001
Sections:
- Type: TYPE
Signatures:
- Index: 0
ReturnType: I32
ParamTypes:
- I32
- Index: 1
ReturnType: NORESULT
ParamTypes:
- I32
- Type: FUNCTION
FunctionTypes: [ 0 ]
- Type: EVENT
Events:
- Index: 0
Attribute: 0
SigIndex: 1
- Type: CODE
Relocations:
- Type: R_WEBASSEMBLY_EVENT_INDEX_LEB
Index: 1
Offset: 0x00000006
Functions:
- Index: 0
Locals:
Body: 200008808080800041000B
- Type: CUSTOM
Name: linking
Version: 1
SymbolTable:
- Index: 0
Kind: FUNCTION
Name: test_throw0
Flags: [ ]
Function: 0
- Index: 1
Kind: EVENT
Name: __cpp_exception
Flags: [ BINDING_WEAK ]
Event: 0
...
# CHECK: --- !WASM
# CHECK-NEXT: FileHeader:
# CHECK-NEXT: Version: 0x00000001
# CHECK-NEXT: Sections:
# CHECK-NEXT: - Type: TYPE
# CHECK-NEXT: Signatures:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: ReturnType: I32
# CHECK-NEXT: ParamTypes:
# CHECK-NEXT: - I32
# CHECK-NEXT: - Index: 1
# CHECK-NEXT: ReturnType: NORESULT
# CHECK-NEXT: ParamTypes:
# CHECK-NEXT: - I32
# CHECK-NEXT: - Type: FUNCTION
# CHECK-NEXT: FunctionTypes: [ 0 ]
# CHECK-NEXT: - Type: EVENT
# CHECK-NEXT: Events:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: Attribute: 0
# CHECK-NEXT: SigIndex: 1
# CHECK-NEXT: - Type: CODE
# CHECK-NEXT: Relocations:
# CHECK-NEXT: - Type: R_WEBASSEMBLY_EVENT_INDEX_LEB
# CHECK-NEXT: Index: 1
# CHECK-NEXT: Offset: 0x00000006
# CHECK-NEXT: Functions:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: Locals:
# CHECK-NEXT: Body: 200008808080800041000B
# CHECK-NEXT: - Type: CUSTOM
# CHECK-NEXT: Name: linking
# CHECK-NEXT: Version: 1
# CHECK-NEXT: SymbolTable:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: Kind: FUNCTION
# CHECK-NEXT: Name: test_throw0
# CHECK-NEXT: Flags: [ ]
# CHECK-NEXT: Function: 0
# CHECK-NEXT: - Index: 1
# CHECK-NEXT: Kind: EVENT
# CHECK-NEXT: Name: __cpp_exception
# CHECK-NEXT: Flags: [ BINDING_WEAK ]
# CHECK-NEXT: Event: 0

View File

@ -25,10 +25,8 @@ namespace {
static const EnumEntry<unsigned> WasmSymbolTypes[] = { static const EnumEntry<unsigned> WasmSymbolTypes[] = {
#define ENUM_ENTRY(X) \ #define ENUM_ENTRY(X) \
{ #X, wasm::WASM_SYMBOL_TYPE_##X } { #X, wasm::WASM_SYMBOL_TYPE_##X }
ENUM_ENTRY(FUNCTION), ENUM_ENTRY(FUNCTION), ENUM_ENTRY(DATA), ENUM_ENTRY(GLOBAL),
ENUM_ENTRY(DATA), ENUM_ENTRY(SECTION), ENUM_ENTRY(EVENT),
ENUM_ENTRY(GLOBAL),
ENUM_ENTRY(SECTION),
#undef ENUM_ENTRY #undef ENUM_ENTRY
}; };
@ -37,8 +35,9 @@ static const EnumEntry<uint32_t> WasmSectionTypes[] = {
{ #X, wasm::WASM_SEC_##X } { #X, wasm::WASM_SEC_##X }
ENUM_ENTRY(CUSTOM), ENUM_ENTRY(TYPE), ENUM_ENTRY(IMPORT), ENUM_ENTRY(CUSTOM), ENUM_ENTRY(TYPE), ENUM_ENTRY(IMPORT),
ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE), ENUM_ENTRY(MEMORY), ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE), ENUM_ENTRY(MEMORY),
ENUM_ENTRY(GLOBAL), ENUM_ENTRY(EXPORT), ENUM_ENTRY(START), ENUM_ENTRY(GLOBAL), ENUM_ENTRY(EVENT), ENUM_ENTRY(EXPORT),
ENUM_ENTRY(ELEM), ENUM_ENTRY(CODE), ENUM_ENTRY(DATA), ENUM_ENTRY(START), ENUM_ENTRY(ELEM), ENUM_ENTRY(CODE),
ENUM_ENTRY(DATA),
#undef ENUM_ENTRY #undef ENUM_ENTRY
}; };

View File

@ -107,6 +107,7 @@ WasmDumper::dumpCustomSection(const WasmSection &WasmSec) {
break; break;
case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_FUNCTION:
case wasm::WASM_SYMBOL_TYPE_GLOBAL: case wasm::WASM_SYMBOL_TYPE_GLOBAL:
case wasm::WASM_SYMBOL_TYPE_EVENT:
Info.ElementIndex = Symbol.ElementIndex; Info.ElementIndex = Symbol.ElementIndex;
break; break;
case wasm::WASM_SYMBOL_TYPE_SECTION: case wasm::WASM_SYMBOL_TYPE_SECTION:
@ -182,6 +183,10 @@ ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
Im.GlobalImport.Type = Import.Global.Type; Im.GlobalImport.Type = Import.Global.Type;
Im.GlobalImport.Mutable = Import.Global.Mutable; Im.GlobalImport.Mutable = Import.Global.Mutable;
break; break;
case wasm::WASM_EXTERNAL_EVENT:
Im.EventImport.Attribute = Import.Event.Attribute;
Im.EventImport.SigIndex = Import.Event.SigIndex;
break;
case wasm::WASM_EXTERNAL_TABLE: case wasm::WASM_EXTERNAL_TABLE:
Im.TableImport = make_table(Import.Table); Im.TableImport = make_table(Import.Table);
break; break;
@ -231,6 +236,18 @@ ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
S = std::move(GlobalSec); S = std::move(GlobalSec);
break; break;
} }
case wasm::WASM_SEC_EVENT: {
auto EventSec = make_unique<WasmYAML::EventSection>();
for (auto &Event : Obj.events()) {
WasmYAML::Event E;
E.Index = Event.Index;
E.Attribute = Event.Type.Attribute;
E.SigIndex = Event.Type.SigIndex;
EventSec->Events.push_back(E);
}
S = std::move(EventSec);
break;
}
case wasm::WASM_SEC_START: { case wasm::WASM_SEC_START: {
auto StartSec = make_unique<WasmYAML::StartSection>(); auto StartSec = make_unique<WasmYAML::StartSection>();
StartSec->StartFunction = Obj.startFunction(); StartSec->StartFunction = Obj.startFunction();

View File

@ -37,6 +37,7 @@ private:
int writeSectionContent(raw_ostream &OS, WasmYAML::TableSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::TableSection &Section);
int writeSectionContent(raw_ostream &OS, WasmYAML::MemorySection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::MemorySection &Section);
int writeSectionContent(raw_ostream &OS, WasmYAML::GlobalSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::GlobalSection &Section);
int writeSectionContent(raw_ostream &OS, WasmYAML::EventSection &Section);
int writeSectionContent(raw_ostream &OS, WasmYAML::ExportSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::ExportSection &Section);
int writeSectionContent(raw_ostream &OS, WasmYAML::StartSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::StartSection &Section);
int writeSectionContent(raw_ostream &OS, WasmYAML::ElemSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::ElemSection &Section);
@ -49,6 +50,7 @@ private:
WasmYAML::Object &Obj; WasmYAML::Object &Obj;
uint32_t NumImportedFunctions = 0; uint32_t NumImportedFunctions = 0;
uint32_t NumImportedGlobals = 0; uint32_t NumImportedGlobals = 0;
uint32_t NumImportedEvents = 0;
}; };
static int writeUint64(raw_ostream &OS, uint64_t Value) { static int writeUint64(raw_ostream &OS, uint64_t Value) {
@ -152,6 +154,7 @@ int WasmWriter::writeSectionContent(raw_ostream &OS,
switch (Info.Kind) { switch (Info.Kind) {
case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_FUNCTION:
case wasm::WASM_SYMBOL_TYPE_GLOBAL: case wasm::WASM_SYMBOL_TYPE_GLOBAL:
case wasm::WASM_SYMBOL_TYPE_EVENT:
encodeULEB128(Info.ElementIndex, SubSection.GetStream()); encodeULEB128(Info.ElementIndex, SubSection.GetStream());
if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0)
writeStringRef(Info.Name, SubSection.GetStream()); writeStringRef(Info.Name, SubSection.GetStream());
@ -292,6 +295,11 @@ int WasmWriter::writeSectionContent(raw_ostream &OS,
writeUint8(OS, Import.GlobalImport.Mutable); writeUint8(OS, Import.GlobalImport.Mutable);
NumImportedGlobals++; NumImportedGlobals++;
break; break;
case wasm::WASM_EXTERNAL_EVENT:
writeUint32(OS, Import.EventImport.Attribute);
writeUint32(OS, Import.EventImport.SigIndex);
NumImportedGlobals++;
break;
case wasm::WASM_EXTERNAL_MEMORY: case wasm::WASM_EXTERNAL_MEMORY:
writeLimits(Import.Memory, OS); writeLimits(Import.Memory, OS);
break; break;
@ -369,6 +377,22 @@ int WasmWriter::writeSectionContent(raw_ostream &OS,
return 0; return 0;
} }
int WasmWriter::writeSectionContent(raw_ostream &OS,
WasmYAML::EventSection &Section) {
encodeULEB128(Section.Events.size(), OS);
uint32_t ExpectedIndex = NumImportedEvents;
for (auto &Event : Section.Events) {
if (Event.Index != ExpectedIndex) {
errs() << "Unexpected event index: " << Event.Index << "\n";
return 1;
}
++ExpectedIndex;
encodeULEB128(Event.Attribute, OS);
encodeULEB128(Event.SigIndex, OS);
}
return 0;
}
int WasmWriter::writeSectionContent(raw_ostream &OS, int WasmWriter::writeSectionContent(raw_ostream &OS,
WasmYAML::ElemSection &Section) { WasmYAML::ElemSection &Section) {
encodeULEB128(Section.Segments.size(), OS); encodeULEB128(Section.Segments.size(), OS);
@ -474,17 +498,7 @@ int WasmWriter::writeWasm(raw_ostream &OS) {
writeUint32(OS, Obj.Header.Version); writeUint32(OS, Obj.Header.Version);
// Write each section // Write each section
uint32_t LastType = 0;
for (const std::unique_ptr<WasmYAML::Section> &Sec : Obj.Sections) { for (const std::unique_ptr<WasmYAML::Section> &Sec : Obj.Sections) {
uint32_t Type = Sec->Type;
if (Type != wasm::WASM_SEC_CUSTOM) {
if (Type < LastType) {
errs() << "Out of order section type: " << Type << "\n";
return 1;
}
LastType = Type;
}
encodeULEB128(Sec->Type, OS); encodeULEB128(Sec->Type, OS);
std::string OutString; std::string OutString;
raw_string_ostream StringStream(OutString); raw_string_ostream StringStream(OutString);
@ -509,6 +523,9 @@ int WasmWriter::writeWasm(raw_ostream &OS) {
} else if (auto S = dyn_cast<WasmYAML::GlobalSection>(Sec.get())) { } else if (auto S = dyn_cast<WasmYAML::GlobalSection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S)) if (auto Err = writeSectionContent(StringStream, *S))
return Err; return Err;
} else if (auto S = dyn_cast<WasmYAML::EventSection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S))
return Err;
} else if (auto S = dyn_cast<WasmYAML::ExportSection>(Sec.get())) { } else if (auto S = dyn_cast<WasmYAML::ExportSection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S)) if (auto Err = writeSectionContent(StringStream, *S))
return Err; return Err;