Breaking Changes

Documentation of breaking changes.

Overview

AsmJit is a live project that is being actively developed. Deprecating the existing API in favor of a new one is preferred, but it's not always possible if the changes are significant. AsmJit authors prefer to do accumulated breaking changes at once instead of breaking the API often. This page documents deprecated and removed APIs and should serve as a how-to guide for people that want to port existing code to work with the newest AsmJit.

Tips

Useful tips before you start:

  • Visit our Public Gitter Chat if you need a quick help.
  • Build AsmJit with ASMJIT_NO_DEPRECATED macro defined to make sure that you are not using deprecated functionality at all. Deprecated functions are decorated with ASMJIT_DEPRECATED() macro, but sometimes it's not possible to decorate everything like classes, which are used by deprecated functions as well, because some compilers would warn about that. If your project compiles fine with ASMJIT_NO_DEPRECATED it's not using anything, which was deprecated.

Changes committed at 2024-01-01

Core changes:

  • Renamed equality functions eq() to equals() - Only related to String, ZoneVector, and CpuFeatures. Old function names were deprecated.
  • Removed CallConvId::kNone in favor of CallConvId::kCDecl, which is now the default calling convention.
  • Deprecated CallConvId::kHost in favor of CallConvId::kCDecl - host calling convention is now not part of CallConvId, it can be calculated from CallConvId and Environment instead.

Changes committed at 2023-12-27

Core changes:

  • Renamed a64::Vec::ElementType to a64::VecElementType and made it a typed enum. This enum was used mostly internally, but there is a public API using it, so it's a breaking change.
  • Refactored FuncSignature, FuncSignatureT, and FuncSignatureBuilder. There is only FuncSignature now, which acts as a function signature holder and builder. Replace FuncSignatureBuilder with FuncSignature and use FuncSignature::build<args> instead of FuncSignatureT<args>. The old API has been deprecated.
  • The maximum number of function arguments was raised from 16 to 32.

Changes committed at 2023-12-26

Core changes:

  • Reworked InstNode and InstExNode to be friendlier to static analysis and to not cause undefined behavior. InstNode has no operands visually embedded within the struct so there is no _opArray (which was internal). This means that sizeof(InstNode) changed, but since it's allocated by AsmJit this should be fine. Moreover, there is no longer InstExNode as that was more a hack, instead there is now InstNodeWithOperands, which is a template and specifies the number of operands embedded (InstNode accesses these). All nodes that inherited InstExNode now just inherit InstNodeWithOperands<InstNode::kBaseOpCapacity>, which would provide the same number of nodes as InstNode.
  • Moved GP and Vec registers from asmjit::arm namespace to asmjit::a64 namespace. At this time there was no prior deprecation as having arm::Vec would collide with a64::Vec as arm namespace is used within a64 namespace. Just change arm::Gp to a64::Gp and arm::Vec to a64::Vec.

Changes committed at 2023-09-10

Core changes:

  • Changed allocation API to work with spans (JitAllocator).
    • This change is required to support more hardened platforms in the future that make it very difficult to write JIT compilers.
    • JitAllocator::Span now represents a memory that the user can access. It abstracts both regular and dual mappings.
    • The Span is mostly designed to make it possible to write into it, so in general the read+execute pointer is what user is intended to keep. Use span.rx() to access RX pointer. Span is not needed after the memory it references has been modified, only remember span.rx() pointer, which is then used to deallocate or change the memory the span references.
    • Use a new JitAllocator::alloc() to allocate a Span, then pass the populated Span to JitAllocator write API such as JitAllocator::write() - note that JitAllocator can also establish a scope, so you can use a lambda function that would perform the write, but since it's going through JitAllocator it's able to ensure that the memory is actually writable.
    • If you need to repopulate a Span from rx pointer, use JitAllocator::query(<span-out>, rx) to get it.
    • Study what JitRuntime is doing to better understand how this new API works in detail.
    • Users of JitRuntime do not have to do anything as JitRuntime properly abstracts the allocation.
  • Renamed some X86 CPU features to make them compatible with architecture manuals:
    • Changed AVX512_CDI to AVX512_CD.
    • Changed AVX512_ERI to AVX512_ER.
    • Changed AVX512_PFI to AVX512_PF.
    • Old names were deprecated.

