[WebAssembly] Add support for shared tags (#188367)
Mostly following the structure of other Shared* constructs
Fixes: #188120
diff --git a/lld/test/wasm/Inputs/libsearch-dyn.s b/lld/test/wasm/Inputs/libsearch-dyn.s
index bb59580..96c351d 100644
--- a/lld/test/wasm/Inputs/libsearch-dyn.s
+++ b/lld/test/wasm/Inputs/libsearch-dyn.s
@@ -1,4 +1,4 @@
-.globl _bar,_dynamic
+.globl _bar,_dynamic,_foo_tag
.section .data,"",@
_bar:
@@ -6,3 +6,6 @@
_dynamic:
.size _dynamic,4
+
+.tagtype _foo_tag i32
+_foo_tag:
diff --git a/lld/test/wasm/dylink.s b/lld/test/wasm/dylink.s
index ab604fc..d40778c 100644
--- a/lld/test/wasm/dylink.s
+++ b/lld/test/wasm/dylink.s
@@ -1,4 +1,4 @@
-# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-emscripten -o %t.o %s
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-emscripten -mattr=+exception-handling -o %t.o %s
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-emscripten %p/Inputs/ret32.s -o %t.ret32.o
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-emscripten %p/Inputs/libsearch-dyn.s -o %t.dyn.o
# RUN: wasm-ld --experimental-pic -shared %t.ret32.o %t.dyn.o -o %t.lib.so
@@ -8,7 +8,7 @@
# Same again for wasm64
-# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-emscripten -o %t.o %s
+# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-emscripten -mattr=+exception-handling -o %t.o %s
# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-emscripten %p/Inputs/ret32.s -o %t.ret32.o
# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-emscripten %p/Inputs/libsearch-dyn.s -o %t.dyn.o
# RUN: wasm-ld --experimental-pic -mwasm64 -shared %t.ret32.o %t.dyn.o -o %t.lib.so
@@ -18,8 +18,9 @@
# ERROR: error: {{.*}}: undefined symbol: ret32
# ERROR: error: {{.*}}: undefined symbol: _bar
+# ERROR: error: {{.*}}: undefined symbol: _foo_tag
.functype ret32 (f32) -> (i32)
-
+.tagtype _foo_tag i32
.globl _start
_start:
.functype _start () -> ()
@@ -28,6 +29,8 @@
drop
i32.const _bar@GOT
drop
+ i32.const 0
+ throw _foo_tag
end_function
# CHECK: Sections:
@@ -39,3 +42,7 @@
# CHECK-NEXT: TableAlignment: 0
# CHECK-NEXT: Needed:
# CHECK-NEXT: - {{.*}}.lib.so
+#
+# CHECK: Field: _foo_tag
+# CHECK-NEXT: Kind: TAG
+# CHECK-NEXT: SigIndex: 1
diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index dcdd138..ad7f207 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -453,6 +453,9 @@
case WASM_SYMBOL_TYPE_DATA:
s = symtab->addSharedData(name, flags, this);
break;
+ case WASM_SYMBOL_TYPE_TAG:
+ s = symtab->addSharedTag(name, flags, this, wasmSym.Signature);
+ break;
default:
continue;
}
diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
index 9bd93f3..05e653e 100644
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -352,6 +352,44 @@
isError);
}
+Symbol *SymbolTable::addSharedTag(StringRef name, uint32_t flags,
+ InputFile *file, const WasmSignature *sig) {
+ LLVM_DEBUG(dbgs() << "addSharedTag: " << name << " [" << toString(*sig)
+ << "]\n");
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name, file);
+
+ auto replaceSym = [&](Symbol *sym) {
+ replaceSymbol<SharedTagSymbol>(sym, name, flags, file, sig);
+ };
+
+ // same as addSharedFunction, but this is in its own function
+ if (wasInserted || s->isLazy()) {
+ replaceSym(s);
+ return s;
+ }
+
+ auto *existingTag = dyn_cast<TagSymbol>(s);
+ if (!existingTag) {
+ reportTypeError(s, file, WASM_SYMBOL_TYPE_TAG);
+ return s;
+ }
+
+ if (s->isDefined()) {
+ return s;
+ }
+
+ // undefined existing sym
+ const WasmSignature *oldSig = existingTag->signature;
+ if (oldSig && sig && *oldSig != *sig)
+ error("Tag signature mismatch: " + name + "\n>>> defined as " +
+ toString(*oldSig) + " in " + toString(existingTag->getFile()) +
+ "\n>>> defined as " + toString(*sig) + " in " + toString(file));
+ replaceSym(s);
+ return s;
+}
+
Symbol *SymbolTable::addSharedFunction(StringRef name, uint32_t flags,
InputFile *file,
const WasmSignature *sig) {
diff --git a/lld/wasm/SymbolTable.h b/lld/wasm/SymbolTable.h
index 6496142..0667ced 100644
--- a/lld/wasm/SymbolTable.h
+++ b/lld/wasm/SymbolTable.h
@@ -53,6 +53,8 @@
Symbol *addSharedFunction(StringRef name, uint32_t flags, InputFile *file,
const WasmSignature *sig);
Symbol *addSharedData(StringRef name, uint32_t flags, InputFile *file);
+ Symbol *addSharedTag(StringRef name, uint32_t flags, InputFile *file,
+ const WasmSignature *sig);
Symbol *addDefinedFunction(StringRef name, uint32_t flags, InputFile *file,
InputFunction *function);
Symbol *addDefinedData(StringRef name, uint32_t flags, InputFile *file,
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index 97a9871..9ce2a9f 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -72,6 +72,8 @@
return "SharedFunctionKind";
case wasm::Symbol::SharedDataKind:
return "SharedDataKind";
+ case wasm::Symbol::SharedTagKind:
+ return "SharedTagSymbol";
}
llvm_unreachable("invalid symbol kind");
}
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index 3dda36f..47f1b3a 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -62,6 +62,7 @@
LazyKind,
SharedFunctionKind,
SharedDataKind,
+ SharedTagKind,
};
Kind kind() const { return symbolKind; }
@@ -77,7 +78,8 @@
bool isLazy() const { return symbolKind == LazyKind; }
bool isShared() const {
- return symbolKind == SharedFunctionKind || symbolKind == SharedDataKind;
+ return symbolKind == SharedFunctionKind || symbolKind == SharedDataKind ||
+ symbolKind == SharedTagKind;
}
bool isLocal() const;
@@ -461,7 +463,8 @@
class TagSymbol : public Symbol {
public:
static bool classof(const Symbol *s) {
- return s->kind() == DefinedTagKind || s->kind() == UndefinedTagKind;
+ return s->kind() == DefinedTagKind || s->kind() == UndefinedTagKind ||
+ s->kind() == SharedTagKind;
}
// Get/set the tag index
@@ -501,6 +504,15 @@
static bool classof(const Symbol *s) { return s->kind() == UndefinedTagKind; }
};
+class SharedTagSymbol : public TagSymbol {
+public:
+ SharedTagSymbol(StringRef name, uint32_t flags, InputFile *f,
+ const WasmSignature *sig)
+ : TagSymbol(name, SharedTagKind, flags, f, sig) {}
+
+ static bool classof(const Symbol *s) { return s->kind() == SharedTagKind; }
+};
+
class SharedFunctionSymbol : public FunctionSymbol {
public:
SharedFunctionSymbol(StringRef name, uint32_t flags, InputFile *file,
@@ -553,6 +565,7 @@
alignas(UndefinedTable) char j[sizeof(UndefinedTable)];
alignas(SectionSymbol) char k[sizeof(SectionSymbol)];
alignas(SharedFunctionSymbol) char l[sizeof(SharedFunctionSymbol)];
+ alignas(SharedTagSymbol) char m[sizeof(SharedTagSymbol)];
};
// It is important to keep the size of SymbolUnion small for performance and
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 852dc23..5f125ff 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -1547,6 +1547,10 @@
object_error::parse_failed);
Info.Kind = wasm::WASM_SYMBOL_TYPE_TAG;
Info.ElementIndex = Ex.Index;
+ if (isDefinedTagIndex(Ex.Index)) {
+ unsigned TagIndex = Ex.Index - NumImportedTags;
+ Signature = &Signatures[Tags[TagIndex].SigIndex];
+ }
break;
case wasm::WASM_EXTERNAL_MEMORY:
break;