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;
WasmGlobalType Global;
WasmTable Table;
WasmLimits Memory;
+ WasmEventType Event;
};
};
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.
WASM_EXTERNAL_TABLE = 0x1,
WASM_EXTERNAL_MEMORY = 0x2,
WASM_EXTERNAL_GLOBAL = 0x3,
+ WASM_EXTERNAL_EVENT = 0x4,
};
// Opcodes used in initializer expressions.
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;
-
#ifndef WASM_RELOC
#error "WASM_RELOC must be defined"
#endif
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)
namespace llvm {
+enum EventTag { CPP_EXCEPTION = 0, C_LONGJMP = 1 };
+
using BBOrMBB = PointerUnion<const BasicBlock *, MachineBasicBlock *>;
struct WasmEHFuncInfo {
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
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.
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; }
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
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;
}
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;
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 {
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; }
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;
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;
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);
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;
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
wasm::WasmInitExpr InitExpr;
};
+struct Event {
+ uint32_t Index;
+ uint32_t Attribute;
+ uint32_t SigIndex;
+};
+
struct Import {
StringRef Module;
StringRef Field;
Global GlobalImport;
Table TableImport;
Limits Memory;
+ Event EventImport;
};
};
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) {}
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 {
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
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");
}
//===----------------------------------------------------------------------===//
#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()) {
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;
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";
.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)
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;
// 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;
}
};
// A wasm function to be written into the function section.
struct WasmFunction {
- uint32_t Type;
+ uint32_t SigIndex;
const MCSymbolWasm *Sym;
};
// 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;
// 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.
TableIndices.clear();
DataLocations.clear();
CustomSectionsRelocations.clear();
- FunctionTypeIndices.clear();
- FunctionTypes.clear();
+ SignatureIndices.clear();
+ Signatures.clear();
Globals.clear();
DataSegments.clear();
SectionFunctions.clear();
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);
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(
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
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());
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:
}
}
-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);
}
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");
}
encodeULEB128(Functions.size(), W.OS);
for (const WasmFunction &Func : Functions)
- encodeULEB128(Func.Type, W.OS);
+ encodeULEB128(Func.SigIndex, W.OS);
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) {
if (Exports.empty())
return;
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);
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
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;
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;
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()) {
if (WS.isFunction())
registerFunctionType(WS);
+ if (WS.isEvent())
+ registerEventType(WS);
+
if (WS.isTemporary())
continue;
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++;
}
}
}
// 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);
}
LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n");
+
} else if (WS.isData()) {
if (WS.isTemporary() && !WS.getSize())
continue;
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())
// 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());
}
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");
}
}
// 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);
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:
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);
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);
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");
}
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:
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);
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);
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;
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();
}
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();
}
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))
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
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");
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");
}
ECase(TABLE);
ECase(MEMORY);
ECase(GLOBAL);
+ ECase(EVENT);
ECase(EXPORT);
ECase(START);
ECase(ELEM);
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);
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());
ECase(TABLE);
ECase(MEMORY);
ECase(GLOBAL);
+ ECase(EVENT);
ECase(EXPORT);
ECase(START);
ECase(ELEM);
} 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) {
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);
}
}
+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)
ECase(DATA);
ECase(GLOBAL);
ECase(SECTION);
+ ECase(EVENT);
#undef ECase
}
ECase(TABLE);
ECase(MEMORY);
ECase(GLOBAL);
+ ECase(EVENT);
#undef ECase
}
const MCOperand &MO = MI.getOperand(i);
if (MO.isReg()) {
/* nothing to encode */
+
} else if (MO.isImm()) {
if (i < Desc.getNumOperands()) {
assert(Desc.TSFlags == 0 &&
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");
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(),
OPERAND_SIGNATURE,
/// type signature immediate for call_indirect.
OPERAND_TYPEINDEX,
+ /// Event index.
+ OPERAND_EVENT,
};
} // end namespace WebAssembly
// 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
}
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';
// Not needed.
}
+void WebAssemblyTargetWasmStreamer::emitEventType(MCSymbolWasm *Sym) {
+ // Not needed.
+}
void WebAssemblyTargetWasmStreamer::emitImportModule(MCSymbolWasm *Sym,
StringRef ModuleName) {
Sym->setModuleName(ModuleName);
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;
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;
};
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;
};
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
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)
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) {
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...
#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"
// Exception handling intrinsics
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
+ setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
setMaxAtomicSizeInBitsSupported(64);
}
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:
}
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 {
SDLoc DL(Op);
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;
// 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>;
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.
SDT_WebAssemblyReturn, [SDNPHasChain]>;
def WebAssemblywrapper : SDNode<"WebAssemblyISD::Wrapper",
SDT_WebAssemblyWrapper>;
+def WebAssemblythrow : SDNode<"WebAssemblyISD::THROW", SDT_WebAssemblyThrow,
+ [SDNPHasChain]>;
//===----------------------------------------------------------------------===//
// WebAssembly-specific Operands.
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 {
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{
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);
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);
}
"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
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;
}
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)
; 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
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
--- /dev/null
+; 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
--- /dev/null
+# 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
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
};
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:
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;
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();
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);
WasmYAML::Object &Obj;
uint32_t NumImportedFunctions = 0;
uint32_t NumImportedGlobals = 0;
+ uint32_t NumImportedEvents = 0;
};
static int writeUint64(raw_ostream &OS, uint64_t Value) {
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());
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;
}
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);
for (auto &Segment : Section.Segments) {
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);
} 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;