Changes committed at 2021-12-13

Core changes:

  • Removed old deprecated API.
  • Many enumerations were changed to enum class, and many public APIs were changed to use such enums instead of uint32_t. This change makes some APIs backward incompatible - there are no deprecations this time.
  • Extracted operand signature manipulation to OperandSignature.
  • Setting function arguments through Compiler::setArg() was deprecated, use FuncNode::setArg() instead.
  • Moved {arch}Features::k to CpuFeatures::{arch}k.
  • Moved BaseEmitter::kEncodingOption to EncodingOptions::k.
  • Moved BaseEmitter::kFlag to EmitterFlags::k.
  • Moved BaseEmitter::kType to EmitterType::k.
  • Moved BaseEmitter::kValidationOption to DiagnosticOptions::kValidate.
  • Moved BaseFeatures to CpuFeatures.
  • Moved BaseInst::kControl to InstControlFlow::k.
  • Moved BaseInst::kOption and x86::Inst::kOption to InstOptions::k.
  • Moved BaseNode::kNode to NodeType::k.
  • Moved BaseReg::kGroup and x86::Reg::kGroup to RegGroup::k.
  • Moved BaseReg::kType and x86::Reg::kType to RegType::k.
  • Moved CallConv::kFlag to CallConvFlags::k.
  • Moved CallConv::kId to CallConvId::k.
  • Moved CallConv::kStrategy to CallConvStrategy::k.
  • Moved CodeBuffer::kFlag to CodeBufferFlags.
  • Moved ConstPool::kScope to ConstPoolScope::k.
  • Moved Environment::kArch to Arch::k.
  • Moved Environment::kSubArch to SubArch::k.
  • Moved Environment::kFormat to OjectFormat::k.
  • Moved Environment::kPlatform to Platform::k.
  • Moved Environment::kAbi to PlatformABI::k.
  • Moved Environment::kVendor to Vendor::k.
  • Moved FormatOptions::kFlag to FormatFlags::k and DiagnosticOptions::k (Compiler diagnostics flags).
  • Moved FormatOptions::kIndentation to FormatIndentationGroup::k.
  • Moved FuncFrame::kAttr to FuncAttributes::k.
  • Moved Globals::kReset to ResetPolicy::k.
  • Moved InstDB::kAvx512Flag to InstDB::Avx512Flags::k.
  • Moved InstDB::kFlag to InstDB::InstFlags::k.
  • Moved InstDB::kMemFlag to InstDB::OpFlags::kMem.
  • Moved InstDB::kMode to InstDB::Mode::k.
  • Moved InstDB::kOpFlag to InstDB::OpFlags::k{OpType}....
  • Moved JitAllocator::kOption to JitAllocatorOptions::k.
  • Moved Label::kType to LabelType::k.
  • Moved Operand::kOpType to OperandType::k.
  • Moved OpRWInfo::kFlag to OpRWFlags::k.
  • Moved Type::kId to TypeId::k.
  • Moved VirtMem::k to VirtMem::MemoryFlags::k.

Changes committed at 2020-05-30

AsmJit has been cleaned up significantly, many todo items have been fixed and many functions and classes have been redesigned, some in an incompatible way.

