-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[CodeGen][ObjC] Initial WebAssembly Support for GNUstep #169043
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-clang @llvm/pr-subscribers-backend-webassembly Author: Hugo Melder (hmelder) ChangesThis pull request adds initial support for compiling Objective-C to WebAssembly. I tested my changes with libobjc2 and the swift-corelibs-blocksruntime. There are two outstanding issues, which I cannot fix as deeper knowledge of the subsystems is required:
First IssueEmscripten is processing the generated The core of the problem is that symbols with the I'm currently hacking around this by not exporting no-strip symbols. This is the default behaviour for Wasm. Second IssueHere is a minimal example that triggers the crash. #include<stdio.h>
int main(void) {
int ret = 0;
@<!-- -->try {
}
@<!-- -->catch (id a)
{
ret = 1;
puts("abc");
}
return ret;
}The following assertion is triggered: Here is the crash report main-c3884.zip. You can use emcc -fobjc-runtime=gnustep-2.2 -fwasm-exceptions -c main.mor just invoke clang directly: /home/vm/llvm-build-wasm/bin/clang -target wasm32-unknown-emscripten -mllvm -combiner-global-alias-analysis=false -mllvm -wasm-enable-sjlj -mllvm -wasm-use-legacy-eh=false -mllvm -disable-lsr --sysroot=/home/vm/emsdk/upstream/emscripten/cache/sysroot -DEMSCRIPTEN -fobjc-runtime=gnustep-2.2 -fwasm-exceptions -c main.mBuilding libobjc2 and the BlocksRuntimeBuilding the BlocksRuntimecmake -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_INSTALL_PREFIX=/home/vm/demo-install -DCMAKE_BUILD_TYPE=Debug -B build -G NinjaBuilding libobjc2cmake -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_INSTALL_PREFIX=/home/vm/demo-install -DBlocksRuntime_LIBRARIES=/home/vm/demo-install/lib/libBlocksRuntime.a -DBlocksRuntime_INCLUDE_DIR=/home/vm/demo-install/include/BlocksRuntime -DEMBEDDED_BLOCKS_RUNTIME=OFF -DTESTS=OFF -B build -DCMAKE_BUILD_TYPE=Debug -G NinjaFull diff: https://github.com/llvm/llvm-project/pull/169043.diff 3 Files Affected:
diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index 06643d4bdc211..3b9f9f306829d 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -179,8 +179,15 @@ class CGObjCGNU : public CGObjCRuntime {
(R.getVersion() >= VersionTuple(major, minor));
}
- std::string ManglePublicSymbol(StringRef Name) {
- return (StringRef(CGM.getTriple().isOSBinFormatCOFF() ? "$_" : "._") + Name).str();
+ const std::string ManglePublicSymbol(StringRef Name) {
+ auto triple = CGM.getTriple();
+
+ // Exported symbols in Emscripten must be a valid Javascript identifier.
+ if (triple.isOSBinFormatCOFF() || triple.isOSBinFormatWasm()) {
+ return (StringRef("$_") + Name).str();
+ } else {
+ return (StringRef("._") + Name).str();
+ }
}
std::string SymbolForProtocol(Twine Name) {
@@ -4106,8 +4113,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
if (!ClassAliases.empty()) {
llvm::Type *ArgTypes[2] = {PtrTy, PtrToInt8Ty};
llvm::FunctionType *RegisterAliasTy =
- llvm::FunctionType::get(Builder.getVoidTy(),
- ArgTypes, false);
+ llvm::FunctionType::get(BoolTy, ArgTypes, false);
llvm::Function *RegisterAlias = llvm::Function::Create(
RegisterAliasTy,
llvm::GlobalValue::ExternalWeakLinkage, "class_registerAlias_np",
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 30d3e5293a31b..6cbec5e17ae1a 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -8001,7 +8001,8 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
if ((runtime.getKind() == ObjCRuntime::GNUstep) &&
(runtime.getVersion() >= VersionTuple(2, 0)))
if (!getToolChain().getTriple().isOSBinFormatELF() &&
- !getToolChain().getTriple().isOSBinFormatCOFF()) {
+ !getToolChain().getTriple().isOSBinFormatCOFF() &&
+ !getToolChain().getTriple().isOSBinFormatWasm()) {
getToolChain().getDriver().Diag(
diag::err_drv_gnustep_objc_runtime_incompatible_binary)
<< runtime.getVersion().getMajor();
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index 15590b31fd07f..d882146e21b8a 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -1794,9 +1794,6 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
Flags |= wasm::WASM_SYMBOL_UNDEFINED;
if (WS.isNoStrip()) {
Flags |= wasm::WASM_SYMBOL_NO_STRIP;
- if (isEmscripten()) {
- Flags |= wasm::WASM_SYMBOL_EXPORTED;
- }
}
if (WS.hasImportName())
Flags |= wasm::WASM_SYMBOL_EXPLICIT_NAME;
|
|
@llvm/pr-subscribers-llvm-mc Author: Hugo Melder (hmelder) ChangesThis pull request adds initial support for compiling Objective-C to WebAssembly. I tested my changes with libobjc2 and the swift-corelibs-blocksruntime. There are two outstanding issues, which I cannot fix as deeper knowledge of the subsystems is required:
First IssueEmscripten is processing the generated The core of the problem is that symbols with the I'm currently hacking around this by not exporting no-strip symbols. This is the default behaviour for Wasm. Second IssueHere is a minimal example that triggers the crash. #include<stdio.h>
int main(void) {
int ret = 0;
@<!-- -->try {
}
@<!-- -->catch (id a)
{
ret = 1;
puts("abc");
}
return ret;
}The following assertion is triggered: Here is the crash report main-c3884.zip. You can use emcc -fobjc-runtime=gnustep-2.2 -fwasm-exceptions -c main.mor just invoke clang directly: /home/vm/llvm-build-wasm/bin/clang -target wasm32-unknown-emscripten -mllvm -combiner-global-alias-analysis=false -mllvm -wasm-enable-sjlj -mllvm -wasm-use-legacy-eh=false -mllvm -disable-lsr --sysroot=/home/vm/emsdk/upstream/emscripten/cache/sysroot -DEMSCRIPTEN -fobjc-runtime=gnustep-2.2 -fwasm-exceptions -c main.mBuilding libobjc2 and the BlocksRuntimeBuilding the BlocksRuntimecmake -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_INSTALL_PREFIX=/home/vm/demo-install -DCMAKE_BUILD_TYPE=Debug -B build -G NinjaBuilding libobjc2cmake -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_INSTALL_PREFIX=/home/vm/demo-install -DBlocksRuntime_LIBRARIES=/home/vm/demo-install/lib/libBlocksRuntime.a -DBlocksRuntime_INCLUDE_DIR=/home/vm/demo-install/include/BlocksRuntime -DEMBEDDED_BLOCKS_RUNTIME=OFF -DTESTS=OFF -B build -DCMAKE_BUILD_TYPE=Debug -G NinjaFull diff: https://github.com/llvm/llvm-project/pull/169043.diff 3 Files Affected:
diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index 06643d4bdc211..3b9f9f306829d 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -179,8 +179,15 @@ class CGObjCGNU : public CGObjCRuntime {
(R.getVersion() >= VersionTuple(major, minor));
}
- std::string ManglePublicSymbol(StringRef Name) {
- return (StringRef(CGM.getTriple().isOSBinFormatCOFF() ? "$_" : "._") + Name).str();
+ const std::string ManglePublicSymbol(StringRef Name) {
+ auto triple = CGM.getTriple();
+
+ // Exported symbols in Emscripten must be a valid Javascript identifier.
+ if (triple.isOSBinFormatCOFF() || triple.isOSBinFormatWasm()) {
+ return (StringRef("$_") + Name).str();
+ } else {
+ return (StringRef("._") + Name).str();
+ }
}
std::string SymbolForProtocol(Twine Name) {
@@ -4106,8 +4113,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
if (!ClassAliases.empty()) {
llvm::Type *ArgTypes[2] = {PtrTy, PtrToInt8Ty};
llvm::FunctionType *RegisterAliasTy =
- llvm::FunctionType::get(Builder.getVoidTy(),
- ArgTypes, false);
+ llvm::FunctionType::get(BoolTy, ArgTypes, false);
llvm::Function *RegisterAlias = llvm::Function::Create(
RegisterAliasTy,
llvm::GlobalValue::ExternalWeakLinkage, "class_registerAlias_np",
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 30d3e5293a31b..6cbec5e17ae1a 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -8001,7 +8001,8 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
if ((runtime.getKind() == ObjCRuntime::GNUstep) &&
(runtime.getVersion() >= VersionTuple(2, 0)))
if (!getToolChain().getTriple().isOSBinFormatELF() &&
- !getToolChain().getTriple().isOSBinFormatCOFF()) {
+ !getToolChain().getTriple().isOSBinFormatCOFF() &&
+ !getToolChain().getTriple().isOSBinFormatWasm()) {
getToolChain().getDriver().Diag(
diag::err_drv_gnustep_objc_runtime_incompatible_binary)
<< runtime.getVersion().getMajor();
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index 15590b31fd07f..d882146e21b8a 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -1794,9 +1794,6 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
Flags |= wasm::WASM_SYMBOL_UNDEFINED;
if (WS.isNoStrip()) {
Flags |= wasm::WASM_SYMBOL_NO_STRIP;
- if (isEmscripten()) {
- Flags |= wasm::WASM_SYMBOL_EXPORTED;
- }
}
if (WS.hasImportName())
Flags |= wasm::WASM_SYMBOL_EXPLICIT_NAME;
|
🐧 Linux x64 Test Results
|
|
@sunfishcode, I see that you are the original author of https://reviews.llvm.org/D62542. As @dschuff said in the review back then:
This was in 2019, is this hack still required now that fastcomp is deprecated? Then problem with the current behaviour is that hidden no-strip symbols, added during codegen, are exported. |
|
@davidchisnall the changes in codegen are trivial:
|
|
Assuming that the new WASM exception implementation implements the mandatory functions and data structure of the Itanium EH ABI correctly, not much needs to be done to get EH working with libobjc2. I just need to find the root course of the crash... |
davidchisnall
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Objective-C bits look fine to me, the MC bit possibly should be a separate PR.
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
davidchisnall
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code LGTM once clang-format is happy.
We probably should have a test in tests/CodeGenObjC checking that the mangling is correct for WAsm.
Emscripten requires that exported symbols. See emscripten-core/emscripten#23563.
This pull request adds initial support for compiling Objective-C to WebAssembly. I tested my changes with libobjc2 and the swift-corelibs-blocksruntime.
There are two outstanding issues, which I cannot fix as deeper knowledge of the subsystems is required:
-fwasm-exceptionsFirst Issue
Emscripten is processing the generated
.wasmfile inemscripten.pyand checks if all exported symbols are valid javascript identifiers (tools/js_manipulation.py#L104). However, hidden symbols such as.objc_initare intentionally an invalid C identifier.The core of the problem is that symbols with the
WASM_SYMBOL_NO_STRIPattribute are exported when targeting Emscripten (https://reviews.llvm.org/D62542). This attribute is added to the symbol during relocation inWasmObjectWriter::recordRelocation. So we are accidentally exporting a lot of hidden symbols and not only ones generated by ObjC CG...I'm currently hacking around this by not exporting no-strip symbols. This is the default behaviour for Wasm.
Second Issue
Here is a minimal example that triggers the crash.
The following assertion is triggered:
Here is the crash report main-c3884.zip.
You can use
emccwith a modified LLVM build by exportingEM_LLVM_ROOTbefore sourcingemsdk/emsdk_env.sh:or just invoke clang directly:
Building libobjc2 and the BlocksRuntime
Building the BlocksRuntime
cmake -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_INSTALL_PREFIX=/home/vm/demo-install -DCMAKE_BUILD_TYPE=Debug -B build -G NinjaBuilding libobjc2
cmake -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_INSTALL_PREFIX=/home/vm/demo-install -DBlocksRuntime_LIBRARIES=/home/vm/demo-install/lib/libBlocksRuntime.a -DBlocksRuntime_INCLUDE_DIR=/home/vm/demo-install/include/BlocksRuntime -DEMBEDDED_BLOCKS_RUNTIME=OFF -DTESTS=OFF -B build -DCMAKE_BUILD_TYPE=Debug -G Ninja