From 2fa0b3f8fbe99c93c87e19f3c74b094e4d05d81d Mon Sep 17 00:00:00 2001 From: kobalicek Date: Sun, 10 Sep 2023 16:32:46 +0200 Subject: [PATCH] [ABI] Added implementation of all pure virtual functions This changes virtually nothing from API perspective, however, it allows to embed asmjit well in C projects that do not link to C++ standard library. In normal circumstances, when a pure virtual function is declared, but not implemented, the compiler would replace it with it's default version, which would print a message and terminate the program. However, this function is part of a C++ standard library, so we don't want to use it. --- src/asmjit/core/builder.cpp | 9 ++++ src/asmjit/core/builder.h | 2 +- src/asmjit/core/compiler.cpp | 6 +++ src/asmjit/core/compiler.h | 2 +- src/asmjit/core/emithelper.cpp | 18 ++++++++ src/asmjit/core/emitter.cpp | 74 ++++++++++++++++++++++++++++++++ src/asmjit/core/emitter.h | 28 ++++++------ src/asmjit/core/errorhandler.cpp | 4 ++ src/asmjit/core/errorhandler.h | 2 +- src/asmjit/core/logger.cpp | 8 ++++ src/asmjit/core/logger.h | 2 +- src/asmjit/core/rapass.cpp | 55 ++++++++++++++++++++++++ src/asmjit/core/rapass_p.h | 8 ++-- 13 files changed, 196 insertions(+), 22 deletions(-) diff --git a/src/asmjit/core/builder.cpp b/src/asmjit/core/builder.cpp index 77f94e7..dcf7b4f 100644 --- a/src/asmjit/core/builder.cpp +++ b/src/asmjit/core/builder.cpp @@ -886,6 +886,15 @@ Pass::Pass(const char* name) noexcept : _name(name) {} Pass::~Pass() noexcept {} +// Pass - Interface +// ================ + +// [[pure virtual]] +Error Pass::run(Zone* zone, Logger* logger) { + DebugUtils::unused(zone, logger); + return DebugUtils::errored(kErrorInvalidState); +} + ASMJIT_END_NAMESPACE #endif // !ASMJIT_NO_BUILDER diff --git a/src/asmjit/core/builder.h b/src/asmjit/core/builder.h index b77b16e..cfca7cc 100644 --- a/src/asmjit/core/builder.h +++ b/src/asmjit/core/builder.h @@ -1378,7 +1378,7 @@ public: //! //! This is the only function that is called by the `BaseBuilder` to process the code. It passes `zone`, //! which will be reset after the `run()` finishes. - virtual Error run(Zone* zone, Logger* logger) = 0; + ASMJIT_API virtual Error run(Zone* zone, Logger* logger) = 0; //! \} }; diff --git a/src/asmjit/core/compiler.cpp b/src/asmjit/core/compiler.cpp index ee959f7..f7cca47 100644 --- a/src/asmjit/core/compiler.cpp +++ b/src/asmjit/core/compiler.cpp @@ -587,6 +587,12 @@ Error FuncPass::run(Zone* zone, Logger* logger) { return kErrorOk; } +// [[pure virtual]] +Error FuncPass::runOnFunction(Zone* zone, Logger* logger, FuncNode* func) { + DebugUtils::unused(zone, logger, func); + return DebugUtils::errored(kErrorInvalidState); +} + ASMJIT_END_NAMESPACE #endif // !ASMJIT_NO_COMPILER diff --git a/src/asmjit/core/compiler.h b/src/asmjit/core/compiler.h index edfe1fe..6c32133 100644 --- a/src/asmjit/core/compiler.h +++ b/src/asmjit/core/compiler.h @@ -712,7 +712,7 @@ public: ASMJIT_API Error run(Zone* zone, Logger* logger) override; //! Called once per `FuncNode`. - virtual Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) = 0; + ASMJIT_API virtual Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) = 0; //! \} }; diff --git a/src/asmjit/core/emithelper.cpp b/src/asmjit/core/emithelper.cpp index bcdf098..c06bbe2 100644 --- a/src/asmjit/core/emithelper.cpp +++ b/src/asmjit/core/emithelper.cpp @@ -61,6 +61,24 @@ static void dumpAssignment(String& sb, const FuncArgsContext& ctx) noexcept { } #endif +// BaseEmitHelper - Abstract +// ========================= + +Error BaseEmitHelper::emitRegMove(const Operand_& dst_, const Operand_& src_, TypeId typeId, const char* comment) { + DebugUtils::unused(dst_, src_, typeId, comment); + return DebugUtils::errored(kErrorInvalidState); +} + +Error BaseEmitHelper::emitRegSwap(const BaseReg& a, const BaseReg& b, const char* comment) { + DebugUtils::unused(a, b, comment); + return DebugUtils::errored(kErrorInvalidState); +} + +Error BaseEmitHelper::emitArgMove(const BaseReg& dst_, TypeId dstTypeId, const Operand_& src_, TypeId srcTypeId, const char* comment) { + DebugUtils::unused(dst_, dstTypeId, src_, srcTypeId, comment); + return DebugUtils::errored(kErrorInvalidState); +} + // BaseEmitHelper - EmitArgsAssignment // =================================== diff --git a/src/asmjit/core/emitter.cpp b/src/asmjit/core/emitter.cpp index 92d67a7..fd036b1 100644 --- a/src/asmjit/core/emitter.cpp +++ b/src/asmjit/core/emitter.cpp @@ -125,13 +125,39 @@ Error BaseEmitter::reportError(Error err, const char* message) { return err; } +// BaseEmitter - Sections +// ====================== + +// [[pure virtual]] +Error BaseEmitter::section(Section* section) { + DebugUtils::unused(section); + return DebugUtils::errored(kErrorInvalidState); +} + // BaseEmitter - Labels // ==================== +// [[pure virtual]] +Label BaseEmitter::newLabel() { + return Label(Globals::kInvalidId); +} + +// [[pure virtual]] +Label BaseEmitter::newNamedLabel(const char* name, size_t nameSize, LabelType type, uint32_t parentId) { + DebugUtils::unused(name, nameSize, type, parentId); + return Label(Globals::kInvalidId); +} + Label BaseEmitter::labelByName(const char* name, size_t nameSize, uint32_t parentId) noexcept { return Label(_code ? _code->labelIdByName(name, nameSize, parentId) : Globals::kInvalidId); } +// [[pure virtual]] +Error BaseEmitter::bind(const Label& label) { + DebugUtils::unused(label); + return DebugUtils::errored(kErrorInvalidState); +} + bool BaseEmitter::isLabelValid(uint32_t labelId) const noexcept { return _code && labelId < _code->labelCount(); } @@ -172,6 +198,12 @@ Error BaseEmitter::_emitI(InstId instId, const Operand_& o0, const Operand_& o1, return _emit(instId, o0, o1, o2, opExt); } +// [[pure virtual]] +Error BaseEmitter::_emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* oExt) { + DebugUtils::unused(instId, o0, o1, o2, oExt); + return DebugUtils::errored(kErrorInvalidState); +} + Error BaseEmitter::_emitOpArray(InstId instId, const Operand_* operands, size_t opCount) { const Operand_* op = operands; Operand_ opExt[3]; @@ -233,9 +265,51 @@ Error BaseEmitter::emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssi return _funcs.emitArgsAssignment(this, frame, args); } +// BaseEmitter - Align +// =================== + +// [[pure virtual]] +Error BaseEmitter::align(AlignMode alignMode, uint32_t alignment) { + DebugUtils::unused(alignMode, alignment); + return DebugUtils::errored(kErrorInvalidState); +} + +// BaseEmitter - Embed +// =================== + +// [[pure virtual]] +Error BaseEmitter::embed(const void* data, size_t dataSize) { + DebugUtils::unused(data, dataSize); + return DebugUtils::errored(kErrorInvalidState); +} + +// [[pure virtual]] +Error BaseEmitter::embedDataArray(TypeId typeId, const void* data, size_t itemCount, size_t repeatCount) { + DebugUtils::unused(typeId, data, itemCount, repeatCount); + return DebugUtils::errored(kErrorInvalidState); +} + +// [[pure virtual]] +Error BaseEmitter::embedLabel(const Label& label, size_t dataSize) { + DebugUtils::unused(label, dataSize); + return DebugUtils::errored(kErrorInvalidState); +} + +// [[pure virtual]] +Error BaseEmitter::embedLabelDelta(const Label& label, const Label& base, size_t dataSize) { + DebugUtils::unused(label, base, dataSize); + return DebugUtils::errored(kErrorInvalidState); +} + // BaseEmitter - Comment // ===================== +// [[pure virtual]] +Error comment(const char* data, size_t size = SIZE_MAX) { + DebugUtils::unused(data, size); + return DebugUtils::errored(kErrorInvalidState); +} + Error BaseEmitter::commentf(const char* fmt, ...) { if (!hasEmitterFlag(EmitterFlags::kLogComments)) { if (!hasEmitterFlag(EmitterFlags::kAttached)) diff --git a/src/asmjit/core/emitter.h b/src/asmjit/core/emitter.h index 38af690..e3cdd56 100644 --- a/src/asmjit/core/emitter.h +++ b/src/asmjit/core/emitter.h @@ -557,7 +557,7 @@ public: //! \name Sections //! \{ - virtual Error section(Section* section) = 0; + ASMJIT_API virtual Error section(Section* section) = 0; //! \} @@ -565,9 +565,9 @@ public: //! \{ //! Creates a new label. - virtual Label newLabel() = 0; + ASMJIT_API virtual Label newLabel() = 0; //! Creates a new named label. - virtual Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, LabelType type = LabelType::kGlobal, uint32_t parentId = Globals::kInvalidId) = 0; + ASMJIT_API virtual Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, LabelType type = LabelType::kGlobal, uint32_t parentId = Globals::kInvalidId) = 0; //! Creates a new anonymous label with a name, which can only be used for debugging purposes. ASMJIT_INLINE_NODEBUG Label newAnonymousLabel(const char* name, size_t nameSize = SIZE_MAX) { return newNamedLabel(name, nameSize, LabelType::kAnonymous); } @@ -585,7 +585,7 @@ public: //! Binds the `label` to the current position of the current section. //! //! \note Attempt to bind the same label multiple times will return an error. - virtual Error bind(const Label& label) = 0; + ASMJIT_API virtual Error bind(const Label& label) = 0; //! Tests whether the label `id` is valid (i.e. registered). ASMJIT_API bool isLabelValid(uint32_t labelId) const noexcept; @@ -637,7 +637,7 @@ public: //! \cond INTERNAL //! Emits an instruction - all 6 operands must be defined. - virtual Error _emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* oExt) = 0; + ASMJIT_API virtual Error _emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* oExt) = 0; //! Emits instruction having operands stored in array. ASMJIT_API virtual Error _emitOpArray(InstId instId, const Operand_* operands, size_t opCount); //! \endcond @@ -661,7 +661,7 @@ public: //! The sequence that is used to fill the gap between the aligned location and the current location depends on the //! align `mode`, see \ref AlignMode. The `alignment` argument specifies alignment in bytes, so for example when //! it's `32` it means that the code buffer will be aligned to `32` bytes. - virtual Error align(AlignMode alignMode, uint32_t alignment) = 0; + ASMJIT_API virtual Error align(AlignMode alignMode, uint32_t alignment) = 0; //! \} @@ -669,7 +669,7 @@ public: //! \{ //! Embeds raw data into the \ref CodeBuffer. - virtual Error embed(const void* data, size_t dataSize) = 0; + ASMJIT_API virtual Error embed(const void* data, size_t dataSize) = 0; //! Embeds a typed data array. //! @@ -680,7 +680,7 @@ public: //! //! - Repeat the given data `repeatCount` times, so the data can be used as a fill pattern for example, or as a //! pattern used by SIMD instructions. - virtual Error embedDataArray(TypeId typeId, const void* data, size_t itemCount, size_t repeatCount = 1) = 0; + ASMJIT_API virtual Error embedDataArray(TypeId typeId, const void* data, size_t itemCount, size_t repeatCount = 1) = 0; //! Embeds int8_t `value` repeated by `repeatCount`. ASMJIT_INLINE_NODEBUG Error embedInt8(int8_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kInt8, &value, 1, repeatCount); } @@ -707,17 +707,17 @@ public: //! 1. Aligns by using AlignMode::kData to the minimum `pool` alignment. //! 2. Binds the ConstPool label so it's bound to an aligned location. //! 3. Emits ConstPool content. - virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0; + ASMJIT_API virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0; //! Embeds an absolute `label` address as data. //! //! The `dataSize` is an optional argument that can be used to specify the size of the address data. If it's zero //! (default) the address size is deduced from the target architecture (either 4 or 8 bytes). - virtual Error embedLabel(const Label& label, size_t dataSize = 0) = 0; + ASMJIT_API virtual Error embedLabel(const Label& label, size_t dataSize = 0) = 0; //! Embeds a delta (distance) between the `label` and `base` calculating it as `label - base`. This function was //! designed to make it easier to embed lookup tables where each index is a relative distance of two labels. - virtual Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize = 0) = 0; + ASMJIT_API virtual Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize = 0) = 0; //! \} @@ -725,7 +725,7 @@ public: //! \{ //! Emits a comment stored in `data` with an optional `size` parameter. - virtual Error comment(const char* data, size_t size = SIZE_MAX) = 0; + ASMJIT_API virtual Error comment(const char* data, size_t size = SIZE_MAX) = 0; //! Emits a formatted comment specified by `fmt` and variable number of arguments. ASMJIT_API Error commentf(const char* fmt, ...); @@ -738,9 +738,9 @@ public: //! \{ //! Called after the emitter was attached to `CodeHolder`. - virtual Error onAttach(CodeHolder* ASMJIT_NONNULL(code)) noexcept = 0; + ASMJIT_API virtual Error onAttach(CodeHolder* ASMJIT_NONNULL(code)) noexcept; //! Called after the emitter was detached from `CodeHolder`. - virtual Error onDetach(CodeHolder* ASMJIT_NONNULL(code)) noexcept = 0; + ASMJIT_API virtual Error onDetach(CodeHolder* ASMJIT_NONNULL(code)) noexcept; //! Called when \ref CodeHolder has updated an important setting, which involves the following: //! diff --git a/src/asmjit/core/errorhandler.cpp b/src/asmjit/core/errorhandler.cpp index 5a7dac5..ce2ad01 100644 --- a/src/asmjit/core/errorhandler.cpp +++ b/src/asmjit/core/errorhandler.cpp @@ -11,4 +11,8 @@ ASMJIT_BEGIN_NAMESPACE ErrorHandler::ErrorHandler() noexcept {} ErrorHandler::~ErrorHandler() noexcept {} +void ErrorHandler::handleError(Error err, const char* message, BaseEmitter* origin) { + DebugUtils::unused(err, message, origin); +} + ASMJIT_END_NAMESPACE diff --git a/src/asmjit/core/errorhandler.h b/src/asmjit/core/errorhandler.h index 3b0096f..d2c37b3 100644 --- a/src/asmjit/core/errorhandler.h +++ b/src/asmjit/core/errorhandler.h @@ -215,7 +215,7 @@ public: //! calling `handleError()` so `longjmp()` can be used without any issues to cancel the code generation if an //! error occurred. There is no difference between exceptions and `longjmp()` from AsmJit's perspective, however, //! never jump outside of `CodeHolder` and `BaseEmitter` scope as you would leak memory. - virtual void handleError(Error err, const char* message, BaseEmitter* origin) = 0; + ASMJIT_API virtual void handleError(Error err, const char* message, BaseEmitter* origin) = 0; //! \} }; diff --git a/src/asmjit/core/logger.cpp b/src/asmjit/core/logger.cpp index 4567b3c..9bc14ba 100644 --- a/src/asmjit/core/logger.cpp +++ b/src/asmjit/core/logger.cpp @@ -19,6 +19,14 @@ Logger::Logger() noexcept : _options() {} Logger::~Logger() noexcept {} +// [[pure virtual]] +Error Logger::_log(const char* data, size_t size) noexcept { + DebugUtils::unused(data, size); + + // Do not error in this case - the logger would just sink to /dev/null. + return kErrorOk; +} + Error Logger::logf(const char* fmt, ...) noexcept { Error err; va_list ap; diff --git a/src/asmjit/core/logger.h b/src/asmjit/core/logger.h index fba5444..b599d2c 100644 --- a/src/asmjit/core/logger.h +++ b/src/asmjit/core/logger.h @@ -90,7 +90,7 @@ public: //! The function can accept either a null terminated string if `size` is `SIZE_MAX` or a non-null terminated //! string of the given `size`. The function cannot assume that the data is null terminated and must handle //! non-null terminated inputs. - virtual Error _log(const char* data, size_t size) noexcept = 0; + ASMJIT_API virtual Error _log(const char* data, size_t size) noexcept = 0; //! Logs string `str`, which is either null terminated or having size `size`. ASMJIT_INLINE_NODEBUG Error log(const char* data, size_t size = SIZE_MAX) noexcept { return _log(data, size); } diff --git a/src/asmjit/core/rapass.cpp b/src/asmjit/core/rapass.cpp index 29b7dea..0fc1a00 100644 --- a/src/asmjit/core/rapass.cpp +++ b/src/asmjit/core/rapass.cpp @@ -196,6 +196,12 @@ Error BaseRAPass::onPerformAllSteps() noexcept { return kErrorOk; } +// BaseRAPass - Events +// =================== + +void BaseRAPass::onInit() noexcept {} +void BaseRAPass::onDone() noexcept {} + // BaseRAPass - CFG - Basic Block Management // ========================================= @@ -307,6 +313,11 @@ Error BaseRAPass::addBlock(RABlock* block) noexcept { // BaseRAPass - CFG - Build // ======================== +// [[pure virtual]] +Error BaseRAPass::buildCFG() noexcept { + return DebugUtils::errored(kErrorInvalidState); +} + Error BaseRAPass::initSharedAssignments(const ZoneVector& sharedAssignmentsMap) noexcept { if (sharedAssignmentsMap.empty()) return kErrorOk; @@ -1814,6 +1825,50 @@ Error BaseRAPass::rewrite() noexcept { return _rewrite(_func, _stop); } +// [[pure virtual]] +Error BaseRAPass::_rewrite(BaseNode* first, BaseNode* stop) noexcept { + DebugUtils::unused(first, stop); + return DebugUtils::errored(kErrorInvalidState); +} + +// BaseRAPass - Emit +// ================= + +// [[pure virtual]] +Error BaseRAPass::emitMove(uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept { + DebugUtils::unused(workId, dstPhysId, srcPhysId); + return DebugUtils::errored(kErrorInvalidState); +} + +// [[pure virtual]] +Error BaseRAPass::emitSwap(uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, uint32_t bPhysId) noexcept { + DebugUtils::unused(aWorkId, aPhysId, bWorkId, bPhysId); + return DebugUtils::errored(kErrorInvalidState); +} + +// [[pure virtual]] +Error BaseRAPass::emitLoad(uint32_t workId, uint32_t dstPhysId) noexcept { + DebugUtils::unused(workId, dstPhysId); + return DebugUtils::errored(kErrorInvalidState); +} + +// [[pure virtual]] +Error BaseRAPass::emitSave(uint32_t workId, uint32_t srcPhysId) noexcept { + DebugUtils::unused(workId, srcPhysId); + return DebugUtils::errored(kErrorInvalidState); +} + +// [[pure virtual]] +Error BaseRAPass::emitJump(const Label& label) noexcept { + DebugUtils::unused(label); + return DebugUtils::errored(kErrorInvalidState); +} + +Error BaseRAPass::emitPreCall(InvokeNode* invokeNode) noexcept { + DebugUtils::unused(invokeNode); + return DebugUtils::errored(kErrorOk); +} + // BaseRAPass - Logging // ==================== diff --git a/src/asmjit/core/rapass_p.h b/src/asmjit/core/rapass_p.h index 52b2a94..821d458 100644 --- a/src/asmjit/core/rapass_p.h +++ b/src/asmjit/core/rapass_p.h @@ -793,7 +793,7 @@ public: ASMJIT_INLINE_NODEBUG uint32_t endPosition() const noexcept { return _instructionCount * 2; } ASMJIT_INLINE_NODEBUG const RARegMask& availableRegs() const noexcept { return _availableRegs; } - ASMJIT_INLINE_NODEBUG const RARegMask& cloberredRegs() const noexcept { return _clobberedRegs; } + ASMJIT_INLINE_NODEBUG const RARegMask& clobberedRegs() const noexcept { return _clobberedRegs; } //! \} @@ -818,11 +818,11 @@ public: //! Called by \ref runOnFunction() before the register allocation to initialize //! architecture-specific data and constraints. - virtual void onInit() noexcept = 0; + virtual void onInit() noexcept; //! Called by \ref runOnFunction(` after register allocation to clean everything //! up. Called even if the register allocation failed. - virtual void onDone() noexcept = 0; + virtual void onDone() noexcept; //! \} @@ -1160,7 +1160,7 @@ public: virtual Error emitSave(uint32_t workId, uint32_t srcPhysId) noexcept = 0; virtual Error emitJump(const Label& label) noexcept = 0; - virtual Error emitPreCall(InvokeNode* invokeNode) noexcept = 0; + virtual Error emitPreCall(InvokeNode* invokeNode) noexcept; //! \} };