1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  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_tstd::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 } } // namespace cmajor::rt
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* assertionconst char* functionconst char* sourceFilePathint lineNumber)
132 {
133     if (userAssertionFailureFunction)
134     {
135         userAssertionFailureFunction(assertionfunctionsourceFilePathlineNumber);
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(2errorStringHandle);
144         RtWrite(stdErrorreinterpret_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* exceptionvoid* 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** exceptionuint64_t& exceptionClassIdHiuint64_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* exceptionuint64_t exceptionClassIdHiuint64_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 }