LCOV - code coverage report
Current view: top level - asmjit - codeholder.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 120 259 46.3 %
Date: 2024-10-18 14:00:27 Functions: 12 25 48.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             : Copyright (c) 2008-2017, Petr Kobalicek
       3             : 
       4             : This software is provided 'as-is', without any express or implied
       5             : warranty. In no event will the authors be held liable for any damages
       6             : arising from the use of this software.
       7             : 
       8             : Permission is granted to anyone to use this software for any purpose,
       9             : including commercial applications, and to alter it and redistribute it
      10             : freely, subject to the following restrictions:
      11             : 
      12             : 1. The origin of this software must not be misrepresented; you must not
      13             :    claim that you wrote the original software. If you use this software
      14             :    in a product, an acknowledgment in the product documentation would be
      15             :    appreciated but is not required.
      16             : 2. Altered source versions must be plainly marked as such, and must not be
      17             :    misrepresented as being the original software.
      18             : 3. This notice may not be removed or altered from any source distribution.
      19             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      20             : #ifdef __PLUMED_HAS_ASMJIT
      21             : #pragma GCC diagnostic push
      22             : #pragma GCC diagnostic ignored "-Wpedantic"
      23             : // [AsmJit]
      24             : // Complete x86/x64 JIT and Remote Assembler for C++.
      25             : //
      26             : // [License]
      27             : // Zlib - See LICENSE.md file in the package.
      28             : 
      29             : // [Export]
      30             : #define ASMJIT_EXPORTS
      31             : 
      32             : // [Dependencies]
      33             : #include "./assembler.h"
      34             : #include "./utils.h"
      35             : #include "./vmem.h"
      36             : 
      37             : // [Api-Begin]
      38             : #include "./asmjit_apibegin.h"
      39             : 
      40             : namespace PLMD {
      41             : namespace asmjit {
      42             : 
      43             : // ============================================================================
      44             : // [asmjit::ErrorHandler]
      45             : // ============================================================================
      46             : 
      47           0 : ErrorHandler::ErrorHandler() noexcept {}
      48           0 : ErrorHandler::~ErrorHandler() noexcept {}
      49             : 
      50             : // ============================================================================
      51             : // [asmjit::CodeHolder - Utilities]
      52             : // ============================================================================
      53             : 
      54           0 : static void CodeHolder_setGlobalOption(CodeHolder* self, uint32_t clear, uint32_t add) noexcept {
      55             :   // Modify global options of `CodeHolder` itself.
      56           0 :   self->_globalOptions = (self->_globalOptions & ~clear) | add;
      57             : 
      58             :   // Modify all global options of all `CodeEmitter`s attached.
      59           0 :   CodeEmitter* emitter = self->_emitters;
      60           0 :   while (emitter) {
      61           0 :     emitter->_globalOptions = (emitter->_globalOptions & ~clear) | add;
      62           0 :     emitter = emitter->_nextEmitter;
      63             :   }
      64           0 : }
      65             : 
      66       32111 : static void CodeHolder_resetInternal(CodeHolder* self, bool releaseMemory) noexcept {
      67             :   // Detach all `CodeEmitter`s.
      68       32111 :   while (self->_emitters)
      69           0 :     self->detach(self->_emitters);
      70             : 
      71             :   // Reset everything into its construction state.
      72             :   self->_codeInfo.reset();
      73       32111 :   self->_globalHints = 0;
      74       32111 :   self->_globalOptions = 0;
      75       32111 :   self->_logger = nullptr;
      76       32111 :   self->_errorHandler = nullptr;
      77             : 
      78       32111 :   self->_unresolvedLabelsCount = 0;
      79       32111 :   self->_trampolinesSize = 0;
      80             : 
      81             :   // Reset all sections.
      82             :   size_t numSections = self->_sections.getLength();
      83       64222 :   for (size_t i = 0; i < numSections; i++) {
      84       32111 :     SectionEntry* section = self->_sections[i];
      85       32111 :     if (section->_buffer.hasData() && !section->_buffer.isExternal())
      86             :       Internal::releaseMemory(section->_buffer._data);
      87       32111 :     section->_buffer._data = nullptr;
      88       32111 :     section->_buffer._capacity = 0;
      89             :   }
      90             : 
      91             :   // Reset zone allocator and all containers using it.
      92       32111 :   ZoneHeap* heap = &self->_baseHeap;
      93             : 
      94       32111 :   self->_namedLabels.reset(heap);
      95             :   self->_relocations.reset();
      96             :   self->_labels.reset();
      97             :   self->_sections.reset();
      98             : 
      99       32111 :   heap->reset(&self->_baseZone);
     100       32111 :   self->_baseZone.reset(releaseMemory);
     101       32111 : }
     102             : 
     103             : // ============================================================================
     104             : // [asmjit::CodeHolder - Construction / Destruction]
     105             : // ============================================================================
     106             : 
     107       32111 : CodeHolder::CodeHolder() noexcept
     108             :   : _codeInfo(),
     109       32111 :     _globalHints(0),
     110       32111 :     _globalOptions(0),
     111       32111 :     _emitters(nullptr),
     112       32111 :     _cgAsm(nullptr),
     113       32111 :     _logger(nullptr),
     114       32111 :     _errorHandler(nullptr),
     115       32111 :     _unresolvedLabelsCount(0),
     116       32111 :     _trampolinesSize(0),
     117       32111 :     _baseZone(16384 - Zone::kZoneOverhead),
     118       32111 :     _dataZone(16384 - Zone::kZoneOverhead),
     119       32111 :     _baseHeap(&_baseZone),
     120       32111 :     _namedLabels(&_baseHeap) {}
     121             : 
     122       32111 : CodeHolder::~CodeHolder() noexcept {
     123       32111 :   CodeHolder_resetInternal(this, true);
     124       32111 : }
     125             : 
     126             : // ============================================================================
     127             : // [asmjit::CodeHolder - Init / Reset]
     128             : // ============================================================================
     129             : 
     130       32111 : Error CodeHolder::init(const CodeInfo& info) noexcept {
     131             :   // Cannot reinitialize if it's locked or there is one or more CodeEmitter
     132             :   // attached.
     133       32111 :   if (isInitialized())
     134             :     return DebugUtils::errored(kErrorAlreadyInitialized);
     135             : 
     136             :   // If we are just initializing there should be no emitters attached).
     137             :   ASMJIT_ASSERT(_emitters == nullptr);
     138             : 
     139             :   // Create the default section and insert it to the `_sections` array.
     140       32111 :   Error err = _sections.willGrow(&_baseHeap);
     141       32111 :   if (err == kErrorOk) {
     142       32111 :     SectionEntry* se = _baseZone.allocZeroedT<SectionEntry>();
     143       32111 :     if (ASMJIT_LIKELY(se)) {
     144       32111 :       se->_flags = SectionEntry::kFlagExec | SectionEntry::kFlagConst;
     145             :       se->_setDefaultName('.', 't', 'e', 'x', 't');
     146             :       _sections.appendUnsafe(se);
     147             :     }
     148             :     else {
     149             :       err = DebugUtils::errored(kErrorNoHeapMemory);
     150             :     }
     151             :   }
     152             : 
     153       32111 :   if (ASMJIT_UNLIKELY(err)) {
     154           0 :     _baseZone.reset(false);
     155           0 :     return err;
     156             :   }
     157             :   else {
     158             :     _codeInfo = info;
     159       32111 :     return kErrorOk;
     160             :   }
     161             : }
     162             : 
     163           0 : void CodeHolder::reset(bool releaseMemory) noexcept {
     164           0 :   CodeHolder_resetInternal(this, releaseMemory);
     165           0 : }
     166             : 
     167             : // ============================================================================
     168             : // [asmjit::CodeHolder - Attach / Detach]
     169             : // ============================================================================
     170             : 
     171       64222 : Error CodeHolder::attach(CodeEmitter* emitter) noexcept {
     172             :   // Catch a possible misuse of the API.
     173       64222 :   if (!emitter)
     174             :     return DebugUtils::errored(kErrorInvalidArgument);
     175             : 
     176             :   uint32_t type = emitter->getType();
     177       64222 :   if (type == CodeEmitter::kTypeNone || type >= CodeEmitter::kTypeCount)
     178             :     return DebugUtils::errored(kErrorInvalidState);
     179             : 
     180             :   // This is suspicious, but don't fail if `emitter` matches.
     181       64222 :   if (emitter->_code != nullptr) {
     182           0 :     if (emitter->_code == this) return kErrorOk;
     183             :     return DebugUtils::errored(kErrorInvalidState);
     184             :   }
     185             : 
     186             :   // Special case - attach `Assembler`.
     187             :   CodeEmitter** pSlot = nullptr;
     188       64222 :   if (type == CodeEmitter::kTypeAssembler) {
     189       32111 :     if (_cgAsm)
     190             :       return DebugUtils::errored(kErrorSlotOccupied);
     191       32111 :     pSlot = reinterpret_cast<CodeEmitter**>(&_cgAsm);
     192             :   }
     193             : 
     194       64222 :   Error err = emitter->onAttach(this);
     195       64222 :   if (err != kErrorOk) return err;
     196             : 
     197             :   // Add to a single-linked list of `CodeEmitter`s.
     198       64222 :   emitter->_nextEmitter = _emitters;
     199       64222 :   _emitters = emitter;
     200       64222 :   if (pSlot) *pSlot = emitter;
     201             : 
     202             :   // Establish the connection.
     203       64222 :   emitter->_code = this;
     204       64222 :   return kErrorOk;
     205             : }
     206             : 
     207       64222 : Error CodeHolder::detach(CodeEmitter* emitter) noexcept {
     208       64222 :   if (!emitter)
     209             :     return DebugUtils::errored(kErrorInvalidArgument);
     210             : 
     211       64222 :   if (emitter->_code != this)
     212             :     return DebugUtils::errored(kErrorInvalidState);
     213             : 
     214             :   uint32_t type = emitter->getType();
     215             :   Error err = kErrorOk;
     216             : 
     217             :   // NOTE: We always detach if we were asked to, if error happens during
     218             :   // `emitter->onDetach()` we just propagate it, but the CodeEmitter will
     219             :   // be detached.
     220       64222 :   if (!emitter->_destroyed) {
     221           0 :     if (type == CodeEmitter::kTypeAssembler)
     222           0 :       static_cast<Assembler*>(emitter)->sync();
     223           0 :     err = emitter->onDetach(this);
     224             :   }
     225             : 
     226             :   // Special case - detach `Assembler`.
     227       64222 :   if (type == CodeEmitter::kTypeAssembler)
     228       32111 :     _cgAsm = nullptr;
     229             : 
     230             :   // Remove from a single-linked list of `CodeEmitter`s.
     231       64222 :   CodeEmitter** pPrev = &_emitters;
     232             :   for (;;) {
     233             :     ASMJIT_ASSERT(*pPrev != nullptr);
     234       64222 :     CodeEmitter* cur = *pPrev;
     235             : 
     236       64222 :     if (cur == emitter) {
     237       64222 :       *pPrev = emitter->_nextEmitter;
     238             :       break;
     239             :     }
     240             : 
     241           0 :     pPrev = &cur->_nextEmitter;
     242           0 :   }
     243             : 
     244       64222 :   emitter->_code = nullptr;
     245       64222 :   emitter->_nextEmitter = nullptr;
     246             : 
     247       64222 :   return err;
     248             : }
     249             : 
     250             : // ============================================================================
     251             : // [asmjit::CodeHolder - Sync]
     252             : // ============================================================================
     253             : 
     254       64222 : void CodeHolder::sync() noexcept {
     255       64222 :   if (_cgAsm) _cgAsm->sync();
     256       64222 : }
     257             : 
     258             : // ============================================================================
     259             : // [asmjit::CodeHolder - Result Information]
     260             : // ============================================================================
     261             : 
     262       64222 : size_t CodeHolder::getCodeSize() const noexcept {
     263             :   // Reflect all changes first.
     264       64222 :   const_cast<CodeHolder*>(this)->sync();
     265             : 
     266             :   // TODO: Support sections.
     267       64222 :   return _sections[0]->_buffer._length + getTrampolinesSize();
     268             : }
     269             : 
     270             : // ============================================================================
     271             : // [asmjit::CodeHolder - Logging & Error Handling]
     272             : // ============================================================================
     273             : 
     274             : #if !defined(ASMJIT_DISABLE_LOGGING)
     275           0 : void CodeHolder::setLogger(Logger* logger) noexcept {
     276             :   uint32_t opt = 0;
     277           0 :   if (logger) opt = CodeEmitter::kOptionLoggingEnabled;
     278             : 
     279           0 :   _logger = logger;
     280           0 :   CodeHolder_setGlobalOption(this, CodeEmitter::kOptionLoggingEnabled, opt);
     281           0 : }
     282             : #endif // !ASMJIT_DISABLE_LOGGING
     283             : 
     284           0 : Error CodeHolder::setErrorHandler(ErrorHandler* handler) noexcept {
     285           0 :   _errorHandler = handler;
     286           0 :   return kErrorOk;
     287             : }
     288             : 
     289             : // ============================================================================
     290             : // [asmjit::CodeHolder - Sections]
     291             : // ============================================================================
     292             : 
     293       32111 : static Error CodeHolder_reserveInternal(CodeHolder* self, CodeBuffer* cb, size_t n) noexcept {
     294       32111 :   uint8_t* oldData = cb->_data;
     295             :   uint8_t* newData;
     296             : 
     297       32111 :   if (oldData && !cb->isExternal())
     298             :     newData = static_cast<uint8_t*>(Internal::reallocMemory(oldData, n));
     299             :   else
     300             :     newData = static_cast<uint8_t*>(Internal::allocMemory(n));
     301             : 
     302       32111 :   if (ASMJIT_UNLIKELY(!newData))
     303             :     return DebugUtils::errored(kErrorNoHeapMemory);
     304             : 
     305       32111 :   cb->_data = newData;
     306       32111 :   cb->_capacity = n;
     307             : 
     308             :   // Update the `Assembler` pointers if attached. Maybe we should introduce an
     309             :   // event for this, but since only one Assembler can be attached at a time it
     310             :   // should not matter how these pointers are updated.
     311       32111 :   Assembler* a = self->_cgAsm;
     312       32111 :   if (a && &a->_section->_buffer == cb) {
     313             :     size_t offset = a->getOffset();
     314             : 
     315       32111 :     a->_bufferData = newData;
     316       32111 :     a->_bufferEnd  = newData + n;
     317       32111 :     a->_bufferPtr  = newData + offset;
     318             :   }
     319             : 
     320             :   return kErrorOk;
     321             : }
     322             : 
     323       32111 : Error CodeHolder::growBuffer(CodeBuffer* cb, size_t n) noexcept {
     324             :   // This is most likely called by `Assembler` so `sync()` shouldn't be needed,
     325             :   // however, if this is called by the user and the currently attached Assembler
     326             :   // did generate some code we could lose that, so sync now and make sure the
     327             :   // section length is updated.
     328       32111 :   if (_cgAsm) _cgAsm->sync();
     329             : 
     330             :   // Now the length of the section must be valid.
     331             :   size_t length = cb->getLength();
     332       32111 :   if (ASMJIT_UNLIKELY(n > IntTraits<uintptr_t>::maxValue() - length))
     333             :     return DebugUtils::errored(kErrorNoHeapMemory);
     334             : 
     335             :   // We can now check if growing the buffer is really necessary. It's unlikely
     336             :   // that this function is called while there is still room for `n` bytes.
     337             :   size_t capacity = cb->getCapacity();
     338       32111 :   size_t required = cb->getLength() + n;
     339       32111 :   if (ASMJIT_UNLIKELY(required <= capacity)) return kErrorOk;
     340             : 
     341       32111 :   if (cb->isFixedSize())
     342             :     return DebugUtils::errored(kErrorCodeTooLarge);
     343             : 
     344       32111 :   if (capacity < 8096)
     345             :     capacity = 8096;
     346             :   else
     347           0 :     capacity += Globals::kAllocOverhead;
     348             : 
     349             :   do {
     350             :     size_t old = capacity;
     351       32111 :     if (capacity < Globals::kAllocThreshold)
     352       32111 :       capacity *= 2;
     353             :     else
     354           0 :       capacity += Globals::kAllocThreshold;
     355             : 
     356       32111 :     if (capacity < Globals::kAllocThreshold)
     357       32111 :       capacity *= 2;
     358             :     else
     359           0 :       capacity += Globals::kAllocThreshold;
     360             : 
     361             :     // Overflow.
     362       32111 :     if (ASMJIT_UNLIKELY(old > capacity))
     363             :       return DebugUtils::errored(kErrorNoHeapMemory);
     364       32111 :   } while (capacity - Globals::kAllocOverhead < required);
     365             : 
     366       32111 :   return CodeHolder_reserveInternal(this, cb, capacity - Globals::kAllocOverhead);
     367             : }
     368             : 
     369           0 : Error CodeHolder::reserveBuffer(CodeBuffer* cb, size_t n) noexcept {
     370             :   size_t capacity = cb->getCapacity();
     371           0 :   if (n <= capacity) return kErrorOk;
     372             : 
     373           0 :   if (cb->isFixedSize())
     374             :     return DebugUtils::errored(kErrorCodeTooLarge);
     375             : 
     376             :   // We must sync, as mentioned in `growBuffer()` as well.
     377           0 :   if (_cgAsm) _cgAsm->sync();
     378             : 
     379           0 :   return CodeHolder_reserveInternal(this, cb, n);
     380             : }
     381             : 
     382             : // ============================================================================
     383             : // [asmjit::CodeHolder - Labels & Symbols]
     384             : // ============================================================================
     385             : 
     386             : namespace {
     387             : 
     388             : //! \internal
     389             : //!
     390             : //! Only used to lookup a label from `_namedLabels`.
     391             : class LabelByName {
     392             : public:
     393             :   ASMJIT_INLINE LabelByName(const char* name, size_t nameLength, uint32_t hVal) noexcept
     394             :     : name(name),
     395           0 :       nameLength(static_cast<uint32_t>(nameLength)),
     396             :       hVal(hVal) {}
     397             : 
     398             :   ASMJIT_INLINE bool matches(const LabelEntry* entry) const noexcept {
     399           0 :     return static_cast<uint32_t>(entry->getNameLength()) == nameLength &&
     400           0 :            ::memcmp(entry->getName(), name, nameLength) == 0;
     401             :   }
     402             : 
     403             :   const char* name;
     404             :   uint32_t nameLength;
     405             :   uint32_t hVal;
     406             : };
     407             : 
     408             : // Returns a hash of `name` and fixes `nameLength` if it's `Globals::kInvalidIndex`.
     409           0 : static uint32_t CodeHolder_hashNameAndFixLen(const char* name, size_t& nameLength) noexcept {
     410             :   uint32_t hVal = 0;
     411           0 :   if (nameLength == Globals::kInvalidIndex) {
     412             :     size_t i = 0;
     413             :     for (;;) {
     414           0 :       uint8_t c = static_cast<uint8_t>(name[i]);
     415           0 :       if (!c) break;
     416           0 :       hVal = Utils::hashRound(hVal, c);
     417           0 :       i++;
     418           0 :     }
     419           0 :     nameLength = i;
     420             :   }
     421             :   else {
     422           0 :     for (size_t i = 0; i < nameLength; i++) {
     423           0 :       uint8_t c = static_cast<uint8_t>(name[i]);
     424           0 :       if (ASMJIT_UNLIKELY(!c)) return DebugUtils::errored(kErrorInvalidLabelName);
     425           0 :       hVal = Utils::hashRound(hVal, c);
     426             :     }
     427             :   }
     428             :   return hVal;
     429             : }
     430             : 
     431             : } // anonymous namespace
     432             : 
     433           0 : LabelLink* CodeHolder::newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel) noexcept {
     434           0 :   LabelLink* link = _baseHeap.allocT<LabelLink>();
     435           0 :   if (ASMJIT_UNLIKELY(!link)) return nullptr;
     436             : 
     437           0 :   link->prev = le->_links;
     438           0 :   le->_links = link;
     439             : 
     440           0 :   link->sectionId = sectionId;
     441           0 :   link->relocId = RelocEntry::kInvalidId;
     442           0 :   link->offset = offset;
     443           0 :   link->rel = rel;
     444             : 
     445           0 :   _unresolvedLabelsCount++;
     446           0 :   return link;
     447             : }
     448             : 
     449       64222 : Error CodeHolder::newLabelId(uint32_t& idOut) noexcept {
     450       64222 :   idOut = 0;
     451             : 
     452             :   size_t index = _labels.getLength();
     453       64222 :   if (ASMJIT_LIKELY(index >= Operand::kPackedIdCount))
     454             :     return DebugUtils::errored(kErrorLabelIndexOverflow);
     455             : 
     456       96333 :   ASMJIT_PROPAGATE(_labels.willGrow(&_baseHeap));
     457       64222 :   LabelEntry* le = _baseHeap.allocZeroedT<LabelEntry>();
     458             : 
     459       64222 :   if (ASMJIT_UNLIKELY(!le))
     460             :     return DebugUtils::errored(kErrorNoHeapMemory);;
     461             : 
     462       64222 :   uint32_t id = Operand::packId(static_cast<uint32_t>(index));
     463             :   le->_setId(id);
     464       64222 :   le->_parentId = 0;
     465       64222 :   le->_sectionId = SectionEntry::kInvalidId;
     466       64222 :   le->_offset = 0;
     467             : 
     468             :   _labels.appendUnsafe(le);
     469       64222 :   idOut = id;
     470       64222 :   return kErrorOk;
     471             : }
     472             : 
     473           0 : Error CodeHolder::newNamedLabelId(uint32_t& idOut, const char* name, size_t nameLength, uint32_t type, uint32_t parentId) noexcept {
     474           0 :   idOut = 0;
     475           0 :   uint32_t hVal = CodeHolder_hashNameAndFixLen(name, nameLength);
     476             : 
     477           0 :   if (ASMJIT_UNLIKELY(nameLength == 0))
     478             :     return DebugUtils::errored(kErrorInvalidLabelName);
     479             : 
     480           0 :   if (ASMJIT_UNLIKELY(nameLength > Globals::kMaxLabelLength))
     481             :     return DebugUtils::errored(kErrorLabelNameTooLong);
     482             : 
     483           0 :   switch (type) {
     484             :     case Label::kTypeLocal:
     485           0 :       if (ASMJIT_UNLIKELY(Operand::unpackId(parentId) >= _labels.getLength()))
     486             :         return DebugUtils::errored(kErrorInvalidParentLabel);
     487             : 
     488           0 :       hVal ^= parentId;
     489           0 :       break;
     490             : 
     491           0 :     case Label::kTypeGlobal:
     492           0 :       if (ASMJIT_UNLIKELY(parentId != 0))
     493             :         return DebugUtils::errored(kErrorNonLocalLabelCantHaveParent);
     494             : 
     495             :       break;
     496             : 
     497             :     default:
     498             :       return DebugUtils::errored(kErrorInvalidArgument);
     499             :   }
     500             : 
     501             :   // Don't allow to insert duplicates. Local labels allow duplicates that have
     502             :   // different id, this is already accomplished by having a different hashes
     503             :   // between the same label names having different parent labels.
     504           0 :   LabelEntry* le = _namedLabels.get(LabelByName(name, nameLength, hVal));
     505           0 :   if (ASMJIT_UNLIKELY(le))
     506             :     return DebugUtils::errored(kErrorLabelAlreadyDefined);
     507             : 
     508             :   Error err = kErrorOk;
     509             :   size_t index = _labels.getLength();
     510             : 
     511           0 :   if (ASMJIT_UNLIKELY(index >= Operand::kPackedIdCount))
     512             :     return DebugUtils::errored(kErrorLabelIndexOverflow);
     513             : 
     514           0 :   ASMJIT_PROPAGATE(_labels.willGrow(&_baseHeap));
     515           0 :   le = _baseHeap.allocZeroedT<LabelEntry>();
     516             : 
     517           0 :   if (ASMJIT_UNLIKELY(!le))
     518             :     return  DebugUtils::errored(kErrorNoHeapMemory);
     519             : 
     520           0 :   uint32_t id = Operand::packId(static_cast<uint32_t>(index));
     521           0 :   le->_hVal = hVal;
     522             :   le->_setId(id);
     523           0 :   le->_type = static_cast<uint8_t>(type);
     524           0 :   le->_parentId = 0;
     525           0 :   le->_sectionId = SectionEntry::kInvalidId;
     526           0 :   le->_offset = 0;
     527             : 
     528           0 :   if (le->_name.mustEmbed(nameLength)) {
     529             :     le->_name.setEmbedded(name, nameLength);
     530             :   }
     531             :   else {
     532           0 :     char* nameExternal = static_cast<char*>(_dataZone.dup(name, nameLength, true));
     533           0 :     if (ASMJIT_UNLIKELY(!nameExternal))
     534             :       return DebugUtils::errored(kErrorNoHeapMemory);
     535           0 :     le->_name.setExternal(nameExternal, nameLength);
     536             :   }
     537             : 
     538             :   _labels.appendUnsafe(le);
     539             :   _namedLabels.put(le);
     540             : 
     541           0 :   idOut = id;
     542           0 :   return err;
     543             : }
     544             : 
     545           0 : uint32_t CodeHolder::getLabelIdByName(const char* name, size_t nameLength, uint32_t parentId) noexcept {
     546           0 :   uint32_t hVal = CodeHolder_hashNameAndFixLen(name, nameLength);
     547           0 :   if (ASMJIT_UNLIKELY(!nameLength)) return 0;
     548             : 
     549             :   LabelEntry* le = _namedLabels.get(LabelByName(name, nameLength, hVal));
     550           0 :   return le ? le->getId() : static_cast<uint32_t>(0);
     551             : }
     552             : 
     553             : // ============================================================================
     554             : // [asmjit::CodeEmitter - Relocations]
     555             : // ============================================================================
     556             : 
     557             : //! Encode MOD byte.
     558             : static ASMJIT_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcept {
     559             :   return (m << 6) | (o << 3) | rm;
     560             : }
     561             : 
     562           0 : Error CodeHolder::newRelocEntry(RelocEntry** dst, uint32_t type, uint32_t size) noexcept {
     563           0 :   ASMJIT_PROPAGATE(_relocations.willGrow(&_baseHeap));
     564             : 
     565             :   size_t index = _relocations.getLength();
     566           0 :   if (ASMJIT_UNLIKELY(index > size_t(0xFFFFFFFFU)))
     567             :     return DebugUtils::errored(kErrorRelocIndexOverflow);
     568             : 
     569           0 :   RelocEntry* re = _baseHeap.allocZeroedT<RelocEntry>();
     570           0 :   if (ASMJIT_UNLIKELY(!re))
     571             :     return DebugUtils::errored(kErrorNoHeapMemory);
     572             : 
     573           0 :   re->_id = static_cast<uint32_t>(index);
     574           0 :   re->_type = static_cast<uint8_t>(type);
     575           0 :   re->_size = static_cast<uint8_t>(size);
     576           0 :   re->_sourceSectionId = SectionEntry::kInvalidId;
     577           0 :   re->_targetSectionId = SectionEntry::kInvalidId;
     578             :   _relocations.appendUnsafe(re);
     579             : 
     580           0 :   *dst = re;
     581           0 :   return kErrorOk;
     582             : }
     583             : 
     584             : // TODO: Support multiple sections, this only relocates the first.
     585             : // TODO: This should go to Runtime as it's responsible for relocating the
     586             : //       code, CodeHolder should just hold it.
     587       32111 : size_t CodeHolder::relocate(void* _dst, uint64_t baseAddress) const noexcept {
     588       32111 :   SectionEntry* section = _sections[0];
     589             :   ASMJIT_ASSERT(section != nullptr);
     590             : 
     591             :   uint8_t* dst = static_cast<uint8_t*>(_dst);
     592       32111 :   if (baseAddress == Globals::kNoBaseAddress)
     593       32111 :     baseAddress = static_cast<uint64_t>((uintptr_t)dst);
     594             : 
     595             : #if !defined(ASMJIT_DISABLE_LOGGING)
     596             :   Logger* logger = getLogger();
     597             : #endif // ASMJIT_DISABLE_LOGGING
     598             : 
     599             :   size_t minCodeSize = section->getBuffer().getLength(); // Minimum code size.
     600       32111 :   size_t maxCodeSize = getCodeSize();                    // Includes all possible trampolines.
     601             : 
     602             :   // We will copy the exact size of the generated code. Extra code for trampolines
     603             :   // is generated on-the-fly by the relocator (this code doesn't exist at the moment).
     604       32111 :   ::memcpy(dst, section->_buffer._data, minCodeSize);
     605             : 
     606             :   // Trampoline offset from the beginning of dst/baseAddress.
     607             :   size_t trampOffset = minCodeSize;
     608             : 
     609             :   // Relocate all recorded locations.
     610             :   size_t numRelocs = _relocations.getLength();
     611             :   const RelocEntry* const* reArray = _relocations.getData();
     612             : 
     613       32111 :   for (size_t i = 0; i < numRelocs; i++) {
     614           0 :     const RelocEntry* re = reArray[i];
     615             : 
     616             :     // Possibly deleted or optimized out relocation entry.
     617           0 :     if (re->getType() == RelocEntry::kTypeNone)
     618           0 :       continue;
     619             : 
     620             :     uint64_t ptr = re->getData();
     621             :     size_t codeOffset = static_cast<size_t>(re->getSourceOffset());
     622             : 
     623             :     // Make sure that the `RelocEntry` is correct, we don't want to write
     624             :     // out of bounds in `dst`.
     625           0 :     if (ASMJIT_UNLIKELY(codeOffset + re->getSize() > maxCodeSize))
     626             :       return DebugUtils::errored(kErrorInvalidRelocEntry);
     627             : 
     628             :     // Whether to use trampoline, can be only used if relocation type is `kRelocTrampoline`.
     629             :     bool useTrampoline = false;
     630             : 
     631           0 :     switch (re->getType()) {
     632             :       case RelocEntry::kTypeAbsToAbs: {
     633             :         break;
     634             :       }
     635             : 
     636           0 :       case RelocEntry::kTypeRelToAbs: {
     637           0 :         ptr += baseAddress;
     638           0 :         break;
     639             :       }
     640             : 
     641             :       case RelocEntry::kTypeAbsToRel: {
     642           0 :         ptr -= baseAddress + re->getSourceOffset() + re->getSize();
     643           0 :         break;
     644             :       }
     645             : 
     646             :       case RelocEntry::kTypeTrampoline: {
     647           0 :         if (re->getSize() != 4)
     648             :           return DebugUtils::errored(kErrorInvalidRelocEntry);
     649             : 
     650           0 :         ptr -= baseAddress + re->getSourceOffset() + re->getSize();
     651           0 :         if (!Utils::isInt32(static_cast<int64_t>(ptr))) {
     652           0 :           ptr = (uint64_t)trampOffset - re->getSourceOffset() - re->getSize();
     653             :           useTrampoline = true;
     654             :         }
     655             :         break;
     656             :       }
     657             : 
     658             :       default:
     659             :         return DebugUtils::errored(kErrorInvalidRelocEntry);
     660             :     }
     661             : 
     662           0 :     switch (re->getSize()) {
     663           0 :       case 1:
     664           0 :         Utils::writeU8(dst + codeOffset, static_cast<uint32_t>(ptr & 0xFFU));
     665             :         break;
     666             : 
     667           0 :       case 4:
     668           0 :         Utils::writeU32u(dst + codeOffset, static_cast<uint32_t>(ptr & 0xFFFFFFFFU));
     669             :         break;
     670             : 
     671           0 :       case 8:
     672           0 :         Utils::writeU64u(dst + codeOffset, ptr);
     673             :         break;
     674             : 
     675             :       default:
     676             :         return DebugUtils::errored(kErrorInvalidRelocEntry);
     677             :     }
     678             : 
     679             :     // Handle the trampoline case.
     680           0 :     if (useTrampoline) {
     681             :       // Bytes that replace [REX, OPCODE] bytes.
     682             :       uint32_t byte0 = 0xFF;
     683           0 :       uint32_t byte1 = dst[codeOffset - 1];
     684             : 
     685           0 :       if (byte1 == 0xE8) {
     686             :         // Patch CALL/MOD byte to FF/2 (-> 0x15).
     687             :         byte1 = x86EncodeMod(0, 2, 5);
     688             :       }
     689           0 :       else if (byte1 == 0xE9) {
     690             :         // Patch JMP/MOD byte to FF/4 (-> 0x25).
     691             :         byte1 = x86EncodeMod(0, 4, 5);
     692             :       }
     693             :       else {
     694             :         return DebugUtils::errored(kErrorInvalidRelocEntry);
     695             :       }
     696             : 
     697             :       // Patch `jmp/call` instruction.
     698             :       ASMJIT_ASSERT(codeOffset >= 2);
     699           0 :       dst[codeOffset - 2] = static_cast<uint8_t>(byte0);
     700           0 :       dst[codeOffset - 1] = static_cast<uint8_t>(byte1);
     701             : 
     702             :       // Store absolute address and advance the trampoline pointer.
     703           0 :       Utils::writeU64u(dst + trampOffset, re->getData());
     704           0 :       trampOffset += 8;
     705             : 
     706             : #if !defined(ASMJIT_DISABLE_LOGGING)
     707           0 :       if (logger)
     708           0 :         logger->logf("[reloc] dq 0x%016llX ; Trampoline\n", re->getData());
     709             : #endif // !ASMJIT_DISABLE_LOGGING
     710             :     }
     711             :   }
     712             : 
     713             :   // If there are no trampolines this is the same as `minCodeSize`.
     714             :   return trampOffset;
     715             : }
     716             : 
     717             : } // asmjit namespace
     718             : } // namespace PLMD
     719             : 
     720             : // [Api-End]
     721             : #include "./asmjit_apiend.h"
     722             : #pragma GCC diagnostic pop
     723             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16