Core changes:

  • Imm operand has now only Imm::value() and Imm::valueAs() functions that return its value content, and Imm::setValue() function that sets the content. Functions like setI8(), setU8() were deprecated.

    Old functions were deprecated, but code using them should still compile.

  • ArchInfo has been replaced with Environment. Environment provides more details about the architecture, but drops some properties that were used by arch info - gpSize() and gpCount(). gpSize() can be replaced with registerSize() getter, which returns a native register size of the architecture the environment uses. However, gpCount() was removed - at the moment ArchTraits can be used to access such properties.

    Some other functions were renamed, like ArchInfo::isX86Family() is now Environment::isFamilyX86(), etc. The reason for changing the order was support for more properties and all the accessors now start with the type of the property, like Environment::isPlatformWindows().

    This function causes many other classes to provide environment() getter instead of archInfo() getter. In addition, AsmJit now uses arch() to get an architecture instead of archId(). ArchInfo::kIdXXX was renamed to Environment::kArchXXX.

    Some functions were deprecated, some removed...

  • CodeInfo has been removed in favor of Environment. If you used CodeInfo to set architecture and base address, this is now possible with Environment and setting base address explicitly by CodeHolder::init()

    • the first argument is Environment, and the second argument is base address, which defaults to Globals::kNoBaseAddress.

    CodeInfo class was deprecated, but the code using it should still compile with warnings.

  • CallConv has been updated to offer a more unified way of representing calling conventions - many calling conventions were abstracted to follow standard naming like CallConvId::kCDecl or CallConvId::kStdCall.

    This change means that other APIs like FuncDetail::init() now require both, calling convention and target Environment.

  • Logging namespace has been renamed to Formatter, which now provides general functionality for formatting in AsmJit.

    Logging namespace should still work, but its use is deprecated. Unfortunately this will be without deprecation warnings, so make sure you don't use it.

  • Data64, Data128, and Data256 structs were deprecated and should no longer be used. There is no replacement, AsmJit users should simply create their own structures if they need them or use the new repeated embed API in emitters, see BaseEmitter::embedDataArray().

Emitter changes:

  • BaseEmitter::emit() function signature has been changed to accept 3 operands by reference and the rest 3 operands as a continuous array. This change is purely cosmetic and shouldn't affect users as emit() has many overloads that dispatch to the right function.
  • x86::Emitter (Assembler, Builder, Compiler) deprecates embed utilities like dint8(), duint8(), duint16(), dxmm(), etc... in favor of a new and more powerful BaseEmitter::embedDataArray(). This function also allows emitting repeated values and/or patterns, which is used by helpers BaseEmitter::embedUInt8(), and others...
  • Validation is now available through BaseEmitter::DiagnosticOptions, which can be enabled/disabled through BaseEmitter::addDiagnosticOptions() and BaseEmitter::clearDiagnosticOptions(), respectively. Validation options now separate between encoding and Builder/Compiler so it's possible to choose the granularity required.

Builder changes:

  • Internal functions for creating nodes were redesigned. They now accept a pointer to the node created as a first parameter. These changes should not affect AsmJit users as these functions were used internally.

Compiler changes:

  • FuncCallNode has been renamed to InvokeNode. Additionally, function calls should now use x86::Compiler::invoke() instead of call(). The reason behind this is to remove the confusion between a call instruction and AsmJit's call() intrinsic, which is now invoke().
  • Creating new nodes also changed. Now the preferred way of invoking a function is to call x86::Compiler::invoke() where the first argument is InvokeNode**. The function now returns an error and would call ErrorHandler in case of a failure. Error handling was unspecified in the past - the function was marked noexcept, but called error handler, which could throw.

    The reason behind this change is to make the API consistent with other changes and to also make it possible to inspect the possible error. In the previous API it returned a new node or nullptr in case of error, which the user couldn't inspect unless there was an attached ErrorHandler.

Samples:

#include <asmjit/x86.h>
using namespace asmjit;
// The basic setup of JitRuntime and CodeHolder changed, use environment()
// instead of codeInfo().
void basicSetup() {
CodeHolder code(rt.environment());
}
// Calling a function (Compiler) changed - use invoke() instead of call().
void functionInvocation(x86::Compiler& cc) {
InvokeNode* invokeNode;
cc.invoke(&invokeNode, targetOperand, FuncSignature::build<...>(...));
}