Skip to content

Commit

Permalink
[SH] Changes to compile with wasi-sdk
Browse files Browse the repository at this point in the history
Wasi-sdk is much less Unix-like than the environment provided by
Emscripten and requires more profound changes for support.

Unix mman emulation requires:
- `-lwasi-emulated-mman`

Unfortunately JS and C++ exceptions are both a mess.

Wasi-sdk [does not support C++ exceptions yet](https://github.com/WebAssembly/wasi-sdk/tree/a4d918fa119c9beb712bf08bbb8fa9996aab0a71?tab=readme-ov-file#notable-limitations).

We can live with that, since Hermes for the most part compiles with
exceptions disabled anyway. However JSI relies on exceptions and it is
part of the compiled library. To get things working one needs to rely
on the following hack (which isn't included in this commit):

```c++

extern "C" void __cxa_throw(void* thrown_exception,
    std::type_info* tinfo,
    void (*dest)(void*)) {
  llvh::report_fatal_error("C++ exceptions not supported on Wasi");
}

extern "C" void* __cxa_allocate_exception(size_t) {
  llvh::report_fatal_error("C++ exceptions not supported on Wasi");
}
```

This causes any JSI exception to simply abort.

JS exceptions work fine with the bytecode interpreter, however code
produced by the *native backend* relies on `setjmp/longjmp`. Alas,
`setjmp/longjmp` are not well supported by Wasm. This fact was hidden by
Emscripten, which used its own JS shim and exceptions to implement them.
That, however, does not work with standalone WASI.

According to the [Wasi-sdk documentation](https://github.com/WebAssembly/wasi-sdk/blob/a4d918fa119c9beb712bf08bbb8fa9996aab0a71/SetjmpLongjmp.md), `setjmp/longjmp` can be supported,
using the Wasm exception handling proposal.

This requires:
- `-mllvm -wasm-enable-sjlj`
- `-lsetjmp`

I was able to successfully compile the shermes-generated code to a Wasm
binary with the following flags, however I was **not** able to find a
single standalone runtime that was able to run it out of the box!

Wasmtime and Wasmer refused to load the module with the error
"exceptions proposal not enabled". Iwasm failed to load it some error
about Wasm operand stack.

I am sure that it is possible to either find or configure a Wasm runtime
to support the exceptions proposal, but since none of the major runtimes
support if out of the box, I consider it useless for now. Sadly.

I am sure v8 supports it, but what's the point of using v8 for this?
First, v8 already supports JS, and second, Emscripten has that covered
already.

There is an experimental followup commit which turns setjmp() into noop
and longjmp() into abort(). That at least allows natively compiled JS to
run, until the first exception...
  • Loading branch information
tmikov committed Dec 30, 2024
1 parent 2bb1073 commit e6095b0
Show file tree
Hide file tree
Showing 34 changed files with 2,369 additions and 92 deletions.
2 changes: 2 additions & 0 deletions cmake/modules/Hermes.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ else (WIN32)
else ()
set(LLVM_HAVE_LINK_VERSION_SCRIPT 1)
endif ()
elseif (WASI)
# Do nothing for WASI. It will be detected at compile time.
else (FUCHSIA OR UNIX)
MESSAGE(SEND_ERROR "Unable to determine platform")
endif (FUCHSIA OR UNIX)
Expand Down
10 changes: 10 additions & 0 deletions external/dtoa/locks.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#include "llvh/Config/llvm-config.h"

#if LLVM_ENABLE_THREADS
#include <cassert>
#include <mutex>

Expand All @@ -15,3 +18,10 @@ extern "C" void FREE_DTOA_LOCK(int n) {
assert(n == 1 && "only dtoa lock 1 is supported");
mutex.unlock();
}
#else
extern "C" void ACQUIRE_DTOA_LOCK(int) {
}

extern "C" void FREE_DTOA_LOCK(int) {
}
#endif
4 changes: 3 additions & 1 deletion external/llvh/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ set(PACKAGE_NAME "LLVH")
set(PACKAGE_STRING "LLVH 8.0.0svn")
set(PACKAGE_VERSION "8.0.0svn")

set(LLVM_ENABLE_THREADS 1)
if ("${LLVM_ENABLE_THREADS}" STREQUAL "")
set(LLVM_ENABLE_THREADS 1)
endif ()
if (LLVH_REVERSE_ITERATION)
set(LLVM_ENABLE_REVERSE_ITERATION 1)
endif ()
Expand Down
1 change: 1 addition & 0 deletions external/llvh/cmake/config-ix.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ check_symbol_exists(strerror string.h HAVE_STRERROR)
check_symbol_exists(strerror_r string.h HAVE_STRERROR_R)
check_symbol_exists(strerror_s string.h HAVE_DECL_STRERROR_S)
check_symbol_exists(setenv stdlib.h HAVE_SETENV)
check_symbol_exists(tzset time.h HAVE_TZSET)
if( PURE_WINDOWS )
check_symbol_exists(_chsize_s io.h HAVE__CHSIZE_S)

Expand Down
3 changes: 3 additions & 0 deletions external/llvh/include/llvh/Config/config.h.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@
/* Define to 1 if you have the `setenv' function. */
#cmakedefine HAVE_SETENV ${HAVE_SETENV}

/* Define to 1 if you have the `tzset' function. */
#cmakedefine HAVE_TZSET ${HAVE_TZSET}

/* Define to 1 if you have the `sched_getaffinity' function. */
#cmakedefine HAVE_SCHED_GETAFFINITY ${HAVE_SCHED_GETAFFINITY}

Expand Down
16 changes: 16 additions & 0 deletions external/llvh/include/llvh/Support/Atomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,20 @@ namespace llvh {
}
}

#ifdef __GNUC__

namespace llvh::sys {
inline void MemoryFence() {
__sync_synchronize();
}
inline cas_flag CompareAndSwap(volatile cas_flag* ptr,
cas_flag new_value,
cas_flag old_value) {
return __sync_val_compare_and_swap(ptr, old_value, new_value);
}

}

#endif

#endif
10 changes: 5 additions & 5 deletions external/llvh/include/llvh/Support/FileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ class UniqueID {
/// represents the information provided by Windows FileFirstFile/FindNextFile.
class basic_file_status {
protected:
#if defined(LLVM_ON_UNIX)
#if defined(LLVM_ON_UNIX) || defined(__wasi__)
time_t fs_st_atime = 0;
time_t fs_st_mtime = 0;
uid_t fs_st_uid = 0;
Expand All @@ -179,7 +179,7 @@ class basic_file_status {

explicit basic_file_status(file_type Type) : Type(Type) {}

#if defined(LLVM_ON_UNIX)
#if defined(LLVM_ON_UNIX) || defined(__wasi__)
basic_file_status(file_type Type, perms Perms, time_t ATime, time_t MTime,
uid_t UID, gid_t GID, off_t Size)
: fs_st_atime(ATime), fs_st_mtime(MTime), fs_st_uid(UID), fs_st_gid(GID),
Expand All @@ -202,7 +202,7 @@ class basic_file_status {
TimePoint<> getLastAccessedTime() const;
TimePoint<> getLastModificationTime() const;

#if defined(LLVM_ON_UNIX)
#if defined(LLVM_ON_UNIX) || defined(__wasi__)
uint32_t getUser() const { return fs_st_uid; }
uint32_t getGroup() const { return fs_st_gid; }
uint64_t getSize() const { return fs_st_size; }
Expand All @@ -229,7 +229,7 @@ class basic_file_status {
class file_status : public basic_file_status {
friend bool equivalent(file_status A, file_status B);

#if defined(LLVM_ON_UNIX)
#if defined(LLVM_ON_UNIX) || defined(__wasi__)
dev_t fs_st_dev = 0;
nlink_t fs_st_nlinks = 0;
ino_t fs_st_ino = 0;
Expand All @@ -245,7 +245,7 @@ class file_status : public basic_file_status {

explicit file_status(file_type Type) : basic_file_status(Type) {}

#if defined(LLVM_ON_UNIX)
#if defined(LLVM_ON_UNIX) || defined(__wasi__)
file_status(file_type Type, perms Perms, dev_t Dev, nlink_t Links, ino_t Ino,
time_t ATime, time_t MTime, uid_t UID, gid_t GID, off_t Size)
: basic_file_status(Type, Perms, ATime, MTime, UID, GID, Size),
Expand Down
2 changes: 1 addition & 1 deletion external/llvh/include/llvh/Support/Program.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace sys {

/// This is the OS-specific separator for PATH like environment variables:
// a colon on Unix or a semicolon on Windows.
#if defined(LLVM_ON_UNIX)
#if defined(LLVM_ON_UNIX) || defined(__wasi__)
const char EnvPathSeparator = ':';
#elif defined (_WIN32)
const char EnvPathSeparator = ';';
Expand Down
3 changes: 3 additions & 0 deletions external/llvh/lib/Support/Host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
#ifdef _WIN32
#include "Windows/Host.inc"
#endif
#ifdef __wasi__
#include "Wasi/Host.inc"
#endif
#ifdef _MSC_VER
#include <intrin.h>
#endif
Expand Down
3 changes: 3 additions & 0 deletions external/llvh/lib/Support/Path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,9 @@ ErrorOr<perms> getPermissions(const Twine &Path) {
#if defined(_WIN32)
#include "Windows/Path.inc"
#endif
#ifdef __wasi__
#include "Wasi/Path.inc"
#endif

namespace llvh {
namespace sys {
Expand Down
3 changes: 3 additions & 0 deletions external/llvh/lib/Support/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,6 @@ bool Process::AreCoreFilesPrevented() { return coreFilesPrevented; }
#ifdef _WIN32
#include "Windows/Process.inc"
#endif
#ifdef __wasi__
#include "Wasi/Process.inc"
#endif
3 changes: 3 additions & 0 deletions external/llvh/lib/Support/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,6 @@ bool sys::commandLineFitsWithinSystemLimits(StringRef Program,
#ifdef _WIN32
#include "Windows/Program.inc"
#endif
#ifdef __wasi__
#include "Wasi/Program.inc"
#endif
3 changes: 3 additions & 0 deletions external/llvh/lib/Support/Signals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,6 @@ static bool printSymbolizedStackTrace(StringRef Argv0, void **StackTrace,
#ifdef _WIN32
#include "Windows/Signals.inc"
#endif
#ifdef __wasi__
#include "Wasi/Signals.inc"
#endif
68 changes: 68 additions & 0 deletions external/llvh/lib/Support/Wasi/Host.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//===- llvm/Support/Unix/Host.inc -------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the UNIX Host support.
//
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only generic UNIX code that
//=== is guaranteed to work on *all* UNIX variants.
//===----------------------------------------------------------------------===//

#include "Unix.h"
#include "llvh/ADT/StringRef.h"
#include "llvh/Config/config.h"
#include <cctype>
#include <string>
#include <sys/utsname.h>

using namespace llvh;

static std::string getOSVersion() {
struct utsname info;

if (uname(&info))
return "";

return info.release;
}

static std::string updateTripleOSVersion(std::string TargetTripleString) {
// On darwin, we want to update the version to match that of the target.
std::string::size_type DarwinDashIdx = TargetTripleString.find("-darwin");
if (DarwinDashIdx != std::string::npos) {
TargetTripleString.resize(DarwinDashIdx + strlen("-darwin"));
TargetTripleString += getOSVersion();
return TargetTripleString;
}
std::string::size_type MacOSDashIdx = TargetTripleString.find("-macos");
if (MacOSDashIdx != std::string::npos) {
TargetTripleString.resize(MacOSDashIdx);
// Reset the OS to darwin as the OS version from `uname` doesn't use the
// macOS version scheme.
TargetTripleString += "-darwin";
TargetTripleString += getOSVersion();
}
return TargetTripleString;
}

std::string sys::getDefaultTargetTriple() {
std::string TargetTripleString =
updateTripleOSVersion(LLVM_DEFAULT_TARGET_TRIPLE);

// Override the default target with an environment variable named by
// LLVM_TARGET_TRIPLE_ENV.
#if defined(LLVM_TARGET_TRIPLE_ENV)
if (const char *EnvTriple = std::getenv(LLVM_TARGET_TRIPLE_ENV))
TargetTripleString = EnvTriple;
#endif

return TargetTripleString;
}
Loading

0 comments on commit e6095b0

Please sign in to comment.