// AsmJit - Machine code generation for C++ // // * Official AsmJit Home Page: https://asmjit.com // * Official Github Repository: https://github.com/asmjit/asmjit // // Copyright (c) 2008-2020 The AsmJit Authors // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. #include "../core/api-build_p.h" #include "../core/emitterutils_p.h" #include "../core/errorhandler.h" #include "../core/logger.h" #include "../core/support.h" #ifdef ASMJIT_BUILD_X86 #include "../x86/x86emithelper_p.h" #include "../x86/x86instdb_p.h" #endif // ASMJIT_BUILD_X86 #ifdef ASMJIT_BUILD_ARM #include "../arm/a64emithelper_p.h" #include "../arm/a64instdb.h" #endif // ASMJIT_BUILD_ARM ASMJIT_BEGIN_NAMESPACE // ============================================================================ // [asmjit::BaseEmitter - Construction / Destruction] // ============================================================================ BaseEmitter::BaseEmitter(uint32_t emitterType) noexcept : _emitterType(uint8_t(emitterType)) {} BaseEmitter::~BaseEmitter() noexcept { if (_code) { _addEmitterFlags(kFlagDestroyed); _code->detach(this); } } // ============================================================================ // [asmjit::BaseEmitter - Finalize] // ============================================================================ Error BaseEmitter::finalize() { // Does nothing by default, overridden by `BaseBuilder` and `BaseCompiler`. return kErrorOk; } // ============================================================================ // [asmjit::BaseEmitter - Internals] // ============================================================================ static constexpr uint32_t kEmitterPreservedFlags = BaseEmitter::kFlagOwnLogger | BaseEmitter::kFlagOwnErrorHandler; static ASMJIT_NOINLINE void BaseEmitter_updateForcedOptions(BaseEmitter* self) noexcept { bool emitComments = false; bool hasValidationOptions = false; if (self->emitterType() == BaseEmitter::kTypeAssembler) { // Assembler: Don't emit comments if logger is not attached. emitComments = self->_code != nullptr && self->_logger != nullptr; hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionAssembler); } else { // Builder/Compiler: Always emit comments, we cannot assume they won't be used. emitComments = self->_code != nullptr; hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionIntermediate); } if (emitComments) self->_addEmitterFlags(BaseEmitter::kFlagLogComments); else self->_clearEmitterFlags(BaseEmitter::kFlagLogComments); // The reserved option tells emitter (Assembler/Builder/Compiler) that there // may be either a border case (CodeHolder not attached, for example) or that // logging or validation is required. if (self->_code == nullptr || self->_logger || hasValidationOptions) self->_forcedInstOptions |= BaseInst::kOptionReserved; else self->_forcedInstOptions &= ~BaseInst::kOptionReserved; } // ============================================================================ // [asmjit::BaseEmitter - Validation Options] // ============================================================================ void BaseEmitter::addValidationOptions(uint32_t options) noexcept { _validationOptions = uint8_t(_validationOptions | options); BaseEmitter_updateForcedOptions(this); } void BaseEmitter::clearValidationOptions(uint32_t options) noexcept { _validationOptions = uint8_t(_validationOptions | options); BaseEmitter_updateForcedOptions(this); } // ============================================================================ // [asmjit::BaseEmitter - Logging] // ============================================================================ void BaseEmitter::setLogger(Logger* logger) noexcept { #ifndef ASMJIT_NO_LOGGING if (logger) { _logger = logger; _addEmitterFlags(kFlagOwnLogger); } else { _logger = nullptr; _clearEmitterFlags(kFlagOwnLogger); if (_code) _logger = _code->logger(); } BaseEmitter_updateForcedOptions(this); #else DebugUtils::unused(logger); #endif } // ============================================================================ // [asmjit::BaseEmitter - Error Handling] // ============================================================================ void BaseEmitter::setErrorHandler(ErrorHandler* errorHandler) noexcept { if (errorHandler) { _errorHandler = errorHandler; _addEmitterFlags(kFlagOwnErrorHandler); } else { _errorHandler = nullptr; _clearEmitterFlags(kFlagOwnErrorHandler); if (_code) _errorHandler = _code->errorHandler(); } } Error BaseEmitter::reportError(Error err, const char* message) { ErrorHandler* eh = _errorHandler; if (eh) { if (!message) message = DebugUtils::errorAsString(err); eh->handleError(err, message, this); } return err; } // ============================================================================ // [asmjit::BaseEmitter - Labels] // ============================================================================ Label BaseEmitter::labelByName(const char* name, size_t nameSize, uint32_t parentId) noexcept { return Label(_code ? _code->labelIdByName(name, nameSize, parentId) : uint32_t(Globals::kInvalidId)); } bool BaseEmitter::isLabelValid(uint32_t labelId) const noexcept { return _code && labelId < _code->labelCount(); } // ============================================================================ // [asmjit::BaseEmitter - Emit (Low-Level)] // ============================================================================ using EmitterUtils::noExt; Error BaseEmitter::_emitI(uint32_t instId) { return _emit(instId, noExt[0], noExt[1], noExt[2], noExt); } Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0) { return _emit(instId, o0, noExt[1], noExt[2], noExt); } Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1) { return _emit(instId, o0, o1, noExt[2], noExt); } Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2) { return _emit(instId, o0, o1, o2, noExt); } Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { Operand_ opExt[3] = { o3 }; return _emit(instId, o0, o1, o2, opExt); } Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4) { Operand_ opExt[3] = { o3, o4 }; return _emit(instId, o0, o1, o2, opExt); } Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) { Operand_ opExt[3] = { o3, o4, o5 }; return _emit(instId, o0, o1, o2, opExt); } Error BaseEmitter::_emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount) { const Operand_* op = operands; Operand_ opExt[3]; switch (opCount) { case 0: return _emit(instId, noExt[0], noExt[1], noExt[2], noExt); case 1: return _emit(instId, op[0], noExt[1], noExt[2], noExt); case 2: return _emit(instId, op[0], op[1], noExt[2], noExt); case 3: return _emit(instId, op[0], op[1], op[2], noExt); case 4: opExt[0] = op[3]; opExt[1].reset(); opExt[2].reset(); return _emit(instId, op[0], op[1], op[2], opExt); case 5: opExt[0] = op[3]; opExt[1] = op[4]; opExt[2].reset(); return _emit(instId, op[0], op[1], op[2], opExt); case 6: return _emit(instId, op[0], op[1], op[2], op + 3); default: return DebugUtils::errored(kErrorInvalidArgument); } } // ============================================================================ // [asmjit::BaseEmitter - Emit (High-Level)] // ============================================================================ ASMJIT_FAVOR_SIZE Error BaseEmitter::emitProlog(const FuncFrame& frame) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); #ifdef ASMJIT_BUILD_X86 if (environment().isFamilyX86()) { x86::EmitHelper emitHelper(this, frame.isAvxEnabled()); return emitHelper.emitProlog(frame); } #endif #ifdef ASMJIT_BUILD_ARM if (environment().isArchAArch64()) { a64::EmitHelper emitHelper(this); return emitHelper.emitProlog(frame); } #endif return DebugUtils::errored(kErrorInvalidArch); } ASMJIT_FAVOR_SIZE Error BaseEmitter::emitEpilog(const FuncFrame& frame) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); #ifdef ASMJIT_BUILD_X86 if (environment().isFamilyX86()) { x86::EmitHelper emitHelper(this, frame.isAvxEnabled()); return emitHelper.emitEpilog(frame); } #endif #ifdef ASMJIT_BUILD_ARM if (environment().isArchAArch64()) { a64::EmitHelper emitHelper(this); return emitHelper.emitEpilog(frame); } #endif return DebugUtils::errored(kErrorInvalidArch); } ASMJIT_FAVOR_SIZE Error BaseEmitter::emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); #ifdef ASMJIT_BUILD_X86 if (environment().isFamilyX86()) { x86::EmitHelper emitHelper(this, frame.isAvxEnabled()); return emitHelper.emitArgsAssignment(frame, args); } #endif #ifdef ASMJIT_BUILD_ARM if (environment().isArchAArch64()) { a64::EmitHelper emitHelper(this); return emitHelper.emitArgsAssignment(frame, args); } #endif return DebugUtils::errored(kErrorInvalidArch); } // ============================================================================ // [asmjit::BaseEmitter - Comment] // ============================================================================ Error BaseEmitter::commentf(const char* fmt, ...) { if (!hasEmitterFlag(kFlagLogComments)) { if (!hasEmitterFlag(kFlagAttached)) return reportError(DebugUtils::errored(kErrorNotInitialized)); return kErrorOk; } #ifndef ASMJIT_NO_LOGGING StringTmp<1024> sb; va_list ap; va_start(ap, fmt); Error err = sb.appendVFormat(fmt, ap); va_end(ap); ASMJIT_PROPAGATE(err); return comment(sb.data(), sb.size()); #else DebugUtils::unused(fmt); return kErrorOk; #endif } Error BaseEmitter::commentv(const char* fmt, va_list ap) { if (!hasEmitterFlag(kFlagLogComments)) { if (!hasEmitterFlag(kFlagAttached)) return reportError(DebugUtils::errored(kErrorNotInitialized)); return kErrorOk; } #ifndef ASMJIT_NO_LOGGING StringTmp<1024> sb; Error err = sb.appendVFormat(fmt, ap); ASMJIT_PROPAGATE(err); return comment(sb.data(), sb.size()); #else DebugUtils::unused(fmt, ap); return kErrorOk; #endif } // ============================================================================ // [asmjit::BaseEmitter - Events] // ============================================================================ Error BaseEmitter::onAttach(CodeHolder* code) noexcept { _code = code; _environment = code->environment(); _addEmitterFlags(kFlagAttached); const ArchTraits& archTraits = ArchTraits::byArch(code->arch()); uint32_t nativeRegType = Environment::is32Bit(code->arch()) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64; _gpRegInfo.setSignature(archTraits._regInfo[nativeRegType].signature()); onSettingsUpdated(); return kErrorOk; } Error BaseEmitter::onDetach(CodeHolder* code) noexcept { DebugUtils::unused(code); if (!hasOwnLogger()) _logger = nullptr; if (!hasOwnErrorHandler()) _errorHandler = nullptr; _clearEmitterFlags(~kEmitterPreservedFlags); _forcedInstOptions = BaseInst::kOptionReserved; _privateData = 0; _environment.reset(); _gpRegInfo.reset(); _instOptions = 0; _extraReg.reset(); _inlineComment = nullptr; return kErrorOk; } void BaseEmitter::onSettingsUpdated() noexcept { // Only called when attached to CodeHolder by CodeHolder. ASMJIT_ASSERT(_code != nullptr); if (!hasOwnLogger()) _logger = _code->logger(); if (!hasOwnErrorHandler()) _errorHandler = _code->errorHandler(); BaseEmitter_updateForcedOptions(this); } ASMJIT_END_NAMESPACE