[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
};
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 {
StringRef Module;
StringRef Field;
@ -84,6 +96,7 @@ struct WasmImport {
WasmGlobalType Global;
WasmTable Table;
WasmLimits Memory;
WasmEventType Event;
};
};
@ -178,7 +191,8 @@ enum : unsigned {
WASM_SEC_START = 8, // Start function declaration
WASM_SEC_ELEM = 9, // Elements section
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.
@ -200,6 +214,7 @@ enum : unsigned {
WASM_EXTERNAL_TABLE = 0x1,
WASM_EXTERNAL_MEMORY = 0x2,
WASM_EXTERNAL_GLOBAL = 0x3,
WASM_EXTERNAL_EVENT = 0x4,
};
// Opcodes used in initializer expressions.
@ -243,6 +258,12 @@ enum WasmSymbolType : unsigned {
WASM_SYMBOL_TYPE_DATA = 0x1,
WASM_SYMBOL_TYPE_GLOBAL = 0x2,
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;

View File

@ -1,4 +1,3 @@
#ifndef WASM_RELOC
#error "WASM_RELOC must be defined"
#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_FUNCTION_OFFSET_I32, 8)
WASM_RELOC(R_WEBASSEMBLY_SECTION_OFFSET_I32, 9)
WASM_RELOC(R_WEBASSEMBLY_EVENT_INDEX_LEB, 10)

View File

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

View File

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

View File

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

View File

@ -333,6 +333,7 @@ private:
case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
case wasm::R_WEBASSEMBLY_FUNCTION_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
return 0;
}

View File

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

View File

@ -74,6 +74,12 @@ struct Global {
wasm::WasmInitExpr InitExpr;
};
struct Event {
uint32_t Index;
uint32_t Attribute;
uint32_t SigIndex;
};
struct Import {
StringRef Module;
StringRef Field;
@ -83,6 +89,7 @@ struct Import {
Global GlobalImport;
Table TableImport;
Limits Memory;
Event EventImport;
};
};
@ -262,6 +269,16 @@ struct GlobalSection : Section {
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 {
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::ComdatEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Comdat)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Event)
namespace llvm {
namespace yaml {
@ -471,6 +489,10 @@ template <> struct ScalarEnumerationTraits<WasmYAML::RelocType> {
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 llvm

View File

@ -19,6 +19,8 @@ std::string llvm::wasm::toString(wasm::WasmSymbolType type) {
return "WASM_SYMBOL_TYPE_DATA";
case wasm::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");
}

View File

@ -13,9 +13,25 @@
//===----------------------------------------------------------------------===//
#include "WasmException.h"
#include "llvm/IR/Mangler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCStreamer.h"
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() {
// Get rid of any dead landing pads.
if (!Asm->MF->getLandingPads().empty()) {

View File

@ -24,7 +24,7 @@ class LLVM_LIBRARY_VISIBILITY WasmException : public EHStreamer {
public:
WasmException(AsmPrinter *A) : EHStreamer(A) {}
void endModule() override {}
void endModule() override;
void beginFunction(const MachineFunction *MF) override {}
virtual void markFunctionEnd() 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_GLOBAL: return "GLOBAL";
case VK_WebAssembly_TYPEINDEX: return "TYPEINDEX";
case VK_WebAssembly_EVENT: return "EVENT";
case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo";
case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi";
case VK_AMDGPU_REL32_LO: return "rel32@lo";
@ -421,6 +422,7 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) {
.Case("function", VK_WebAssembly_FUNCTION)
.Case("global", VK_WebAssembly_GLOBAL)
.Case("typeindex", VK_WebAssembly_TYPEINDEX)
.Case("event", VK_WebAssembly_EVENT)
.Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO)
.Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI)
.Case("rel32@lo", VK_AMDGPU_REL32_LO)

View File

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

View File

@ -295,6 +295,8 @@ Error WasmObjectFile::parseSection(WasmSection &Sec) {
return parseMemorySection(Ctx);
case wasm::WASM_SEC_GLOBAL:
return parseGlobalSection(Ctx);
case wasm::WASM_SEC_EVENT:
return parseEventSection(Ctx);
case wasm::WASM_SEC_EXPORT:
return parseExportSection(Ctx);
case wasm::WASM_SEC_START:
@ -439,19 +441,24 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
std::vector<wasm::WasmImport *> ImportedGlobals;
std::vector<wasm::WasmImport *> ImportedFunctions;
std::vector<wasm::WasmImport *> ImportedEvents;
ImportedGlobals.reserve(Imports.size());
ImportedFunctions.reserve(Imports.size());
ImportedEvents.reserve(Imports.size());
for (auto &I : Imports) {
if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
ImportedFunctions.emplace_back(&I);
else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
ImportedGlobals.emplace_back(&I);
else if (I.Kind == wasm::WASM_EXTERNAL_EVENT)
ImportedEvents.emplace_back(&I);
}
while (Count--) {
wasm::WasmSymbolInfo Info;
const wasm::WasmSignature *FunctionType = nullptr;
const wasm::WasmGlobalType *GlobalType = nullptr;
const wasm::WasmEventType *EventType = nullptr;
Info.Kind = readUint8(Ctx);
Info.Flags = readVaruint32(Ctx);
@ -532,6 +539,32 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
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:
return make_error<GenericBinaryError>("Invalid symbol type",
object_error::parse_failed);
@ -545,7 +578,7 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
object_error::parse_failed);
LinkingData.SymbolTable.emplace_back(Info);
Symbols.emplace_back(LinkingData.SymbolTable.back(), FunctionType,
GlobalType);
GlobalType, EventType);
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",
object_error::parse_failed);
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_SLEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
@ -755,6 +793,11 @@ Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
return make_error<GenericBinaryError>("Invalid table element type",
object_error::parse_failed);
break;
case wasm::WASM_EXTERNAL_EVENT:
NumImportedEvents++;
Im.Event.Attribute = readVarint32(Ctx);
Im.Event.SigIndex = readVarint32(Ctx);
break;
default:
return make_error<GenericBinaryError>("Unexpected import kind",
object_error::parse_failed);
@ -831,6 +874,24 @@ Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
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) {
uint32_t Count = readVaruint32(Ctx);
Exports.reserve(Count);
@ -850,6 +911,11 @@ Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
return make_error<GenericBinaryError>("Invalid global export",
object_error::parse_failed);
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_TABLE:
break;
@ -881,6 +947,14 @@ bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
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 {
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();
}
bool WasmObjectFile::isValidEventSymbol(uint32_t Index) const {
return Index < Symbols.size() && Symbols[Index].isTypeEvent();
}
bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
return Index < Symbols.size() && Symbols[Index].isTypeData();
}
@ -907,6 +985,11 @@ wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) {
return Globals[Index - NumImportedGlobals];
}
wasm::WasmEvent &WasmObjectFile::getDefinedEvent(uint32_t Index) {
assert(isDefinedEventIndex(Index));
return Events[Index - NumImportedEvents];
}
Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
StartFunction = readVaruint32(Ctx);
if (!isValidFunctionIndex(StartFunction))
@ -1070,6 +1153,7 @@ uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
switch (Sym.Info.Kind) {
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
case wasm::WASM_SYMBOL_TYPE_EVENT:
return Sym.Info.ElementIndex;
case wasm::WASM_SYMBOL_TYPE_DATA: {
// 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;
case wasm::WASM_SYMBOL_TYPE_SECTION:
return SymbolRef::ST_Debug;
case wasm::WASM_SYMBOL_TYPE_EVENT:
return SymbolRef::ST_Other;
}
llvm_unreachable("Unknown WasmSymbol::SymbolType");
@ -1135,10 +1221,12 @@ WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
case wasm::WASM_SYMBOL_TYPE_DATA:
Ref.d.a = DataSection;
break;
case wasm::WASM_SYMBOL_TYPE_SECTION: {
case wasm::WASM_SYMBOL_TYPE_SECTION:
Ref.d.a = Sym.Info.ElementIndex;
break;
}
case wasm::WASM_SYMBOL_TYPE_EVENT:
Ref.d.a = EventSection;
break;
default:
llvm_unreachable("Unknown WasmSymbol::SymbolType");
}
@ -1161,6 +1249,7 @@ std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec,
ECase(TABLE);
ECase(MEMORY);
ECase(GLOBAL);
ECase(EVENT);
ECase(EXPORT);
ECase(START);
ECase(ELEM);

View File

@ -100,6 +100,11 @@ static void sectionMapping(IO &IO, WasmYAML::GlobalSection &Section) {
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) {
commonSectionMapping(IO, Section);
IO.mapOptional("Exports", Section.Exports);
@ -187,6 +192,11 @@ void MappingTraits<std::unique_ptr<WasmYAML::Section>>::mapping(
Section.reset(new WasmYAML::GlobalSection());
sectionMapping(IO, *cast<WasmYAML::GlobalSection>(Section.get()));
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:
if (!IO.outputting())
Section.reset(new WasmYAML::ExportSection());
@ -227,6 +237,7 @@ void ScalarEnumerationTraits<WasmYAML::SectionType>::enumeration(
ECase(TABLE);
ECase(MEMORY);
ECase(GLOBAL);
ECase(EVENT);
ECase(EXPORT);
ECase(START);
ECase(ELEM);
@ -307,6 +318,9 @@ void MappingTraits<WasmYAML::Import>::mapping(IO &IO,
} else if (Import.Kind == wasm::WASM_EXTERNAL_GLOBAL) {
IO.mapRequired("GlobalType", Import.GlobalImport.Type);
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) {
IO.mapRequired("Table", Import.TableImport);
} else if (Import.Kind == wasm::WASM_EXTERNAL_MEMORY) {
@ -399,6 +413,8 @@ void MappingTraits<WasmYAML::SymbolInfo>::mapping(IO &IO,
IO.mapRequired("Function", Info.ElementIndex);
} else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL) {
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) {
if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) {
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(
IO &IO, WasmYAML::LimitFlags &Value) {
#define BCase(X) IO.bitSetCase(Value, #X, wasm::WASM_LIMITS_FLAG_##X)
@ -443,6 +465,7 @@ void ScalarEnumerationTraits<WasmYAML::SymbolKind>::enumeration(
ECase(DATA);
ECase(GLOBAL);
ECase(SECTION);
ECase(EVENT);
#undef ECase
}
@ -467,6 +490,7 @@ void ScalarEnumerationTraits<WasmYAML::ExportKind>::enumeration(
ECase(TABLE);
ECase(MEMORY);
ECase(GLOBAL);
ECase(EVENT);
#undef ECase
}

View File

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

View File

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

View File

@ -100,12 +100,28 @@ void WebAssemblyTargetAsmStreamer::emitIndirectFunctionType(
}
void WebAssemblyTargetAsmStreamer::emitGlobalType(MCSymbolWasm *Sym) {
assert(Sym->isGlobal());
OS << "\t.globaltype\t" << Sym->getName() << ", " <<
WebAssembly::TypeToString(
static_cast<wasm::ValType>(Sym->getGlobalType().Type)) <<
'\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,
StringRef ModuleName) {
OS << "\t.import_module\t" << Sym->getName() << ", " << ModuleName << '\n';
@ -159,6 +175,9 @@ void WebAssemblyTargetWasmStreamer::emitGlobalType(MCSymbolWasm *Sym) {
// Not needed.
}
void WebAssemblyTargetWasmStreamer::emitEventType(MCSymbolWasm *Sym) {
// Not needed.
}
void WebAssemblyTargetWasmStreamer::emitImportModule(MCSymbolWasm *Sym,
StringRef ModuleName) {
Sym->setModuleName(ModuleName);

View File

@ -45,6 +45,8 @@ public:
virtual void emitIndIdx(const MCExpr *Value) = 0;
/// .globaltype
virtual void emitGlobalType(MCSymbolWasm *Sym) = 0;
/// .eventtype
virtual void emitEventType(MCSymbolWasm *Sym) = 0;
/// .import_module
virtual void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) = 0;
@ -66,6 +68,7 @@ public:
void emitIndirectFunctionType(MCSymbolWasm *Symbol) override;
void emitIndIdx(const MCExpr *Value) override;
void emitGlobalType(MCSymbolWasm *Sym) override;
void emitEventType(MCSymbolWasm *Sym) override;
void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) override;
};
@ -81,6 +84,7 @@ public:
void emitIndirectFunctionType(MCSymbolWasm *Symbol) override;
void emitIndIdx(const MCExpr *Value) override;
void emitGlobalType(MCSymbolWasm *Sym) override;
void emitEventType(MCSymbolWasm *Sym) 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;
}
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,
const MCFixup &Fixup) const {
// 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;
if (IsFunction)
return wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB;
if (IsEventType(Target))
return wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB;
return wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB;
case FK_Data_4:
if (IsFunction)

View File

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

View File

@ -25,5 +25,6 @@ HANDLE_NODETYPE(SHUFFLE)
HANDLE_NODETYPE(VEC_SHL)
HANDLE_NODETYPE(VEC_SHR_S)
HANDLE_NODETYPE(VEC_SHR_U)
HANDLE_NODETYPE(THROW)
// 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/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/WasmEHFuncInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/Function.h"
@ -234,6 +235,7 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
// Exception handling intrinsics
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
setMaxAtomicSizeInBitsSupported(64);
}
@ -882,6 +884,8 @@ SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
case ISD::EXTRACT_VECTOR_ELT:
case ISD::INSERT_VECTOR_ELT:
return LowerAccessVectorElement(Op, DAG);
case ISD::INTRINSIC_VOID:
return LowerINTRINSIC_VOID(Op, DAG);
case ISD::VECTOR_SHUFFLE:
return LowerVECTOR_SHUFFLE(Op, DAG);
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
WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
SelectionDAG &DAG) const {

View File

@ -98,6 +98,7 @@ private:
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerCopyToReg(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 LowerAccessVectorElement(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
let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
defm THROW_I32 : I<(outs), (ins i32imm:$tag, I32:$val),
(outs), (ins i32imm:$tag),
[(int_wasm_throw imm:$tag, I32:$val)],
defm THROW_I32 : I<(outs), (ins event_op:$tag, I32:$val),
(outs), (ins event_op:$tag),
[(WebAssemblythrow (WebAssemblywrapper texternalsym:$tag),
I32:$val)],
"throw \t$tag, $val", "throw \t$tag",
0x08>;
defm THROW_I64 : I<(outs), (ins i32imm:$tag, I64:$val),
(outs), (ins i32imm:$tag),
[(int_wasm_throw imm:$tag, I64:$val)],
defm THROW_I64 : I<(outs), (ins event_op:$tag, I64:$val),
(outs), (ins event_op:$tag),
[(WebAssemblythrow (WebAssemblywrapper texternalsym:$tag),
I64:$val)],
"throw \t$tag, $val", "throw \t$tag",
0x08>;
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_WebAssemblyWrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>,
SDTCisPtrTy<0>]>;
def SDT_WebAssemblyThrow : SDTypeProfile<0, 2, [SDTCisPtrTy<0>]>;
//===----------------------------------------------------------------------===//
// WebAssembly-specific DAG Nodes.
@ -90,6 +91,8 @@ def WebAssemblyreturn : SDNode<"WebAssemblyISD::RETURN",
SDT_WebAssemblyReturn, [SDNPHasChain]>;
def WebAssemblywrapper : SDNode<"WebAssemblyISD::Wrapper",
SDT_WebAssemblyWrapper>;
def WebAssemblythrow : SDNode<"WebAssemblyISD::THROW", SDT_WebAssemblyThrow,
[SDNPHasChain]>;
//===----------------------------------------------------------------------===//
// WebAssembly-specific Operands.
@ -140,6 +143,10 @@ let OperandType = "OPERAND_P2ALIGN" in {
def P2Align : Operand<i32> {
let PrintMethod = "printWebAssemblyP2AlignOperand";
}
let OperandType = "OPERAND_EVENT" in
def event_op : Operand<i32>;
} // OperandType = "OPERAND_P2ALIGN"
let OperandType = "OPERAND_SIGNATURE" in {

View File

@ -75,10 +75,10 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
cast<MCSymbolWasm>(Printer.GetExternalSymbolSymbol(Name));
const WebAssemblySubtarget &Subtarget = Printer.getSubtarget();
// __stack_pointer is a global variable; all other external symbols used by
// CodeGen are functions. It's OK to hardcode knowledge of specific symbols
// here; this method is precisely there for fetching the signatures of known
// Clang-provided symbols.
// Except for the two exceptions (__stack_pointer and __cpp_exception), all
// other external symbols used by CodeGen are functions. It's OK to hardcode
// knowledge of specific symbols here; this method is precisely there for
// fetching the signatures of known Clang-provided symbols.
if (strcmp(Name, "__stack_pointer") == 0) {
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
WasmSym->setGlobalType(wasm::WasmGlobalType{
@ -90,24 +90,45 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
SmallVector<wasm::ValType, 4> Returns;
SmallVector<wasm::ValType, 4> Params;
GetLibcallSignature(Subtarget, Name, Returns, 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);
}
auto Signature =
make_unique<wasm::WasmSignature>(std::move(Returns), std::move(Params));
WasmSym->setSignature(Signature.get());
Printer.addSignature(std::move(Signature));
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
return WasmSym;
}
MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym,
int64_t Offset,
bool IsFunc,
bool IsGlob) const {
bool IsFunc, bool IsGlob,
bool IsEvent) const {
MCSymbolRefExpr::VariantKind VK =
IsFunc ? MCSymbolRefExpr::VK_WebAssembly_FUNCTION
: IsGlob ? MCSymbolRefExpr::VK_WebAssembly_GLOBAL
: MCSymbolRefExpr::VK_None;
: IsEvent ? MCSymbolRefExpr::VK_WebAssembly_EVENT
: MCSymbolRefExpr::VK_None;
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");
if (IsGlob)
report_fatal_error("Global indexes with offsets not supported");
if (IsEvent)
report_fatal_error("Event indexes with offsets not supported");
Expr =
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");
MCOp = LowerSymbolOperand(GetGlobalAddressSymbol(MO), MO.getOffset(),
MO.getGlobal()->getValueType()->isFunctionTy(),
false);
false, false);
break;
case MachineOperand::MO_ExternalSymbol:
// The target flag indicates whether this is a symbol for a
@ -228,14 +251,16 @@ void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
MCOp = LowerSymbolOperand(
GetExternalSymbolSymbol(MO), /*Offset=*/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;
case MachineOperand::MO_MCSymbol:
// This is currently used only for LSDA symbols (GCC_except_table),
// because global addresses or other external symbols are handled above.
assert(MO.getTargetFlags() == 0 &&
"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;
}

View File

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

View File

@ -13,7 +13,7 @@ declare void @llvm.wasm.throw(i32, i8*)
; CHECK-LABEL: test_throw:
; CHECK-NEXT: i32.const $push0=, 0
; CHECK-NEXT: throw 0, $pop0
; CHECK-NEXT: throw __cpp_exception@EVENT, $pop0
define void @test_throw() {
call void @llvm.wasm.throw(i32 0, i8* null)
ret void
@ -259,3 +259,6 @@ declare void @__cxa_rethrow()
declare void @__clang_call_terminate(i8*)
declare void @_ZSt9terminatev()
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,20 +25,19 @@ namespace {
static const EnumEntry<unsigned> WasmSymbolTypes[] = {
#define ENUM_ENTRY(X) \
{ #X, wasm::WASM_SYMBOL_TYPE_##X }
ENUM_ENTRY(FUNCTION),
ENUM_ENTRY(DATA),
ENUM_ENTRY(GLOBAL),
ENUM_ENTRY(SECTION),
ENUM_ENTRY(FUNCTION), ENUM_ENTRY(DATA), ENUM_ENTRY(GLOBAL),
ENUM_ENTRY(SECTION), ENUM_ENTRY(EVENT),
#undef ENUM_ENTRY
};
static const EnumEntry<uint32_t> WasmSectionTypes[] = {
#define ENUM_ENTRY(X) \
{ #X, wasm::WASM_SEC_##X }
ENUM_ENTRY(CUSTOM), ENUM_ENTRY(TYPE), ENUM_ENTRY(IMPORT),
ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE), ENUM_ENTRY(MEMORY),
ENUM_ENTRY(GLOBAL), ENUM_ENTRY(EXPORT), ENUM_ENTRY(START),
ENUM_ENTRY(ELEM), ENUM_ENTRY(CODE), ENUM_ENTRY(DATA),
ENUM_ENTRY(CUSTOM), ENUM_ENTRY(TYPE), ENUM_ENTRY(IMPORT),
ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE), ENUM_ENTRY(MEMORY),
ENUM_ENTRY(GLOBAL), ENUM_ENTRY(EVENT), ENUM_ENTRY(EXPORT),
ENUM_ENTRY(START), ENUM_ENTRY(ELEM), ENUM_ENTRY(CODE),
ENUM_ENTRY(DATA),
#undef ENUM_ENTRY
};

View File

@ -107,6 +107,7 @@ WasmDumper::dumpCustomSection(const WasmSection &WasmSec) {
break;
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
case wasm::WASM_SYMBOL_TYPE_EVENT:
Info.ElementIndex = Symbol.ElementIndex;
break;
case wasm::WASM_SYMBOL_TYPE_SECTION:
@ -182,6 +183,10 @@ ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
Im.GlobalImport.Type = Import.Global.Type;
Im.GlobalImport.Mutable = Import.Global.Mutable;
break;
case wasm::WASM_EXTERNAL_EVENT:
Im.EventImport.Attribute = Import.Event.Attribute;
Im.EventImport.SigIndex = Import.Event.SigIndex;
break;
case wasm::WASM_EXTERNAL_TABLE:
Im.TableImport = make_table(Import.Table);
break;
@ -231,6 +236,18 @@ ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
S = std::move(GlobalSec);
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: {
auto StartSec = make_unique<WasmYAML::StartSection>();
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::MemorySection &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::StartSection &Section);
int writeSectionContent(raw_ostream &OS, WasmYAML::ElemSection &Section);
@ -49,6 +50,7 @@ private:
WasmYAML::Object &Obj;
uint32_t NumImportedFunctions = 0;
uint32_t NumImportedGlobals = 0;
uint32_t NumImportedEvents = 0;
};
static int writeUint64(raw_ostream &OS, uint64_t Value) {
@ -152,6 +154,7 @@ int WasmWriter::writeSectionContent(raw_ostream &OS,
switch (Info.Kind) {
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
case wasm::WASM_SYMBOL_TYPE_EVENT:
encodeULEB128(Info.ElementIndex, SubSection.GetStream());
if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0)
writeStringRef(Info.Name, SubSection.GetStream());
@ -292,6 +295,11 @@ int WasmWriter::writeSectionContent(raw_ostream &OS,
writeUint8(OS, Import.GlobalImport.Mutable);
NumImportedGlobals++;
break;
case wasm::WASM_EXTERNAL_EVENT:
writeUint32(OS, Import.EventImport.Attribute);
writeUint32(OS, Import.EventImport.SigIndex);
NumImportedGlobals++;
break;
case wasm::WASM_EXTERNAL_MEMORY:
writeLimits(Import.Memory, OS);
break;
@ -369,6 +377,22 @@ int WasmWriter::writeSectionContent(raw_ostream &OS,
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,
WasmYAML::ElemSection &Section) {
encodeULEB128(Section.Segments.size(), OS);
@ -474,17 +498,7 @@ int WasmWriter::writeWasm(raw_ostream &OS) {
writeUint32(OS, Obj.Header.Version);
// Write each section
uint32_t LastType = 0;
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);
std::string 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())) {
if (auto Err = writeSectionContent(StringStream, *S))
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())) {
if (auto Err = writeSectionContent(StringStream, *S))
return Err;