1
2
3
4
5
6 #include <cmajor/rt/Error.hpp>
7 #include <cmajor/rt/CallStack.hpp>
8 #include <cmajor/rt/Io.hpp>
9 #include <cmajor/rt/Classes.hpp>
10 #include <soulng/util/Error.hpp>
11 #include <mutex>
12 #include <sstream>
13 #include <unordered_map>
14 #include <stdlib.h>
15 #include <memory>
16
17 namespace cmajor { namespace rt {
18
19 class ErrorTable
20 {
21 public:
22 static void Init();
23 static void Done();
24 static ErrorTable& Instance() { Assert(instance, "error table not initialized"); return *instance; }
25 int32_t InstallError(const std::string& errorMessage);
26 const char* GetError(int32_t errorId);
27 void DisposeError(int32_t errorId);
28 private:
29 static std::unique_ptr<ErrorTable> instance;
30 std::mutex mtx;
31 std::unordered_map<int32_t, std::string> errorMap;
32 int32_t nextErrorId;
33 ErrorTable();
34 };
35
36 std::unique_ptr<ErrorTable> ErrorTable::instance;
37
38 void ErrorTable::Init()
39 {
40 instance.reset(new ErrorTable());
41 }
42
43 void ErrorTable::Done()
44 {
45 instance.reset();
46 }
47
48 ErrorTable::ErrorTable() : nextErrorId(1)
49 {
50 }
51
52 int32_t ErrorTable::InstallError(const std::string& errorMessage)
53 {
54 std::lock_guard<std::mutex> lock(mtx);
55 int32_t errorId = nextErrorId++;
56 errorMap[errorId] = errorMessage;
57 return errorId;
58 }
59
60 const char* ErrorTable::GetError(int32_t errorId)
61 {
62 std::lock_guard<std::mutex> lock(mtx);
63 auto it = errorMap.find(errorId);
64 if (it != errorMap.cend())
65 {
66 return it->second.c_str();
67 }
68 else
69 {
70 return "<error message not found>";
71 }
72 }
73
74 void ErrorTable::DisposeError(int32_t errorId)
75 {
76 std::lock_guard<std::mutex> lock(mtx);
77 errorMap.erase(errorId);
78 }
79
80 int32_t InstallError(const std::string& errorMessage)
81 {
82 return -ErrorTable::Instance().InstallError(errorMessage);
83 }
84
85 const char* GetError(int32_t errorId)
86 {
87 return ErrorTable::Instance().GetError(-errorId);
88 }
89
90 void DisposeError(int32_t errorId)
91 {
92 ErrorTable::Instance().DisposeError(-errorId);
93 }
94
95 #ifdef _WIN32
96
97
98
99
100 #else
101
102 void* currentException = nullptr;
103 uint64_t currentExceptionClassId[2];
104
105 #endif
106
107 void InitError()
108 {
109 ErrorTable::Init();
110 }
111
112 void DoneError()
113 {
114 ErrorTable::Done();
115 }
116
117 } }
118
119 AssertionFailureFunction userAssertionFailureFunction;
120
121 bool RtIsUserAssertionFailureFunctionSet()
122 {
123 return userAssertionFailureFunction != nullptr;
124 }
125
126 void RtSetUserAssertionFailureFunction(AssertionFailureFunction userAssertionFailureFunc)
127 {
128 userAssertionFailureFunction = userAssertionFailureFunc;
129 }
130
131 void RtFailAssertion(const char* assertion, const char* function, const char* sourceFilePath, int lineNumber)
132 {
133 if (userAssertionFailureFunction)
134 {
135 userAssertionFailureFunction(assertion, function, sourceFilePath, lineNumber);
136 }
137 else
138 {
139 std::stringstream s;
140 s << "assertion '" << assertion << "' failed in function '" << function << "' at " << sourceFilePath << ":" << lineNumber << "\n";
141 std::string str = s.str();
142 int32_t errorStringHandle = -1;
143 void* stdError = RtOpenStdFile(2, errorStringHandle);
144 RtWrite(stdError, reinterpret_cast<const uint8_t*>(str.c_str()), str.length(), errorStringHandle);
145 RtPrintCallStack(stdError);
146 exit(exitCodeAssertionFailed);
147 }
148 }
149
150 const char* RtGetError(int32_t errorId)
151 {
152 return cmajor::rt::GetError(errorId);
153 }
154
155 void RtDisposeError(int32_t errorId)
156 {
157 cmajor::rt::DisposeError(errorId);
158 }
159
160 void RtThrowException(void* exception, void* exceptionTypeId)
161 {
162 cmajor::rt::currentException = exception;
163 boost::uuids::uuid* exTypeId = reinterpret_cast<boost::uuids::uuid*>(exceptionTypeId);
164 boost::multiprecision::uint128_t exceptionClassId = cmajor::rt::GetClassId(*exTypeId);
165 cmajor::rt::currentExceptionClassId[0] = static_cast<uint64_t>(exceptionClassId >> 64);
166 cmajor::rt::currentExceptionClassId[1] = static_cast<uint64_t>(exceptionClassId);
167 throw cmajor::eh::Exception();
168 }
169
170 void RtCaptureException(void** exception, uint64_t& exceptionClassIdHi, uint64_t& exceptionClassIdLo)
171 {
172 *exception = cmajor::rt::currentException;
173 cmajor::rt::currentException = nullptr;
174 exceptionClassIdHi = static_cast<uint64_t>(cmajor::rt::currentExceptionClassId[0]);
175 exceptionClassIdLo = static_cast<uint64_t>(cmajor::rt::currentExceptionClassId[1]);
176 cmajor::rt::currentExceptionClassId[0] = 0;
177 cmajor::rt::currentExceptionClassId[1] = 0;
178 }
179
180 void RtThrowCapturedException(void* exception, uint64_t exceptionClassIdHi, uint64_t exceptionClassIdLo)
181 {
182 cmajor::rt::currentException = exception;
183 cmajor::rt::currentExceptionClassId[0] = exceptionClassIdHi;
184 cmajor::rt::currentExceptionClassId[1] = exceptionClassIdLo;
185 throw cmajor::eh::Exception();
186 }
187
188 bool RtHandleException(void* exceptionTypeId)
189 {
190 boost::multiprecision::uint128_t currentExceptionClassId = boost::multiprecision::uint128_t(cmajor::rt::currentExceptionClassId[0]) << 64 | cmajor::rt::currentExceptionClassId[1];
191 boost::uuids::uuid* exTypeId = reinterpret_cast<boost::uuids::uuid*>(exceptionTypeId);
192 boost::multiprecision::uint128_t exceptionClassId = cmajor::rt::GetClassId(*exTypeId);
193 bool handle = currentExceptionClassId % exceptionClassId == 0;
194 return handle;
195 }
196
197 void* RtGetException()
198 {
199 return cmajor::rt::currentException;
200 }
201
202 void* RtGetExceptionTypeId()
203 {
204 return EhGetExceptionTypeId();
205 }