odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

errorhandler.h (7893B)


      1 // This file is part of AsmJit project <https://asmjit.com>
      2 //
      3 // See <asmjit/core.h> or LICENSE.md for license and copyright information
      4 // SPDX-License-Identifier: Zlib
      5 
      6 #ifndef ASMJIT_CORE_ERRORHANDLER_H_INCLUDED
      7 #define ASMJIT_CORE_ERRORHANDLER_H_INCLUDED
      8 
      9 #include "../core/globals.h"
     10 
     11 ASMJIT_BEGIN_NAMESPACE
     12 
     13 //! \addtogroup asmjit_error_handling
     14 //! \{
     15 
     16 class BaseEmitter;
     17 
     18 //! Error handler can be used to override the default behavior of error handling.
     19 //!
     20 //! It's available to all classes that inherit `BaseEmitter`. Override \ref ErrorHandler::handle_error() to implement
     21 //! your own error handler.
     22 //!
     23 //! The following use-cases are supported:
     24 //!
     25 //!   - Record the error and continue code generation. This is the simplest approach that can be used to at least log
     26 //!     possible errors.
     27 //!   - Throw an exception. AsmJit doesn't use exceptions and is completely exception-safe, but it's perfectly legal
     28 //!     to throw an exception from the error handler.
     29 //!   - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler, Builder and Compiler to
     30 //!     a consistent state before calling \ref handle_error(), so `longjmp()` can be used without issues to cancel the
     31 //!     code generation if an error occurred. This method can be used if exception handling in your project is turned
     32 //!     off and you still want some comfort. In most cases it should be safe as AsmJit uses \ref Arena allocator and
     33 //!     the ownership of allocated memory it allocates always ends with the instance that allocated it. If using this
     34 //!     approach please never jump outside the life-time of \ref CodeHolder and \ref BaseEmitter.
     35 //!
     36 //! \ref ErrorHandler can be attached to \ref CodeHolder or \ref BaseEmitter, which has a priority. The example below
     37 //! uses error handler that just prints the error, but lets AsmJit continue:
     38 //!
     39 //! ```
     40 //! // Error Handling #1 - Logging and returning Error.
     41 //! #include <asmjit/x86.h>
     42 //! #include <stdio.h>
     43 //!
     44 //! using namespace asmjit;
     45 //!
     46 //! // Error handler that just prints the error and lets AsmJit ignore it.
     47 //! class SimpleErrorHandler : public ErrorHandler {
     48 //! public:
     49 //!   Error err;
     50 //!
     51 //!   inline SimpleErrorHandler() : err(Error::kOk) {}
     52 //!
     53 //!   void handle_error(Error err, const char* message, BaseEmitter* origin) override {
     54 //!     this->err = err;
     55 //!     fprintf(stderr, "ERROR: %s\n", message);
     56 //!   }
     57 //! };
     58 //!
     59 //! int main() {
     60 //!   JitRuntime rt;
     61 //!   SimpleErrorHandler eh;
     62 //!
     63 //!   CodeHolder code;
     64 //!   code.init(rt.environment(), rt.cpu_features());
     65 //!   code.set_error_handler(&eh);
     66 //!
     67 //!   // Try to emit instruction that doesn't exist.
     68 //!   x86::Assembler a(&code);
     69 //!   a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1);
     70 //!
     71 //!   if (eh.err) {
     72 //!     // Assembler failed!
     73 //!     return 1;
     74 //!   }
     75 //!
     76 //!   return 0;
     77 //! }
     78 //! ```
     79 //!
     80 //! If error happens during instruction emitting / encoding the assembler behaves transactionally - the output buffer
     81 //! won't advance if encoding failed, thus either a fully encoded instruction or nothing is emitted. The error handling
     82 //! shown above is useful, but it's still not the best way of dealing with errors in AsmJit. The following example
     83 //! shows how to use exception handling to handle errors in a more C++ way:
     84 //!
     85 //! ```
     86 //! // Error Handling #2 - Throwing an exception.
     87 //! #include <asmjit/x86.h>
     88 //! #include <exception>
     89 //! #include <string>
     90 //! #include <stdio.h>
     91 //!
     92 //! using namespace asmjit;
     93 //!
     94 //! // Error handler that throws a user-defined `AsmJitException`.
     95 //! class AsmJitException : public std::exception {
     96 //! public:
     97 //!   Error err;
     98 //!   std::string message;
     99 //!
    100 //!   AsmJitException(Error err, const char* message) noexcept
    101 //!     : err(err),
    102 //!       message(message) {}
    103 //!
    104 //!   const char* what() const noexcept override { return message.c_str(); }
    105 //! };
    106 //!
    107 //! class ThrowableErrorHandler : public ErrorHandler {
    108 //! public:
    109 //!   // Throw is possible, functions that use ErrorHandler are never 'noexcept'.
    110 //!   void handle_error(Error err, const char* message, BaseEmitter* origin) override {
    111 //!     throw AsmJitException(err, message);
    112 //!   }
    113 //! };
    114 //!
    115 //! int main() {
    116 //!   JitRuntime rt;
    117 //!   ThrowableErrorHandler eh;
    118 //!
    119 //!   CodeHolder code;
    120 //!   code.init(rt.environment(), rt.cpu_features());
    121 //!   code.set_error_handler(&eh);
    122 //!
    123 //!   x86::Assembler a(&code);
    124 //!
    125 //!   // Try to emit instruction that doesn't exist.
    126 //!   try {
    127 //!     a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1);
    128 //!   }
    129 //!   catch (const AsmJitException& ex) {
    130 //!     printf("EXCEPTION THROWN: %s\n", ex.what());
    131 //!     return 1;
    132 //!   }
    133 //!
    134 //!   return 0;
    135 //! }
    136 //! ```
    137 //!
    138 //! If C++ exceptions are not what you like or your project turns off them completely there is still a way of reducing
    139 //! the error handling to a minimum by using a standard setjmp/longjmp approach. AsmJit is exception-safe and cleans
    140 //! up everything before calling the ErrorHandler, so any approach is safe. You can simply jump from the error handler
    141 //! without causing any side-effects or memory leaks. The following example demonstrates how it could be done:
    142 //!
    143 //! ```
    144 //! // Error Handling #3 - Using setjmp/longjmp if exceptions are not allowed.
    145 //! #include <asmjit/x86.h>
    146 //! #include <setjmp.h>
    147 //! #include <stdio.h>
    148 //!
    149 //! class LongJmpErrorHandler : public asmjit::ErrorHandler {
    150 //! public:
    151 //!   inline LongJmpErrorHandler() : err(asmjit::Error::kOk) {}
    152 //!
    153 //!   void handle_error(asmjit::Error err, const char* message, asmjit::BaseEmitter* origin) override {
    154 //!     this->err = err;
    155 //!     longjmp(state, 1);
    156 //!   }
    157 //!
    158 //!   jmp_buf state;
    159 //!   asmjit::Error err;
    160 //! };
    161 //!
    162 //! int main(int argc, char* argv[]) {
    163 //!   using namespace asmjit;
    164 //!
    165 //!   JitRuntime rt;
    166 //!   LongJmpErrorHandler eh;
    167 //!
    168 //!   CodeHolder code;
    169 //!   code.init(rt.environment(), rt.cpu_features());
    170 //!   code.set_error_handler(&eh);
    171 //!
    172 //!   x86::Assembler a(&code);
    173 //!
    174 //!   if (!setjmp(eh.state)) {
    175 //!     // Try to emit instruction that doesn't exist.
    176 //!     a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1);
    177 //!   }
    178 //!   else {
    179 //!     Error err = eh.err;
    180 //!     printf("ASMJIT ERROR: 0x%08X [%s]\n", err, DebugUtils::error_as_string(err));
    181 //!   }
    182 //!
    183 //!   return 0;
    184 //! }
    185 //! ```
    186 class ASMJIT_VIRTAPI ErrorHandler {
    187 public:
    188   ASMJIT_BASE_CLASS(ErrorHandler)
    189 
    190   //! \name Construction & Destruction
    191   //! \{
    192 
    193   //! Creates a new `ErrorHandler` instance.
    194   ASMJIT_API ErrorHandler() noexcept;
    195   //! Destroys the `ErrorHandler` instance.
    196   ASMJIT_API virtual ~ErrorHandler() noexcept;
    197 
    198   //! \}
    199 
    200   //! \name Interface
    201   //! \{
    202 
    203   //! Error handler (must be reimplemented).
    204   //!
    205   //! Error handler is called after an error happened and before it's propagated to the caller. There are multiple
    206   //! ways how the error handler can be used:
    207   //!
    208   //! 1. User-based error handling without throwing exception or using C's`longjmp()`. This is for users that don't
    209   //!     use exceptions and want customized error handling.
    210   //!
    211   //! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely exception-safe, but you can throw
    212   //!     exception from your error handler if this way is the preferred way of handling errors in your project.
    213   //!
    214   //! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts `BaseEmitter` to a consistent state before
    215   //!    calling `handle_error()`  so `longjmp()` can be used without any issues to cancel the code generation if an
    216   //!    error occurred. There is no difference between exceptions and `longjmp()` from AsmJit's perspective, however,
    217   //!    never jump outside of `CodeHolder` and `BaseEmitter` scope as you would leak memory.
    218   ASMJIT_API virtual void handle_error(Error err, const char* message, BaseEmitter* origin);
    219 
    220   //! \}
    221 };
    222 
    223 //! \}
    224 
    225 ASMJIT_END_NAMESPACE
    226 
    227 #endif // ASMJIT_CORE_ERRORHANDLER_H_INCLUDED
    228