1 | /* |
2 | * Copyright 2016 WebAssembly Community Group participants |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #ifndef wasm_support_utilities_h |
18 | #define wasm_support_utilities_h |
19 | |
20 | #include "compiler-support.h" |
21 | |
22 | #include <cassert> |
23 | #include <cstdint> |
24 | #include <cstring> |
25 | #include <iostream> |
26 | #include <memory> |
27 | #include <sstream> |
28 | #include <type_traits> |
29 | |
30 | #include "support/bits.h" |
31 | |
32 | namespace wasm { |
33 | |
34 | // Type punning needs to be done through this function to avoid undefined |
35 | // behavior: unions and reinterpret_cast aren't valid approaches. |
36 | template<class Destination, class Source> |
37 | inline Destination bit_cast(const Source& source) { |
38 | static_assert(sizeof(Destination) == sizeof(Source), |
39 | "bit_cast needs to be between types of the same size" ); |
40 | static_assert(std::is_trivial_v<Destination> && |
41 | std::is_standard_layout_v<Destination>, |
42 | "non-POD bit_cast undefined" ); |
43 | static_assert(std::is_trivial_v<Source> && std::is_standard_layout_v<Source>, |
44 | "non-POD bit_cast undefined" ); |
45 | Destination destination; |
46 | std::memcpy(&destination, &source, sizeof(destination)); |
47 | return destination; |
48 | } |
49 | |
50 | inline size_t alignAddr(size_t address, size_t alignment) { |
51 | assert(alignment && Bits::isPowerOf2((uint32_t)alignment) && |
52 | "Alignment is not a power of two!" ); |
53 | |
54 | assert(address + alignment - 1 >= address); |
55 | |
56 | return ((address + alignment - 1) & ~(alignment - 1)); |
57 | } |
58 | |
59 | // For fatal errors which could arise from input (i.e. not assertion failures) |
60 | class Fatal { |
61 | private: |
62 | std::stringstream buffer; |
63 | |
64 | public: |
65 | Fatal() { buffer << "Fatal: " ; } |
66 | template<typename T> Fatal& operator<<(T&& arg) { |
67 | buffer << arg; |
68 | return *this; |
69 | } |
70 | #ifndef THROW_ON_FATAL |
71 | [[noreturn]] ~Fatal() { |
72 | std::cerr << buffer.str() << std::endl; |
73 | // Use _Exit here to avoid calling static destructors. This avoids deadlocks |
74 | // in (for example) the thread worker pool, where workers hold a lock while |
75 | // performing their work. |
76 | _Exit(EXIT_FAILURE); |
77 | } |
78 | #else |
79 | // This variation is a best-effort attempt to make fatal errors recoverable |
80 | // for embedders of Binaryen as a library, namely wasm-opt-rs. |
81 | // |
82 | // Throwing in destructors is strongly discouraged, since it is easy to |
83 | // accidentally throw during unwinding, which will trigger an abort. Since |
84 | // `Fatal` is a special type that only occurs on error paths, we are hoping it |
85 | // is never constructed during unwinding or while destructing another type. |
86 | [[noreturn]] ~Fatal() noexcept(false) { |
87 | throw std::runtime_error(buffer.str()); |
88 | } |
89 | #endif |
90 | }; |
91 | |
92 | [[noreturn]] void handle_unreachable(const char* msg = nullptr, |
93 | const char* file = nullptr, |
94 | unsigned line = 0); |
95 | |
96 | // If control flow reaches the point of the WASM_UNREACHABLE(), the program is |
97 | // undefined. |
98 | #ifndef NDEBUG |
99 | #define WASM_UNREACHABLE(msg) wasm::handle_unreachable(msg, __FILE__, __LINE__) |
100 | #elif defined(WASM_BUILTIN_UNREACHABLE) |
101 | #define WASM_UNREACHABLE(msg) WASM_BUILTIN_UNREACHABLE |
102 | #else |
103 | #define WASM_UNREACHABLE(msg) wasm::handle_unreachable() |
104 | #endif |
105 | |
106 | } // namespace wasm |
107 | |
108 | #endif // wasm_support_utilities_h |
109 | |