mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-10 01:51:03 +09:00
LibWasm/WASI+wasm: Make WASI exit() "noreturn" instead of making it exit
This makes it so exit() traps with a known error; an embedder (wasm.cpp) can simply match this format and handle the request accordingly.
This commit is contained in:
parent
e08a7cb94d
commit
16dd8d4d3b
Notes:
sideshowbarker
2024-07-18 23:45:34 +09:00
Author: https://github.com/alimpfard
Commit: 16dd8d4d3b
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/671
3 changed files with 41 additions and 10 deletions
|
@ -428,9 +428,9 @@ ErrorOr<Result<EnvironSizes>> Implementation::impl$environ_sizes_get(Configurati
|
|||
});
|
||||
}
|
||||
|
||||
ErrorOr<Result<void>> Implementation::impl$proc_exit(Configuration&, ExitCode exit_code)
|
||||
ErrorOr<void> Implementation::impl$proc_exit(Configuration&, ExitCode exit_code)
|
||||
{
|
||||
exit(exit_code);
|
||||
return Error::from_errno(-static_cast<i32>(exit_code + 1));
|
||||
}
|
||||
|
||||
ErrorOr<Result<void>> Implementation::impl$fd_close(Configuration&, FD fd)
|
||||
|
@ -963,18 +963,37 @@ struct HostTypeImpl<T> {
|
|||
using Type = UnderlyingType<T>;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct HostTypeImpl<LittleEndian<T>> {
|
||||
using Type = typename HostTypeImpl<T>::Type;
|
||||
};
|
||||
|
||||
template<typename T, typename t, typename... Fs>
|
||||
struct HostTypeImpl<DistinctNumeric<T, t, Fs...>> {
|
||||
using Type = typename HostTypeImpl<T>::Type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using HostType = typename HostTypeImpl<T>::Type;
|
||||
|
||||
template<typename T>
|
||||
auto CompatibleValueType = IsOneOf<HostType<T>, i8, i16, i32, u8, u16>
|
||||
auto CompatibleValueType = IsOneOf<HostType<T>, char, i8, i16, i32, u8, u16>
|
||||
? Wasm::ValueType(Wasm::ValueType::I32)
|
||||
: Wasm::ValueType(Wasm::ValueType::I64);
|
||||
|
||||
template<typename R, typename... Args, ErrorOr<Result<R>> (Implementation::*impl)(Configuration&, Args...)>
|
||||
template<typename RV, typename... Args, ErrorOr<RV> (Implementation::*impl)(Configuration&, Args...)>
|
||||
struct InvocationOf<impl> {
|
||||
HostFunction operator()(Implementation& self, StringView function_name)
|
||||
{
|
||||
using R = typename decltype([] {
|
||||
if constexpr (IsSame<RV, Result<void>>)
|
||||
return TypeWrapper<void> {};
|
||||
else if constexpr (IsSpecializationOf<RV, Result>)
|
||||
return TypeWrapper<RemoveCVReference<decltype(*declval<RV>().result())>> {};
|
||||
else
|
||||
return TypeWrapper<RV> {};
|
||||
}())::Type;
|
||||
|
||||
Vector<ValueType> arguments_types { CompatibleValueType<typename ABI::ToCompatibleValue<Args>::Type>... };
|
||||
if constexpr (!IsVoid<R>) {
|
||||
if constexpr (requires { declval<typename R::SerializationComponents>(); }) {
|
||||
|
@ -986,6 +1005,10 @@ struct InvocationOf<impl> {
|
|||
}
|
||||
}
|
||||
|
||||
Vector<ValueType> return_ty;
|
||||
if constexpr (IsSpecializationOf<RV, Result>)
|
||||
return_ty.append(ValueType(ValueType::I32));
|
||||
|
||||
return HostFunction(
|
||||
[&self, function_name](Configuration& configuration, Vector<Value>& arguments) -> Wasm::Result {
|
||||
Tuple args = [&]<typename... Ts, auto... Is>(IndexSequence<Is...>) {
|
||||
|
@ -994,12 +1017,18 @@ struct InvocationOf<impl> {
|
|||
|
||||
auto result = args.apply_as_args([&](auto&&... impl_args) { return (self.*impl)(configuration, impl_args...); });
|
||||
dbgln_if(WASI_DEBUG, "WASI: {}({}) = {}", function_name, arguments, result);
|
||||
if (result.is_error())
|
||||
return Wasm::Trap { ByteString::formatted("Invalid call to {}() = {}", function_name, result.error()) };
|
||||
if (result.is_error()) {
|
||||
auto error = result.release_error();
|
||||
if (error.is_errno())
|
||||
return Wasm::Trap { ByteString::formatted("exit:{}", error.code() + 1) };
|
||||
return Wasm::Trap { ByteString::formatted("Invalid call to {}() = {}", function_name, error) };
|
||||
}
|
||||
|
||||
auto value = result.release_value();
|
||||
if (value.is_error())
|
||||
return Wasm::Result { Vector { Value { ValueType(ValueType::I32), static_cast<u64>(to_underlying(value.error().value())) } } };
|
||||
if constexpr (IsSpecializationOf<RV, Result>) {
|
||||
if (value.is_error())
|
||||
return Wasm::Result { Vector { Value { ValueType(ValueType::I32), static_cast<u64>(to_underlying(value.error().value())) } } };
|
||||
}
|
||||
|
||||
if constexpr (!IsVoid<R>) {
|
||||
// Return values are passed as pointers, after the arguments
|
||||
|
@ -1015,7 +1044,7 @@ struct InvocationOf<impl> {
|
|||
},
|
||||
FunctionType {
|
||||
move(arguments_types),
|
||||
{ ValueType(ValueType::I32) },
|
||||
return_ty,
|
||||
},
|
||||
function_name);
|
||||
}
|
||||
|
|
|
@ -884,7 +884,7 @@ private:
|
|||
ErrorOr<Result<void>> impl$path_symlink(Configuration&, Pointer<u8> old_path, Size old_path_len, FD, Pointer<u8> new_path, Size new_path_len);
|
||||
ErrorOr<Result<void>> impl$path_unlink_file(Configuration&, FD, Pointer<u8> path, Size path_len);
|
||||
ErrorOr<Result<Size>> impl$poll_oneoff(Configuration&, ConstPointer<Subscription> in, Pointer<Event> out, Size nsubscriptions);
|
||||
ErrorOr<Result<void>> impl$proc_exit(Configuration&, ExitCode); // Note: noreturn.
|
||||
ErrorOr<void> impl$proc_exit(Configuration&, ExitCode);
|
||||
ErrorOr<Result<void>> impl$proc_raise(Configuration&, Signal);
|
||||
ErrorOr<Result<void>> impl$sched_yield(Configuration&);
|
||||
ErrorOr<Result<void>> impl$random_get(Configuration&, Pointer<u8> buf, Size buf_len);
|
||||
|
|
|
@ -804,6 +804,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
launch_repl();
|
||||
|
||||
if (result.is_trap()) {
|
||||
if (result.trap().reason.starts_with("exit:"sv))
|
||||
return -result.trap().reason.substring_view(5).to_number<i32>().value_or(-1);
|
||||
warnln("Execution trapped: {}", result.trap().reason);
|
||||
} else {
|
||||
if (!result.values().is_empty())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue