diff --git a/.travis.yml b/.travis.yml
index ce0d1c328d0a83ce65d77e0450f8d17b0df95059..008faff02a3bf4cae06562e41940e813c2c262a2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,6 +2,12 @@ language: cpp
compiler:
- clang
+env:
+ global:
+ # encrypted AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to push docs to s3
+ - secure: "VVKz+yOMbKsskR+PfU1HfKBWdGYYrmIXNWQz4nqXCjtg2MRCQmjDulFZaPVDvsBzis9BUhnzAQrBYUrAtN8bZSTYRg7ADFVGdPFicg3Sv0owcghTQwokIvbw3G+HDz/WAnFmqEhqm3t5pNVWNinyHpMM3zYZOVKagyj53cwAM0M="
+ - secure: "W2iPU6ooMujfzJNw9ElaEB8Go1rlNFJ5zEldr3FaH7SDRwqtqNOEp9CegCeG/hHtjg1j8TMyytQtvW+OaMKFIbq7Qqu7nIfwIFTV45vBHW6uwT/jAq/J3EgZ8K7JGyysVVHk86D8jT+xu90YVH5Tx/w97luxHOQGfSK8alhCszw="
+
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq libpcre3 libpcre3-dev gromacs
@@ -15,8 +21,10 @@ script:
- make -j2
- make -j2 install
- sudo make PythonInstall
- - # run all of the tests
- - ctest -j2 -V
+ - # Run the testInstallation script
+ - python -m simtk.testInstallation
+ - # run all of the tests, making sure failures at this stage don't cause travis failures
+ - ctest -j2 -V || true
- # get a list of all of the failed tests into this stupid ctest format
- python -c 'fn = "Testing/Temporary/LastTestsFailed.log"; import os; os.path.exists(fn) or exit(0); l = [line.split(":")[0] for line in open(fn)]; triplets = zip(l, l, [","]*len(l)); print "".join(",".join(t) for t in triplets)' > FailedTests.log
- # rerun all of the failed tests
@@ -24,3 +32,12 @@ script:
- # run the python tests too
- cd python/tests
- nosetests -vv --processes=-1 --process-timeout=200
+
+after_success:
+ # Get libraries necessary for building docs and pushing
+ # them to S3
+ - sudo apt-get install python-sphinx python-yaml
+ - sudo pip install sphinxcontrib-bibtex boto
+ - make DoxygenApiDocs
+ - make sphinxhtml
+ - python devtools/ci/push-docs-to-s3.py
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d083dd7c7f378d34a4faaffb8b39a6d76ef77795..67aa8eaf64431661549a945cbd7fc33e08176889 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -78,7 +78,7 @@ ENDIF(${CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT})
# The source is organized into subdirectories, but we handle them all from
# this CMakeLists file rather than letting CMake visit them as SUBDIRS.
-SET(OPENMM_SOURCE_SUBDIRS . openmmapi olla libraries/jama libraries/quern libraries/lepton libraries/sfmt libraries/lbfgs libraries/hilbert libraries/csha1 platforms/reference serialization libraries/validate)
+SET(OPENMM_SOURCE_SUBDIRS . openmmapi olla libraries/jama libraries/quern libraries/lepton libraries/sfmt libraries/lbfgs libraries/hilbert libraries/csha1 platforms/reference serialization libraries/validate libraries/irrxml)
IF(WIN32)
SET(OPENMM_SOURCE_SUBDIRS ${OPENMM_SOURCE_SUBDIRS} libraries/pthreads)
ADD_CUSTOM_TARGET(PthreadsLibraries ALL)
@@ -89,8 +89,12 @@ IF(WIN32)
INSTALL(FILES ${lib} DESTINATION "lib/")
ENDFOREACH(lib)
LINK_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
- SET(PTHREADS_LIB pthreadVC2)
- SET(PTHREADS_LIB_STATIC pthreadVC2_static_mt)
+ IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ SET(PTHREADS_LIB pthreadVC2_x64)
+ ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ SET(PTHREADS_LIB pthreadVC2)
+ SET(PTHREADS_LIB_STATIC pthreadVC2_static_mt)
+ ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8)
ELSE(WIN32)
IF (NOT ANDROID)
SET(PTHREADS_LIB pthread)
@@ -116,12 +120,12 @@ ELSE( CMAKE_SIZEOF_VOID_P EQUAL 8 )
ENDIF( CMAKE_SIZEOF_VOID_P EQUAL 8 )
IF (APPLE AND (NOT PNACL))
- # Build universal binaries compatible with OS X 10.7
+ # Build 64 bit binaries compatible with OS X 10.7
IF (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
SET (CMAKE_OSX_DEPLOYMENT_TARGET "10.7" CACHE STRING "The minimum version of OS X to support" FORCE)
ENDIF (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
IF (NOT CMAKE_OSX_ARCHITECTURES)
- SET (CMAKE_OSX_ARCHITECTURES "i386;x86_64" CACHE STRING "The processor architectures to build for" FORCE)
+ SET (CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "The processor architectures to build for" FORCE)
ENDIF (NOT CMAKE_OSX_ARCHITECTURES)
# Improve the linking behavior of Mac libraries
@@ -160,10 +164,10 @@ ENDIF (NOT CMAKE_CXX_FLAGS_RELEASE)
SET(OPENMM_LIBRARY_NAME OpenMM)
SET(OPENMM_MAJOR_VERSION 6)
-SET(OPENMM_MINOR_VERSION 1)
+SET(OPENMM_MINOR_VERSION 3)
SET(OPENMM_BUILD_VERSION 0)
-SET(OPENMM_COPYRIGHT_YEARS "2008-2014")
+SET(OPENMM_COPYRIGHT_YEARS "2008-2015")
# underbar separated list of dotted authors, no spaces or commas
SET(OPENMM_AUTHORS "Peter.Eastman")
@@ -269,6 +273,14 @@ IF (ANDROID OR PNACL)
ELSE (ANDROID OR PNACL)
SET_SOURCE_FILES_PROPERTIES(${CMAKE_SOURCE_DIR}/libraries/sfmt/src/SFMT.cpp PROPERTIES COMPILE_FLAGS "-DHAVE_SSE2=1")
ENDIF(ANDROID OR PNACL)
+IF (NOT (ANDROID OR PNACL))
+ FILE(GLOB src_files ${CMAKE_CURRENT_SOURCE_DIR}/libraries/asmjit/*/*.cpp)
+ FILE(GLOB incl_files ${CMAKE_CURRENT_SOURCE_DIR}/libraries/asmjit/*.h)
+ SET(SOURCE_FILES ${SOURCE_FILES} ${src_files})
+ SET(SOURCE_INCLUDE_FILES ${SOURCE_INCLUDE_FILES} ${incl_files})
+ INCLUDE_DIRECTORIES(BEFORE "${CMAKE_CURRENT_SOURCE_DIR}/libraries/asmjit")
+ SET(EXTRA_COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DLEPTON_USE_JIT")
+ENDIF (NOT (ANDROID OR PNACL))
# If API wrappers are being generated, and add them to the build.
SET(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS ON CACHE BOOL "Build wrappers for C and Fortran")
@@ -282,9 +294,16 @@ INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/src)
SET(OPENMM_BUILD_SHARED_LIB ON CACHE BOOL "Whether to build shared OpenMM libraries")
+SET(EXTRA_LINK_FLAGS ${EXTRA_COMPILE_FLAGS})
+IF (CMAKE_SYSTEM_NAME MATCHES "Linux")
+ IF (NOT ANDROID)
+ SET(EXTRA_LINK_FLAGS "${EXTRA_LINK_FLAGS} -Wl,--no-as-needed -lrt")
+ ENDIF (NOT ANDROID)
+ENDIF (CMAKE_SYSTEM_NAME MATCHES "Linux")
+
IF(OPENMM_BUILD_SHARED_LIB)
ADD_LIBRARY(${SHARED_TARGET} SHARED ${SOURCE_FILES} ${SOURCE_INCLUDE_FILES} ${API_ABS_INCLUDE_FILES})
- SET_TARGET_PROPERTIES(${SHARED_TARGET} PROPERTIES LINK_FLAGS "${EXTRA_COMPILE_FLAGS}" COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_BUILDING_SHARED_LIBRARY -DLEPTON_BUILDING_SHARED_LIBRARY -DOPENMM_VALIDATE_BUILDING_SHARED_LIBRARY")
+ SET_TARGET_PROPERTIES(${SHARED_TARGET} PROPERTIES LINK_FLAGS "${EXTRA_LINK_FLAGS}" COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_BUILDING_SHARED_LIBRARY -DLEPTON_BUILDING_SHARED_LIBRARY -DOPENMM_VALIDATE_BUILDING_SHARED_LIBRARY")
IF(WIN32)
ADD_DEPENDENCIES(${SHARED_TARGET} PthreadsLibraries)
ENDIF(WIN32)
@@ -294,7 +313,7 @@ SET(OPENMM_BUILD_STATIC_LIB OFF CACHE BOOL "Whether to build static OpenMM libra
IF(OPENMM_BUILD_STATIC_LIB)
ADD_LIBRARY(${STATIC_TARGET} STATIC ${SOURCE_FILES} ${SOURCE_INCLUDE_FILES} ${API_ABS_INCLUDE_FILES})
SET(EXTRA_COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_USE_STATIC_LIBRARIES -DLEPTON_USE_STATIC_LIBRARIES -DPTW32_STATIC_LIB")
- SET_TARGET_PROPERTIES(${STATIC_TARGET} PROPERTIES LINK_FLAGS "${EXTRA_COMPILE_FLAGS}" COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_BUILDING_STATIC_LIBRARY -DLEPTON_BUILDING_STATIC_LIBRARY -DOPENMMM_VALIDATE_BUILDING_STATIC_LIBRARY -DOPENMM_VALIDATE_BUILDING_STATIC_LIBRARY")
+ SET_TARGET_PROPERTIES(${STATIC_TARGET} PROPERTIES LINK_FLAGS "${EXTRA_LINK_FLAGS}" COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_BUILDING_STATIC_LIBRARY -DLEPTON_BUILDING_STATIC_LIBRARY -DOPENMMM_VALIDATE_BUILDING_STATIC_LIBRARY -DOPENMM_VALIDATE_BUILDING_STATIC_LIBRARY")
ENDIF(OPENMM_BUILD_STATIC_LIB)
IF(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS)
@@ -324,7 +343,9 @@ ELSE(DL_LIBRARY)
ENDIF(OPENMM_BUILD_SHARED_LIB)
ENDIF(DL_LIBRARY)
-ADD_SUBDIRECTORY(platforms/reference/tests)
+IF(BUILD_TESTING)
+ ADD_SUBDIRECTORY(platforms/reference/tests)
+ENDIF(BUILD_TESTING)
# Which hardware platforms to build
@@ -441,6 +462,21 @@ IF(OPENMM_BUILD_PME_PLUGIN)
ADD_SUBDIRECTORY(plugins/cpupme)
ENDIF(OPENMM_BUILD_PME_PLUGIN)
+# CUDA compiler plugin
+
+GET_FILENAME_COMPONENT(CUDA_LIB_DIR "${CUDA_cufft_LIBRARY}" PATH)
+FIND_LIBRARY(CUDA_nvrtc_LIBRARY nvrtc "${CUDA_LIB_DIR}")
+IF(CUDA_nvrtc_LIBRARY)
+ SET(OPENMM_BUILD_CUDA_COMPILER_PLUGIN ON CACHE BOOL "Build CUDA runtime compiler plugin")
+ELSE(CUDA_nvrtc_LIBRARY)
+ SET(OPENMM_BUILD_CUDA_COMPILER_PLUGIN OFF CACHE BOOL "Build CUDA runtime compiler plugin")
+ENDIF(CUDA_nvrtc_LIBRARY)
+SET(OPENMM_BUILD_CUDACOMPILER_PATH)
+IF(OPENMM_BUILD_CUDA_COMPILER_PLUGIN)
+ SET(OPENMM_BUILD_CUDACOMPILER_PATH ${CMAKE_CURRENT_SOURCE_DIR}/plugins/cudacompiler)
+ ADD_SUBDIRECTORY(plugins/cudacompiler)
+ENDIF(OPENMM_BUILD_CUDA_COMPILER_PLUGIN)
+
IF(OPENMM_BUILD_SHARED_LIB)
INSTALL_TARGETS(/lib RUNTIME_DIRECTORY /lib ${SHARED_TARGET})
ENDIF(OPENMM_BUILD_SHARED_LIB)
@@ -506,7 +542,9 @@ ELSE (EXECUTABLE_OUTPUT_PATH)
ENDIF (EXECUTABLE_OUTPUT_PATH)
ADD_SUBDIRECTORY(docs-source)
-ADD_SUBDIRECTORY(tests)
+IF(BUILD_TESTING)
+ ADD_SUBDIRECTORY(tests)
+ENDIF(BUILD_TESTING)
ADD_SUBDIRECTORY(examples)
ENDIF(NOT cmv EQUAL "2.4") # This whole file...
diff --git a/README.md b/README.md
index cc03c71c5ba11bf9f22a028446ecab6754790e5c..db6f5cd85fc2242f8e19983ca39b9e14f95cd1c7 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
## OpenMM: A High Performance Molecular Dynamics Library
-[](https://travis-ci.org/SimTk/openmm)
+[](https://travis-ci.org/pandegroup/openmm)
Introduction
------------
diff --git a/devtools/build-vm/linux/Vagrantfile b/devtools/build-vm/linux/Vagrantfile
deleted file mode 100644
index 1595c6f0f36266fef991a6182c8254dab5001d4c..0000000000000000000000000000000000000000
--- a/devtools/build-vm/linux/Vagrantfile
+++ /dev/null
@@ -1,88 +0,0 @@
-# -*- mode: ruby -*-
-# vi: set ft=ruby :
-
-# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
-VAGRANTFILE_API_VERSION = "2"
-
-Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
- # All Vagrant configuration is done here. The most common configuration
- # options are documented and commented below. For a complete reference,
- # please see the online documentation at vagrantup.com.
-
- # Every Vagrant virtual environment requires a box to build off of.
- config.vm.box = "chef/centos-6.5"
-
- # Disable automatic box update checking. If you disable this, then
- # boxes will only be checked for updates when the user runs
- # `vagrant box outdated`. This is not recommended.
- # config.vm.box_check_update = false
-
- # Create a forwarded port mapping which allows access to a specific port
- # within the machine from a port on the host machine. In the example below,
- # accessing "localhost:8080" will access port 80 on the guest machine.
- # config.vm.network "forwarded_port", guest: 80, host: 8080
-
- # Create a private network, which allows host-only access to the machine
- # using a specific IP.
- # config.vm.network "private_network", ip: "192.168.33.10"
-
- # Create a public network, which generally matched to bridged network.
- # Bridged networks make the machine appear as another physical device on
- # your network.
- # config.vm.network "public_network"
-
- # If true, then any SSH connections made will enable agent forwarding.
- # Default value: false
- # config.ssh.forward_agent = true
-
- # Share an additional folder to the guest VM. The first argument is
- # the path on the host to the actual folder. The second argument is
- # the path on the guest to mount the folder. And the optional third
- # argument is a set of non-required options.
- # config.vm.synced_folder "../data", "/vagrant_data"
-
- # Provider-specific configuration so you can fine-tune various
- # backing providers for Vagrant. These expose provider-specific options.
- # Example for VirtualBox:
- #
- # config.vm.provider "virtualbox" do |vb|
- # # Don't boot with headless mode
- # vb.gui = true
- #
- # # Use VBoxManage to customize the VM. For example to change memory:
- # vb.customize ["modifyvm", :id, "--memory", "1024"]
- # end
- #
- # View the documentation for the provider you're using for more
- # information on available options.
-
- # Enable provisioning with CFEngine. CFEngine Community packages are
- # automatically installed. For example, configure the host as a
- # policy server and optionally a policy file to run:
- #
- # config.vm.provision "cfengine" do |cf|
- # cf.am_policy_hub = true
- # # cf.run_file = "motd.cf"
- # end
- #
- # You can also configure and bootstrap a client to an existing
- # policy server:
- #
- # config.vm.provision "cfengine" do |cf|
- # cf.policy_server_address = "10.0.2.15"
- # end
-
- # Enable provisioning with Puppet stand alone. Puppet manifests
- # are contained in a directory path relative to this Vagrantfile.
- # You will need to create the manifests directory and a manifest in
- # the file default.pp in the manifests_path directory.
- #
- # config.vm.provision "puppet" do |puppet|
- # puppet.manifests_path = "manifests"
- # puppet.manifest_file = "site.pp"
- # end
-
- config.vm.provision "shell",
- inline: "su -c 'source /vagrant/setup_centos_vm.sh' vagrant"
-
-end
diff --git a/devtools/build-vm/linux/build_conda_package_vagrant.sh b/devtools/build-vm/linux/build_conda_package_vagrant.sh
deleted file mode 100644
index 4b8fa278bd9c3b995d00337decd7a61a8d33071c..0000000000000000000000000000000000000000
--- a/devtools/build-vm/linux/build_conda_package_vagrant.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-export PATH=$HOME/miniconda/bin:$PATH
-export SWIG_LIB=$HOME/miniconda/share/swig/
-export CC="clang++"
-
-git clone -b vagrant https://github.com/simtk/openmm.git
-cd openmm
-conda install --file tools/ci/requirements-conda.txt --yes
-conda build tools/conda-recipe
diff --git a/devtools/build-vm/linux/setup_centos_vm.sh b/devtools/build-vm/linux/setup_centos_vm.sh
deleted file mode 100644
index ca46b1e363b33e1bdf0384177328493e03ed0cd4..0000000000000000000000000000000000000000
--- a/devtools/build-vm/linux/setup_centos_vm.sh
+++ /dev/null
@@ -1,60 +0,0 @@
-# Prepare a vagrant CentOS 6.5 VM for building OpenMM
-# Needs latest version of vagrant to auto-download the chef package
-#vagrant init chef/centos-6.5
-#vagrant up
-#vagrant ssh
-
-
-# Download and enable the EPEL RedHat EL extras repository
-mkdir ~/Software
-cd Software
-sudo yum install wget -y
-wget http://mirror.umd.edu/fedora/epel/6/i386/epel-release-6-8.noarch.rpm
-sudo rpm -i epel-release-6-8.noarch.rpm
-
-sudo yum update -y
-
-# Several of these come from the EPEL repo
-sudo yum install clang-3.4 cmake28 graphviz perl flex bison rpm-build texlive texlive-latex ghostscript gcc gcc-c++ git vim -y
-
-# Probably can't use RHEL6 version of doxygen because it's very old.
-wget http://ftp.stack.nl/pub/users/dimitri/doxygen-1.8.7.src.tar.gz
-rpmbuild -ta doxygen-1.8.7.src.tar.gz
-sudo rpm -i ~/rpmbuild/RPMS/x86_64/doxygen-1.8.7-1.x86_64.rpm
-rm ~/rpmbuild -r
-
-
-sudo yum clean headers
-sudo yum clean packages
-
-# Install CUDA6 for RHEL6
-cd ~/Software
-wget http://developer.download.nvidia.com/compute/cuda/repos/rhel6/x86_64/cuda-repo-rhel6-6.0-37.x86_64.rpm
-sudo rpm -i cuda-repo-rhel6-6.0-37.x86_64.rpm
-sudo yum clean expire-cache
-sudo yum install cuda -y
-rm cuda-repo-rhel6-6.0-37.x86_64.rpm
-
-
-# Install Conda
-cd ~/Software
-wget http://repo.continuum.io/miniconda/Miniconda-3.0.5-Linux-x86_64.sh
-bash Miniconda-3.0.5-Linux-x86_64.sh -b
-
-# So there is a bug in some versions of anaconda where the path to swig files is HARDCODED. Below is workaround. See https://github.com/ContinuumIO/anaconda-issues/issues/48
-sudo ln -s ~/miniconda/ /opt/anaconda1anaconda2anaconda3
-
-export PATH=$HOME/miniconda/bin:$PATH
-conda config --add channels http://conda.binstar.org/omnia
-conda install --yes fftw3f jinja2 swig sphinx conda-build cmake
-
-
-# Download AMD APP SDK from here, requires click agreement: http://developer.amd.com/amd-license-agreement-appsdk/
-# Ideally we could cache this on AWS or something...
-mkdir ~/Software/AMD
-cd ~/Software/AMD
-# Copy the tarball to this directory from wherever you got it.
-cp /vagrant/AMD-APP-SDK-v2.9-lnx64.tgz ./
-tar -zxvf /vagrant/AMD-APP-SDK-v2.9-lnx64.tgz
-sudo ./Install-AMD-APP.sh
-
diff --git a/devtools/ci/push-docs-to-s3.py b/devtools/ci/push-docs-to-s3.py
new file mode 100644
index 0000000000000000000000000000000000000000..f2aad5a2ff94a82aec7a7ba9539b757741599401
--- /dev/null
+++ b/devtools/ci/push-docs-to-s3.py
@@ -0,0 +1,34 @@
+from __future__ import print_function
+import os
+import boto
+import simtk
+from boto.s3.key import Key
+
+# The secret key is available as a secure environment variable
+# on travis-ci to push the build documentation to Amazon S3.
+AWS_ACCESS_KEY_ID = os.environ['AWS_ACCESS_KEY_ID']
+AWS_SECRET_ACCESS_KEY = os.environ['AWS_SECRET_ACCESS_KEY']
+BUCKET_NAME = 'docs.openmm.org'
+
+bucket_name = AWS_ACCESS_KEY_ID.lower() + '-' + BUCKET_NAME
+conn = boto.connect_s3(AWS_ACCESS_KEY_ID,
+ AWS_SECRET_ACCESS_KEY)
+bucket = conn.get_bucket(BUCKET_NAME)
+
+def upload(path, root=None, prefix='', versioned=True):
+ if root is None:
+ root = path
+ for dirpath, dirnames, filenames in os.walk(path):
+ for filename in filenames:
+ fn = os.path.join(dirpath, filename)
+ k = Key(bucket)
+ k.key = os.path.join(prefix, os.path.relpath(fn, root))
+ if versioned:
+ k.key = os.path.join(simtk.version.short_version, k.key)
+ print('Uploading', k.key, '...')
+ k.set_contents_from_filename(fn)
+
+upload('api-c++/', 'build')
+upload('api-python/', 'build')
+upload('sphinx-docs/developerguide/html', prefix='developerguide')
+upload('sphinx-docs/userguide/html', prefix='userguide')
diff --git a/devtools/forcefield-scripts/residuesFinal.xml b/devtools/forcefield-scripts/residuesFinal.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b19c320bf2cf391138877b751adf052c392d89bc
--- /dev/null
+++ b/devtools/forcefield-scripts/residuesFinal.xml
@@ -0,0 +1,945 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/devtools/packaging/manifests/README.md b/devtools/packaging/manifests/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..23beab9e7d0476ffda396d3c3fe69afdce77e7a8
--- /dev/null
+++ b/devtools/packaging/manifests/README.md
@@ -0,0 +1,9 @@
+# Manifests for automated packaging of source and binary distributions
+
+A detailed explanation of packaging protocols can be found on the developer wiki:
+https://github.com/pandegroup/openmm/wiki/Packaging-OpenMM-installers
+
+## Contents
+* `source/` - directories and files to be copied from the GitHub repo for a source distribution
+* `binary/` - directories and files to be copied from install directory after build for a binary distribution
+
diff --git a/devtools/packaging/manifests/binary/manifest.txt b/devtools/packaging/manifests/binary/manifest.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4ff612d6c05b23c399e0ca0785df5749b5279a50
--- /dev/null
+++ b/devtools/packaging/manifests/binary/manifest.txt
@@ -0,0 +1,5 @@
+docs
+examples
+include
+lib
+licenses
diff --git a/devtools/packaging/manifests/source/manifest.txt b/devtools/packaging/manifests/source/manifest.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ebe522954bc3bdeb732bf9aa6f999977069a874b
--- /dev/null
+++ b/devtools/packaging/manifests/source/manifest.txt
@@ -0,0 +1,12 @@
+cmake_modules
+CMakeLists.txt
+docs-source
+examples
+libraries
+olla
+openmmapi
+platforms
+plugins
+serialization
+tests
+wrappers
diff --git a/devtools/packaging/scripts/linux/build.sh b/devtools/packaging/scripts/linux/build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2fccf99705419e2261339ef980e6934c3218bdcf
--- /dev/null
+++ b/devtools/packaging/scripts/linux/build.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+# Build script for Linux distribution, for use in automated packaging.
+# Note that this must be run from outside the checked-out openmm/ directory.
+
+# Set relative workspace path.
+export WORKSPACE=`pwd`
+
+# Add conda binaries to path.
+PATH=$WORKSPACE/miniconda/bin:$PATH
+
+INSTALL=`pwd`/install
+if [ -e $INSTALL ]; then
+ rm -rf $INSTALL
+fi
+
+CMAKE_FLAGS="-DCMAKE_INSTALL_PREFIX=$INSTALL"
+
+# setting the rpath so that libOpenMMPME.so finds the right libfftw3
+#CMAKE_FLAGS+=" -DCMAKE_INSTALL_RPATH=.."
+CMAKE_FLAGS+=" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
+CMAKE_FLAGS+=" -DCUDA_CUDART_LIBRARY=/usr/local/cuda-6.5/lib64/libcudart.so"
+CMAKE_FLAGS+=" -DCUDA_NVCC_EXECUTABLE=/usr/local/cuda-6.5/bin/nvcc"
+CMAKE_FLAGS+=" -DCUDA_SDK_ROOT_DIR=/usr/local/cuda-6.5/"
+CMAKE_FLAGS+=" -DCUDA_TOOLKIT_INCLUDE=/usr/local/cuda-6.5/include"
+CMAKE_FLAGS+=" -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-6.5/"
+CMAKE_FLAGS+=" -DOPENCL_INCLUDE_DIR=/usr/local/cuda-6.5/include"
+CMAKE_FLAGS+=" -DOPENCL_LIBRARY=/usr/local/cuda-6.5/lib64/libOpenCL.so"
+
+# Set location for FFTW3
+PREFIX="$WORKSPACE/miniconda"
+CMAKE_FLAGS+=" -DFFTW_INCLUDES=$PREFIX/include"
+CMAKE_FLAGS+=" -DFFTW_LIBRARY=$PREFIX/lib/libfftw3f.so"
+CMAKE_FLAGS+=" -DFFTW_THREADS_LIBRARY=$PREFIX/lib/libfftw3f_threads.so"
+
+# Build in subdirectory.
+if [ -e build ]; then
+ rm -rf build
+fi
+mkdir build
+cd build
+cmake ../openmm $CMAKE_FLAGS
+make -j4 all DoxygenApiDocs sphinxpdf
+
+# Install.
+make install
diff --git a/devtools/packaging/scripts/linux/package.sh b/devtools/packaging/scripts/linux/package.sh
new file mode 100755
index 0000000000000000000000000000000000000000..56803707f29a8184d6ac20dd98cdb7f4160afa7d
--- /dev/null
+++ b/devtools/packaging/scripts/linux/package.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+# Packaging script for Linux distribution, for use in automated packaging.
+# Note that this must be run from outside the checked-out openmm/ directory.
+
+# CONFIGURE HERE
+export PACKAGE_DIR="packaging" # directory to stuff packaged source distribution
+export VERSION=$(sed -nr "s/OPENMM_VERSION:STRING=(.*)/\1/p" build/CMakeCache.txt)
+export PACKAGE_SUBDIR="OpenMM-${VERSION}-Linux" # directory where distribution will be unpacked
+export DISTRO_PREFIX="OpenMM-${VERSION}-Linux" # prefix for source distribution (e.g. ${DISTRIBUTION_NAME}.zip)
+
+# Perform all work in a work directory.
+cd work
+
+# Clean up.
+rm -rf $PACKAGE_DIR
+
+# Make a directory to contain packaged source distribution
+mkdir $PACKAGE_DIR
+mkdir $PACKAGE_DIR/$PACKAGE_SUBDIR
+for filename in $( cat openmm/devtools/packaging/manifests/binary/manifest.txt ); do
+ CMD="cp -r install/$filename $PACKAGE_DIR/$PACKAGE_SUBDIR"
+ echo $CMD
+ `$CMD`
+done
+
+# Add the install.sh script
+CMD="cp -r openmm/install.sh $PACKAGE_DIR/$PACKAGE_SUBDIR"
+echo $CMD
+`$CMD`
+
+# Make Python source distribution.
+echo "Building Python source distribution..."
+pushd .
+cd build
+make PythonSdist
+cd python/dist
+tar zxf OpenMM-${VERSION}.tar.gz
+mv OpenMM-${VERSION} python
+popd
+cp -r build/python/dist/python $PACKAGE_DIR/$PACKAGE_SUBDIR
+
+# Create archives.
+cd $PACKAGE_DIR
+mkdir compressed
+tar zcf compressed/${DISTRO_PREFIX}.tgz $PACKAGE_SUBDIR
+zip -r compressed/${DISTRO_PREFIX}.zip $PACKAGE_SUBDIR
+cd ..
diff --git a/devtools/packaging/scripts/linux/prepare.sh b/devtools/packaging/scripts/linux/prepare.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9d6c1c31ea06977c8b7e6affbecbd30f04c62d05
--- /dev/null
+++ b/devtools/packaging/scripts/linux/prepare.sh
@@ -0,0 +1,30 @@
+#!/bin/tcsh
+
+# Prepare for build by ensuring necessary prerequisites are locally installed.
+
+# Set relative workspace path.
+export WORKSPACE=`pwd`
+
+# Install miniconda
+export VERSION="3.7.0"
+export PLATFORM="Linux"
+export ARCH="x86_64"
+export MINICONDA="Miniconda-$VERSION-$PLATFORM-$ARCH.sh"
+if [ -f miniconda ];
+then
+ echo "miniconda already exists"
+else
+ echo "Downloading miniconda..."
+ rm -rf Miniconda-*
+ wget --quiet http://repo.continuum.io/miniconda/${MINICONDA}
+ bash ${MINICONDA} -b -p miniconda
+ PIP_ARGS="-U"
+fi
+
+# Add to path.
+export PATH=$WORKSPACE/miniconda/bin:$PATH
+
+# Ensure configuration is up to date.
+conda config --add channels http://conda.binstar.org/omnia
+conda install --yes --quiet swig fftw3f pip
+pip install sphinxcontrib-bibtex
diff --git a/devtools/packaging/scripts/osx/build.sh b/devtools/packaging/scripts/osx/build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ce992e5050dd1c0ceffa0de3a1772b3e5d92abf6
--- /dev/null
+++ b/devtools/packaging/scripts/osx/build.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+# Build script for Mac OS X distribution, for use in automated packaging.
+# Note that this must be run from outside the checked-out openmm/ directory.
+
+# Set relative workspace path.
+export WORKSPACE=`pwd`
+
+# Add conda binaries to path.
+PATH=$WORKSPACE/miniconda/bin:$PATH
+
+# Set install directory.
+INSTALL=`pwd`/install
+if [ -e $INSTALL ]; then
+ rm -rf $INSTALL
+fi
+
+CMAKE_FLAGS="-DCMAKE_INSTALL_PREFIX=$INSTALL"
+
+# setting the rpath so that libOpenMMPME.so finds the right libfftw3
+#CMAKE_FLAGS+=" -DCMAKE_INSTALL_RPATH=.."
+CMAKE_FLAGS+=" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
+CMAKE_FLAGS+=" -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9"
+CMAKE_FLAGS+=" -DCMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk"
+CMAKE_FLAGS+=" -DOPENMM_BUILD_OPENCL_LIB=OFF"
+CMAKE_FLAGS+=" -DOPENMM_BUILD_DRUDE_OPENCL_LIB=OFF"
+CMAKE_FLAGS+=" -DOPENMM_BUILD_RPMD_OPENCL_LIB=OFF"
+CMAKE_FLAGS+=" -DOPENMM_BUILD_OPENCL_TESTS=FALSE"
+CMAKE_FLAGS+=" -DOPENMM_BUILD_OPENCL_DOUBLE_PRECISION_TESTS=FALSE"
+
+# Build in subdirectory.
+# Set location for FFTW3
+PREFIX="$WORKSPACE/miniconda"
+CMAKE_FLAGS+=" -DFFTW_INCLUDES=$PREFIX/include"
+CMAKE_FLAGS+=" -DFFTW_LIBRARY=$PREFIX/lib/libfftw3f.dylib"
+CMAKE_FLAGS+=" -DFFTW_THREADS_LIBRARY=$PREFIX/lib/libfftw3f_threads.dylib"
+
+# Build in subdirectory.
+if [ -e build ]; then
+ rm -rf build
+fi
+mkdir build
+cd build
+cmake ../openmm $CMAKE_FLAGS
+make -j4 all DoxygenApiDocs sphinxpdf
+
+# Install.
+make install
diff --git a/devtools/packaging/scripts/osx/package.sh b/devtools/packaging/scripts/osx/package.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ce3ec74d04de74a09db8ae70feeb77ef90ee46a6
--- /dev/null
+++ b/devtools/packaging/scripts/osx/package.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+# Packaging script for Mac OS X distribution, for use in automated packaging.
+# Note that this must be run from outside the checked-out openmm/ directory.
+
+# CONFIGURE HERE
+export PACKAGE_DIR="packaging" # directory to stuff packaged source distribution
+export VERSION=$(grep "OPENMM_VERSION:STRING" build/CMakeCache.txt | sed -E "s/OPENMM_VERSION:STRING=(.*)/\1/")
+export PACKAGE_SUBDIR="OpenMM-${VERSION}-Mac" # directory where distribution will be unpacked
+export DISTRO_PREFIX="OpenMM-${VERSION}-Mac" # prefix for source distribution (e.g. ${DISTRIBUTION_NAME}.zip)
+
+# Clean up.
+rm -rf $PACKAGE_DIR
+
+# Make a directory to contain packaged source distribution
+mkdir $PACKAGE_DIR
+mkdir $PACKAGE_DIR/$PACKAGE_SUBDIR
+for filename in $( cat openmm/devtools/packaging/manifests/binary/manifest.txt ); do
+ CMD="cp -r install/$filename $PACKAGE_DIR/$PACKAGE_SUBDIR"
+ echo $CMD
+ `$CMD`
+done
+
+# Add the install.sh script
+CMD="cp -r openmm/install.sh $PACKAGE_DIR/$PACKAGE_SUBDIR"
+echo $CMD
+`$CMD`
+
+# Make Python source distribution.
+echo "Building Python source distribution..."
+pushd .
+cd build
+make PythonSdist
+cd python/dist
+tar zxf OpenMM-${VERSION}.tar.gz
+mv OpenMM-${VERSION} python
+popd
+cp -r build/python/dist/python $PACKAGE_DIR/$PACKAGE_SUBDIR
+
+# Create archives.
+cd $PACKAGE_DIR
+mkdir compressed
+tar zcf compressed/${DISTRO_PREFIX}.tgz $PACKAGE_SUBDIR
+zip -r compressed/${DISTRO_PREFIX}.zip $PACKAGE_SUBDIR
+cd ..
diff --git a/devtools/packaging/scripts/osx/prepare.sh b/devtools/packaging/scripts/osx/prepare.sh
new file mode 100755
index 0000000000000000000000000000000000000000..94b9d2d45d3c21c84631cd6c871653719cecc0df
--- /dev/null
+++ b/devtools/packaging/scripts/osx/prepare.sh
@@ -0,0 +1,30 @@
+#!/bin/tcsh
+
+# Prepare for build by ensuring necessary prerequisites are locally installed.
+
+# Set relative workspace path.
+export WORKSPACE=`pwd`
+
+# Install miniconda
+export VERSION="3.7.0"
+export PLATFORM="MacOSX"
+export ARCH="x86_64"
+export MINICONDA="Miniconda-$VERSION-$PLATFORM-$ARCH.sh"
+if [ -f miniconda ];
+then
+ echo "miniconda already exists"
+else
+ echo "Downloading miniconda..."
+ rm -rf Miniconda-*
+ wget --quiet http://repo.continuum.io/miniconda/${MINICONDA}
+ bash ${MINICONDA} -b -p miniconda
+ PIP_ARGS="-U"
+fi
+
+# Add to path.
+export PATH=$WORKSPACE/miniconda/bin:$PATH
+
+# Ensure configuration is up to date.
+conda config --add channels http://conda.binstar.org/omnia
+conda install --yes --quiet swig fftw3f pip
+pip install sphinxcontrib-bibtex
diff --git a/docs-source/Lepton User's Manual.doc b/docs-source/Lepton User's Manual.doc
index 10c8a2d53d95feb157ecbf24186dca985ee44f2b..8bf84d06fef28ea22e94835ac8b85b0d31f5c9c2 100644
Binary files a/docs-source/Lepton User's Manual.doc and b/docs-source/Lepton User's Manual.doc differ
diff --git a/docs-source/licenses/Licenses.txt b/docs-source/licenses/Licenses.txt
index 0c53a4416b0bf6071eadd8d1321ade3141e54717..f42b3584c60b22f9e08927b59160fa00665133c0 100644
--- a/docs-source/licenses/Licenses.txt
+++ b/docs-source/licenses/Licenses.txt
@@ -2,16 +2,16 @@ OpenMM was developed by Simbios, the NIH National Center for Physics-Based
Simulation of Biological Structures at Stanford, funded under the NIH Roadmap
for Medical Research, grant U54 GM072970. See https://simtk.org.
-Portions copyright © 2008-2009 Stanford University and the Authors.
+Portions copyright � 2008-2015 Stanford University and the Authors.
There are several licenses which cover different parts of OpenMM as described
below.
-1. API and Reference Platform
+1. API, Reference Platform, CPU Platform
-The OpenMM API and the Reference Platform may be used under the terms of the
-MIT License:
+The OpenMM API, the Reference Platform, and the CPU platform may be used under
+the terms of the MIT License:
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -99,10 +99,52 @@ name of the person performing the modification, the date of modification,
and the reason for such modification.
-5. GPU-BBSort
+5. AsmJit
-The CUDA platform uses the GPU-BBSort library written by Chen Shifu. It
-includes the following license statement:
+OpenMM uses the AsmJit library which is copyright 2008-2014 by Petr Kobalicek.
+It may be used under the following terms:
-The code is distributed under BSD license, you are allowed to use, modify
-or sell this code, but a statement is required if you used this code any where.
\ No newline at end of file
+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.
+
+
+6. PdbxReader
+
+OpenMM uses the PDBx/mmCIF parser written by John Westbrook. It is distributed
+under the Creative Commons Attribution 3.0 Unported license. For details, see
+https://creativecommons.org/licenses/by/3.0. This library was modified to move
+it inside the simtk.openmm.app.internal module.
+
+7. irrXML
+
+OpenMM uses the irrXML library which is copyright 2002-2005 Nikolaus Gebhardt.
+It may be used under the following terms:
+
+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.
diff --git a/docs-source/usersguide/application.rst b/docs-source/usersguide/application.rst
index 48ab7d5af1e6de59894b8683e09cdea4521a3b2c..5f8b97290e5084bacdc507e2895e52bf2429bf98 100644
--- a/docs-source/usersguide/application.rst
+++ b/docs-source/usersguide/application.rst
@@ -43,15 +43,13 @@ troubleshooting guide that describes common problems and how to fix them
Installing on Mac OS X
**********************
-OpenMM works on Mac OS X 10.7 or later. GPU acceleration is currently only
-supported on Nvidia GPUs, not on AMD or Intel GPUs.
+OpenMM works on Mac OS X 10.7 or later.
-.. warning::
- A serious bug was introduced in Mac OS X 10.7.5 that prevents
- OpenMM’s OpenCL platform from working correctly. At the time of this writing,
- the bug is present in all versions from 10.7.5 onward. The CUDA platform (see
- below) is not affected by the bug, so if you have an affected version of OS X,
- you should use it instead of the OpenCL platform.
+.. note::
+ The OpenCL implementations on all recent versions of Mac OS X contain serious
+ bugs that make them unsuitable for use with OpenMM. GPU acceleration is
+ therefore only supported with the CUDA platform. This limits it to only Nvidia
+ GPUs, not AMD or Intel GPUs.
1. Download the pre-compiled binary of OpenMM for Mac OS X, then double click
the .zip file to expand it.
@@ -63,7 +61,7 @@ and tell it to install the command line tools. With Xcode 4.2 and earlier, the
command line tools are automatically installed when you install Xcode.)
3. (Optional) If you have an Nvidia GPU and want to use the CUDA platform,
-download CUDA 6.0 from https://developer.nvidia.com/cuda-downloads. Be sure to
+download CUDA 6.5 from https://developer.nvidia.com/cuda-downloads. Be sure to
install both the drivers and toolkit.
4. (Optional) If you plan to use the CPU platform, it is recommended that you
@@ -107,14 +105,12 @@ example,
export OPENMM_CUDA_COMPILER=/opt/CUDA/cuda-6.0/bin/nvcc
-7. Verify your installation by running the :file:`testInstallation.py` script found in
-the :file:`examples` folder of your OpenMM installation. To run it, cd to the
-examples folder and type
+7. Verify your installation by typing the following command:
::
- python testInstallation.py
+ python -m simtk.testInstallation
-This script confirms that OpenMM is installed, checks whether GPU acceleration
+This command confirms that OpenMM is installed, checks whether GPU acceleration
is available (via the OpenCL and/or CUDA platforms), and verifies that all
platforms produce consistent results.
@@ -139,7 +135,7 @@ into a console window.
3. (Optional) If you want to run OpenMM on a GPU, install CUDA and/or OpenCL.
- * If you have an Nvidia GPU, download CUDA 6.0 from
+ * If you have an Nvidia GPU, download CUDA 6.5 from
https://developer.nvidia.com/cuda-downloads. Be sure to install both the
drivers and toolkit. OpenCL is included with the CUDA drivers.
* If you have an AMD GPU, download the latest version of the Catalyst driver
@@ -188,15 +184,13 @@ example,
export OPENMM_CUDA_COMPILER=/opt/CUDA/cuda-6.0/bin/nvcc
-7. Verify your installation by running the :file:`testInstallation.py` script found in
-the :file:`examples` folder of your OpenMM installation. To run it, :command:`cd` to the
-:file:`examples` folder and type
+7. Verify your installation by typing the following command:
::
- python testInstallation.py
+ python -m simtk.testInstallation
-This script confirms that OpenMM is installed, checks whether GPU acceleration
-is available (via that OpenCL and/or CUDA platforms), and verifies that all
+This command confirms that OpenMM is installed, checks whether GPU acceleration
+is available (via the OpenCL and/or CUDA platforms), and verifies that all
platforms produce consistent results.
.. _installing-on-windows:
@@ -222,11 +216,9 @@ and ignore it.)
4. (Optional) If you want to run OpenMM on a GPU, install CUDA and/or OpenCL.
- * If you have an Nvidia GPU, download CUDA 6.0 from
+ * If you have an Nvidia GPU, download CUDA 6.5 from
https://developer.nvidia.com/cuda-downloads. Be sure to install both the
- drivers and toolkit. For 64-bit machines, you should install the 64-bit driver,
- but download the 32-bit version of the toolkit since the OpenMM binary is
- 32-bit. OpenCL is included with the CUDA drivers.
+ drivers and toolkit. OpenCL is included with the CUDA drivers.
* If you have an AMD GPU, download the latest version of the Catalyst driver
from http://support.amd.com.
@@ -276,15 +268,13 @@ your PATH.
not set, it will assume plugins are in the default location (:file:`C:\\Program
Files\\OpenMM\\lib\\plugins` or :file:`C:\\Program Files (x86)\\OpenMM\\lib\\plugins`).
-7. Verify your installation by running the :file:`testInstallation.py` script found in
-the :file:`examples` folder of your OpenMM installation. To run it, open a command
-window, :command:`cd` to the :file:`examples` folder, and type
+7. Verify your installation by typing the following command:
::
- python testInstallation.py
+ python -m simtk.testInstallation
-This script confirms that OpenMM is installed, checks whether GPU acceleration
-is available (via that OpenCL and/or CUDA platforms), and verifies that all
+This command confirms that OpenMM is installed, checks whether GPU acceleration
+is available (via the OpenCL and/or CUDA platforms), and verifies that all
platforms produce consistent results.
.. _running-simulations:
@@ -370,7 +360,8 @@ molecular topology and atom positions. Your file need not be called
:file:`input.pdb`. Feel free to change this line to specify any file you want,
though it must contain all of the atoms needed by the force field.
(More information on how to add missing atoms and residues using OpenMM tools can be found in Chapter :ref:`model-building-and-editing`.)
-Make sure you include the single quotes around the file name.
+Make sure you include the single quotes around the file name. OpenMM also can load
+files in the newer PDBx/mmCIF format: just change :class:`PDBFile` to :class:`PDBxFile`.
::
forcefield = ForceField('amber99sb.xml', 'tip3p.xml')
@@ -581,7 +572,7 @@ with the name :file:`simulateGromacs.py`.
from sys import stdout
gro = GromacsGroFile('input.gro')
- top = GromacsTopFile('input.top', unitCellDimensions=gro.getUnitCellDimensions(),
+ top = GromacsTopFile('input.top', periodicBoxVectors=gro.getPeriodicBoxVectors(),
includeDir='/usr/local/gromacs/share/gromacs/top')
system = top.createSystem(nonbondedMethod=PME, nonbondedCutoff=1*nanometer,
constraints=HBonds)
@@ -602,10 +593,10 @@ This script is nearly identical to the previous one, just replacing
:class:`AmberInpcrdFile` and :class:`AmberPrmtopFile` with :class:`GromacsGroFile` and :class:`GromacsTopFile`.
Note that when we create the :class:`GromacsTopFile`, we specify values for two extra
options. First, we specify
-:code:`unitCellDimensions=gro.getUnitCellDimensions()`\ . Unlike OpenMM and
-AMBER, which can store periodic unit cell dimensions with the topology, Gromacs
-only stores them with the coordinates. To let :class:`GromacsTopFile` create a :class:`Topology`
-object, we therefore need to tell it the unit cell dimensions that were loaded
+:code:`periodicBoxVectors=gro.getPeriodicBoxVectors()`\ . Unlike OpenMM and
+AMBER, which can store periodic unit cell information with the topology, Gromacs
+only stores it with the coordinates. To let :class:`GromacsTopFile` create a :class:`Topology`
+object, we therefore need to tell it the periodic box vectors that were loaded
from the :file:`gro` file. You only need to do this if you are simulating a periodic
system. For implicit solvent simulations, it usually can be omitted.
@@ -809,8 +800,12 @@ you would type:
forcefield = ForceField('amber99sb.xml', 'amber99_obc.xml')
+Note that the GBSA-OBC parameters in these files are those used in TINKER.\ :cite:`Tinker`
+They are designed for use with Amber force fields, but they are different from
+the parameters found in the AMBER application.
+
If you are running a vacuum simulation, you do not need to specify a water
-model. The following line specifies the AMBER10 force field and no water model.
+model. The following line specifies the Amber10 force field and no water model.
If you try to use it with a PDB file that contains explicit water, it will
produce an error since no water parameters are defined:
::
@@ -1196,6 +1191,22 @@ change size.
system.addForce(MonteCarloAnisotropicBarostat((1, 1, 1)*bar, 300*kelvin,
False, True, False))
+There is a third barostat designed specifically for simulations of membranes.
+It assumes the membrane lies in the XY plane, and treats the X and Y axes of the
+box differently from the Z axis. It also applies a uniform surface tension in
+the plane of the membrane. The following line adds a membrane barostat that
+applies a pressure of 1 bar and a surface tension of 200 bar*nm. It specifies
+that the X and Y axes are treated isotropically while the Z axis is free to
+change independently.
+::
+
+ system.addForce(MonteCarloMembraneBarostat(1*bar, 200*bar*nanometer,
+ MonteCarloMembraneBarostat.XYIsotropic, MonteCarloMembraneBarostat.ZFree, 300*kelvin))
+
+See the API documentation for details about the allowed parameter values and
+their meanings.
+
+
Energy Minimization
===================
diff --git a/docs-source/usersguide/library.rst b/docs-source/usersguide/library.rst
index 6c99e4d78b7bff7b8716ee30b7acf3646e6f9508..cee61a4a3aa6809740c85ad320828bcad4157a0b 100644
--- a/docs-source/usersguide/library.rst
+++ b/docs-source/usersguide/library.rst
@@ -434,7 +434,7 @@ To download and unpack OpenMM source code:
Alternatively, if you want the most recent development version of the code rather
than the version corresponding to a particular release, you can get it from
-https://github.com/SimTk/openmm. Be aware that the development code is constantly
+https://github.com/pandegroup/openmm. Be aware that the development code is constantly
changing, may contain bugs, and should never be used for production work. If
you want a stable, well tested version of OpenMM, you should download the source
code for the latest release as described above.
diff --git a/docs-source/usersguide/references.bib b/docs-source/usersguide/references.bib
index e22b7286d582f15a7cf8c10a070d6b525240241b..81360064a10b5a39c5979dace2360b0f2d11adb6 100644
--- a/docs-source/usersguide/references.bib
+++ b/docs-source/usersguide/references.bib
@@ -1,441 +1,475 @@
-@article{Andersen1980
- author = {Andersen, Hans C.},
- title = {Molecular dynamics simulations at constant pressure and/or temperature},
- journal = {Journal of Chemical Physics},
- volume = {72},
- number = {4},
- pages = {2384-2393},
- year = {1980},
- type = {Journal Article}
-}
-
-@article{Aqvist2004
- author = {Åqvist, Johan and Wennerström, Petra and Nervall, Martin and Bjelic, Sinisa and Brandsdal, Bjørn O.},
- title = {Molecular dynamics simulations of water and biomolecules with a Monte Carlo constant pressure algorithm},
- journal = {Chemical Physics Letters},
- volume = {384},
- pages = {288-294},
- year = {2004},
- type = {Journal Article}
-}
-
-@article{Berendsen1987
- author = {Berendsen, H. J. C. and Grigera, J. R. and Straatsma, T. P.},
- title = {The missing term in effective pair potentials},
- journal = {Journal of Physical Chemistry},
- volume = {91},
- pages = {6269-6271},
- year = {1987},
- type = {Journal Article}
-}
-
-@article{Ceriotti2010
- author = {Ceriotti, M. and Parrinello, M. and Markland, Thomas E. and Manolopoulos, David E.},
- title = {Efficient stochastic thermostatting of path integral molecular dynamics},
- journal = {Journal of Chemical Physics},
- volume = {133},
- number = {12},
- year = {2010},
- type = {Journal Article}
-}
-
-@article{Chow1995
- author = {Chow, Kim-Hung and Ferguson, David M.},
- title = {Isothermal-isobaric molecular dynamics simulations with Monte Carlo volume sampling},
- journal = {Computer Physics Communications},
- volume = {91},
- pages = {283-289},
- year = {1995},
- type = {Journal Article}
-}
-
-@article{Craig2004
- author = {Craig, I. R. and Manolopoulos, David E.},
- title = {Quantum statistics and classical mechanics: Real time correlation functions from ring polymer molecular dynamics},
- journal = {Journal of Chemical Physics},
- volume = {121},
- pages = {3368-3373},
- year = {2004},
- type = {Journal Article}
-}
-
-@article{Duan2003
- author = {Duan, Y.; Wu, C. and Chowdhury, S. and Lee, M.C. and Xiong, G. and Zhang, W. and Yang, R. and Cieplak, P. and Luo, R. and Lee, T.},
- title = {A point-charge force field for molecular mechanics simulations of proteins based on condensed-phase quantum mechanical calculations},
- journal = {Journal of Computational Chemistry},
- volume = {24},
- pages = {1999-2012},
- year = {2003},
- type = {Journal Article}
-}
-
-@article{Essmann1995
- author = {Essmann, Ulrich and Perera, Lalith and Berkowitz, Max L. and Darden, Tom and Lee, Hsing and Pedersen, Lee G.},
- title = {A smooth particle mesh Ewald method},
- journal = {Journal of Chemical Physics},
- volume = {103},
- number = {19},
- pages = {8577-8593},
- year = {1995},
- type = {Journal Article}
-}
-
-@article{Hall1984
- author = {Hall, Randall W. and Berne, B. J.},
- title = {Nonergodicity in path integral molecular dynamics},
- journal = {Journal of Chemical Physics},
- volume = {81},
- number = {8},
- year = {1984},
- type = {Journal Article}
-}
-
-@article{Hawkins1995
- author = {Hawkins, Gregory D. and Cramer, Christopher J. and Truhlar, Donald G.},
- title = {Pairwise solute descreening of solute charges from a dielectric medium},
- journal = {Chemical Physics Letters},
- volume = {246},
- number = {1-2},
- pages = {122-129},
- year = {1995},
- type = {Journal Article}
-}
-
-@article{Horn2004
- author = {Horn, Hans W. and Swope, William C. and Pitera, Jed W. and Madura, Jeffry D. and Dick, Thomas J. and Hura, Greg L. and Head-Gordon, Teresa},
- title = {Development of an improved four-site water model for biomolecular simulations: TIP4P-Ew},
- journal = {Journal of Chemical Physics},
- volume = {120},
- pages = {9665-9678},
- year = {2004},
- type = {Journal Article}
-}
-
-@article{Hornak2006
- author = {Hornak, V. and Abel, R. and Okur, A. and Strockbine, B. and Roitberg, A. and Simmerling, C.},
- title = {Comparison of multiple Amber force fields and development of improved protein backbone parameters},
- journal = {Proteins},
- volume = {65},
- pages = {712-725},
- year = {2006},
- type = {Journal Article}
-}
-
-@article{Izaguirre2010
- author = {Izaguirre, Jesús A. and Sweet, Chris R. and Pande, Vijay S.},
- title = {Multiscale dynamics of macromolecules using Normal Mode Langevin},
- journal = {Pacific Symposium on Biocomputing},
- volume = {15},
- pages = {240-251},
- year = {2010},
- type = {Journal Article}
-}
-
-@article{Jorgensen1983
- author = {Jorgensen, William L. and Chandrasekhar, Jayaraman and Madura, Jeffry D. and Impey, Roger W. and Klein, Michael L.},
- title = {Comparison of simple potential functions for simulating liquid water},
- journal = {Journal of Chemical Physics},
- volume = {79},
- pages = {926-935},
- year = {1983},
- type = {Journal Article}
-}
-
-@inbook{Kollman1997
- author = {Kollman, P.A. and Dixon, R. and Cornell, W. and Fox, T. and Chipot, C. and Pohorille, A.},
- title = {Computer Simulation of Biomolecular Systems},
- editor = {Wilkinson, A. and Weiner, P. and van Gunsteren, Wilfred F.},
- publisher = {Elsevier},
- volume = {3},
- pages = {83-96},
- year = {1997},
- type = {Book Section}
-}
-
-@article{Labute2008
- author = {Labute, Paul},
- title = {The generalized Born/volume integral implicit solvent model: Estimation of the free energy of hydration using London dispersion instead of atomic surface area},
- journal = {Journal of Computational Chemistry},
- volume = {29},
- number = {10},
- pages = {1693-1698},
- year = {2008},
- type = {Journal Article}
-}
-
-@article{Lamoureux2006
- author = {Lamoureux, Guillaume and Harder, Edward and Vorobyov, Igor V. and Roux, Benoit and MacKerell Jr., Alexander D.},
- title = {A polarizable model of water for molecular dynamics simulations of biomolecules},
- journal = {Chemical Physics Letters},
- volume = {418},
- number = {1-3},
- pages = {245-249},
- year = {2006},
- type = {Journal Article}
-}
-
-@article{Lamoureux2003
- author = {Lamoureux, Guillaume and Roux, Benoit},
- title = {Modeling induced polarization with classical Drude oscillators: Theory and molecular dynamics simulation algorithm},
- journal = {Journal of Chemical Physics},
- volume = {119},
- number = {6},
- pages = {3025-3039},
- year = {2003},
- type = {Journal Article}
-}
-
-@article{Li2010
- author = {Li, D.W. and Br{\"u}schweiler, R.},
- title = {NMR-based protein potentials},
- journal = {Angewandte Chemie International Edition},
- volume = {49},
- pages = {6778-6780},
- year = {2010},
- type = {Journal Article}
-}
-
-@article{Lindorff-Larsen2010
- author = {Lindorff-Larsen, K. and Piana, S. and Palmo, K. and Maragakis, P. and Klepeis, J. and Dror, R.O. and Shaw, D.E.},
- title = {Improved side-chain torsion potentials for the Amber ff99SB protein force field},
- journal = {Proteins},
- volume = {78},
- pages = {1950-1958},
- year = {2010},
- type = {Journal Article}
-}
-
-@article{Liu1989
- author = {Liu, Dong C. and Nocedal, Jorge},
- title = {On the Limited Memory BFGS Method For Large Scale Optimization},
- journal = {Mathematical Programming},
- volume = {45},
- pages = {503-528},
- year = {1989},
- type = {Journal Article}
-}
-
-@article{Lopes2013,
- author = {Lopes, Pedro E. M. and Huang, Jing and Shim, Jihyun and Luo, Yun and Li, Hui and Roux, Benoît and MacKerell, Alexander D.},
- title = {Polarizable Force Field for Peptides and Proteins Based on the Classical Drude Oscillator},
- journal = {Journal of Chemical Theory and Computation},
- volume = {9},
- number = {12},
- pages = {5430-5449},
- year = {2013},
- type = {Journal Article}
-}
-
-@article{Mahoney2000
- author = {Mahoney, Michael W. and Jorgensen, William L.},
- title = {A five-site model for liquid water and the reproduction of the density anomaly by rigid, nonpolarizable potential functions},
- journal = {Journal of Chemical Physics},
- volume = {112},
- pages = {8910-8922},
- year = {2000},
- type = {Journal Article}
-}
-
-@article{Markland2008
- author = {Markland, Thomas E. and Manolopoulos, David E.},
- title = {An efficient ring polymer contraction scheme for imaginary time path integral simulations},
- journal = {Journal of Chemical Physics},
- volume = {129},
- number = {2},
- year = {2008},
- type = {Journal Article}
-}
-
-@article{Mongan2007
- author = {Mongan, John and Simmerling, Carlos and McCammon, J. Andrew and Case, David A. and Onufriev, Alexey},
- title = {Generalized Born model with a simple, robust molecular volume correction},
- journal = {Journal of Chemical Theory and Computation},
- volume = {3},
- number = {1},
- pages = {156-169},
- year = {2007},
- type = {Journal Article}
-}
-
-@article{Nguyen2013
- author = {Nguyen, Hai and Roe, Daniel R. and Simmerling, Carlos},
- title = {Improved Generalized Born Solvent Model Parameters for Protein Simulations},
- journal = {Journal of Chemical Theory and Computation},
- volume = {9},
- number = {4},
- pages = {2020-2034},
- year = {2013},
- type = {Journal Article}
-}
-
-@article{Onufriev2004
- author = {Onufriev, Alexey and Bashford, Donald and Case, David A.},
- title = {Exploring protein native states and large-scale conformational changes with a modified generalized born model},
- journal = {Proteins},
- volume = {55},
- number = {22},
- pages = {383-394},
- year = {2004},
- type = {Journal Article}
-}
-
-@article{Parrinello1984
- author = {Parrinello, M. and Rahman, A.},
- title = {Study of an F center in molten KCl},
- journal = {Journal of Chemical Physics},
- volume = {80},
- number = {2},
- pages = {860-867},
- year = {1984},
- type = {Journal Article}
-}
-
-@misc{Ponder
- author = {Ponder, Jay W.},
- title = {Personal communication},
- type = {Personal Communication}
-}
-
-@article{Ren2002
- author = {Ren, P. and Ponder, Jay W.},
- title = {A Consistent Treatment of Inter- and Intramolecular Polarization in Molecular Mechanics Calculations},
- journal = {Journal of Computational Chemistry},
- volume = {23},
- pages = {1497-1506},
- year = {2002},
- type = {Journal Article}
-}
-
-@article{Ren2003
- author = {Ren, P. and Ponder, Jay W.},
- title = {Polarizable Atomic Multipole Water Model for Molecular Mechanics Simulation},
- journal = {Journal of Physical Chemistry B},
- volume = {107},
- pages = {5933-5947},
- year = {2003},
- type = {Journal Article}
-}
-
-@article{Schaefer1998
- author = {Schaefer, Michael and Bartels, Christian and Karplus, Martin},
- title = {Solution conformations and thermodynamics of structured peptides: molecular dynamics simulation with an implicit solvation model},
- journal = {Journal of Molecular Biology},
- volume = {284},
- number = {3},
- pages = {835-848},
- year = {1998},
- type = {Journal Article}
-}
-
-@article{Schnieders2007
- author = {Schnieders, Michael J. and Ponder, Jay W.},
- title = {Polarizable Atomic Multipole Solutes in a Generalized Kirkwood Continuum},
- journal = {Journal of Chemical Theory and Computation},
- volume = {3},
- pages = {2083-2097},
- year = {2007},
- type = {Journal Article}
-}
-
-@article{Shirts2008
- author = {Shirts, Michael R. and Chodera, John D.},
- title = {Statistically optimal analysis of samples from multiple equilibrium states},
- journal = {Journal of Chemical Physics},
- volume = {129},
- pages = {124105},
- year = {2008},
- type = {Journal Article}
-}
-
-@article{Shi2013
- author = {Shi, Yue and Xia, Zhen and Zhang, Jiajing and Best, Robert and Wu, Chuanjie and Ponder, Jay W. and Ren, Pengyu},
- title = {Polarizable Atomic Multipole-Based AMOEBA Force Field for Proteins},
- journal = {Journal of Chemical Theory and Computation},
- volume = {9},
- number = {9},
- pages = {4046-4063},
- year = {2013},
- type = {Journal Article}
-}
-
-@article{Shirts2007
- author = {Shirts, Michael R. and Mobley, David L. and Chodera, John D. and Pande, Vijay S.},
- title = {Accurate and Efficient Corrections for Missing Dispersion Interactions in Molecular Simulations},
- journal = {Journal of Physical Chemistry B},
- volume = {111},
- pages = {13052-13063},
- year = {2007},
- type = {Journal Article}
-}
-
-@article{Shirts2005
- author = {Shirts, Michael R. and Pande, Vijay S.},
- title = {Solvation free energies of amino acid side chain analogs for common molecular mechanics water models},
- journal = {Journal of Chemical Physics},
- volume = {132},
- pages = {134508},
- year = {2005},
- type = {Journal Article}
-}
-
-@article{Srinivasan1999
- author = {Srinivasan, J and Trevathan, M. W. and Beroza, P. and Case, D. A.},
- title = {Application of a pairwise generalized {Born} model to proteins and nucleic acids: inclusion of salt effects},
- journal = {Theor. Chem. Acc.},
- volume = {101},
- pages = {426-434},
- year = {1999},
- type = {Journal Article}
-}
-
-@article{Thole1981
- author = {Thole, B. T.},
- title = {Molecular polarizabilities calculated with a modified dipole interaction},
- journal = {Chemical Physics},
- volume = {59},
- number = {3},
- pages = {341-350},
- year = {1981},
- type = {Journal Article}
-}
-
-@article{Tironi1995
- author = {Tironi, Ilario G. and Sperb, René and Smith, Paul E. and van Gunsteren, Wilfred F.},
- title = {A generalized reaction field method for molecular dynamics simulations},
- journal = {Journal of Chemical Physics},
- volume = {102},
- number = {13},
- pages = {5451-5459},
- year = {1995},
- type = {Journal Article}
-}
-
-@article{Toukmaji1996
- author = {Toukmaji, Abdulnour Y. and Board Jr, John A.},
- title = {Ewald summation techniques in perspective: a survey},
- journal = {Computer Physics Communications},
- volume = {95},
- pages = {73-92},
- year = {1996},
- type = {Journal Article}
-}
-
-@article{Wang2000
- author = {Wang, J. and Cieplak, P. and Kollman, P.A.},
- title = {How well does a restrained electrostatic potential (RESP) model perform in calculating conformational energies of organic and biological molecules?},
- journal = {Journal of Computational Chemistry},
- volume = {21},
- pages = {1049-1074},
- year = {2000},
- type = {Journal Article}
-}
-
-@article{Wang2014
- author = {Wang, Lee-Ping and Martinez, Todd J. and Pande, Vijay S.},
- title = {Building force fields: an automatic, systematic, and reproducible approach},
- journal = {Journal of Physical Chemistry Letters},
- volume = {5},
- pages = {1885-1891},
- year = {2014},
- type = {Journal Article}
-}
+@article{Andersen1980
+ author = {Andersen, Hans C.},
+ title = {Molecular dynamics simulations at constant pressure and/or temperature},
+ journal = {Journal of Chemical Physics},
+ volume = {72},
+ number = {4},
+ pages = {2384-2393},
+ year = {1980},
+ type = {Journal Article}
+}
+
+@article{Aqvist2004
+ author = {Åqvist, Johan and Wennerström, Petra and Nervall, Martin and Bjelic, Sinisa and Brandsdal, Bjørn O.},
+ title = {Molecular dynamics simulations of water and biomolecules with a {Monte Carlo} constant pressure algorithm},
+ journal = {Chemical Physics Letters},
+ volume = {384},
+ pages = {288-294},
+ year = {2004},
+ type = {Journal Article}
+}
+
+@article{Berendsen1987
+ author = {Berendsen, H. J. C. and Grigera, J. R. and Straatsma, T. P.},
+ title = {The missing term in effective pair potentials},
+ journal = {Journal of Physical Chemistry},
+ volume = {91},
+ pages = {6269-6271},
+ year = {1987},
+ type = {Journal Article}
+}
+
+@article{Ceriotti2010
+ author = {Ceriotti, M. and Parrinello, M. and Markland, Thomas E. and Manolopoulos, David E.},
+ title = {Efficient stochastic thermostatting of path integral molecular dynamics},
+ journal = {Journal of Chemical Physics},
+ volume = {133},
+ number = {12},
+ year = {2010},
+ type = {Journal Article}
+}
+
+@article{Chow1995
+ author = {Chow, Kim-Hung and Ferguson, David M.},
+ title = {Isothermal-isobaric molecular dynamics simulations with {Monte Carlo} volume sampling},
+ journal = {Computer Physics Communications},
+ volume = {91},
+ pages = {283-289},
+ year = {1995},
+ type = {Journal Article}
+}
+
+@article{Craig2004
+ author = {Craig, I. R. and Manolopoulos, David E.},
+ title = {Quantum statistics and classical mechanics: Real time correlation functions from ring polymer molecular dynamics},
+ journal = {Journal of Chemical Physics},
+ volume = {121},
+ pages = {3368-3373},
+ year = {2004},
+ type = {Journal Article}
+}
+
+@article{Duan2003
+ author = {Duan, Y.; Wu, C. and Chowdhury, S. and Lee, M.C. and Xiong, G. and Zhang, W. and Yang, R. and Cieplak, P. and Luo, R. and Lee, T.},
+ title = {A point-charge force field for molecular mechanics simulations of proteins based on condensed-phase quantum mechanical calculations},
+ journal = {Journal of Computational Chemistry},
+ volume = {24},
+ pages = {1999-2012},
+ year = {2003},
+ type = {Journal Article}
+}
+
+@article{Essmann1995
+ author = {Essmann, Ulrich and Perera, Lalith and Berkowitz, Max L. and Darden, Tom and Lee, Hsing and Pedersen, Lee G.},
+ title = {A smooth particle mesh {Ewald} method},
+ journal = {Journal of Chemical Physics},
+ volume = {103},
+ number = {19},
+ pages = {8577-8593},
+ year = {1995},
+ type = {Journal Article}
+}
+
+@article{Hall1984
+ author = {Hall, Randall W. and Berne, B. J.},
+ title = {Nonergodicity in path integral molecular dynamics},
+ journal = {Journal of Chemical Physics},
+ volume = {81},
+ number = {8},
+ year = {1984},
+ type = {Journal Article}
+}
+
+@article{Hawkins1995
+ author = {Hawkins, Gregory D. and Cramer, Christopher J. and Truhlar, Donald G.},
+ title = {Pairwise solute descreening of solute charges from a dielectric medium},
+ journal = {Chemical Physics Letters},
+ volume = {246},
+ number = {1-2},
+ pages = {122-129},
+ year = {1995},
+ type = {Journal Article}
+}
+
+@article{Horn2004
+ author = {Horn, Hans W. and Swope, William C. and Pitera, Jed W. and Madura, Jeffry D. and Dick, Thomas J. and Hura, Greg L. and Head-Gordon, Teresa},
+ title = {Development of an improved four-site water model for biomolecular simulations: {TIP4P-Ew}},
+ journal = {Journal of Chemical Physics},
+ volume = {120},
+ pages = {9665-9678},
+ year = {2004},
+ type = {Journal Article}
+}
+
+@article{Hornak2006
+ author = {Hornak, V. and Abel, R. and Okur, A. and Strockbine, B. and Roitberg, A. and Simmerling, C.},
+ title = {Comparison of multiple {Amber} force fields and development of improved protein backbone parameters},
+ journal = {Proteins},
+ volume = {65},
+ pages = {712-725},
+ year = {2006},
+ type = {Journal Article}
+}
+
+@article{Izaguirre2010
+ author = {Izaguirre, Jesús A. and Sweet, Chris R. and Pande, Vijay S.},
+ title = {Multiscale dynamics of macromolecules using {Normal Mode Langevin}},
+ journal = {Pacific Symposium on Biocomputing},
+ volume = {15},
+ pages = {240-251},
+ year = {2010},
+ type = {Journal Article}
+}
+
+@article{Jorgensen1983
+ author = {Jorgensen, William L. and Chandrasekhar, Jayaraman and Madura, Jeffry D. and Impey, Roger W. and Klein, Michael L.},
+ title = {Comparison of simple potential functions for simulating liquid water},
+ journal = {Journal of Chemical Physics},
+ volume = {79},
+ pages = {926-935},
+ year = {1983},
+ type = {Journal Article}
+}
+
+@inbook{Kollman1997
+ author = {Kollman, P.A. and Dixon, R. and Cornell, W. and Fox, T. and Chipot, C. and Pohorille, A.},
+ title = {Computer Simulation of Biomolecular Systems},
+ editor = {Wilkinson, A. and Weiner, P. and van Gunsteren, Wilfred F.},
+ publisher = {Elsevier},
+ volume = {3},
+ pages = {83-96},
+ year = {1997},
+ type = {Book Section}
+}
+
+@article{Labute2008
+ author = {Labute, Paul},
+ title = {The generalized {Born}/volume integral implicit solvent model: Estimation of the free energy of hydration using {London} dispersion instead of atomic surface area},
+ journal = {Journal of Computational Chemistry},
+ volume = {29},
+ number = {10},
+ pages = {1693-1698},
+ year = {2008},
+ type = {Journal Article}
+}
+
+@article{Lamoureux2006
+ author = {Lamoureux, Guillaume and Harder, Edward and Vorobyov, Igor V. and Roux, Benoit and MacKerell Jr., Alexander D.},
+ title = {A polarizable model of water for molecular dynamics simulations of biomolecules},
+ journal = {Chemical Physics Letters},
+ volume = {418},
+ number = {1-3},
+ pages = {245-249},
+ year = {2006},
+ type = {Journal Article}
+}
+
+@article{Lamoureux2003
+ author = {Lamoureux, Guillaume and Roux, Benoit},
+ title = {Modeling induced polarization with classical {Drude} oscillators: Theory and molecular dynamics simulation algorithm},
+ journal = {Journal of Chemical Physics},
+ volume = {119},
+ number = {6},
+ pages = {3025-3039},
+ year = {2003},
+ type = {Journal Article}
+}
+
+@article{Li2010
+ author = {Li, D.W. and Br{\"u}schweiler, R.},
+ title = {{NMR}-based protein potentials},
+ journal = {Angewandte Chemie International Edition},
+ volume = {49},
+ pages = {6778-6780},
+ year = {2010},
+ type = {Journal Article}
+}
+
+@article{Lindorff-Larsen2010
+ author = {Lindorff-Larsen, K. and Piana, S. and Palmo, K. and Maragakis, P. and Klepeis, J. and Dror, R.O. and Shaw, D.E.},
+ title = {Improved side-chain torsion potentials for the {Amber ff99SB} protein force field},
+ journal = {Proteins},
+ volume = {78},
+ pages = {1950-1958},
+ year = {2010},
+ type = {Journal Article}
+}
+
+@article{Liu1989
+ author = {Liu, Dong C. and Nocedal, Jorge},
+ title = {On the Limited Memory {BFGS} Method For Large Scale Optimization},
+ journal = {Mathematical Programming},
+ volume = {45},
+ pages = {503-528},
+ year = {1989},
+ type = {Journal Article}
+}
+
+@article{Lopes2013,
+ author = {Lopes, Pedro E. M. and Huang, Jing and Shim, Jihyun and Luo, Yun and Li, Hui and Roux, Benoît and MacKerell, Alexander D.},
+ title = {Polarizable Force Field for Peptides and Proteins Based on the Classical {Drude} Oscillator},
+ journal = {Journal of Chemical Theory and Computation},
+ volume = {9},
+ number = {12},
+ pages = {5430-5449},
+ year = {2013},
+ type = {Journal Article}
+}
+
+@article{Mahoney2000
+ author = {Mahoney, Michael W. and Jorgensen, William L.},
+ title = {A five-site model for liquid water and the reproduction of the density anomaly by rigid, nonpolarizable potential functions},
+ journal = {Journal of Chemical Physics},
+ volume = {112},
+ pages = {8910-8922},
+ year = {2000},
+ type = {Journal Article}
+}
+
+@article{Markland2008
+ author = {Markland, Thomas E. and Manolopoulos, David E.},
+ title = {An efficient ring polymer contraction scheme for imaginary time path integral simulations},
+ journal = {Journal of Chemical Physics},
+ volume = {129},
+ number = {2},
+ year = {2008},
+ type = {Journal Article}
+}
+
+@article{Mongan2007
+ author = {Mongan, John and Simmerling, Carlos and McCammon, J. Andrew and Case, David A. and Onufriev, Alexey},
+ title = {Generalized {Born} model with a simple, robust molecular volume correction},
+ journal = {Journal of Chemical Theory and Computation},
+ volume = {3},
+ number = {1},
+ pages = {156-169},
+ year = {2007},
+ type = {Journal Article}
+}
+
+@article{Nguyen2013
+ author = {Nguyen, Hai and Roe, Daniel R. and Simmerling, Carlos},
+ title = {Improved Generalized {Born} Solvent Model Parameters for Protein Simulations},
+ journal = {Journal of Chemical Theory and Computation},
+ volume = {9},
+ number = {4},
+ pages = {2020-2034},
+ year = {2013},
+ type = {Journal Article}
+}
+
+@article{Onufriev2004
+ author = {Onufriev, Alexey and Bashford, Donald and Case, David A.},
+ title = {Exploring protein native states and large-scale conformational changes with a modified generalized {Born} model},
+ journal = {Proteins},
+ volume = {55},
+ number = {22},
+ pages = {383-394},
+ year = {2004},
+ type = {Journal Article}
+}
+
+@article{Parrinello1984
+ author = {Parrinello, M. and Rahman, A.},
+ title = {Study of an {F} center in molten {KCl}},
+ journal = {Journal of Chemical Physics},
+ volume = {80},
+ number = {2},
+ pages = {860-867},
+ year = {1984},
+ type = {Journal Article}
+}
+
+@misc{Ponder
+ author = {Ponder, Jay W.},
+ title = {Personal communication},
+ type = {Personal Communication}
+}
+
+@article{Ren2002
+ author = {Ren, P. and Ponder, Jay W.},
+ title = {A Consistent Treatment of Inter- and Intramolecular Polarization in Molecular Mechanics Calculations},
+ journal = {Journal of Computational Chemistry},
+ volume = {23},
+ pages = {1497-1506},
+ year = {2002},
+ type = {Journal Article}
+}
+
+@article{Ren2003
+ author = {Ren, P. and Ponder, Jay W.},
+ title = {Polarizable Atomic Multipole Water Model for Molecular Mechanics Simulation},
+ journal = {Journal of Physical Chemistry B},
+ volume = {107},
+ pages = {5933-5947},
+ year = {2003},
+ type = {Journal Article}
+}
+
+@article{Schaefer1998
+ author = {Schaefer, Michael and Bartels, Christian and Karplus, Martin},
+ title = {Solution conformations and thermodynamics of structured peptides: molecular dynamics simulation with an implicit solvation model},
+ journal = {Journal of Molecular Biology},
+ volume = {284},
+ number = {3},
+ pages = {835-848},
+ year = {1998},
+ type = {Journal Article}
+}
+
+@article{Schnieders2007
+ author = {Schnieders, Michael J. and Ponder, Jay W.},
+ title = {Polarizable Atomic Multipole Solutes in a Generalized {Kirkwood} Continuum},
+ journal = {Journal of Chemical Theory and Computation},
+ volume = {3},
+ pages = {2083-2097},
+ year = {2007},
+ type = {Journal Article}
+}
+
+@article{Shirts2008
+ author = {Shirts, Michael R. and Chodera, John D.},
+ title = {Statistically optimal analysis of samples from multiple equilibrium states},
+ journal = {Journal of Chemical Physics},
+ volume = {129},
+ pages = {124105},
+ year = {2008},
+ type = {Journal Article}
+}
+
+@article{Shi2013
+ author = {Shi, Yue and Xia, Zhen and Zhang, Jiajing and Best, Robert and Wu, Chuanjie and Ponder, Jay W. and Ren, Pengyu},
+ title = {Polarizable Atomic Multipole-Based {AMOEBA} Force Field for Proteins},
+ journal = {Journal of Chemical Theory and Computation},
+ volume = {9},
+ number = {9},
+ pages = {4046-4063},
+ year = {2013},
+ type = {Journal Article}
+}
+
+@article{Shirts2007
+ author = {Shirts, Michael R. and Mobley, David L. and Chodera, John D. and Pande, Vijay S.},
+ title = {Accurate and Efficient Corrections for Missing Dispersion Interactions in Molecular Simulations},
+ journal = {Journal of Physical Chemistry B},
+ volume = {111},
+ pages = {13052-13063},
+ year = {2007},
+ type = {Journal Article}
+}
+
+@article{Shirts2005
+ author = {Shirts, Michael R. and Pande, Vijay S.},
+ title = {Solvation free energies of amino acid side chain analogs for common molecular mechanics water models},
+ journal = {Journal of Chemical Physics},
+ volume = {132},
+ pages = {134508},
+ year = {2005},
+ type = {Journal Article}
+}
+
+@article{Sindhikara2009,
+ author = {Sindhikara, Daniel J. and Kim, Seonah and Voter,
+ Arthur F. and Roitberg, Adrian E.},
+ title = {{Bad Seeds Sprout Perilous Dynamics: Stochastic
+ Thermostat Induced Trajectory Synchronization in
+ Biomolecules}},
+ journal = {Journal of Chemical Theory and Computation},
+ year = 2009,
+ volume = 5,
+ number = 6,
+ pages = {1624--1631},
+ month = {April},
+}
+
+@article{Srinivasan1999
+ author = {Srinivasan, J and Trevathan, M. W. and Beroza, P. and Case, D. A.},
+ title = {Application of a pairwise generalized {Born} model to proteins and nucleic acids: inclusion of salt effects},
+ journal = {Theor. Chem. Acc.},
+ volume = {101},
+ pages = {426-434},
+ year = {1999},
+ type = {Journal Article}
+}
+
+@article{Thole1981
+ author = {Thole, B. T.},
+ title = {Molecular polarizabilities calculated with a modified dipole interaction},
+ journal = {Chemical Physics},
+ volume = {59},
+ number = {3},
+ pages = {341-350},
+ year = {1981},
+ type = {Journal Article}
+}
+
+@misc{Tinker
+ author = {Ponder, Jay W.},
+ title = {{TINKER - Software Tools for Molecular Design, 4.2}},
+ year = {2004}
+}
+
+@article{Tironi1995
+ author = {Tironi, Ilario G. and Sperb, René and Smith, Paul E. and van Gunsteren, Wilfred F.},
+ title = {A generalized reaction field method for molecular dynamics simulations},
+ journal = {Journal of Chemical Physics},
+ volume = {102},
+ number = {13},
+ pages = {5451-5459},
+ year = {1995},
+ type = {Journal Article}
+}
+
+@article{Toukmaji1996
+ author = {Toukmaji, Abdulnour Y. and Board Jr, John A.},
+ title = {{Ewald} summation techniques in perspective: a survey},
+ journal = {Computer Physics Communications},
+ volume = {95},
+ pages = {73-92},
+ year = {1996},
+ type = {Journal Article}
+}
+
+@article{Uberuaga2004,
+ author = {Blas P. Uberuaga and Marian Anghel and Arthur
+ F. Voter},
+ title = {{Synchronization of trajectories in canonical
+ molecular-dynamics simulations: observation,
+ explanation, and exploitation}},
+ journal = {Journal of Chemical Physics},
+ year = 2004,
+ key = {synchronization, parallelization},
+ volume = 120,
+ number = 14,
+ pages = {6363--6374},
+}
+
+@article{Wang2000
+ author = {Wang, J. and Cieplak, P. and Kollman, P.A.},
+ title = {How well does a restrained electrostatic potential ({RESP}) model perform in calculating conformational energies of organic and biological molecules?},
+ journal = {Journal of Computational Chemistry},
+ volume = {21},
+ pages = {1049-1074},
+ year = {2000},
+ type = {Journal Article}
+}
+
+@article{Wang2014
+ author = {Wang, Lee-Ping and Martinez, Todd J. and Pande, Vijay S.},
+ title = {Building force fields: an automatic, systematic, and reproducible approach},
+ journal = {Journal of Physical Chemistry Letters},
+ volume = {5},
+ pages = {1885-1891},
+ year = {2014},
+ type = {Journal Article}
+}
diff --git a/docs-source/usersguide/theory.rst b/docs-source/usersguide/theory.rst
index dd51c1aeed3fb0b35c118d6cd4ab17202c9f8738..f3837df28ae24e13357fb292bd555113d483d8aa 100644
--- a/docs-source/usersguide/theory.rst
+++ b/docs-source/usersguide/theory.rst
@@ -489,12 +489,12 @@ The surface area term is given by\ :cite:`Schaefer1998`\ :cite:`Ponder`
.. math::
- E=4\pi \cdot 2\text{.}\text{26}\sum _{i}{\left({r}_{i}+{r}_{\mathit{solvent}}\right)}^{2}{\left(\frac{{r}_{i}}{{R}_{i}}\right)}^{6}
+ E=E_{SA} \cdot 4\pi \sum _{i}{\left({r}_{i}+{r}_{\mathit{solvent}}\right)}^{2}{\left(\frac{{r}_{i}}{{R}_{i}}\right)}^{6}
where :math:`r_i` is the atomic radius of particle *i*\ , :math:`r_i` is
-its Born radius, and :math:`r_\mathit{solvent}` is the solvent radius, which is taken
-to be 0.14 nm.
+its atomic radius, and :math:`r_\mathit{solvent}` is the solvent radius, which is taken
+to be 0.14 nm. The default value for the energy scale :math:`E_{SA}` is 2.25936 kJ/mol/nm\ :sup:`2`\ .
AndersenThermostat
@@ -534,18 +534,18 @@ of the periodic box to vary with time.\ :cite:`Chow1995`\ :cite:`Aqvist2004`
At regular intervals, it attempts a Monte Carlo step by scaling the box vectors
and the coordinates of each molecule’s center by a factor *s*\ . The scale
factor *s* is chosen to change the volume of the periodic box from *V*
-to *V*\ +\ :math:`\delta`\ *V*\ :
+to *V*\ +\ :math:`\Delta`\ *V*\ :
.. math::
- s={\left(\frac{V+\delta V}{V}\right)}^{1/3}
+ s={\left(\frac{V+\Delta V}{V}\right)}^{1/3}
The change in volume is chosen randomly as
.. math::
- \delta V=A\cdot r
+ \Delta V=A\cdot r
where *A* is a scale factor and *r* is a random number uniformly
@@ -554,7 +554,7 @@ weight function
.. math::
- \Delta W=\Delta E+P\delta V-Nk_{B}T \text{ln}\left(\frac{V+\delta V}{V}\right)
+ \Delta W=\Delta E+P\Delta V-Nk_{B}T \text{ln}\left(\frac{V+\Delta V}{V}\right)
where :math:`\Delta E` is the change in potential energy resulting from the step,
@@ -602,6 +602,39 @@ You can specify that the barostat should only be applied to certain axes of the
box, keeping the other axes fixed. This is useful, for example, when doing
constant surface area simulations of membranes.
+MonteCarloMembraneBarostat
+**************************
+
+MonteCarloMembraneBarostat is very similar to MonteCarloBarostat, but it is
+specialized for simulations of membranes. It assumes the membrane lies in the
+XY plane. In addition to applying a uniform pressure to regulate the volume of
+the periodic box, it also applies a uniform surface tension to regulate the
+cross sectional area of the periodic box in the XY plane. The weight function
+for deciding whether to accept a step is
+
+.. math::
+ \Delta W=\Delta E+P\Delta V-S\Delta A-Nk_{B}T \text{ln}\left(\frac{V+\Delta V}{V}\right)
+
+where *S* is the surface tension and :math:`\Delta`\ *A* is the change in cross
+sectional area. Notice that pressure and surface tension are defined with
+opposite senses: a larger pressure tends to make the box smaller, but a larger
+surface tension tends to make the box larger.
+
+MonteCarloMembraneBarostat offers some additional options to customize the
+behavior of the periodic box:
+
+* The X and Y axes can be either
+
+ * isotropic (they are always scaled by the same amount, so their ratio remains fixed)
+ * anisotropic (they can change size independently)
+
+* The Z axis can be either
+
+ * free (its size changes independently of the X and Y axes)
+ * fixed (its size does not change)
+ * inversely varying with the X and Y axes (so the total box volume does not
+ change)
+
CMMotionRemover
***************
@@ -1007,7 +1040,7 @@ The following operators are supported: + (add), - (subtract), * (multiply), /
The following standard functions are supported: sqrt, exp, log, sin, cos, sec,
csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, erf, erfc, min, max, abs,
-step, delta. step(x) = 0 if x < 0, 1 otherwise. delta(x) = 1 if x is 0, 0
+floor, ceil, step, delta. step(x) = 0 if x < 0, 1 otherwise. delta(x) = 1 if x is 0, 0
otherwise. Some custom forces allow additional functions to be defined from
tabulated values.
@@ -1228,6 +1261,61 @@ Other Features
##############
+Periodic Boundary Conditions
+****************************
+
+Many Force objects support periodic boundary conditions. They act as if space
+were tiled with infinitely repeating copies of the system, then compute the
+forces acting on a single copy based on the infinite periodic copies. In most
+(but not all) cases, they apply a cutoff so that each particle only interacts
+with a single copy of each other particle.
+
+OpenMM supports triclinic periodic boxes. This means the periodicity is defined
+by three vectors, :math:`\mathbf{a}`\ , :math:`\mathbf{b}`\ , and
+:math:`\mathbf{c}`\ . Given a particle position, the infinite periodic copies
+of that particle are generated by adding vectors of the form
+:math:`i \mathbf{a}+j \mathbf{b}+k \mathbf{c}`\ , where :math:`i`\ ,
+:math:`j`\ , and :math:`k` are arbitrary integers.
+
+The periodic box vectors must be chosen to satisfy certain requirements.
+Roughly speaking, :math:`\mathbf{a}`\ , :math:`\mathbf{b}`\ , and
+:math:`\mathbf{c}` need to "mostly" correspond to the x, y, and z axes. They
+must have the form
+
+.. math::
+ \mathbf{a} = (a_x, 0, 0)
+
+ \mathbf{b} = (b_x, b_y, 0)
+
+ \mathbf{c} = (c_x, c_y, c_z)
+
+It is always possible to put the box vectors into this form by rotating the
+system until :math:`\mathbf{a}` is parallel to x and :math:`\mathbf{b}` lies in
+the xy plane.
+
+Furthermore, they must obey the following constraints:
+
+.. math::
+ a_x > 0, b_y > 0, c_z > 0
+
+ a_x \ge 2 |b_x|
+
+ a_x \ge 2 |c_x|
+
+ b_y \ge 2 |c_y|
+
+This effectively requires the box vectors to be specified in a particular
+reduced form. By forming combinations of box vectors (a process known as
+"lattice reduction"), it is always possible to put them in this form without
+changing the periodic system they represent.
+
+These requirements have an important consequence: the periodic unit cell can
+always be treated as an axis-aligned rectangular box of size
+:math:`(a_x, b_y, c_z)`\ . The remaining non-zero elements of the box vectors
+cause the repeating copies of the system to be staggered relative to each other,
+but they do not affect the shape or size of each copy. The volume of the unit
+cell is simply given by :math:`a_x b_y c_z`\ .
+
LocalEnergyMinimizer
********************
@@ -1346,3 +1434,67 @@ specific types of rules. They are:
.. math::
\mathbf{r}=\mathbf{o}+p_1\mathbf{\hat{x}}+p_2\mathbf{\hat{y}}+p_3\mathbf{\hat{z}}
..
+
+Random Numbers with Stochastic Integrators and Forces
+*****************************************************
+
+OpenMM includes many stochastic integrators and forces that make extensive use
+of random numbers. It is impossible to generate truly random numbers on a
+computer like you would with a dice roll or coin flip in real life---instead
+programs rely on pseudo-random number generators (PRNGs) that take some sort of
+initial "seed" value and steps through a sequence of seemingly random numbers.
+
+The exact implementation of the PRNGs is not important (in fact, each platform
+may have its own PRNG whose performance is optimized for that hardware). What
+*is* important, however, is that the PRNG must generate a uniform distribution
+of random numbers between 0 and 1. Random numbers drawn from this distribution
+can be manipulated to yield random integers in a desired range or even a random
+number from a different type of probability distribution function (e.g., a
+normal distribution).
+
+What this means is that the random numbers used by integrators and forces within
+OpenMM cannot have any discernible pattern to them. Patterns can be induced in
+PRNGs in two principal ways:
+
+1. The PRNG uses a bad algorithm with a short period.
+2. Two PRNGs are started using the same seed
+
+All PRNG algorithms in common use are periodic---that is their sequence of
+random numbers repeats after a given *period*, defined by the number of "unique"
+random numbers in the repeating pattern. As long as this period is longer than
+the total number of random numbers your application requires (preferably by
+orders of magnitude), the first problem described above is avoided. All PRNGs
+employed by OpenMM have periods far longer than any current simulation can cycle
+through.
+
+Point two is far more common in biomolecular simulation, and can result in very
+strange artifacts that may be difficult to detect. For example, with Langevin
+dynamics, two simulations that use the same sequence of random numbers appear to
+synchronize in their global movements.\ :cite:`Uberuaga2004`\
+:cite:`Sindhikara2009` It is therefore very important that the stochastic forces
+and integrators in OpenMM generate unique sequences of pseudo-random numbers not
+only within a single simulation, but between two different simulations of the
+same system as well (including any restarts of previous simulations).
+
+Every stochastic force and integrator that does (or could) make use of random
+numbers has two instance methods attached to it: :meth:`getRandomNumberSeed()`
+and :meth:`setRandomNumberSeed(int seed)`. If you set a unique random seed for
+two different simulations (or different forces/integrators if applicable),
+OpenMM guarantees that the generated sequences of random numbers will be
+different (by contrast, no guarantee is made that the same seed will result in
+identical random number sequences).
+
+Since breaking simulations up into pieces and/or running multiple replicates of
+a system to obtain more complete statistics is common practice, a new strategy
+has been employed for OpenMM versions 6.3 and later with the aim of trying to
+ensure that each simulation will be started with a unique random seed. A random
+seed value of 0 (the default) will cause a unique random seed to be generated
+when a new :class:`Context` is instantiated.
+
+Prior to the introduction of this feature, deserializing a serialized
+:class:`System` XML file would result in each stochastic force or integrator
+being assigned the same random seed as the original instance that was
+serialized. If you use a :class:`System` XML file generated by a version of
+OpenMM older than 6.3 to start a new simulation, you should manually set the
+random number seed of each stochastic force or integrator to 0 (or another
+unique value).
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index f1c0d937be87dde78a390867c5a304ad0b68f32e..0bdef126a59a877049a034d79996b078f200fae6 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -93,7 +93,7 @@ FOREACH(EX_ROOT ${F_EXAMPLES})
INSTALL(FILES ${EX_ROOT}.f90 DESTINATION examples)
ENDFOREACH(EX_ROOT ${F_EXAMPLES})
-INSTALL(FILES simulateAmber.py simulatePdb.py simulateGromacs.py testInstallation.py argon-chemical-potential.py input.inpcrd input.prmtop input.pdb input.gro input.top
+INSTALL(FILES simulateAmber.py simulatePdb.py simulateGromacs.py benchmark.py argon-chemical-potential.py input.inpcrd input.prmtop input.pdb input.gro input.top 5dfr_minimized.pdb 5dfr_solv-cube_equil.pdb
DESTINATION examples)
INSTALL(FILES VisualStudio/HelloArgon.vcproj
diff --git a/examples/benchmark.py b/examples/benchmark.py
index 650f3848dc3ac7fe1c89a9d0962c636b869aba6a..629162509d864de7b1afab84fb16b83e8d4a9a5b 100644
--- a/examples/benchmark.py
+++ b/examples/benchmark.py
@@ -6,9 +6,9 @@ import sys
from datetime import datetime
from optparse import OptionParser
-def timeIntegration(context, steps):
+def timeIntegration(context, steps, initialSteps):
"""Integrate a Context for a specified number of steps, then return how many seconds it took."""
- context.getIntegrator().step(5) # Make sure everything is fully initialized
+ context.getIntegrator().step(initialSteps) # Make sure everything is fully initialized
context.getState(getEnergy=True)
start = datetime.now()
context.getIntegrator().step(steps)
@@ -79,11 +79,14 @@ def runOneTest(testName, options):
system = ff.createSystem(pdb.topology, nonbondedMethod=method, nonbondedCutoff=cutoff, constraints=constraints, hydrogenMass=hydrogenMass)
print('Step Size: %g fs' % dt.value_in_unit(unit.femtoseconds))
properties = {}
+ initialSteps = 5
if options.device is not None:
if platform.getName() == 'CUDA':
properties['CudaDeviceIndex'] = options.device
elif platform.getName() == 'OpenCL':
properties['OpenCLDeviceIndex'] = options.device
+ if ',' in options.device or ' ' in options.device:
+ initialSteps = 250
if options.precision is not None:
if platform.getName() == 'CUDA':
properties['CudaPrecision'] = options.precision
@@ -102,7 +105,7 @@ def runOneTest(testName, options):
context.setVelocitiesToTemperature(300*unit.kelvin)
steps = 20
while True:
- time = timeIntegration(context, steps)
+ time = timeIntegration(context, steps, initialSteps)
if time >= 0.5*options.seconds:
break
if time < 0.5:
diff --git a/examples/simulateGromacs.py b/examples/simulateGromacs.py
index 65bd4e3405fbf6594841982f9fb420b2c3ec63e1..e0513a0436f152418f24595a844e6cb001217c83 100644
--- a/examples/simulateGromacs.py
+++ b/examples/simulateGromacs.py
@@ -4,7 +4,7 @@ from simtk.unit import *
from sys import stdout
gro = GromacsGroFile('input.gro')
-top = GromacsTopFile('input.top', unitCellDimensions=gro.getUnitCellDimensions(), includeDir='/usr/local/gromacs/share/gromacs/top')
+top = GromacsTopFile('input.top', periodicBoxVectors=gro.getPeriodicBoxVectors(), includeDir='/usr/local/gromacs/share/gromacs/top')
system = top.createSystem(nonbondedMethod=PME, nonbondedCutoff=1*nanometer, constraints=HBonds)
integrator = LangevinIntegrator(300*kelvin, 1/picosecond, 0.002*picoseconds)
simulation = Simulation(top.topology, system, integrator)
diff --git a/examples/testInstallation.py b/examples/testInstallation.py
deleted file mode 100644
index d5a48913338d52a54a696c97a8d78b4959e07823..0000000000000000000000000000000000000000
--- a/examples/testInstallation.py
+++ /dev/null
@@ -1,56 +0,0 @@
-from __future__ import print_function
-# First make sure OpenMM is installed.
-
-
-import sys
-try:
- from simtk.openmm.app import *
- from simtk.openmm import *
- from simtk.unit import *
-except ImportError as err:
- print("Failed to import OpenMM packages:", err.message)
- print("Make sure OpenMM is installed and the library path is set correctly.")
- sys.exit()
-
-# Create a System for the tests.
-
-pdb = PDBFile('input.pdb')
-forcefield = ForceField('amber99sb.xml', 'tip3p.xml')
-system = forcefield.createSystem(pdb.topology, nonbondedMethod=PME, nonbondedCutoff=1*nanometer, constraints=HBonds)
-
-# List all installed platforms and compute forces with each one.
-
-numPlatforms = Platform.getNumPlatforms()
-print("There are", numPlatforms, "Platforms available:")
-print()
-forces = [None]*numPlatforms
-for i in range(numPlatforms):
- platform = Platform.getPlatform(i)
- print(i+1, platform.getName(), end=" ")
- integrator = LangevinIntegrator(300*kelvin, 1/picosecond, 0.002*picoseconds)
- try:
- simulation = Simulation(pdb.topology, system, integrator, platform)
- simulation.context.setPositions(pdb.positions)
- forces[i] = simulation.context.getState(getForces=True).getForces()
- del simulation
- print("- Successfully computed forces")
- except:
- print("- Error computing forces with", platform.getName(), "platform")
-
-# See how well the platforms agree.
-
-if numPlatforms > 1:
- print()
- print("Median difference in forces between platforms:")
- print()
- for i in range(numPlatforms):
- for j in range(i):
- if forces[i] is not None and forces[j] is not None:
- errors = []
- for f1, f2 in zip(forces[i], forces[j]):
- d = f1-f2
- error = sqrt((d[0]*d[0]+d[1]*d[1]+d[2]*d[2])/(f1[0]*f1[0]+f1[1]*f1[1]+f1[2]*f1[2]))
- errors.append(error)
- print("{} vs. {}: {:g}".format(Platform.getPlatform(j).getName(),
- Platform.getPlatform(i).getName(),
- sorted(errors)[len(errors)//2]))
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000000000000000000000000000000000000..bbdb1875483350410804ab96e604b89856b53381
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+cd $(dirname $0)
+
+# Ask the user for the install location and Python executable.
+
+defaultInstallDir=/usr/local/openmm
+printf "Enter install location (default=${defaultInstallDir}): "
+read installDir
+if [ -z ${installDir} ]
+then
+ installDir=${defaultInstallDir}
+fi
+defaultPythonBin=$(which python)
+printf "Enter path to Python executable"
+if [ ${defaultPythonBin} ]
+then
+ printf " (default=${defaultPythonBin})"
+fi
+printf ": "
+read pythonBin
+if [ -z ${pythonBin} ]
+then
+ pythonBin=${defaultPythonBin}
+fi
+
+# Make sure it's a supported Python version.
+
+pythonOk=$(${pythonBin} -c "import sys; v=sys.version_info; print((v[0]==2 and v[1]>5) or v[0]>2)")
+if [ ${pythonOk} != "True" ]
+then
+ echo "Unsupported Python version. Only versions 2.6 and higher are supported."
+ exit
+fi
+
+# Copy the files into place.
+
+cp -R docs ${installDir}
+cp -R include ${installDir}
+cp -R lib ${installDir}
+cp -R licenses ${installDir}
+
+# Run the Python installer.
+
+cd python
+export OPENMM_INCLUDE_PATH=${installDir}/include
+export OPENMM_LIB_PATH=${installDir}/lib
+printenv
+if ${pythonBin} setup.py build && ${pythonBin} setup.py install $@
+then
+ # Print instructions to the user.
+
+ echo
+ echo "Installation is complete. You should now test your installation to make sure"
+ echo "it is working correctly by typing the following command:"
+ echo
+ echo "python -m simtk.testInstallation"
+else
+ echo
+ echo "INSTALLATION FAILED"
+ echo
+ echo "An error prevented the installation from completing. See above for details."
+fi
diff --git a/libraries/asmjit/LICENSE.md b/libraries/asmjit/LICENSE.md
new file mode 100644
index 0000000000000000000000000000000000000000..7742e92fff72593b8f75d72b2a896114f9ffa493
--- /dev/null
+++ b/libraries/asmjit/LICENSE.md
@@ -0,0 +1,18 @@
+AsmJit - Complete x86/x64 JIT and Remote Assembler for C++
+Copyright (c) 2008-2014, Petr Kobalicek
+
+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.
diff --git a/libraries/asmjit/apibegin.h b/libraries/asmjit/apibegin.h
new file mode 100644
index 0000000000000000000000000000000000000000..07ff85385f604357b86d1b776f776c5d67c35397
--- /dev/null
+++ b/libraries/asmjit/apibegin.h
@@ -0,0 +1,84 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Dependencies - AsmJit]
+#if !defined(_ASMJIT_BUILD_H)
+#include "build.h"
+#endif // !_ASMJIT_BUILD_H
+
+// [Guard]
+#if !defined(ASMJIT_API_SCOPE)
+# define ASMJIT_API_SCOPE
+#else
+# error "AsmJit - Api-Scope is already active, previous scope not closed by apiend.h?"
+#endif // ASMJIT_API_SCOPE
+
+// ============================================================================
+// [Override]
+// ============================================================================
+
+#if !defined(ASMJIT_CC_HAS_OVERRIDE) && !defined(override)
+# define override
+# define ASMJIT_UNDEF_OVERRIDE
+#endif // !ASMJIT_CC_HAS_OVERRIDE && !override
+
+// ============================================================================
+// [NoExcept]
+// ============================================================================
+
+#if !defined(ASMJIT_CC_HAS_NOEXCEPT) && !defined(noexcept)
+# define noexcept ASMJIT_NOEXCEPT
+# define ASMJIT_UNDEF_NOEXCEPT
+#endif // !ASMJIT_CC_HAS_NOEXCEPT && !noexcept
+
+// ============================================================================
+// [MSC]
+// ============================================================================
+
+#if defined(_MSC_VER)
+// Disable some warnings we know about
+# pragma warning(push)
+# pragma warning(disable: 4127) // conditional expression is constant
+# pragma warning(disable: 4201) // nameless struct/union
+# pragma warning(disable: 4244) // '+=' : conversion from 'int' to 'x', possible
+ // loss of data
+# pragma warning(disable: 4251) // struct needs to have dll-interface to be used
+ // by clients of struct ...
+# pragma warning(disable: 4275) // non dll-interface struct ... used as base for
+ // dll-interface struct
+# pragma warning(disable: 4355) // this used in base member initializer list
+# pragma warning(disable: 4480) // specifying underlying type for enum
+# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false'
+
+// Rename symbols.
+# if !defined(vsnprintf)
+# define ASMJIT_UNDEF_VSNPRINTF
+# define vsnprintf _vsnprintf
+# endif // !vsnprintf
+# if !defined(snprintf)
+# define ASMJIT_UNDEF_SNPRINTF
+# define snprintf _snprintf
+# endif // !snprintf
+#endif // _MSC_VER
+
+// ============================================================================
+// [CLang]
+// ============================================================================
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wunnamed-type-template-args"
+#endif // __clang__
+
+// ============================================================================
+// [GCC]
+// ============================================================================
+
+#if defined(__GNUC__) && !defined(__clang__)
+# if __GNUC__ >= 4 && !defined(__MINGW32__)
+# pragma GCC visibility push(hidden)
+# endif // GCC 4+
+#endif // __GNUC__
diff --git a/libraries/asmjit/apiend.h b/libraries/asmjit/apiend.h
new file mode 100644
index 0000000000000000000000000000000000000000..8341594d4070fbdf29869aa11a158943e8bd2572
--- /dev/null
+++ b/libraries/asmjit/apiend.h
@@ -0,0 +1,67 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Guard]
+#if defined(ASMJIT_API_SCOPE)
+# undef ASMJIT_API_SCOPE
+#else
+# error "AsmJit - Api-Scope not active, forgot to include apibegin.h?"
+#endif // ASMJIT_API_SCOPE
+
+// ============================================================================
+// [Override]
+// ============================================================================
+
+#if defined(ASMJIT_UNDEF_OVERRIDE)
+# undef override
+# undef ASMJIT_UNDEF_OVERRIDE
+#endif // ASMJIT_UNDEF_OVERRIDE
+
+// ============================================================================
+// [NoExcept]
+// ============================================================================
+
+#if defined(ASMJIT_UNDEF_NOEXCEPT)
+# undef noexcept
+# undef ASMJIT_UNDEF_NOEXCEPT
+#endif // ASMJIT_UNDEF_NOEXCEPT
+
+// ============================================================================
+// [MSC]
+// ============================================================================
+
+#if defined(_MSC_VER)
+# pragma warning(pop)
+
+# if defined(ASMJIT_UNDEF_VSNPRINTF)
+# undef vsnprintf
+# undef ASMJIT_UNDEF_VSNPRINTF
+# endif // ASMJIT_UNDEF_VSNPRINTF
+
+# if defined(ASMJIT_UNDEF_SNPRINTF)
+# undef snprintf
+# undef ASMJIT_UNDEF_SNPRINTF
+# endif // ASMJIT_UNDEF_SNPRINTF
+
+#endif // _MSC_VER
+
+// ============================================================================
+// [CLang]
+// ============================================================================
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif // __clang__
+
+// ============================================================================
+// [GCC]
+// ============================================================================
+
+#if defined(__GNUC__) && !defined(__clang__)
+# if __GNUC__ >= 4 && !defined(__MINGW32__)
+# pragma GCC visibility pop
+# endif // GCC 4+
+#endif // __GNUC__
diff --git a/libraries/asmjit/asmjit.h b/libraries/asmjit/asmjit.h
new file mode 100644
index 0000000000000000000000000000000000000000..9b143d44dde956349fdb3ee6650f7b429eb15f07
--- /dev/null
+++ b/libraries/asmjit/asmjit.h
@@ -0,0 +1,379 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Guard]
+#ifndef _ASMJIT_ASMJIT_H
+#define _ASMJIT_ASMJIT_H
+
+// ============================================================================
+// [asmjit_mainpage]
+// ============================================================================
+
+//! @mainpage
+//!
+//! AsmJit - Complete x86/x64 JIT and Remote Assembler for C++.
+//!
+//! AsmJit is a complete JIT and remote assembler for C++ language. It can
+//! generate native code for x86 and x64 architectures having support for
+//! a full instruction set, from legacy MMX to the newest AVX2. It has a
+//! type-safe API that allows C++ compiler to do a semantic checks at
+//! compile-time even before the assembled code is generated or run.
+//!
+//! AsmJit is not a virtual machine (VM). It doesn't have functionality to
+//! implement VM out of the box; however, it can be be used as a JIT backend
+//! for your own VM. The usage of AsmJit is not limited at all; it's suitable
+//! for multimedia, VM backends or remote code generation.
+//!
+//! @section AsmJit_Concepts Code Generation Concepts
+//!
+//! AsmJit has two completely different code generation concepts. The difference
+//! is in how the code is generated. The first concept, also referred as the low
+//! level concept, is called 'Assembler' and it's the same as writing RAW
+//! assembly by using physical registers directly. In this case AsmJit does only
+//! instruction encoding, verification and relocation.
+//!
+//! The second concept, also referred as the high level concept, is called
+//! 'Compiler'. Compiler lets you use virtually unlimited number of registers
+//! (called variables) significantly simplifying the code generation process.
+//! Compiler allocates these virtual registers to physical registers after the
+//! code generation is done. This requires some extra effort - Compiler has to
+//! generate information for each node (instruction, function declaration,
+//! function call) in the code, perform a variable liveness analysis and
+//! translate the code having variables into code having only registers.
+//!
+//! In addition, Compiler understands functions and function calling conventions.
+//! It has been designed in a way that the code generated is always a function
+//! having prototype like in a programming language. By having a function
+//! prototype the Compiler is able to insert prolog and epilog to a function
+//! being generated and it is able to call a function inside a generated one.
+//!
+//! There is no conclusion on which concept is better. Assembler brings full
+//! control on how the code is generated, while Compiler makes the generation
+//! more portable.
+//!
+//! @section AsmJit_Main_CodeGeneration Code Generation
+//!
+//! - \ref asmjit_base_general "Assembler core" - Operands, intrinsics and low-level assembler.
+//! - \ref asmjit_compiler "Compiler" - High level code generation.
+//! - \ref asmjit_cpuinfo "Cpu Information" - Get information about host processor.
+//! - \ref asmjit_logging "Logging" - Logging and error handling.
+//! - \ref AsmJit_MemoryManagement "Memory Management" - Virtual memory management.
+//!
+//! @section AsmJit_Main_HomePage AsmJit Homepage
+//!
+//! - https://github.com/kobalicek/asmjit
+
+// ============================================================================
+// [asmjit_base]
+// ============================================================================
+
+//! \defgroup asmjit_base AsmJit
+//!
+//! \brief AsmJit.
+
+// ============================================================================
+// [asmjit_base_general]
+// ============================================================================
+
+//! \defgroup asmjit_base_general AsmJit General API
+//! \ingroup asmjit_base
+//!
+//! \brief AsmJit general API.
+//!
+//! Contains all `asmjit` classes and helper functions that are architecture
+//! independent or abstract. Abstract classes are implemented by the backend,
+//! for example `Assembler` is implemented by `X86Assembler`.
+//!
+//! - See `Assembler` for low level code generation documentation.
+//! - See `Compiler` for high level code generation documentation.
+//! - See `Operand` for operand's overview.
+//!
+//! Logging and Error Handling
+//! --------------------------
+//!
+//! AsmJit contains robust interface that can be used to log the generated code
+//! and to handle possible errors. Base logging interface is defined in `Logger`
+//! class that is abstract and can be overridden. AsmJit contains two loggers
+//! that can be used out of the box - `FileLogger` that logs into a pure C
+//! `FILE*` stream and `StringLogger` that just concatenates all log messages
+//! by using a `StringBuilder` class.
+//!
+//! The following snippet shows how to setup a logger that logs to `stderr`:
+//!
+//! ~~~
+//! // `FileLogger` instance.
+//! FileLogger logger(stderr);
+//!
+//! // `Compiler` or any other `CodeGen` interface.
+//! host::Compiler c;
+//!
+//! // use `setLogger` to replace the `CodeGen` logger.
+//! c.setLogger(&logger);
+//! ~~~
+//!
+//! \sa \ref Logger, \ref FileLogger, \ref StringLogger.
+
+// ============================================================================
+// [asmjit_base_compiler]
+// ============================================================================
+
+//! \defgroup asmjit_base_compiler AsmJit Compiler
+//! \ingroup asmjit_base
+//!
+//! \brief AsmJit code-tree used by Compiler.
+//!
+//! AsmJit intermediate code-tree is a double-linked list that is made of nodes
+//! that represent assembler instructions, directives, labels and high-level
+//! constructs compiler is using to represent functions and function calls. The
+//! node list can only be used together with \ref Compiler.
+//!
+//! TODO
+
+// ============================================================================
+// [asmjit_base_util]
+// ============================================================================
+
+//! \defgroup asmjit_base_util AsmJit Utilities
+//! \ingroup asmjit_base
+//!
+//! \brief AsmJit utility classes.
+//!
+//! AsmJit contains numerous utility classes that are needed by the library
+//! itself. The most useful ones have been made public and are now exported.
+//!
+//! POD Containers
+//! --------------
+//!
+//! POD containers are used by AsmJit to manage its own data structures. The
+//! following classes can be used by AsmJit consumers:
+//!
+//! - \ref PodVector - Simple growing array-like container for POD data.
+//! - \ref StringBuilder - Simple string builder that can append string
+//! and integers.
+//!
+//! Zone Memory Allocator
+//! ---------------------
+//!
+//! Zone memory allocator is an incremental memory allocator that can be used
+//! to allocate data of short life-time. It has much better performance
+//! characteristics than all other allocators, because the only thing it can do
+//! is to increment a pointer and return its previous address. See \ref Zone
+//! for more details.
+//!
+//! CPU Ticks
+//! ---------
+//!
+//! CPU Ticks is a simple helper that can be used to do basic benchmarks. See
+//! \ref CpuTicks class for more details.
+//!
+//! Integer Utilities
+//! -----------------
+//!
+//! Integer utilities are all implemented by a static class \ref IntUtil.
+//! There are utilities for bit manipulation and bit counting, utilities to get
+//! an integer minimum / maximum and various other helpers required to perform
+//! alignment checks and binary casting from float to integer and vica versa.
+//!
+//! Vector Utilities
+//! ----------------
+//!
+//! SIMD code generation often requires to embed constants after each function
+//! or a block of functions generated. AsmJit contains classes `Vec64`,
+//! `Vec128` and `Vec256` that can be used to prepare data useful when
+//! generating SIMD code.
+//!
+//! X86/X64 code generator contains member functions `dmm`, `dxmm` and `dymm`
+//! which can be used to embed 64-bit, 128-bit and 256-bit data structures into
+//! machine code (both assembler and compiler are supported).
+//!
+//! \note Compiler contains a constant pool, which should be used instead of
+//! embedding constants manually after the function body.
+
+// ============================================================================
+// [asmjit_x86]
+// ============================================================================
+
+//! \defgroup asmjit_x86 X86/X64
+//!
+//! \brief X86/X64 module
+
+// ============================================================================
+// [asmjit_x86_general]
+// ============================================================================
+
+//! \defgroup asmjit_x86_general X86/X64 General API
+//! \ingroup asmjit_x86
+//!
+//! \brief X86/X64 general API.
+//!
+//! X86/X64 Registers
+//! -----------------
+//!
+//! There are static objects that represents X86 and X64 registers. They can
+//! be used directly (like `eax`, `mm`, `xmm`, ...) or created through
+//! these functions:
+//!
+//! - `asmjit::gpb_lo()` - Get Gpb-lo register.
+//! - `asmjit::gpb_hi()` - Get Gpb-hi register.
+//! - `asmjit::gpw()` - Get Gpw register.
+//! - `asmjit::gpd()` - Get Gpd register.
+//! - `asmjit::gpq()` - Get Gpq Gp register.
+//! - `asmjit::gpz()` - Get Gpd/Gpq register.
+//! - `asmjit::fp()` - Get Fp register.
+//! - `asmjit::mm()` - Get Mm register.
+//! - `asmjit::xmm()` - Get Xmm register.
+//! - `asmjit::ymm()` - Get Ymm register.
+//!
+//! X86/X64 Addressing
+//! ------------------
+//!
+//! X86 and x64 architectures contains several addressing modes and most ones
+//! are possible with AsmJit library. Memory represents are represented by
+//! `BaseMem` class. These functions are used to make operands that represents
+//! memory addresses:
+//!
+//! - `asmjit::ptr()` - Address size not specified.
+//! - `asmjit::byte_ptr()` - 1 byte.
+//! - `asmjit::word_ptr()` - 2 bytes (Gpw size).
+//! - `asmjit::dword_ptr()` - 4 bytes (Gpd size).
+//! - `asmjit::qword_ptr()` - 8 bytes (Gpq/Mm size).
+//! - `asmjit::tword_ptr()` - 10 bytes (FPU).
+//! - `asmjit::oword_ptr()` - 16 bytes (Xmm size).
+//! - `asmjit::yword_ptr()` - 32 bytes (Ymm size).
+//! - `asmjit::zword_ptr()` - 64 bytes (Zmm size).
+//!
+//! Most useful function to make pointer should be `asmjit::ptr()`. It creates
+//! pointer to the target with unspecified size. Unspecified size works in all
+//! intrinsics where are used registers (this means that size is specified by
+//! register operand or by instruction itself). For example `asmjit::ptr()`
+//! can't be used with `Assembler::inc()` instruction. In this case size must
+//! be specified and it's also reason to make difference between pointer sizes.
+//!
+//! Supported are simple address forms `[base + displacement]` and complex
+//! address forms `[base + index * scale + displacement]`.
+//!
+//! X86/X64 Immediates
+//! ------------------
+//!
+//! Immediate values are constants thats passed directly after instruction
+//! opcode. To create such value use `imm()` or `imm_u()` methods to create
+//! signed or unsigned immediate value.
+//!
+//! X86/X64 CPU Information
+//! -----------------------
+//!
+//! The CPUID instruction can be used to get an exhaustive information about
+//! the host X86/X64 processor. AsmJit contains utilities that can get the most
+//! important information related to the features supported by the CPU and the
+//! host operating system, in addition to host processor name and number of
+//! cores. Class `X86CpuInfo` extends `CpuInfo` and provides functionality
+//! specific to X86 and X64.
+//!
+//! By default AsmJit queries the CPU information after the library is loaded
+//! and the queried information is reused by all instances of `JitRuntime`.
+//! The global instance of `X86CpuInfo` can't be changed, because it will affect
+//! the code generation of all `Runtime`s. If there is a need to have a
+//! specific CPU information which contains modified features or processor
+//! vendor it's possible by creating a new instance of `X86CpuInfo` and setting
+//! up its members. `X86CpuUtil::detect` can be used to detect CPU features into
+//! an existing `X86CpuInfo` instance - it may become handly if only one property
+//! has to be turned on/off.
+//!
+//! If the high-level interface `X86CpuInfo` offers is not enough there is also
+//! `X86CpuUtil::callCpuId` helper that can be used to call CPUID instruction
+//! with a given parameters and to consume the output.
+//!
+//! Cpu detection is important when generating a JIT code that may or may not
+//! use certain CPU features. For example there used to be a SSE/SSE2 detection
+//! in the past and today there is often AVX/AVX2 detection.
+//!
+//! The example below shows how to detect SSE2:
+//!
+//! ~~~
+//! using namespace asmjit;
+//!
+//! // Get `X86CpuInfo` global instance.
+//! const X86CpuInfo* cpuInfo = X86CpuInfo::getHost();
+//!
+//! if (cpuInfo->hasFeature(kX86CpuFeatureSSE2)) {
+//! // Processor has SSE2.
+//! }
+//! else if (cpuInfo->hasFeature(kX86CpuFeatureMMX)) {
+//! // Processor doesn't have SSE2, but has MMX.
+//! }
+//! else {
+//! // Processor is archaic; it's a wonder AsmJit works here!
+//! }
+//! ~~~
+//!
+//! The next example shows how to call `CPUID` directly:
+//!
+//! ~~~
+//! using namespace asmjit;
+//!
+//! // Call cpuid, first two arguments are passed in Eax/Ecx.
+//! X86CpuId out;
+//! X86CpuUtil::callCpuId(0, 0, &out);
+//!
+//! // If Eax argument is 0, Ebx, Ecx and Edx registers are filled with a cpu vendor.
+//! char cpuVendor[13];
+//! ::memcpy(cpuVendor, &out.ebx, 4);
+//! ::memcpy(cpuVendor + 4, &out.edx, 4);
+//! ::memcpy(cpuVendor + 8, &out.ecx, 4);
+//! vendor[12] = '\0';
+//!
+//! // Print a CPU vendor retrieved from CPUID.
+//! ::printf("%s", cpuVendor);
+//! ~~~
+
+// ============================================================================
+// [asmjit_x86_compiler]
+// ============================================================================
+
+//! \defgroup asmjit_x86_compiler X86/X64 Code-Tree
+//! \ingroup asmjit_x86
+//!
+//! \brief X86/X64 code-tree and helpers.
+
+// ============================================================================
+// [asmjit_x86_inst]
+// ============================================================================
+
+//! \defgroup asmjit_x86_inst X86/X64 Instructions
+//! \ingroup asmjit_x86
+//!
+//! \brief X86/X64 low-level instruction definitions.
+
+// ============================================================================
+// [asmjit_x86_util]
+// ============================================================================
+
+//! \defgroup asmjit_x86_util X86/X64 Utilities
+//! \ingroup asmjit_x86
+//!
+//! \brief X86/X64 utility classes.
+
+// ============================================================================
+// [asmjit_contrib]
+// ============================================================================
+
+//! \defgroup asmjit_contrib Contributions
+//!
+//! \brief Contributions.
+
+// [Dependencies - Base]
+#include "base.h"
+
+// [Dependencies - X86/X64]
+#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
+#include "x86.h"
+#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
+
+// [Dependencies - Host]
+#include "host.h"
+
+// [Guard]
+#endif // _ASMJIT_ASMJIT_H
diff --git a/libraries/asmjit/base.h b/libraries/asmjit/base.h
new file mode 100644
index 0000000000000000000000000000000000000000..47e1bfef363d3942753c9e05430c698b58f80a95
--- /dev/null
+++ b/libraries/asmjit/base.h
@@ -0,0 +1,34 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Guard]
+#ifndef _ASMJIT_BASE_H
+#define _ASMJIT_BASE_H
+
+// [Dependencies - AsmJit]
+#include "build.h"
+
+#include "base/assembler.h"
+#include "base/codegen.h"
+#include "base/compiler.h"
+#include "base/constpool.h"
+#include "base/containers.h"
+#include "base/cpuinfo.h"
+#include "base/cputicks.h"
+#include "base/error.h"
+#include "base/globals.h"
+#include "base/intutil.h"
+#include "base/lock.h"
+#include "base/logger.h"
+#include "base/operand.h"
+#include "base/runtime.h"
+#include "base/string.h"
+#include "base/vectypes.h"
+#include "base/vmem.h"
+#include "base/zone.h"
+
+// [Guard]
+#endif // _ASMJIT_BASE_H
diff --git a/libraries/asmjit/base/assembler.cpp b/libraries/asmjit/base/assembler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fea8f664d0aea6597a7c8f63729662344ec22a56
--- /dev/null
+++ b/libraries/asmjit/base/assembler.cpp
@@ -0,0 +1,379 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Export]
+#define ASMJIT_EXPORTS
+
+// [Dependencies - AsmJit]
+#include "../base/assembler.h"
+#include "../base/intutil.h"
+#include "../base/vmem.h"
+
+// [Dependenceis - C]
+#include
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+// ============================================================================
+// [asmjit::Assembler - Construction / Destruction]
+// ============================================================================
+
+Assembler::Assembler(Runtime* runtime) :
+ CodeGen(runtime),
+ _buffer(NULL),
+ _end(NULL),
+ _cursor(NULL),
+ _trampolineSize(0),
+ _comment(NULL),
+ _unusedLinks(NULL) {}
+
+Assembler::~Assembler() {
+ reset(true);
+}
+
+// ============================================================================
+// [asmjit::Assembler - Clear / Reset]
+// ============================================================================
+
+void Assembler::reset(bool releaseMemory) {
+ // CodeGen members.
+ _baseAddress = kNoBaseAddress;
+ _instOptions = 0;
+ _error = kErrorOk;
+
+ _baseZone.reset(releaseMemory);
+
+ // Assembler members.
+ if (releaseMemory && _buffer != NULL) {
+ ASMJIT_FREE(_buffer);
+ _buffer = NULL;
+ _end = NULL;
+ }
+
+ _cursor = _buffer;
+ _trampolineSize = 0;
+
+ _comment = NULL;
+ _unusedLinks = NULL;
+
+ _labelList.reset(releaseMemory);
+ _relocList.reset(releaseMemory);
+}
+
+// ============================================================================
+// [asmjit::Assembler - Buffer]
+// ============================================================================
+
+Error Assembler::_grow(size_t n) {
+ size_t capacity = getCapacity();
+ size_t after = getOffset() + n;
+
+ // Overflow.
+ if (n > IntUtil::maxUInt() - capacity)
+ return setError(kErrorNoHeapMemory);
+
+ // Grow is called when allocation is needed, so it shouldn't happen, but on
+ // the other hand it is simple to catch and it's not an error.
+ if (after <= capacity)
+ return kErrorOk;
+
+ if (capacity < kMemAllocOverhead)
+ capacity = kMemAllocOverhead;
+ else
+ capacity += kMemAllocOverhead;
+
+ do {
+ size_t oldCapacity = capacity;
+
+ if (capacity < kMemAllocGrowMax)
+ capacity *= 2;
+ else
+ capacity += kMemAllocGrowMax;
+
+ // Overflow.
+ if (oldCapacity > capacity)
+ return setError(kErrorNoHeapMemory);
+ } while (capacity - kMemAllocOverhead < after);
+
+ capacity -= kMemAllocOverhead;
+ return _reserve(capacity);
+}
+
+Error Assembler::_reserve(size_t n) {
+ size_t capacity = getCapacity();
+ if (n <= capacity)
+ return kErrorOk;
+
+ uint8_t* newBuffer;
+ if (_buffer == NULL)
+ newBuffer = static_cast(ASMJIT_ALLOC(n));
+ else
+ newBuffer = static_cast(ASMJIT_REALLOC(_buffer, n));
+
+ if (newBuffer == NULL)
+ return setError(kErrorNoHeapMemory);
+
+ size_t offset = getOffset();
+
+ _buffer = newBuffer;
+ _end = _buffer + n;
+ _cursor = newBuffer + offset;
+
+ return kErrorOk;
+}
+
+// ============================================================================
+// [asmjit::Assembler - Label]
+// ============================================================================
+
+Error Assembler::_registerIndexedLabels(size_t index) {
+ size_t i = _labelList.getLength();
+ if (index < i)
+ return kErrorOk;
+
+ if (_labelList._grow(index - i) != kErrorOk)
+ return setError(kErrorNoHeapMemory);
+
+ LabelData data;
+ data.offset = -1;
+ data.links = NULL;
+
+ do {
+ _labelList.append(data);
+ } while (++i < index);
+
+ return kErrorOk;
+}
+
+Error Assembler::_newLabel(Label* dst) {
+ dst->_label.op = kOperandTypeLabel;
+ dst->_label.size = 0;
+ dst->_label.id = OperandUtil::makeLabelId(static_cast(_labelList.getLength()));
+
+ LabelData data;
+ data.offset = -1;
+ data.links = NULL;
+
+ if (_labelList.append(data) != kErrorOk)
+ goto _NoMemory;
+ return kErrorOk;
+
+_NoMemory:
+ dst->_label.id = kInvalidValue;
+ return setError(kErrorNoHeapMemory);
+}
+
+LabelLink* Assembler::_newLabelLink() {
+ LabelLink* link = _unusedLinks;
+
+ if (link) {
+ _unusedLinks = link->prev;
+ }
+ else {
+ link = _baseZone.allocT();
+ if (link == NULL)
+ return NULL;
+ }
+
+ link->prev = NULL;
+ link->offset = 0;
+ link->displacement = 0;
+ link->relocId = -1;
+
+ return link;
+}
+
+Error Assembler::bind(const Label& label) {
+ // Get label data based on label id.
+ uint32_t index = label.getId();
+ LabelData* data = getLabelData(index);
+
+ // Label can be bound only once.
+ if (data->offset != -1)
+ return setError(kErrorLabelAlreadyBound);
+
+#if !defined(ASMJIT_DISABLE_LOGGER)
+ if (_logger)
+ _logger->logFormat(kLoggerStyleLabel, "L%u:\n", index);
+#endif // !ASMJIT_DISABLE_LOGGER
+
+ Error error = kErrorOk;
+ size_t pos = getOffset();
+
+ LabelLink* link = data->links;
+ LabelLink* prev = NULL;
+
+ while (link) {
+ intptr_t offset = link->offset;
+
+ if (link->relocId != -1) {
+ // Handle RelocData - We have to update RelocData information instead of
+ // patching the displacement in LabelData.
+ _relocList[link->relocId].data += static_cast(pos);
+ }
+ else {
+ // Not using relocId, this means that we are overwriting a real
+ // displacement in the binary stream.
+ int32_t patchedValue = static_cast(
+ static_cast(pos) - offset + link->displacement);
+
+ // Size of the value we are going to patch. Only BYTE/DWORD is allowed.
+ uint32_t size = getByteAt(offset);
+ ASMJIT_ASSERT(size == 1 || size == 4);
+
+ if (size == 4) {
+ setInt32At(offset, patchedValue);
+ }
+ else {
+ ASMJIT_ASSERT(size == 1);
+ if (IntUtil::isInt8(patchedValue))
+ setByteAt(offset, static_cast(patchedValue & 0xFF));
+ else
+ error = kErrorIllegalDisplacement;
+ }
+ }
+
+ prev = link->prev;
+ link = prev;
+ }
+
+ // Chain unused links.
+ link = data->links;
+ if (link) {
+ if (prev == NULL)
+ prev = link;
+
+ prev->prev = _unusedLinks;
+ _unusedLinks = link;
+ }
+
+ // Set as bound (offset is zero or greater and no links).
+ data->offset = pos;
+ data->links = NULL;
+
+ if (error != kErrorOk)
+ return setError(error);
+
+ return error;
+}
+
+// ============================================================================
+// [asmjit::Assembler - Embed]
+// ============================================================================
+
+Error Assembler::embed(const void* data, uint32_t size) {
+ if (getRemainingSpace() < size) {
+ Error error = _grow(size);
+ if (error != kErrorOk)
+ return setError(error);
+ }
+
+ uint8_t* cursor = getCursor();
+ ::memcpy(cursor, data, size);
+ setCursor(cursor + size);
+
+#if !defined(ASMJIT_DISABLE_LOGGER)
+ if (_logger)
+ _logger->logBinary(kLoggerStyleData, data, size);
+#endif // !ASMJIT_DISABLE_LOGGER
+
+ return kErrorOk;
+}
+
+// ============================================================================
+// [asmjit::Assembler - Reloc]
+// ============================================================================
+
+size_t Assembler::relocCode(void* dst, Ptr baseAddress) const {
+ if (baseAddress == kNoBaseAddress)
+ baseAddress = hasBaseAddress() ? getBaseAddress() : static_cast((uintptr_t)dst);
+ else if (getBaseAddress() != baseAddress)
+ return 0;
+
+ return _relocCode(dst, baseAddress);
+}
+
+// ============================================================================
+// [asmjit::Assembler - Make]
+// ============================================================================
+
+void* Assembler::make() {
+ // Do nothing on error condition or if no instruction has been emitted.
+ if (_error != kErrorOk || getCodeSize() == 0)
+ return NULL;
+
+ void* p;
+ Error error = _runtime->add(&p, this);
+
+ if (error != kErrorOk)
+ setError(error);
+
+ return p;
+}
+
+// ============================================================================
+// [asmjit::Assembler - Emit (Helpers)]
+// ============================================================================
+
+#define NA noOperand
+
+Error Assembler::emit(uint32_t code) {
+ return _emit(code, NA, NA, NA, NA);
+}
+
+Error Assembler::emit(uint32_t code, const Operand& o0) {
+ return _emit(code, o0, NA, NA, NA);
+}
+
+Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1) {
+ return _emit(code, o0, o1, NA, NA);
+}
+
+Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) {
+ return _emit(code, o0, o1, o2, NA);
+}
+
+Error Assembler::emit(uint32_t code, int o0) {
+ return _emit(code, Imm(o0), NA, NA, NA);
+}
+
+Error Assembler::emit(uint32_t code, const Operand& o0, int o1) {
+ return _emit(code, o0, Imm(o1), NA, NA);
+}
+
+Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, int o2) {
+ return _emit(code, o0, o1, Imm(o2), NA);
+}
+
+Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int o3) {
+ return _emit(code, o0, o1, o2, Imm(o3));
+}
+
+Error Assembler::emit(uint32_t code, int64_t o0) {
+ return _emit(code, Imm(o0), NA, NA, NA);
+}
+
+Error Assembler::emit(uint32_t code, const Operand& o0, int64_t o1) {
+ return _emit(code, o0, Imm(o1), NA, NA);
+}
+
+Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, int64_t o2) {
+ return _emit(code, o0, o1, Imm(o2), NA);
+}
+
+Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int64_t o3) {
+ return _emit(code, o0, o1, o2, Imm(o3));
+}
+
+#undef NA
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
diff --git a/libraries/asmjit/base/assembler.h b/libraries/asmjit/base/assembler.h
new file mode 100644
index 0000000000000000000000000000000000000000..02c4cc3b56a62470dbbb6463efb4f2440dd76012
--- /dev/null
+++ b/libraries/asmjit/base/assembler.h
@@ -0,0 +1,543 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Guard]
+#ifndef _ASMJIT_BASE_ASSEMBLER_H
+#define _ASMJIT_BASE_ASSEMBLER_H
+
+// [Dependencies - AsmJit]
+#include "../base/codegen.h"
+#include "../base/containers.h"
+#include "../base/error.h"
+#include "../base/logger.h"
+#include "../base/operand.h"
+#include "../base/runtime.h"
+#include "../base/zone.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+//! \addtogroup asmjit_base_general
+//! \{
+
+// ============================================================================
+// [asmjit::InstId]
+// ============================================================================
+
+//! Instruction codes (stub).
+ASMJIT_ENUM(InstId) {
+ //! No instruction.
+ kInstIdNone = 0
+};
+
+// ============================================================================
+// [asmjit::InstOptions]
+// ============================================================================
+
+//! Instruction options.
+ASMJIT_ENUM(InstOptions) {
+ //! No instruction options.
+ kInstOptionNone = 0x00000000,
+
+ //! Emit short form of the instruction.
+ //!
+ //! X86/X64:
+ //!
+ //! Short form is mostly related to jmp and jcc instructions, but can be used
+ //! by other instructions supporting 8-bit or 32-bit immediates. This option
+ //! can be dangerous if the short jmp/jcc is required, but not encodable due
+ //! to large displacement, in such case an error happens and the whole
+ //! assembler/compiler stream is unusable.
+ kInstOptionShortForm = 0x00000001,
+
+ //! Emit long form of the instruction.
+ //!
+ //! X86/X64:
+ //!
+ //! Long form is mosrlt related to jmp and jcc instructions, but like the
+ //! `kInstOptionShortForm` option it can be used by other instructions
+ //! supporting both 8-bit and 32-bit immediates.
+ kInstOptionLongForm = 0x00000002,
+
+ //! Condition is likely to be taken.
+ kInstOptionTaken = 0x00000004,
+
+ //! Condition is unlikely to be taken.
+ kInstOptionNotTaken = 0x00000008
+};
+
+// ============================================================================
+// [asmjit::LabelLink]
+// ============================================================================
+
+//! \internal
+//!
+//! Data structure used to link linked-labels.
+struct LabelLink {
+ //! Previous link.
+ LabelLink* prev;
+ //! Offset.
+ intptr_t offset;
+ //! Inlined displacement.
+ intptr_t displacement;
+ //! RelocId if link must be absolute when relocated.
+ intptr_t relocId;
+};
+
+// ============================================================================
+// [asmjit::LabelData]
+// ============================================================================
+
+//! \internal
+//!
+//! Label data.
+struct LabelData {
+ //! Label offset.
+ intptr_t offset;
+ //! Label links chain.
+ LabelLink* links;
+};
+
+// ============================================================================
+// [asmjit::RelocData]
+// ============================================================================
+
+//! \internal
+//!
+//! Code relocation data (relative vs absolute addresses).
+//!
+//! X86/X64:
+//!
+//! X86 architecture uses 32-bit absolute addressing model by memory operands,
+//! but 64-bit mode uses relative addressing model (RIP + displacement). In
+//! code we are always using relative addressing model for referencing labels
+//! and embedded data. In 32-bit mode we must patch all references to absolute
+//! address before we can call generated function.
+struct RelocData {
+ //! Type of relocation.
+ uint32_t type;
+ //! Size of relocation (4 or 8 bytes).
+ uint32_t size;
+
+ //! Offset from code begin address.
+ Ptr from;
+
+ //! Relative displacement from code begin address (not to `offset`) or
+ //! absolute address.
+ Ptr data;
+};
+
+// ============================================================================
+// [asmjit::Assembler]
+// ============================================================================
+
+//! Base assembler.
+//!
+//! This class implements the base interface to an assembler. The architecture
+//! specific API is implemented by backends.
+//!
+//! \sa Compiler.
+struct ASMJIT_VCLASS Assembler : public CodeGen {
+ ASMJIT_NO_COPY(Assembler)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `Assembler` instance.
+ ASMJIT_API Assembler(Runtime* runtime);
+ //! Destroy the `Assembler` instance.
+ ASMJIT_API virtual ~Assembler();
+
+ // --------------------------------------------------------------------------
+ // [Reset]
+ // --------------------------------------------------------------------------
+
+ //! Reset the assembler.
+ //!
+ //! If `releaseMemory` is true all buffers will be released to the system.
+ ASMJIT_API void reset(bool releaseMemory = false);
+
+ // --------------------------------------------------------------------------
+ // [Buffer]
+ // --------------------------------------------------------------------------
+
+ //! Get capacity of the code buffer.
+ ASMJIT_INLINE size_t getCapacity() const {
+ return (size_t)(_end - _buffer);
+ }
+
+ //! Get the number of remaining bytes (space between cursor and the end of
+ //! the buffer).
+ ASMJIT_INLINE size_t getRemainingSpace() const {
+ return (size_t)(_end - _cursor);
+ }
+
+ //! Get buffer.
+ ASMJIT_INLINE uint8_t* getBuffer() const {
+ return _buffer;
+ }
+
+ //! Get the end of the buffer (points to the first byte that is outside).
+ ASMJIT_INLINE uint8_t* getEnd() const {
+ return _end;
+ }
+
+ //! Get the current position in the buffer.
+ ASMJIT_INLINE uint8_t* getCursor() const {
+ return _cursor;
+ }
+
+ //! Set the current position in the buffer.
+ ASMJIT_INLINE void setCursor(uint8_t* cursor) {
+ ASMJIT_ASSERT(cursor >= _buffer && cursor <= _end);
+ _cursor = cursor;
+ }
+
+ //! Get the current offset in the buffer.
+ ASMJIT_INLINE size_t getOffset() const {
+ return (size_t)(_cursor - _buffer);
+ }
+
+ //! Set the current offset in the buffer to `offset` and get the previous
+ //! offset value.
+ ASMJIT_INLINE size_t setOffset(size_t offset) {
+ ASMJIT_ASSERT(offset < getCapacity());
+
+ size_t oldOffset = (size_t)(_cursor - _buffer);
+ _cursor = _buffer + offset;
+ return oldOffset;
+ }
+
+ //! Grow the internal buffer.
+ //!
+ //! The internal buffer will grow at least by `n` bytes so `n` bytes can be
+ //! added to it. If `n` is zero or `getOffset() + n` is not greater than the
+ //! current capacity of the buffer this function does nothing.
+ ASMJIT_API Error _grow(size_t n);
+
+ //! Reserve the internal buffer to at least `n` bytes.
+ ASMJIT_API Error _reserve(size_t n);
+
+ //! Get BYTE at position `pos`.
+ ASMJIT_INLINE uint8_t getByteAt(size_t pos) const {
+ ASMJIT_ASSERT(pos + 1 <= (size_t)(_end - _buffer));
+ return *reinterpret_cast(_buffer + pos);
+ }
+
+ //! Get WORD at position `pos`.
+ ASMJIT_INLINE uint16_t getWordAt(size_t pos) const {
+ ASMJIT_ASSERT(pos + 2 <= (size_t)(_end - _buffer));
+ return *reinterpret_cast(_buffer + pos);
+ }
+
+ //! Get DWORD at position `pos`.
+ ASMJIT_INLINE uint32_t getDWordAt(size_t pos) const {
+ ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
+ return *reinterpret_cast(_buffer + pos);
+ }
+
+ //! Get QWORD at position `pos`.
+ ASMJIT_INLINE uint64_t getQWordAt(size_t pos) const {
+ ASMJIT_ASSERT(pos + 8 <= (size_t)(_end - _buffer));
+ return *reinterpret_cast(_buffer + pos);
+ }
+
+ //! Get int32_t at position `pos`.
+ ASMJIT_INLINE int32_t getInt32At(size_t pos) const {
+ ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
+ return *reinterpret_cast(_buffer + pos);
+ }
+
+ //! Get uint32_t at position `pos`.
+ ASMJIT_INLINE uint32_t getUInt32At(size_t pos) const {
+ ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
+ return *reinterpret_cast(_buffer + pos);
+ }
+
+ //! Set BYTE at position `pos`.
+ ASMJIT_INLINE void setByteAt(size_t pos, uint8_t x) {
+ ASMJIT_ASSERT(pos + 1 <= (size_t)(_end - _buffer));
+ *reinterpret_cast(_buffer + pos) = x;
+ }
+
+ //! Set WORD at position `pos`.
+ ASMJIT_INLINE void setWordAt(size_t pos, uint16_t x) {
+ ASMJIT_ASSERT(pos + 2 <= (size_t)(_end - _buffer));
+ *reinterpret_cast(_buffer + pos) = x;
+ }
+
+ //! Set DWORD at position `pos`.
+ ASMJIT_INLINE void setDWordAt(size_t pos, uint32_t x) {
+ ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
+ *reinterpret_cast(_buffer + pos) = x;
+ }
+
+ //! Set QWORD at position `pos`.
+ ASMJIT_INLINE void setQWordAt(size_t pos, uint64_t x) {
+ ASMJIT_ASSERT(pos + 8 <= (size_t)(_end - _buffer));
+ *reinterpret_cast(_buffer + pos) = x;
+ }
+
+ //! Set int32_t at position `pos`.
+ ASMJIT_INLINE void setInt32At(size_t pos, int32_t x) {
+ ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
+ *reinterpret_cast(_buffer + pos) = x;
+ }
+
+ //! Set uint32_t at position `pos`.
+ ASMJIT_INLINE void setUInt32At(size_t pos, uint32_t x) {
+ ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
+ *reinterpret_cast(_buffer + pos) = x;
+ }
+
+ // --------------------------------------------------------------------------
+ // [GetCodeSize]
+ // --------------------------------------------------------------------------
+
+ //! Get current offset in buffer, same as `getOffset() + getTramplineSize()`.
+ ASMJIT_INLINE size_t getCodeSize() const {
+ return getOffset() + getTrampolineSize();
+ }
+
+ // --------------------------------------------------------------------------
+ // [GetTrampolineSize]
+ // --------------------------------------------------------------------------
+
+ //! Get size of all possible trampolines.
+ //!
+ //! Trampolines are needed to successfuly generate relative jumps to absolute
+ //! addresses. This value is only non-zero if jmp of call instructions were
+ //! used with immediate operand (this means jumping or calling an absolute
+ //! address directly).
+ ASMJIT_INLINE size_t getTrampolineSize() const {
+ return _trampolineSize;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Label]
+ // --------------------------------------------------------------------------
+
+ //! Get number of labels created.
+ ASMJIT_INLINE size_t getLabelsCount() const {
+ return _labelList.getLength();
+ }
+
+ //! Get whether the `label` is valid (created by the assembler).
+ ASMJIT_INLINE bool isLabelValid(const Label& label) const {
+ return isLabelValid(label.getId());
+ }
+
+ //! \overload
+ ASMJIT_INLINE bool isLabelValid(uint32_t id) const {
+ return static_cast(id) < _labelList.getLength();
+ }
+
+ //! Get whether the `label` is bound.
+ //!
+ //! \note It's an error to pass label that is not valid. Check the validity
+ //! of the label by using `isLabelValid()` method before the bound check if
+ //! you are not sure about its validity, otherwise you may hit an assertion
+ //! failure in debug mode, and undefined behavior in release mode.
+ ASMJIT_INLINE bool isLabelBound(const Label& label) const {
+ return isLabelBound(label.getId());
+ }
+
+ //! \overload
+ ASMJIT_INLINE bool isLabelBound(uint32_t id) const {
+ ASMJIT_ASSERT(isLabelValid(id));
+
+ return _labelList[id].offset != -1;
+ }
+
+ //! Get `label` offset or -1 if the label is not yet bound.
+ ASMJIT_INLINE intptr_t getLabelOffset(const Label& label) const {
+ return getLabelOffset(label.getId());
+ }
+
+ //! \overload
+ ASMJIT_INLINE intptr_t getLabelOffset(uint32_t id) const {
+ ASMJIT_ASSERT(isLabelValid(id));
+ return _labelList[id].offset;
+ }
+
+ //! Get `LabelData` by `label`.
+ ASMJIT_INLINE LabelData* getLabelData(const Label& label) const {
+ return getLabelData(label.getId());
+ }
+
+ //! \overload
+ ASMJIT_INLINE LabelData* getLabelData(uint32_t id) const {
+ ASMJIT_ASSERT(isLabelValid(id));
+ return const_cast(&_labelList[id]);
+ }
+
+ //! \internal
+ //!
+ //! Register labels for other code generator, i.e. `Compiler`.
+ ASMJIT_API Error _registerIndexedLabels(size_t index);
+
+ //! \internal
+ //!
+ //! Create and initialize a new `Label`.
+ ASMJIT_API Error _newLabel(Label* dst);
+
+ //! \internal
+ //!
+ //! New LabelLink instance.
+ ASMJIT_API LabelLink* _newLabelLink();
+
+ //! Create and return a new `Label`.
+ ASMJIT_INLINE Label newLabel() {
+ Label result(NoInit);
+ _newLabel(&result);
+ return result;
+ }
+
+ //! Bind label to the current offset.
+ //!
+ //! \note Label can be bound only once!
+ ASMJIT_API virtual Error bind(const Label& label);
+
+ // --------------------------------------------------------------------------
+ // [Embed]
+ // --------------------------------------------------------------------------
+
+ //! Embed data into the code buffer.
+ ASMJIT_API virtual Error embed(const void* data, uint32_t size);
+
+ // --------------------------------------------------------------------------
+ // [Align]
+ // --------------------------------------------------------------------------
+
+ //! Align target buffer to `m` bytes.
+ //!
+ //! Typical usage of this is to align labels at start of the inner loops.
+ //!
+ //! Inserts `nop()` instructions or CPU optimized NOPs.
+ virtual Error align(uint32_t mode, uint32_t offset) = 0;
+
+ // --------------------------------------------------------------------------
+ // [Reloc]
+ // --------------------------------------------------------------------------
+
+ //! Relocate the code to `baseAddress` and copy to `dst`.
+ //!
+ //! \param dst Contains the location where the relocated code should be
+ //! copied. The pointer can be address returned by virtual memory allocator
+ //! or any other address that has sufficient space.
+ //!
+ //! \param base Base address used for relocation. The `JitRuntime` always
+ //! sets the `base` address to be the same as `dst`, but other runtimes, for
+ //! example `StaticRuntime`, do not have to follow this rule.
+ //!
+ //! \retval The number bytes actually used. If the code generator reserved
+ //! space for possible trampolines, but didn't use it, the number of bytes
+ //! used can actually be less than the expected worst case. Virtual memory
+ //! allocator can shrink the memory allocated first time.
+ //!
+ //! A given buffer will be overwritten, to get the number of bytes required,
+ //! use `getCodeSize()`.
+ ASMJIT_API size_t relocCode(void* dst, Ptr baseAddress = kNoBaseAddress) const;
+
+ //! \internal
+ //!
+ //! Reloc code.
+ virtual size_t _relocCode(void* dst, Ptr baseAddress) const = 0;
+
+ // --------------------------------------------------------------------------
+ // [Make]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_API virtual void* make();
+
+ // --------------------------------------------------------------------------
+ // [Emit]
+ // --------------------------------------------------------------------------
+
+ //! Emit an instruction.
+ ASMJIT_API Error emit(uint32_t code);
+ //! \overload
+ ASMJIT_API Error emit(uint32_t code, const Operand& o0);
+ //! \overload
+ ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1);
+ //! \overload
+ ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2);
+ //! \overload
+ ASMJIT_INLINE Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) {
+ return _emit(code, o0, o1, o2, o3);
+ }
+
+ //! Emit an instruction with integer immediate operand.
+ ASMJIT_API Error emit(uint32_t code, int o0);
+ //! \overload
+ ASMJIT_API Error emit(uint32_t code, const Operand& o0, int o1);
+ //! \overload
+ ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, int o2);
+ //! \overload
+ ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int o3);
+
+ //! \overload
+ ASMJIT_API Error emit(uint32_t code, int64_t o0);
+ //! \overload
+ ASMJIT_API Error emit(uint32_t code, const Operand& o0, int64_t o1);
+ //! \overload
+ ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, int64_t o2);
+ //! \overload
+ ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int64_t o3);
+
+ //! Emit an instruction (virtual).
+ virtual Error _emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) = 0;
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Buffer where the code is emitted (either live or temporary).
+ //!
+ //! This is actually the base pointer of the buffer, to get the current
+ //! position (cursor) look at the `_cursor` member.
+ uint8_t* _buffer;
+ //! The end of the buffer (points to the first invalid byte).
+ //!
+ //! The end of the buffer is calculated as _buffer + size.
+ uint8_t* _end;
+ //! The current position in code `_buffer`.
+ uint8_t* _cursor;
+
+ //! Size of possible trampolines.
+ uint32_t _trampolineSize;
+
+ //! Inline comment that will be logged by the next instruction and set to NULL.
+ const char* _comment;
+ //! Unused `LabelLink` structures pool.
+ LabelLink* _unusedLinks;
+
+ //! LabelData list.
+ PodVector _labelList;
+ //! RelocData list.
+ PodVector _relocList;
+};
+
+//! \}
+
+// ============================================================================
+// [Defined-Later]
+// ============================================================================
+
+ASMJIT_INLINE Label::Label(Assembler& a) : Operand(NoInit) {
+ a._newLabel(this);
+}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
+
+// [Guard]
+#endif // _ASMJIT_BASE_ASSEMBLER_H
diff --git a/libraries/asmjit/base/codegen.cpp b/libraries/asmjit/base/codegen.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..55192ed0eac52dc980f296092e2cdfe1a24d951a
--- /dev/null
+++ b/libraries/asmjit/base/codegen.cpp
@@ -0,0 +1,111 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Export]
+#define ASMJIT_EXPORTS
+
+// [Dependencies - AsmJit]
+#include "../base/codegen.h"
+#include "../base/intutil.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+// ============================================================================
+// [asmjit::CodeGen - Construction / Destruction]
+// ============================================================================
+
+CodeGen::CodeGen(Runtime* runtime) :
+ _runtime(runtime),
+ _logger(NULL),
+ _errorHandler(NULL),
+ _baseAddress(runtime->getBaseAddress()),
+ _arch(kArchNone),
+ _regSize(0),
+ _reserved(0),
+ _features(IntUtil::mask(kCodeGenOptimizedAlign)),
+ _instOptions(0),
+ _error(kErrorOk),
+ _baseZone(16384 - kZoneOverhead) {}
+
+CodeGen::~CodeGen() {
+ if (_errorHandler != NULL)
+ _errorHandler->release();
+}
+
+// ============================================================================
+// [asmjit::CodeGen - Logging]
+// ============================================================================
+
+#if !defined(ASMJIT_DISABLE_LOGGER)
+Error CodeGen::setLogger(Logger* logger) {
+ _logger = logger;
+ return kErrorOk;
+}
+#endif // !ASMJIT_DISABLE_LOGGER
+
+// ============================================================================
+// [asmjit::CodeGen - Error]
+// ============================================================================
+
+Error CodeGen::setError(Error error, const char* message) {
+ if (error == kErrorOk) {
+ _error = kErrorOk;
+ return kErrorOk;
+ }
+
+ if (message == NULL) {
+#if !defined(ASMJIT_DISABLE_NAMES)
+ message = ErrorUtil::asString(error);
+#else
+ static const char noMessage[] = "";
+ message = noMessage;
+#endif // ASMJIT_DISABLE_NAMES
+ }
+
+ // Error handler is called before logger so logging can be skipped if error
+ // has been handled.
+ ErrorHandler* handler = _errorHandler;
+ ASMJIT_TLOG("[ERROR] %s %s\n", message, !handler ? "(Possibly unhandled?)" : "");
+
+ if (handler != NULL && handler->handleError(error, message))
+ return error;
+
+#if !defined(ASMJIT_DISABLE_LOGGER)
+ Logger* logger = _logger;
+ if (logger != NULL) {
+ logger->logFormat(kLoggerStyleComment,
+ "*** ERROR: %s (%u).\n", message, static_cast(error));
+ }
+#endif // !ASMJIT_DISABLE_LOGGER
+
+ // The handler->handleError() function may throw an exception or longjmp()
+ // to terminate the execution of setError(). This is the reason why we have
+ // delayed changing the _error member until now.
+ _error = error;
+
+ return error;
+}
+
+Error CodeGen::setErrorHandler(ErrorHandler* handler) {
+ ErrorHandler* oldHandler = _errorHandler;
+
+ if (oldHandler != NULL)
+ oldHandler->release();
+
+ if (handler != NULL)
+ handler = handler->addRef();
+
+ _errorHandler = handler;
+ return kErrorOk;
+}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
diff --git a/libraries/asmjit/base/codegen.h b/libraries/asmjit/base/codegen.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e2db43815a3a414d77a32ff1e4c2685fbb0a76e
--- /dev/null
+++ b/libraries/asmjit/base/codegen.h
@@ -0,0 +1,337 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Guard]
+#ifndef _ASMJIT_BASE_CODEGEN_H
+#define _ASMJIT_BASE_CODEGEN_H
+
+// [Dependencies - AsmJit]
+#include "../base/error.h"
+#include "../base/logger.h"
+#include "../base/runtime.h"
+#include "../base/zone.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+//! \addtogroup asmjit_base_general
+//! \{
+
+// ============================================================================
+// [asmjit::CodeGenFeatures]
+// ============================================================================
+
+//! Features of \ref CodeGen.
+ASMJIT_ENUM(CodeGenFeatures) {
+ //! Emit optimized code-alignment sequences (`Assembler` and `Compiler`).
+ //!
+ //! Default `true`.
+ //!
+ //! X86/X64
+ //! -------
+ //!
+ //! Default align sequence used by X86/X64 architecture is one-byte 0x90
+ //! opcode that is mostly shown by disassemblers as nop. However there are
+ //! more optimized align sequences for 2-11 bytes that may execute faster.
+ //! If this feature is enabled asmjit will generate specialized sequences
+ //! for alignment between 1 to 11 bytes. Also when `X86Compiler` is used,
+ //! it can add REX prefixes into the code to make some instructions greater
+ //! so no alignment sequence is needed.
+ kCodeGenOptimizedAlign = 0,
+
+ //! Emit jump-prediction hints (`Assembler` and `Compiler`).
+ //!
+ //! Default `false`.
+ //!
+ //! X86/X64
+ //! -------
+ //!
+ //! Jump prediction is usually based on the direction of the jump. If the
+ //! jump is backward it is usually predicted as taken; and if the jump is
+ //! forward it is usually predicted as not-taken. The reason is that loops
+ //! generally use backward jumps and conditions usually use forward jumps.
+ //! However this behavior can be overridden by using instruction prefixes.
+ //! If this option is enabled these hints will be emitted.
+ //!
+ //! This feature is disabled by default, because the only processor that
+ //! used to take into consideration prediction hints was P4. Newer processors
+ //! implement heuristics for branch prediction that ignores any static hints.
+ kCodeGenPredictedJumps = 1,
+
+ //! Schedule instructions so they can be executed faster (`Compiler` only).
+ //!
+ //! Default `false` - has to be explicitly enabled as the scheduler needs
+ //! some time to run.
+ //!
+ //! X86/X64
+ //! -------
+ //!
+ //! If scheduling is enabled AsmJit will try to reorder instructions to
+ //! minimize dependency chain. Scheduler always runs after the registers are
+ //! allocated so it doesn't change count of register allocs/spills.
+ //!
+ //! This feature is highly experimental and untested.
+ kCodeGenEnableScheduler = 2
+};
+
+// ============================================================================
+// [asmjit::AlignMode]
+// ============================================================================
+
+//! Code aligning mode.
+ASMJIT_ENUM(AlignMode) {
+ //! Align by emitting a sequence that can be executed (code).
+ kAlignCode = 0,
+ //! Align by emitting sequence that shouldn't be executed (data).
+ kAlignData = 1
+};
+
+// ============================================================================
+// [asmjit::RelocMode]
+// ============================================================================
+
+//! Relocation mode.
+ASMJIT_ENUM(RelocMode) {
+ //! Relocate an absolute address to an absolute address.
+ kRelocAbsToAbs = 0,
+ //! Relocate a relative address to an absolute address.
+ kRelocRelToAbs = 1,
+ //! Relocate an absolute address to a relative address.
+ kRelocAbsToRel = 2,
+ //! Relocate an absolute address to a relative address or use trampoline.
+ kRelocTrampoline = 3
+};
+
+// ============================================================================
+// [asmjit::CodeGen]
+// ============================================================================
+
+//! Abstract class defining basics of \ref Assembler and \ref Compiler.
+struct ASMJIT_VCLASS CodeGen {
+ ASMJIT_NO_COPY(CodeGen)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `CodeGen` instance.
+ ASMJIT_API CodeGen(Runtime* runtime);
+ //! Destroy the `CodeGen` instance.
+ ASMJIT_API virtual ~CodeGen();
+
+ // --------------------------------------------------------------------------
+ // [Runtime]
+ // --------------------------------------------------------------------------
+
+ //! Get runtime.
+ ASMJIT_INLINE Runtime* getRuntime() const {
+ return _runtime;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Logger]
+ // --------------------------------------------------------------------------
+
+#if !defined(ASMJIT_DISABLE_LOGGER)
+ //! Get whether the code generator has a logger.
+ ASMJIT_INLINE bool hasLogger() const {
+ return _logger != NULL;
+ }
+
+ //! Get logger.
+ ASMJIT_INLINE Logger* getLogger() const {
+ return _logger;
+ }
+
+ //! Set logger to `logger`.
+ ASMJIT_API Error setLogger(Logger* logger);
+#endif // !ASMJIT_DISABLE_LOGGER
+
+ // --------------------------------------------------------------------------
+ // [Arch]
+ // --------------------------------------------------------------------------
+
+ //! Get target architecture.
+ ASMJIT_INLINE uint32_t getArch() const {
+ return _arch;
+ }
+
+ //! Get default register size (4 or 8 bytes).
+ ASMJIT_INLINE uint32_t getRegSize() const {
+ return _regSize;
+ }
+
+ // --------------------------------------------------------------------------
+ // [BaseAddress]
+ // --------------------------------------------------------------------------
+
+ //! Get whether the code-generator has a base address.
+ //!
+ //! \sa \ref getBaseAddress()
+ ASMJIT_INLINE bool hasBaseAddress() const {
+ return _baseAddress != kNoBaseAddress;
+ }
+
+ //! Get the base address.
+ ASMJIT_INLINE Ptr getBaseAddress() const {
+ return _baseAddress;
+ }
+
+ //! Set the base address to `baseAddress`.
+ ASMJIT_INLINE void setBaseAddress(Ptr baseAddress) {
+ _baseAddress = baseAddress;
+ }
+
+ //! Reset the base address.
+ ASMJIT_INLINE void resetBaseAddress() {
+ setBaseAddress(kNoBaseAddress);
+ }
+
+ // --------------------------------------------------------------------------
+ // [LastError / ErrorHandler]
+ // --------------------------------------------------------------------------
+
+ //! Get last error code.
+ ASMJIT_INLINE Error getError() const {
+ return _error;
+ }
+
+ //! Set last error code and propagate it through the error handler.
+ ASMJIT_API Error setError(Error error, const char* message = NULL);
+
+ //! Clear the last error code.
+ ASMJIT_INLINE void resetError() {
+ _error = kErrorOk;
+ }
+
+ //! Get error handler.
+ ASMJIT_INLINE ErrorHandler* getErrorHandler() const {
+ return _errorHandler;
+ }
+
+ //! Set error handler.
+ ASMJIT_API Error setErrorHandler(ErrorHandler* handler);
+
+ //! Clear error handler.
+ ASMJIT_INLINE Error resetErrorHandler() {
+ return setErrorHandler(NULL);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Code-Generation Features]
+ // --------------------------------------------------------------------------
+
+ //! Get code-generator `feature`.
+ ASMJIT_INLINE bool hasFeature(uint32_t feature) const {
+ ASMJIT_ASSERT(feature < 32);
+
+ return (_features & (1 << feature)) != 0;
+ }
+
+ //! Set code-generator `feature` to `value`.
+ ASMJIT_INLINE void setFeature(uint32_t feature, bool value) {
+ ASMJIT_ASSERT(feature < 32);
+
+ feature = static_cast(value) << feature;
+ _features = (_features & ~feature) | feature;
+ }
+
+ //! Get code-generator features.
+ ASMJIT_INLINE uint32_t getFeatures() const {
+ return _features;
+ }
+
+ //! Set code-generator features.
+ ASMJIT_INLINE void setFeatures(uint32_t features) {
+ _features = features;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Instruction Options]
+ // --------------------------------------------------------------------------
+
+ //! Get options of the next instruction.
+ ASMJIT_INLINE uint32_t getInstOptions() const {
+ return _instOptions;
+ }
+
+ //! Get options of the next instruction and reset them.
+ ASMJIT_INLINE uint32_t getInstOptionsAndReset() {
+ uint32_t instOptions = _instOptions;
+ _instOptions = 0;
+ return instOptions;
+ };
+
+ //! Set options of the next instruction.
+ ASMJIT_INLINE void setInstOptions(uint32_t instOptions) {
+ _instOptions = instOptions;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Make]
+ // --------------------------------------------------------------------------
+
+ //! Make is a convenience method to make and relocate the current code and
+ //! add it to the associated `Runtime`.
+ //!
+ //! What is needed is only to cast the returned pointer to your function type
+ //! and then use it. If there was an error during `make()` `NULL` is returned
+ //! and the last error code can be obtained by calling `getError()`.
+ virtual void* make() = 0;
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Target runtime.
+ Runtime* _runtime;
+
+#if !defined(ASMJIT_DISABLE_LOGGER)
+ //! Logger.
+ Logger* _logger;
+#else
+ //! \internal
+ //!
+ //! Makes libraries built with or without logging support binary compatible.
+ void* _logger;
+#endif // ASMJIT_DISABLE_LOGGER
+
+ //! Error handler, called by \ref setError().
+ ErrorHandler* _errorHandler;
+
+ //! Base address (-1 if unknown/not used).
+ Ptr _baseAddress;
+
+ //! Target architecture ID.
+ uint8_t _arch;
+ //! Target architecture GP register size in bytes (4 or 8).
+ uint8_t _regSize;
+ //! \internal
+ uint16_t _reserved;
+
+ //! Code-Generation features, used by \ref hasFeature() and \ref setFeature().
+ uint32_t _features;
+ //! Options affecting the next instruction.
+ uint32_t _instOptions;
+
+ //! Last error code.
+ uint32_t _error;
+
+ //! Base zone.
+ Zone _baseZone;
+};
+
+//! \}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
+
+// [Guard]
+#endif // _ASMJIT_BASE_CODEGEN_H
diff --git a/libraries/asmjit/base/compiler.cpp b/libraries/asmjit/base/compiler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ae26de1e183f8fc908ab54583b4c3f1f90988d8f
--- /dev/null
+++ b/libraries/asmjit/base/compiler.cpp
@@ -0,0 +1,621 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Export]
+#define ASMJIT_EXPORTS
+
+// [Guard]
+#include "../build.h"
+#if !defined(ASMJIT_DISABLE_COMPILER)
+
+// [Dependencies - AsmJit]
+#include "../base/assembler.h"
+#include "../base/compiler.h"
+#include "../base/context_p.h"
+#include "../base/cpuinfo.h"
+#include "../base/intutil.h"
+#include "../base/logger.h"
+
+// [Dependencies - C]
+#include
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+// ============================================================================
+// [Constants]
+// ============================================================================
+
+static const char noName[1] = { '\0' };
+enum { kBaseCompilerDefaultLookAhead = 64 };
+
+// ============================================================================
+// [asmjit::Compiler - Construction / Destruction]
+// ============================================================================
+
+Compiler::Compiler(Runtime* runtime) :
+ CodeGen(runtime),
+ _assembler(NULL),
+ _nodeFlowId(0),
+ _nodeFlags(0),
+ _maxLookAhead(kBaseCompilerDefaultLookAhead),
+ _targetVarMapping(NULL),
+ _firstNode(NULL),
+ _lastNode(NULL),
+ _cursor(NULL),
+ _func(NULL),
+ _varZone(4096 - kZoneOverhead),
+ _stringZone(4096 - kZoneOverhead),
+ _localConstZone(4096 - kZoneOverhead),
+ _localConstPool(&_localConstZone),
+ _globalConstPool(&_baseZone) {}
+
+Compiler::~Compiler() {
+ reset(true);
+
+ if (_assembler != NULL)
+ delete _assembler;
+}
+
+// ============================================================================
+// [asmjit::Compiler - Clear / Reset]
+// ============================================================================
+
+void Compiler::reset(bool releaseMemory) {
+ // CodeGen members.
+ _baseAddress = kNoBaseAddress;
+ _instOptions = 0;
+ _error = kErrorOk;
+
+ _baseZone.reset(releaseMemory);
+
+ // Compiler members.
+ _nodeFlowId = 0;
+ _nodeFlags = 0;
+
+ if (_assembler != NULL)
+ _assembler->reset(releaseMemory);
+
+ _firstNode = NULL;
+ _lastNode = NULL;
+
+ _cursor = NULL;
+ _func = NULL;
+
+ _localConstPool.reset();
+ _globalConstPool.reset();
+
+ _localConstPoolLabel.reset();
+ _globalConstPoolLabel.reset();
+
+ _varZone.reset(releaseMemory);
+ _stringZone.reset(releaseMemory);
+ _localConstZone.reset(releaseMemory);
+
+ _targetList.reset(releaseMemory);
+ _varList.reset(releaseMemory);
+}
+
+// ============================================================================
+// [asmjit::Compiler - Node Management]
+// ============================================================================
+
+Node* Compiler::setCursor(Node* node) {
+ Node* old = _cursor;
+ _cursor = node;
+ return old;
+}
+
+Node* Compiler::addNode(Node* node) {
+ ASMJIT_ASSERT(node != NULL);
+ ASMJIT_ASSERT(node->_prev == NULL);
+ ASMJIT_ASSERT(node->_next == NULL);
+
+ if (_cursor == NULL) {
+ if (_firstNode == NULL) {
+ _firstNode = node;
+ _lastNode = node;
+ }
+ else {
+ node->_next = _firstNode;
+ _firstNode->_prev = node;
+ _firstNode = node;
+ }
+ }
+ else {
+ Node* prev = _cursor;
+ Node* next = _cursor->_next;
+
+ node->_prev = prev;
+ node->_next = next;
+
+ prev->_next = node;
+ if (next)
+ next->_prev = node;
+ else
+ _lastNode = node;
+ }
+
+ _cursor = node;
+ return node;
+}
+
+Node* Compiler::addNodeBefore(Node* node, Node* ref) {
+ ASMJIT_ASSERT(node != NULL);
+ ASMJIT_ASSERT(node->_prev == NULL);
+ ASMJIT_ASSERT(node->_next == NULL);
+ ASMJIT_ASSERT(ref != NULL);
+
+ Node* prev = ref->_prev;
+ Node* next = ref;
+
+ node->_prev = prev;
+ node->_next = next;
+
+ next->_prev = node;
+ if (prev)
+ prev->_next = node;
+ else
+ _firstNode = node;
+
+ return node;
+}
+
+Node* Compiler::addNodeAfter(Node* node, Node* ref) {
+ ASMJIT_ASSERT(node != NULL);
+ ASMJIT_ASSERT(node->_prev == NULL);
+ ASMJIT_ASSERT(node->_next == NULL);
+ ASMJIT_ASSERT(ref != NULL);
+
+ Node* prev = ref;
+ Node* next = ref->_next;
+
+ node->_prev = prev;
+ node->_next = next;
+
+ prev->_next = node;
+ if (next)
+ next->_prev = node;
+ else
+ _lastNode = node;
+
+ return node;
+}
+
+static ASMJIT_INLINE void BaseCompiler_nodeRemoved(Compiler* self, Node* node_) {
+ if (node_->isJmpOrJcc()) {
+ JumpNode* node = static_cast(node_);
+ TargetNode* target = node->getTarget();
+
+ // Disconnect.
+ JumpNode** pPrev = &target->_from;
+ for (;;) {
+ ASMJIT_ASSERT(*pPrev != NULL);
+ JumpNode* current = *pPrev;
+
+ if (current == NULL)
+ break;
+
+ if (current == node) {
+ *pPrev = node->_jumpNext;
+ break;
+ }
+
+ pPrev = ¤t->_jumpNext;
+ }
+
+ target->subNumRefs();
+ }
+}
+
+Node* Compiler::removeNode(Node* node) {
+ Node* prev = node->_prev;
+ Node* next = node->_next;
+
+ if (_firstNode == node)
+ _firstNode = next;
+ else
+ prev->_next = next;
+
+ if (_lastNode == node)
+ _lastNode = prev;
+ else
+ next->_prev = prev;
+
+ node->_prev = NULL;
+ node->_next = NULL;
+
+ if (_cursor == node)
+ _cursor = prev;
+ BaseCompiler_nodeRemoved(this, node);
+
+ return node;
+}
+
+void Compiler::removeNodes(Node* first, Node* last) {
+ if (first == last) {
+ removeNode(first);
+ return;
+ }
+
+ Node* prev = first->_prev;
+ Node* next = last->_next;
+
+ if (_firstNode == first)
+ _firstNode = next;
+ else
+ prev->_next = next;
+
+ if (_lastNode == last)
+ _lastNode = prev;
+ else
+ next->_prev = prev;
+
+ Node* node = first;
+ for (;;) {
+ Node* next = node->getNext();
+ ASMJIT_ASSERT(next != NULL);
+
+ node->_prev = NULL;
+ node->_next = NULL;
+
+ if (_cursor == node)
+ _cursor = prev;
+ BaseCompiler_nodeRemoved(this, node);
+
+ if (node == last)
+ break;
+ node = next;
+ }
+}
+
+// ============================================================================
+// [asmjit::Compiler - Align]
+// ============================================================================
+
+AlignNode* Compiler::newAlign(uint32_t mode, uint32_t offset) {
+ AlignNode* node = newNode(mode, offset);
+ if (node == NULL)
+ goto _NoMemory;
+ return node;
+
+_NoMemory:
+ setError(kErrorNoHeapMemory);
+ return NULL;
+}
+
+AlignNode* Compiler::addAlign(uint32_t mode, uint32_t offset) {
+ AlignNode* node = newAlign(mode, offset);
+ if (node == NULL)
+ return NULL;
+ return static_cast(addNode(node));
+}
+
+// ============================================================================
+// [asmjit::Compiler - Target]
+// ============================================================================
+
+TargetNode* Compiler::newTarget() {
+ TargetNode* node = newNode(
+ OperandUtil::makeLabelId(static_cast(_targetList.getLength())));
+
+ if (node == NULL || _targetList.append(node) != kErrorOk)
+ goto _NoMemory;
+ return node;
+
+_NoMemory:
+ setError(kErrorNoHeapMemory);
+ return NULL;
+}
+
+TargetNode* Compiler::addTarget() {
+ TargetNode* node = newTarget();
+ if (node == NULL)
+ return NULL;
+ return static_cast(addNode(node));
+}
+
+// ============================================================================
+// [asmjit::Compiler - Label]
+// ============================================================================
+
+Error Compiler::_newLabel(Label* dst) {
+ dst->_init_packed_op_sz_b0_b1_id(kOperandTypeLabel, 0, 0, 0, kInvalidValue);
+ dst->_init_packed_d2_d3(0, 0);
+
+ TargetNode* node = newTarget();
+ if (node == NULL)
+ goto _NoMemory;
+
+ dst->_label.id = node->getLabelId();
+ return kErrorOk;
+
+_NoMemory:
+ return setError(kErrorNoHeapMemory);
+}
+
+Error Compiler::bind(const Label& label) {
+ uint32_t index = label.getId();
+ ASMJIT_ASSERT(index < _targetList.getLength());
+
+ addNode(_targetList[index]);
+ return kErrorOk;
+}
+
+// ============================================================================
+// [asmjit::Compiler - Embed]
+// ============================================================================
+
+EmbedNode* Compiler::newEmbed(const void* data, uint32_t size) {
+ EmbedNode* node;
+
+ if (size > EmbedNode::kInlineBufferSize) {
+ void* clonedData = _stringZone.alloc(size);
+ if (clonedData == NULL)
+ goto _NoMemory;
+
+ if (data != NULL)
+ ::memcpy(clonedData, data, size);
+ data = clonedData;
+ }
+
+ node = newNode(const_cast(data), size);
+ if (node == NULL)
+ goto _NoMemory;
+ return node;
+
+_NoMemory:
+ setError(kErrorNoHeapMemory);
+ return NULL;
+}
+
+EmbedNode* Compiler::addEmbed(const void* data, uint32_t size) {
+ EmbedNode* node = newEmbed(data, size);
+ if (node == NULL)
+ return node;
+ return static_cast(addNode(node));
+}
+
+// ============================================================================
+// [asmjit::Compiler - Comment]
+// ============================================================================
+
+CommentNode* Compiler::newComment(const char* str) {
+ CommentNode* node;
+
+ if (str != NULL && str[0]) {
+ str = _stringZone.sdup(str);
+ if (str == NULL)
+ goto _NoMemory;
+ }
+
+ node = newNode(str);
+ if (node == NULL)
+ goto _NoMemory;
+ return node;
+
+_NoMemory:
+ setError(kErrorNoHeapMemory);
+ return NULL;
+}
+
+CommentNode* Compiler::addComment(const char* str) {
+ CommentNode* node = newComment(str);
+ if (node == NULL)
+ return NULL;
+ return static_cast(addNode(node));
+}
+
+CommentNode* Compiler::comment(const char* fmt, ...) {
+ char buf[256];
+ char* p = buf;
+
+ if (fmt) {
+ *p++ = ';';
+ *p++ = ' ';
+
+ va_list ap;
+ va_start(ap, fmt);
+ p += vsnprintf(p, 254, fmt, ap);
+ va_end(ap);
+ }
+
+ p[0] = '\n';
+ p[1] = '\0';
+
+ return addComment(fmt);
+}
+
+// ============================================================================
+// [asmjit::Compiler - Hint]
+// ============================================================================
+
+HintNode* Compiler::newHint(Var& var, uint32_t hint, uint32_t value) {
+ if (var.getId() == kInvalidValue)
+ return NULL;
+ VarData* vd = getVd(var);
+
+ HintNode* node = newNode(vd, hint, value);
+ if (node == NULL)
+ goto _NoMemory;
+ return node;
+
+_NoMemory:
+ setError(kErrorNoHeapMemory);
+ return NULL;
+}
+
+HintNode* Compiler::addHint(Var& var, uint32_t hint, uint32_t value) {
+ if (var.getId() == kInvalidValue)
+ return NULL;
+
+ HintNode* node = newHint(var, hint, value);
+ if (node == NULL)
+ return NULL;
+ return static_cast(addNode(node));
+}
+
+// ============================================================================
+// [asmjit::Compiler - Vars]
+// ============================================================================
+
+VarData* Compiler::_newVd(uint32_t type, uint32_t size, uint32_t c, const char* name) {
+ VarData* vd = reinterpret_cast(_varZone.alloc(sizeof(VarData)));
+ if (vd == NULL)
+ goto _NoMemory;
+
+ vd->_name = noName;
+ vd->_id = OperandUtil::makeVarId(static_cast(_varList.getLength()));
+ vd->_contextId = kInvalidValue;
+
+ if (name != NULL && name[0] != '\0') {
+ vd->_name = _stringZone.sdup(name);
+ }
+
+ vd->_type = static_cast(type);
+ vd->_class = static_cast(c);
+ vd->_flags = 0;
+ vd->_priority = 10;
+
+ vd->_state = kVarStateNone;
+ vd->_regIndex = kInvalidReg;
+ vd->_isStack = false;
+ vd->_isMemArg = false;
+ vd->_isCalculated = false;
+ vd->_saveOnUnuse = false;
+ vd->_modified = false;
+ vd->_reserved0 = 0;
+ vd->_alignment = static_cast(IntUtil::iMin(size, 64));
+
+ vd->_size = size;
+ vd->_homeMask = 0;
+
+ vd->_memOffset = 0;
+ vd->_memCell = NULL;
+
+ vd->rReadCount = 0;
+ vd->rWriteCount = 0;
+ vd->mReadCount = 0;
+ vd->mWriteCount = 0;
+
+ vd->_va = NULL;
+
+ if (_varList.append(vd) != kErrorOk)
+ goto _NoMemory;
+ return vd;
+
+_NoMemory:
+ setError(kErrorNoHeapMemory);
+ return NULL;
+}
+
+void Compiler::alloc(Var& var) {
+ addHint(var, kVarHintAlloc, kInvalidValue);
+}
+
+void Compiler::alloc(Var& var, uint32_t regIndex) {
+ addHint(var, kVarHintAlloc, regIndex);
+}
+
+void Compiler::alloc(Var& var, const Reg& reg) {
+ addHint(var, kVarHintAlloc, reg.getRegIndex());
+}
+
+void Compiler::save(Var& var) {
+ addHint(var, kVarHintSave, kInvalidValue);
+}
+
+void Compiler::spill(Var& var) {
+ addHint(var, kVarHintSpill, kInvalidValue);
+}
+
+void Compiler::unuse(Var& var) {
+ addHint(var, kVarHintUnuse, kInvalidValue);
+}
+
+uint32_t Compiler::getPriority(Var& var) const {
+ if (var.getId() == kInvalidValue)
+ return kInvalidValue;
+
+ VarData* vd = getVdById(var.getId());
+ return vd->getPriority();
+}
+
+void Compiler::setPriority(Var& var, uint32_t priority) {
+ if (var.getId() == kInvalidValue)
+ return;
+
+ if (priority > 255)
+ priority = 255;
+
+ VarData* vd = getVdById(var.getId());
+ vd->_priority = static_cast(priority);
+}
+
+bool Compiler::getSaveOnUnuse(Var& var) const {
+ if (var.getId() == kInvalidValue)
+ return false;
+
+ VarData* vd = getVdById(var.getId());
+ return static_cast(vd->_saveOnUnuse);
+}
+
+void Compiler::setSaveOnUnuse(Var& var, bool value) {
+ if (var.getId() == kInvalidValue)
+ return;
+
+ VarData* vd = getVdById(var.getId());
+ vd->_saveOnUnuse = value;
+}
+
+void Compiler::rename(Var& var, const char* name) {
+ if (var.getId() == kInvalidValue)
+ return;
+
+ VarData* vd = getVdById(var.getId());
+ vd->_name = noName;
+
+ if (name != NULL && name[0] != '\0') {
+ vd->_name = _stringZone.sdup(name);
+ }
+}
+
+// ============================================================================
+// [asmjit::Compiler - Assembler]
+// ============================================================================
+
+Assembler* Compiler::getAssembler() {
+ Assembler* a = _assembler;
+
+ if (a != NULL) {
+ a->reset(false);
+ }
+ else {
+ a = _newAssembler();
+ _assembler = a;
+ }
+
+#if !defined(ASMJIT_DISABLE_LOGGER)
+ Logger* logger = _logger;
+ if (logger != NULL)
+ a->setLogger(logger);
+#endif // !ASMJIT_DISABLE_LOGGER
+
+ a->setBaseAddress(_baseAddress);
+ a->setFeatures(_features);
+
+ return a;
+}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
+
+// [Guard]
+#endif // !ASMJIT_DISABLE_COMPILER
diff --git a/libraries/asmjit/base/compiler.h b/libraries/asmjit/base/compiler.h
new file mode 100644
index 0000000000000000000000000000000000000000..ea6217150c26c53f7ec836471b16b00179e4e7bd
--- /dev/null
+++ b/libraries/asmjit/base/compiler.h
@@ -0,0 +1,3145 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Guard]
+#ifndef _ASMJIT_BASE_COMPILER_H
+#define _ASMJIT_BASE_COMPILER_H
+
+#include "../build.h"
+#if !defined(ASMJIT_DISABLE_COMPILER)
+
+// [Dependencies - AsmJit]
+#include "../base/assembler.h"
+#include "../base/codegen.h"
+#include "../base/constpool.h"
+#include "../base/containers.h"
+#include "../base/error.h"
+#include "../base/intutil.h"
+#include "../base/operand.h"
+#include "../base/zone.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+// ============================================================================
+// [Forward Declarations]
+// ============================================================================
+
+struct Compiler;
+
+struct VarAttr;
+struct VarData;
+struct VarMap;
+struct VarState;
+
+struct Node;
+struct EndNode;
+struct InstNode;
+struct JumpNode;
+
+// ============================================================================
+// [asmjit::ConstScope]
+// ============================================================================
+
+//! \addtogroup asmjit_base_compiler
+//! \{
+
+//! Scope of the constant.
+ASMJIT_ENUM(ConstScope) {
+ //! Local constant, always embedded right after the current function.
+ kConstScopeLocal = 0,
+ //! Global constant, embedded at the end of the currently compiled code.
+ kConstScopeGlobal = 1
+};
+
+// ============================================================================
+// [asmjit::VarType]
+// ============================================================================
+
+ASMJIT_ENUM(VarType) {
+ //! Variable is 8-bit signed integer.
+ kVarTypeInt8 = 0,
+ //! Variable is 8-bit unsigned integer.
+ kVarTypeUInt8 = 1,
+ //! Variable is 16-bit signed integer.
+ kVarTypeInt16 = 2,
+ //! Variable is 16-bit unsigned integer.
+ kVarTypeUInt16 = 3,
+ //! Variable is 32-bit signed integer.
+ kVarTypeInt32 = 4,
+ //! Variable is 32-bit unsigned integer.
+ kVarTypeUInt32 = 5,
+ //! Variable is 64-bit signed integer.
+ kVarTypeInt64 = 6,
+ //! Variable is 64-bit unsigned integer.
+ kVarTypeUInt64 = 7,
+
+ //! Variable is target `intptr_t`, not compatible with host `intptr_t`.
+ kVarTypeIntPtr = 8,
+ //! Variable is target `uintptr_t`, not compatible with host `uintptr_t`.
+ kVarTypeUIntPtr = 9,
+
+ //! Variable is 32-bit floating point (single precision).
+ kVarTypeFp32 = 10,
+ //! Variable is 64-bit floating point (double precision).
+ kVarTypeFp64 = 11,
+
+ //! \internal
+ _kVarTypeIntStart = kVarTypeInt8,
+ //! \internal
+ _kVarTypeIntEnd = kVarTypeUIntPtr,
+
+ //! \internal
+ _kVarTypeFpStart = kVarTypeFp32,
+ //! \internal
+ _kVarTypeFpEnd = kVarTypeFp64
+};
+
+// ============================================================================
+// [asmjit::VarFlags]
+// ============================================================================
+
+//! \internal
+//!
+//! X86/X64 variable flags.
+ASMJIT_ENUM(VarFlags) {
+ //! Variable contains single-precision floating-point(s).
+ kVarFlagSp = 0x10,
+ //! Variable contains double-precision floating-point(s).
+ kVarFlagDp = 0x20,
+ //! Variable is packed, i.e. packed floats, doubles, ...
+ kVarFlagPacked = 0x40
+};
+
+// ============================================================================
+// [asmjit::VarAttrFlags]
+// ============================================================================
+
+//! Variable attribute flags.
+ASMJIT_ENUM(VarAttrFlags) {
+ //! Variable is accessed through register on input.
+ kVarAttrInReg = 0x00000001,
+ //! Variable is accessed through register on output.
+ kVarAttrOutReg = 0x00000002,
+ //! Variable is accessed through register on input & output.
+ kVarAttrInOutReg = 0x00000003,
+
+ //! Variable is accessed through memory on input.
+ kVarAttrInMem = 0x00000004,
+ //! Variable is accessed through memory on output.
+ kVarAttrOutMem = 0x00000008,
+ //! Variable is accessed through memory on input & output.
+ kVarAttrInOutMem = 0x0000000C,
+
+ //! Register allocator can decide if input will be in register or memory.
+ kVarAttrInDecide = 0x00000010,
+ //! Register allocator can decide if output will be in register or memory.
+ kVarAttrOutDecide = 0x00000020,
+ //! Register allocator can decide if in/out will be in register or memory.
+ kVarAttrInOutDecide = 0x00000030,
+
+ //! Variable is converted to other type/class on the input.
+ kVarAttrInConv = 0x00000040,
+ //! Variable is converted from other type/class on the output.
+ kVarAttrOutConv = 0x00000080,
+ //! Combination of `kVarAttrInConv` and `kVarAttrOutConv`.
+ kVarAttrInOutConv = 0x000000C0,
+
+ //! Variable is a function call operand.
+ kVarAttrInCall = 0x00000100,
+ //! Variable is a function argument passed in register.
+ kVarAttrInArg = 0x00000200,
+
+ //! Variable is a function return value passed in register.
+ kVarAttrOutRet = 0x00000400,
+ //! Variable should be spilled.
+ kVarAttrSpill = 0x00000800,
+ //! Variable should be unused at the end of the instruction/node.
+ kVarAttrUnuse = 0x00001000,
+
+ //! \internal
+ //!
+ //! All in-flags.
+ kVarAttrInAll =
+ kVarAttrInReg |
+ kVarAttrInMem |
+ kVarAttrInDecide |
+ kVarAttrInCall |
+ kVarAttrInArg,
+
+ //! \internal
+ //!
+ //! All out-flags.
+ kVarAttrOutAll =
+ kVarAttrOutReg |
+ kVarAttrOutMem |
+ kVarAttrOutDecide |
+ kVarAttrOutRet,
+
+ //! Variable is already allocated on the input.
+ kVarAttrAllocInDone = 0x00400000,
+ //! Variable is already allocated on the output.
+ kVarAttrAllocOutDone = 0x00800000
+};
+
+// ============================================================================
+// [asmjit::VarHint]
+// ============================================================================
+
+//! Variable hint (used by `Compiler)`.
+//!
+//! \sa Compiler.
+ASMJIT_ENUM(VarHint) {
+ //! Alloc variable.
+ kVarHintAlloc = 0,
+ //! Spill variable.
+ kVarHintSpill = 1,
+ //! Save variable if modified.
+ kVarHintSave = 2,
+ //! Save variable if modified and mark it as unused.
+ kVarHintSaveAndUnuse = 3,
+ //! Mark variable as unused.
+ kVarHintUnuse = 4
+};
+
+// ============================================================================
+// [asmjit::kVarState]
+// ============================================================================
+
+// TODO: Rename `kVarState` or `VarState`.
+
+//! State of variable.
+//!
+//! \note Variable states are used only during register allocation.
+ASMJIT_ENUM(kVarState) {
+ //! Variable is currently not used.
+ kVarStateNone = 0,
+ //! Variable is currently allocated in register.
+ kVarStateReg = 1,
+ //! Variable is currently allocated in memory (or has been spilled).
+ kVarStateMem = 2
+};
+
+// ============================================================================
+// [asmjit::FuncConv]
+// ============================================================================
+
+//! Function calling convention.
+//!
+//! For a platform specific calling conventions, see:
+//! - `X86FuncConv` - X86/X64 calling conventions.
+ASMJIT_ENUM(FuncConv) {
+ //! Calling convention is invalid (can't be used).
+ kFuncConvNone = 0,
+
+#if defined(ASMJIT_DOCGEN)
+ //! Default calling convention for current platform / operating system.
+ kFuncConvHost = DependsOnHost,
+
+ //! Default C calling convention based on current compiler's settings.
+ kFuncConvHostCDecl = DependsOnHost,
+
+ //! Compatibility for `__stdcall` calling convention.
+ //!
+ //! \note This enumeration is always set to a value which is compatible with
+ //! current compilers __stdcall calling convention. In 64-bit mode the value
+ //! is compatible with `kX86FuncConvW64` or `kX86FuncConvU64`.
+ kFuncConvHostStdCall = DependsOnHost,
+
+ //! Compatibility for `__fastcall` calling convention.
+ //!
+ //! \note This enumeration is always set to a value which is compatible with
+ //! current compilers `__fastcall` calling convention. In 64-bit mode the value
+ //! is compatible with `kX86FuncConvW64` or `kX86FuncConvU64`.
+ kFuncConvHostFastCall = DependsOnHost
+#endif // ASMJIT_DOCGEN
+};
+
+// ============================================================================
+// [asmjit::FuncHint]
+// ============================================================================
+
+//! Function hints.
+//!
+//! For a platform specific calling conventions, see:
+//! - `X86FuncHint` - X86/X64 function hints.
+ASMJIT_ENUM(FuncHint) {
+ //! Make a naked function (default true).
+ //!
+ //! Naked function is function without using standard prolog/epilog sequence).
+ //!
+ //! X86/X64 Specific
+ //! ----------------
+ //!
+ //! Standard prolog sequence is:
+ //!
+ //! ~~~
+ //! push zbp
+ //! mov zsp, zbp
+ //! sub zsp, StackAdjustment
+ //! ~~~
+ //!
+ //! which is an equivalent to:
+ //!
+ //! ~~~
+ //! enter StackAdjustment, 0
+ //! ~~~
+ //!
+ //! Standard epilog sequence is:
+ //!
+ //! ~~~
+ //! mov zsp, zbp
+ //! pop zbp
+ //! ~~~
+ //!
+ //! which is an equavalent to:
+ //!
+ //! ~~~
+ //! leave
+ //! ~~~
+ //!
+ //! Naked functions can omit the prolog/epilog sequence. The advantage of
+ //! doing such modification is that EBP/RBP register can be used by the
+ //! register allocator which can result in less spills/allocs.
+ kFuncHintNaked = 0,
+
+ //! Generate compact function prolog/epilog if possible.
+ //!
+ //! X86/X64 Specific
+ //! ----------------
+ //!
+ //! Use shorter, but possible slower prolog/epilog sequence to save/restore
+ //! registers.
+ kFuncHintCompact = 1
+};
+
+// ============================================================================
+// [asmjit::FuncFlags]
+// ============================================================================
+
+//! Function flags.
+//!
+//! For a platform specific calling conventions, see:
+//! - `X86FuncFlags` - X86/X64 function flags.
+ASMJIT_ENUM(FuncFlags) {
+ //! Whether the function is using naked (minimal) prolog / epilog.
+ kFuncFlagIsNaked = 0x00000001,
+
+ //! Whether an another function is called from this function.
+ kFuncFlagIsCaller = 0x00000002,
+
+ //! Whether the stack is not aligned to the required stack alignment,
+ //! thus it has to be aligned manually.
+ kFuncFlagIsStackMisaligned = 0x00000004,
+
+ //! Whether the stack pointer is adjusted by the stack size needed
+ //! to save registers and function variables.
+ //!
+ //! X86/X64 Specific
+ //! ----------------
+ //!
+ //! Stack pointer (ESP/RSP) is adjusted by 'sub' instruction in prolog and by
+ //! 'add' instruction in epilog (only if function is not naked). If function
+ //! needs to perform manual stack alignment more instructions are used to
+ //! adjust the stack (like "and zsp, -Alignment").
+ kFuncFlagIsStackAdjusted = 0x00000008,
+
+ //! Whether the function is finished using `Compiler::endFunc()`.
+ kFuncFlagIsFinished = 0x80000000
+};
+
+// ============================================================================
+// [asmjit::FuncDir]
+// ============================================================================
+
+//! Function arguments direction.
+ASMJIT_ENUM(FuncDir) {
+ //! Arguments are passed left to right.
+ //!
+ //! This arguments direction is unusual in C, however it's used in Pascal.
+ kFuncDirLtr = 0,
+
+ //! Arguments are passed right ro left
+ //!
+ //! This is the default argument direction in C.
+ kFuncDirRtl = 1
+};
+
+// ============================================================================
+// [asmjit::FuncArgIndex]
+// ============================================================================
+
+//! Function argument index (lo/hi).
+ASMJIT_ENUM(FuncArgIndex) {
+ //! Maxumum number of function arguments supported by AsmJit.
+ kFuncArgCount = 16,
+ //! Extended maximum number of arguments (used internally).
+ kFuncArgCountLoHi = kFuncArgCount * 2,
+
+ //! Index to the LO part of function argument (default).
+ //!
+ //! This value is typically omitted and added only if there is HI argument
+ //! accessed.
+ kFuncArgLo = 0,
+ //! Index to the HI part of function argument.
+ //!
+ //! HI part of function argument depends on target architecture. On x86 it's
+ //! typically used to transfer 64-bit integers (they form a pair of 32-bit
+ //! integers).
+ kFuncArgHi = kFuncArgCount
+};
+
+// ============================================================================
+// [asmjit::FuncRet]
+// ============================================================================
+
+//! Function return value (lo/hi) specification.
+ASMJIT_ENUM(FuncRet) {
+ //! Index to the LO part of function return value.
+ kFuncRetLo = 0,
+ //! Index to the HI part of function return value.
+ kFuncRetHi = 1
+};
+
+// ============================================================================
+// [asmjit::kFuncStackInvalid]
+// ============================================================================
+
+enum {
+ //! Invalid stack offset in function or function parameter.
+ kFuncStackInvalid = -1
+};
+
+// ============================================================================
+// [asmjit::NodeType]
+// ============================================================================
+
+//! Type of node, see \ref Node.
+ASMJIT_ENUM(NodeType) {
+ //! Invalid node (internal, can't be used).
+ kNodeTypeNone = 0,
+ //! Node is an .align directive, see \ref AlignNode.
+ kNodeTypeAlign,
+ //! Node is an embedded data, see \ref EmbedNode.
+ kNodeTypeEmbed,
+ //! Node is a comment, see \ref CommentNode.
+ kNodeTypeComment,
+ //! Node is a variable hint (alloc, spill, use, unuse), see \ref HintNode.
+ kNodeTypeHint,
+ //! Node is a label, see \ref TargetNode.
+ kNodeTypeTarget,
+ //! Node is an instruction, see \ref InstNode.
+ kNodeTypeInst,
+ //! Node is a function declaration, see \ref FuncNode.
+ kNodeTypeFunc,
+ //! Node is an end of the function, see \ref EndNode.
+ kNodeTypeEnd,
+ //! Node is a return, see \ref RetNode.
+ kNodeTypeRet,
+ //! Node is a function call, see \ref CallNode.
+ kNodeTypeCall,
+ //! Node is a function call argument moved on stack, see \ref SArgNode.
+ kNodeTypeSArg
+};
+
+// ============================================================================
+// [asmjit::NodeFlags]
+// ============================================================================
+
+ASMJIT_ENUM(NodeFlags) {
+ //! Whether the node has been translated, thus contains only registers.
+ kNodeFlagIsTranslated = 0x0001,
+
+ //! Whether the node was scheduled - possibly reordered, but basically this
+ //! is a mark that is set by scheduler after the node has been visited.
+ kNodeFlagIsScheduled = 0x0002,
+
+ //! Whether the node is informative only and can be safely removed.
+ kNodeFlagIsInformative = 0x0004,
+
+ //! Whether the `InstNode` is a jump.
+ kNodeFlagIsJmp = 0x0008,
+ //! Whether the `InstNode` is a conditional jump.
+ kNodeFlagIsJcc = 0x0010,
+
+ //! Whether the `InstNode` is an unconditinal jump or conditional
+ //! jump that is likely to be taken.
+ kNodeFlagIsTaken = 0x0020,
+
+ //! Whether the `Node` will return from a function.
+ //!
+ //! This flag is used by both `EndNode` and `RetNode`.
+ kNodeFlagIsRet = 0x0040,
+
+ //! Whether the instruction is special.
+ kNodeFlagIsSpecial = 0x0080,
+
+ //! Whether the instruction is an FPU instruction.
+ kNodeFlagIsFp = 0x0100
+};
+
+// ============================================================================
+// [asmjit::MemCell]
+// ============================================================================
+
+struct MemCell {
+ ASMJIT_NO_COPY(MemCell)
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get cell offset.
+ ASMJIT_INLINE int32_t getOffset() const { return _offset; }
+ //! Set cell offset.
+ ASMJIT_INLINE void setOffset(int32_t offset) { _offset = offset; }
+
+ //! Get cell size.
+ ASMJIT_INLINE uint32_t getSize() const { return _size; }
+ //! Set cell size.
+ ASMJIT_INLINE void setSize(uint32_t size) { _size = size; }
+
+ //! Get cell alignment.
+ ASMJIT_INLINE uint32_t getAlignment() const { return _alignment; }
+ //! Set cell alignment.
+ ASMJIT_INLINE void setAlignment(uint32_t alignment) { _alignment = alignment; }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Next active cell.
+ MemCell* _next;
+
+ //! Offset, relative to base-offset.
+ int32_t _offset;
+ //! Size.
+ uint32_t _size;
+ //! Alignment.
+ uint32_t _alignment;
+};
+
+// ============================================================================
+// [asmjit::Var]
+// ============================================================================
+
+//! Base class for all variables.
+struct Var : public Operand {
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE Var() : Operand(NoInit) {
+ _init_packed_op_sz_b0_b1_id(kOperandTypeVar, 0, 0, 0, kInvalidValue);
+ _init_packed_d2_d3(kInvalidValue, kInvalidValue);
+ }
+
+ ASMJIT_INLINE Var(const Var& other) : Operand(other) {}
+
+ explicit ASMJIT_INLINE Var(const _NoInit&) : Operand(NoInit) {}
+
+ // --------------------------------------------------------------------------
+ // [Var Specific]
+ // --------------------------------------------------------------------------
+
+ //! Clone `Var` operand.
+ ASMJIT_INLINE Var clone() const {
+ return Var(*this);
+ }
+
+ //! Reset Var operand.
+ ASMJIT_INLINE void reset() {
+ _init_packed_op_sz_b0_b1_id(kOperandTypeVar, 0, kInvalidReg, kInvalidReg, kInvalidValue);
+ _init_packed_d2_d3(kInvalidValue, kInvalidValue);
+ }
+
+ //! Get whether the variable has been initialized by `Compiler`.
+ ASMJIT_INLINE bool isInitialized() const {
+ return _vreg.id != kInvalidValue;
+ }
+
+ //! Get variable type.
+ ASMJIT_INLINE uint32_t getVarType() const {
+ return _vreg.vType;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Operator Overload]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE Var& operator=(const Var& other) { _copy(other); return *this; }
+
+ ASMJIT_INLINE bool operator==(const Var& other) const { return _packed[0] == other._packed[0]; }
+ ASMJIT_INLINE bool operator!=(const Var& other) const { return !operator==(other); }
+};
+
+// ============================================================================
+// [asmjit::VarBits]
+// ============================================================================
+
+//! Bit-array used by variable-liveness analysis.
+struct VarBits {
+ // --------------------------------------------------------------------------
+ // [Enums]
+ // --------------------------------------------------------------------------
+
+ enum {
+ kEntitySize = static_cast(sizeof(uintptr_t)),
+ kEntityBits = kEntitySize * 8
+ };
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE uintptr_t getBit(uint32_t index) const {
+ return (data[index / kEntityBits] >> (index % kEntityBits)) & 1;
+ }
+
+ ASMJIT_INLINE void setBit(uint32_t index) {
+ data[index / kEntityBits] |= static_cast(1) << (index % kEntityBits);
+ }
+
+ ASMJIT_INLINE void delBit(uint32_t index) {
+ data[index / kEntityBits] &= ~(static_cast(1) << (index % kEntityBits));
+ }
+
+ // --------------------------------------------------------------------------
+ // [Ops]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE bool copyBits(const VarBits* s0, uint32_t len) {
+ uintptr_t r = 0;
+ for (uint32_t i = 0; i < len; i++) {
+ uintptr_t t = s0->data[i];
+ data[i] = t;
+ r |= t;
+ }
+ return r != 0;
+ }
+
+ ASMJIT_INLINE bool addBits(const VarBits* s0, uint32_t len) {
+ return addBits(this, s0, len);
+ }
+
+ ASMJIT_INLINE bool addBits(const VarBits* s0, const VarBits* s1, uint32_t len) {
+ uintptr_t r = 0;
+ for (uint32_t i = 0; i < len; i++) {
+ uintptr_t t = s0->data[i] | s1->data[i];
+ data[i] = t;
+ r |= t;
+ }
+ return r != 0;
+ }
+
+ ASMJIT_INLINE bool andBits(const VarBits* s1, uint32_t len) {
+ return andBits(this, s1, len);
+ }
+
+ ASMJIT_INLINE bool andBits(const VarBits* s0, const VarBits* s1, uint32_t len) {
+ uintptr_t r = 0;
+ for (uint32_t i = 0; i < len; i++) {
+ uintptr_t t = s0->data[i] & s1->data[i];
+ data[i] = t;
+ r |= t;
+ }
+ return r != 0;
+ }
+
+ ASMJIT_INLINE bool delBits(const VarBits* s1, uint32_t len) {
+ return delBits(this, s1, len);
+ }
+
+ ASMJIT_INLINE bool delBits(const VarBits* s0, const VarBits* s1, uint32_t len) {
+ uintptr_t r = 0;
+ for (uint32_t i = 0; i < len; i++) {
+ uintptr_t t = s0->data[i] & ~s1->data[i];
+ data[i] = t;
+ r |= t;
+ }
+ return r != 0;
+ }
+
+ ASMJIT_INLINE bool _addBitsDelSource(VarBits* s1, uint32_t len) {
+ return _addBitsDelSource(this, s1, len);
+ }
+
+ ASMJIT_INLINE bool _addBitsDelSource(const VarBits* s0, VarBits* s1, uint32_t len) {
+ uintptr_t r = 0;
+ for (uint32_t i = 0; i < len; i++) {
+ uintptr_t a = s0->data[i];
+ uintptr_t b = s1->data[i];
+
+ this->data[i] = a | b;
+ b &= ~a;
+
+ s1->data[i] = b;
+ r |= b;
+ }
+ return r != 0;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ uintptr_t data[1];
+};
+
+// ============================================================================
+// [asmjit::VarData]
+// ============================================================================
+
+//! Base variable data.
+struct VarData {
+ // --------------------------------------------------------------------------
+ // [Accessors - Base]
+ // --------------------------------------------------------------------------
+
+ //! Get variable name.
+ ASMJIT_INLINE const char* getName() const {
+ return _name;
+ }
+
+ //! Get variable id.
+ ASMJIT_INLINE uint32_t getId() const {
+ return _id;
+ }
+
+ //! Get variable type.
+ ASMJIT_INLINE uint32_t getType() const {
+ return _type;
+ }
+
+ //! Get variable class.
+ ASMJIT_INLINE uint32_t getClass() const {
+ return _class;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - ContextId]
+ // --------------------------------------------------------------------------
+
+ //! Get whether the variable has context id.
+ ASMJIT_INLINE bool hasContextId() const {
+ return _contextId != kInvalidValue;
+ }
+
+ //! Get context variable id (used only by `Context)`.
+ ASMJIT_INLINE uint32_t getContextId() const {
+ return _contextId;
+ }
+
+ //! Set context variable id (used only by `Context)`.
+ ASMJIT_INLINE void setContextId(uint32_t contextId) {
+ _contextId = contextId;
+ }
+
+ //! Reset context variable id (used only by `Context)`.
+ ASMJIT_INLINE void resetContextId() {
+ _contextId = kInvalidValue;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - Priority]
+ // --------------------------------------------------------------------------
+
+ //! Get variable priority, used by compiler to decide which variable to spill.
+ ASMJIT_INLINE uint32_t getPriority() const {
+ return _priority;
+ }
+
+ //! Set variable priority.
+ ASMJIT_INLINE void setPriority(uint32_t priority) {
+ ASMJIT_ASSERT(priority <= 0xFF);
+ _priority = static_cast(priority);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - State]
+ // --------------------------------------------------------------------------
+
+ //! Get variable state, only used by `Context`.
+ ASMJIT_INLINE uint32_t getState() const {
+ return _state;
+ }
+
+ //! Set variable state, only used by `Context`.
+ ASMJIT_INLINE void setState(uint32_t state) {
+ ASMJIT_ASSERT(state <= 0xFF);
+ _state = static_cast(state);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - RegIndex]
+ // --------------------------------------------------------------------------
+
+ //! Get register index.
+ ASMJIT_INLINE uint32_t getRegIndex() const {
+ return _regIndex;
+ }
+
+ //! Set register index.
+ ASMJIT_INLINE void setRegIndex(uint32_t regIndex) {
+ ASMJIT_ASSERT(regIndex <= 0xFF);
+ _regIndex = static_cast(regIndex);
+ }
+
+ //! Reset register index.
+ ASMJIT_INLINE void resetRegIndex() {
+ _regIndex = static_cast(kInvalidReg);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - HomeIndex/Mask]
+ // --------------------------------------------------------------------------
+
+ //! Get home registers mask.
+ ASMJIT_INLINE uint32_t getHomeMask() const {
+ return _homeMask;
+ }
+
+ //! Add a home register index to the home registers mask.
+ ASMJIT_INLINE void addHomeIndex(uint32_t regIndex) {
+ _homeMask |= IntUtil::mask(regIndex);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - Flags]
+ // --------------------------------------------------------------------------
+
+ //! Get variable flags.
+ ASMJIT_INLINE uint32_t getFlags() const {
+ return _flags;
+ }
+
+ //! Get whether the VarData is only memory allocated on the stack.
+ ASMJIT_INLINE bool isStack() const { return static_cast(_isStack); }
+
+ //! Get whether the variable is a function argument passed through memory.
+ ASMJIT_INLINE bool isMemArg() const { return static_cast(_isMemArg); }
+
+ //! Get variable content can be calculated by a simple instruction.
+ ASMJIT_INLINE bool isCalculated() const { return static_cast(_isCalculated); }
+ //! Get whether to save variable when it's unused (spill).
+ ASMJIT_INLINE bool saveOnUnuse() const { return static_cast(_saveOnUnuse); }
+
+ //! Get whether the variable was changed.
+ ASMJIT_INLINE bool isModified() const { return static_cast(_modified); }
+ //! Set whether the variable was changed.
+ ASMJIT_INLINE void setModified(bool modified) { _modified = modified; }
+
+ //! Get variable alignment.
+ ASMJIT_INLINE uint32_t getAlignment() const { return _alignment; }
+ //! Get variable size.
+ ASMJIT_INLINE uint32_t getSize() const { return _size; }
+
+ //! Get home memory offset.
+ ASMJIT_INLINE int32_t getMemOffset() const { return _memOffset; }
+ //! Set home memory offset.
+ ASMJIT_INLINE void setMemOffset(int32_t offset) { _memOffset = offset; }
+
+ //! Get home memory cell.
+ ASMJIT_INLINE MemCell* getMemCell() const { return _memCell; }
+ //! Set home memory cell.
+ ASMJIT_INLINE void setMemCell(MemCell* cell) { _memCell = cell; }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - Temporary Usage]
+ // --------------------------------------------------------------------------
+
+ //! Get temporary VarAttr.
+ ASMJIT_INLINE VarAttr* getVa() const { return _va; }
+ //! Set temporary VarAttr.
+ ASMJIT_INLINE void setVa(VarAttr* va) { _va = va; }
+ //! Reset temporary VarAttr.
+ ASMJIT_INLINE void resetVa() { _va = NULL; }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Variable name.
+ const char* _name;
+
+ //! Variable id.
+ uint32_t _id;
+ //! Context variable id, used by `Context` only, initially `kInvalidValue`.
+ uint32_t _contextId;
+
+ //! Variable type.
+ uint8_t _type;
+ //! Variable class.
+ uint8_t _class;
+ //! Variable flags.
+ uint8_t _flags;
+ //! Variable priority.
+ uint8_t _priority;
+
+ //! Variable state (connected with actual `VarState)`.
+ uint8_t _state;
+ //! Actual register index (only used by `Context)`, during translate.
+ uint8_t _regIndex;
+
+ //! Whether the variable is only used as memory allocated on the stack.
+ uint8_t _isStack : 1;
+ //! Whether the variable is a function argument passed through memory.
+ uint8_t _isMemArg : 1;
+ //! Whether variable content can be calculated by a simple instruction.
+ //!
+ //! This is used mainly by MMX and SSE2 code. This flag indicates that
+ //! register allocator should never reserve memory for this variable, because
+ //! the content can be generated by a single instruction (for example PXOR).
+ uint8_t _isCalculated : 1;
+ //! Save on unuse (at end of the variable scope).
+ uint8_t _saveOnUnuse : 1;
+ //! Whether variable was changed (connected with actual `VarState)`.
+ uint8_t _modified : 1;
+ //! \internal
+ uint8_t _reserved0 : 3;
+ //! Variable natural alignment.
+ uint8_t _alignment;
+
+ //! Variable size.
+ uint32_t _size;
+
+ //! Mask of all registers variable has been allocated to.
+ uint32_t _homeMask;
+
+ //! Home memory offset.
+ int32_t _memOffset;
+ //! Home memory cell, used by `Context` (initially NULL).
+ MemCell* _memCell;
+
+ //! Register read access statistics.
+ uint32_t rReadCount;
+ //! Register write access statistics.
+ uint32_t rWriteCount;
+
+ //! Memory read statistics.
+ uint32_t mReadCount;
+ //! Memory write statistics.
+ uint32_t mWriteCount;
+
+ // --------------------------------------------------------------------------
+ // [Members - Temporary Usage]
+ // --------------------------------------------------------------------------
+
+ // These variables are only used during register allocation. They are
+ // initialized by init() phase and reset by cleanup() phase.
+
+ union {
+ //! Temporary link to VarAttr* used by the `Context` used in
+ //! various phases, but always set back to NULL when finished.
+ //!
+ //! This temporary data is designed to be used by algorithms that need to
+ //! store some data into variables themselves during compilation. But it's
+ //! expected that after variable is compiled & translated the data is set
+ //! back to zero/null. Initial value is NULL.
+ VarAttr* _va;
+
+ //! \internal
+ //!
+ //! Same as `_va` just provided as `uintptr_t`.
+ uintptr_t _vaUInt;
+ };
+};
+
+// ============================================================================
+// [asmjit::VarAttr]
+// ============================================================================
+
+struct VarAttr {
+ // --------------------------------------------------------------------------
+ // [Setup]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE void setup(VarData* vd, uint32_t flags = 0, uint32_t inRegs = 0, uint32_t allocableRegs = 0) {
+ _vd = vd;
+ _flags = flags;
+ _varCount = 0;
+ _inRegIndex = kInvalidReg;
+ _outRegIndex = kInvalidReg;
+ _reserved = 0;
+ _inRegs = inRegs;
+ _allocableRegs = allocableRegs;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get VarData.
+ ASMJIT_INLINE VarData* getVd() const { return _vd; }
+ //! Set VarData.
+ ASMJIT_INLINE void setVd(VarData* vd) { _vd = vd; }
+
+ //! Get flags.
+ ASMJIT_INLINE uint32_t getFlags() const { return _flags; }
+ //! Set flags.
+ ASMJIT_INLINE void setFlags(uint32_t flags) { _flags = flags; }
+
+ //! Get whether `flag` is on.
+ ASMJIT_INLINE bool hasFlag(uint32_t flag) { return (_flags & flag) != 0; }
+ //! Add `flags`.
+ ASMJIT_INLINE void orFlags(uint32_t flags) { _flags |= flags; }
+ //! Mask `flags`.
+ ASMJIT_INLINE void andFlags(uint32_t flags) { _flags &= flags; }
+ //! Clear `flags`.
+ ASMJIT_INLINE void andNotFlags(uint32_t flags) { _flags &= ~flags; }
+
+ //! Get how many times the variable is used by the instruction/node.
+ ASMJIT_INLINE uint32_t getVarCount() const { return _varCount; }
+ //! Set how many times the variable is used by the instruction/node.
+ ASMJIT_INLINE void setVarCount(uint32_t count) { _varCount = static_cast(count); }
+ //! Add how many times the variable is used by the instruction/node.
+ ASMJIT_INLINE void addVarCount(uint32_t count = 1) { _varCount += static_cast(count); }
+
+ //! Get whether the variable has to be allocated in a specific input register.
+ ASMJIT_INLINE uint32_t hasInRegIndex() const { return _inRegIndex != kInvalidReg; }
+ //! Get the input register index or `kInvalidReg`.
+ ASMJIT_INLINE uint32_t getInRegIndex() const { return _inRegIndex; }
+ //! Set the input register index.
+ ASMJIT_INLINE void setInRegIndex(uint32_t index) { _inRegIndex = static_cast(index); }
+ //! Reset the input register index.
+ ASMJIT_INLINE void resetInRegIndex() { _inRegIndex = kInvalidReg; }
+
+ //! Get whether the variable has to be allocated in a specific output register.
+ ASMJIT_INLINE uint32_t hasOutRegIndex() const { return _outRegIndex != kInvalidReg; }
+ //! Get the output register index or `kInvalidReg`.
+ ASMJIT_INLINE uint32_t getOutRegIndex() const { return _outRegIndex; }
+ //! Set the output register index.
+ ASMJIT_INLINE void setOutRegIndex(uint32_t index) { _outRegIndex = static_cast(index); }
+ //! Reset the output register index.
+ ASMJIT_INLINE void resetOutRegIndex() { _outRegIndex = kInvalidReg; }
+
+ //! Get whether the mandatory input registers are in used.
+ ASMJIT_INLINE bool hasInRegs() const { return _inRegs != 0; }
+ //! Get mandatory input registers (mask).
+ ASMJIT_INLINE uint32_t getInRegs() const { return _inRegs; }
+ //! Set mandatory input registers (mask).
+ ASMJIT_INLINE void setInRegs(uint32_t mask) { _inRegs = mask; }
+ //! Add mandatory input registers (mask).
+ ASMJIT_INLINE void addInRegs(uint32_t mask) { _inRegs |= mask; }
+ //! And mandatory input registers (mask).
+ ASMJIT_INLINE void andInRegs(uint32_t mask) { _inRegs &= mask; }
+ //! Clear mandatory input registers (mask).
+ ASMJIT_INLINE void delInRegs(uint32_t mask) { _inRegs &= ~mask; }
+
+ //! Get allocable input registers (mask).
+ ASMJIT_INLINE uint32_t getAllocableRegs() const { return _allocableRegs; }
+ //! Set allocable input registers (mask).
+ ASMJIT_INLINE void setAllocableRegs(uint32_t mask) { _allocableRegs = mask; }
+ //! Add allocable input registers (mask).
+ ASMJIT_INLINE void addAllocableRegs(uint32_t mask) { _allocableRegs |= mask; }
+ //! And allocable input registers (mask).
+ ASMJIT_INLINE void andAllocableRegs(uint32_t mask) { _allocableRegs &= mask; }
+ //! Clear allocable input registers (mask).
+ ASMJIT_INLINE void delAllocableRegs(uint32_t mask) { _allocableRegs &= ~mask; }
+
+ // --------------------------------------------------------------------------
+ // [Operator Overload]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE VarAttr& operator=(const VarAttr& other) {
+ ::memcpy(this, &other, sizeof(VarAttr));
+ return *this;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ VarData* _vd;
+ //! Flags.
+ uint32_t _flags;
+
+ union {
+ struct {
+ //! How many times the variable is used by the instruction/node.
+ uint8_t _varCount;
+ //! Input register index or `kInvalidReg` if it's not given.
+ //!
+ //! Even if the input register index is not given (i.e. it may by any
+ //! register), register allocator should assign an index that will be
+ //! used to persist a variable into this specific index. It's helpful
+ //! in situations where one variable has to be allocated in multiple
+ //! registers to determine the register which will be persistent.
+ uint8_t _inRegIndex;
+ //! Output register index or `kInvalidReg` if it's not given.
+ //!
+ //! Typically `kInvalidReg` if variable is only used on input.
+ uint8_t _outRegIndex;
+ //! \internal
+ uint8_t _reserved;
+ };
+
+ //! \internal
+ //!
+ //! Packed data #0.
+ uint32_t _packed;
+ };
+
+ //! Mandatory input registers.
+ //!
+ //! Mandatory input registers are required by the instruction even if
+ //! there are duplicates. This schema allows us to allocate one variable
+ //! in one or more register when needed. Required mostly by instructions
+ //! that have implicit register operands (imul, cpuid, ...) and function
+ //! call.
+ uint32_t _inRegs;
+
+ //! Allocable input registers.
+ //!
+ //! Optional input registers is a mask of all allocable registers for a given
+ //! variable where we have to pick one of them. This mask is usually not used
+ //! when _inRegs is set. If both masks are used then the register
+ //! allocator tries first to find an intersection between these and allocates
+ //! an extra slot if not found.
+ uint32_t _allocableRegs;
+};
+
+// ============================================================================
+// [asmjit::VarMap]
+// ============================================================================
+
+//! Variables' map related to a single node (instruction / other node).
+struct VarMap {
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get count of variables (all).
+ ASMJIT_INLINE uint32_t getVaCount() const {
+ return _vaCount;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Variables count.
+ uint32_t _vaCount;
+};
+
+// ============================================================================
+// [asmjit::VarState]
+// ============================================================================
+
+//! Variables' state.
+struct VarState {};
+
+// ============================================================================
+// [asmjit::TypeId / VarMapping]
+// ============================================================================
+
+//! Function builder 'void' type.
+struct Void {};
+
+//! Function builder 'int8_t' type.
+struct Int8Type {};
+//! Function builder 'uint8_t' type.
+struct UInt8Type {};
+
+//! Function builder 'int16_t' type.
+struct Int16Type {};
+//! Function builder 'uint16_t' type.
+struct UInt16Type {};
+
+//! Function builder 'int32_t' type.
+struct Int32Type {};
+//! Function builder 'uint32_t' type.
+struct UInt32Type {};
+
+//! Function builder 'int64_t' type.
+struct Int64Type {};
+//! Function builder 'uint64_t' type.
+struct UInt64Type {};
+
+//! Function builder 'intptr_t' type.
+struct IntPtrType {};
+//! Function builder 'uintptr_t' type.
+struct UIntPtrType {};
+
+//! Function builder 'float' type.
+struct FloatType {};
+//! Function builder 'double' type.
+struct DoubleType {};
+
+#if !defined(ASMJIT_DOCGEN)
+template
+struct TypeId {
+ // Left empty to report any type, which is not known to asmjit.
+};
+
+template
+struct TypeId {
+ enum { kId = kVarTypeIntPtr };
+};
+
+#define ASMJIT_TYPE_ID(_T_, _Id_) \
+ template<> \
+ struct TypeId<_T_> { enum { kId = _Id_ }; }
+
+ASMJIT_TYPE_ID(void , kInvalidVar);
+ASMJIT_TYPE_ID(char , IntTraits::kIsSigned ? kVarTypeInt8 : kVarTypeUInt8);
+ASMJIT_TYPE_ID(signed char , kVarTypeInt8);
+ASMJIT_TYPE_ID(unsigned char, kVarTypeUInt8);
+ASMJIT_TYPE_ID(int16_t , kVarTypeInt16);
+ASMJIT_TYPE_ID(uint16_t , kVarTypeUInt16);
+ASMJIT_TYPE_ID(int32_t , kVarTypeInt32);
+ASMJIT_TYPE_ID(uint32_t , kVarTypeUInt32);
+ASMJIT_TYPE_ID(int64_t , kVarTypeInt64);
+ASMJIT_TYPE_ID(uint64_t , kVarTypeUInt64);
+ASMJIT_TYPE_ID(float , kVarTypeFp32);
+ASMJIT_TYPE_ID(double , kVarTypeFp64);
+
+ASMJIT_TYPE_ID(Void , kInvalidVar);
+ASMJIT_TYPE_ID(Int8Type , kVarTypeInt8);
+ASMJIT_TYPE_ID(UInt8Type , kVarTypeUInt8);
+ASMJIT_TYPE_ID(Int16Type , kVarTypeInt16);
+ASMJIT_TYPE_ID(UInt16Type , kVarTypeUInt16);
+ASMJIT_TYPE_ID(Int32Type , kVarTypeUInt32);
+ASMJIT_TYPE_ID(UInt32Type , kVarTypeUInt32);
+ASMJIT_TYPE_ID(Int64Type , kVarTypeUInt64);
+ASMJIT_TYPE_ID(UInt64Type , kVarTypeUInt64);
+ASMJIT_TYPE_ID(FloatType , kVarTypeFp32);
+ASMJIT_TYPE_ID(DoubleType , kVarTypeFp64);
+#endif // !ASMJIT_DOCGEN
+
+// ============================================================================
+// [asmjit::FuncInOut]
+// ============================================================================
+
+//! Function in/out - argument or return value translated from `FuncPrototype`.
+struct FuncInOut {
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE uint32_t getVarType() const { return _varType; }
+
+ ASMJIT_INLINE bool hasRegIndex() const { return _regIndex != kInvalidReg; }
+ ASMJIT_INLINE uint32_t getRegIndex() const { return _regIndex; }
+
+ ASMJIT_INLINE bool hasStackOffset() const { return _stackOffset != kFuncStackInvalid; }
+ ASMJIT_INLINE int32_t getStackOffset() const { return static_cast(_stackOffset); }
+
+ //! Get whether the argument / return value is assigned.
+ ASMJIT_INLINE bool isSet() const {
+ return (_regIndex != kInvalidReg) | (_stackOffset != kFuncStackInvalid);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Reset]
+ // --------------------------------------------------------------------------
+
+ //! Reset the function argument to "unassigned state".
+ ASMJIT_INLINE void reset() { _packed = 0xFFFFFFFF; }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ union {
+ struct {
+ //! Variable type, see `VarType`.
+ uint8_t _varType;
+ //! Register index if argument / return value is a register.
+ uint8_t _regIndex;
+ //! Stack offset if argument / return value is on the stack.
+ int16_t _stackOffset;
+ };
+
+ //! All members packed into single 32-bit integer.
+ uint32_t _packed;
+ };
+};
+
+// ============================================================================
+// [asmjit::FuncPrototype]
+// ============================================================================
+
+//! Function prototype.
+//!
+//! Function prototype contains information about function return type, count
+//! of arguments and their types. Function prototype is a low level structure
+//! which doesn't contain platform specific or calling convention specific
+//! information. Function prototype is used to create a `FuncDecl`.
+struct FuncPrototype {
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get function return value.
+ ASMJIT_INLINE uint32_t getRet() const { return _ret; }
+
+ //! Get function arguments' IDs.
+ ASMJIT_INLINE const uint32_t* getArgList() const { return _argList; }
+ //! Get count of function arguments.
+ ASMJIT_INLINE uint32_t getArgCount() const { return _argCount; }
+
+ //! Get argument at index `id`.
+ ASMJIT_INLINE uint32_t getArg(uint32_t id) const {
+ ASMJIT_ASSERT(id < _argCount);
+ return _argList[id];
+ }
+
+ //! Set function definition - return type and arguments.
+ ASMJIT_INLINE void _setPrototype(uint32_t ret, const uint32_t* argList, uint32_t argCount) {
+ _ret = ret;
+ _argList = argList;
+ _argCount = argCount;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ uint32_t _ret;
+ uint32_t _argCount;
+ const uint32_t* _argList;
+};
+
+// ============================================================================
+// [asmjit::FuncBuilderX]
+// ============================================================================
+
+//! Custom function builder for up to 32 function arguments.
+struct FuncBuilderX : public FuncPrototype {
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE FuncBuilderX() {
+ _setPrototype(kInvalidVar, _builderArgList, 0);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Set return type to `retType`.
+ ASMJIT_INLINE void setRet(uint32_t retType) {
+ _ret = retType;
+ }
+
+ ASMJIT_INLINE void setArg(uint32_t id, uint32_t type) {
+ ASMJIT_ASSERT(id < _argCount);
+ _builderArgList[id] = type;
+ }
+
+ ASMJIT_INLINE void addArg(uint32_t type) {
+ ASMJIT_ASSERT(_argCount < kFuncArgCount);
+ _builderArgList[_argCount++] = type;
+ }
+
+ template
+ ASMJIT_INLINE void setRetT() {
+ setRet(TypeId::kId);
+ }
+
+ template
+ ASMJIT_INLINE void setArgT(uint32_t id) {
+ setArg(id, TypeId::kId);
+ }
+
+ template
+ ASMJIT_INLINE void addArgT() {
+ addArg(TypeId::kId);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ uint32_t _builderArgList[kFuncArgCount];
+};
+
+//! \internal
+#define T(_Type_) TypeId<_Type_>::kId
+
+//! Function prototype (no args).
+template
+struct FuncBuilder0 : public FuncPrototype {
+ ASMJIT_INLINE FuncBuilder0() {
+ _setPrototype(T(RET), NULL, 0);
+ }
+};
+
+//! Function prototype (1 argument).
+template
+struct FuncBuilder1 : public FuncPrototype {
+ ASMJIT_INLINE FuncBuilder1() {
+ static const uint32_t args[] = { T(P0) };
+ _setPrototype(T(RET), args, ASMJIT_ARRAY_SIZE(args));
+ }
+};
+
+//! Function prototype (2 arguments).
+template
+struct FuncBuilder2 : public FuncPrototype {
+ ASMJIT_INLINE FuncBuilder2() {
+ static const uint32_t args[] = { T(P0), T(P1) };
+ _setPrototype(T(RET), args, ASMJIT_ARRAY_SIZE(args));
+ }
+};
+
+//! Function prototype (3 arguments).
+template
+struct FuncBuilder3 : public FuncPrototype {
+ ASMJIT_INLINE FuncBuilder3() {
+ static const uint32_t args[] = { T(P0), T(P1), T(P2) };
+ _setPrototype(T(RET), args, ASMJIT_ARRAY_SIZE(args));
+ }
+};
+
+//! Function prototype (4 arguments).
+template
+struct FuncBuilder4 : public FuncPrototype {
+ ASMJIT_INLINE FuncBuilder4() {
+ static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3) };
+ _setPrototype(T(RET), args, ASMJIT_ARRAY_SIZE(args));
+ }
+};
+
+//! Function prototype (5 arguments).
+template
+struct FuncBuilder5 : public FuncPrototype {
+ ASMJIT_INLINE FuncBuilder5() {
+ static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4) };
+ _setPrototype(T(RET), args, ASMJIT_ARRAY_SIZE(args));
+ }
+};
+
+//! Function prototype (6 arguments).
+template
+struct FuncBuilder6 : public FuncPrototype {
+ ASMJIT_INLINE FuncBuilder6() {
+ static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5) };
+ _setPrototype(T(RET), args, ASMJIT_ARRAY_SIZE(args));
+ }
+};
+
+//! Function prototype (7 arguments).
+template
+struct FuncBuilder7 : public FuncPrototype {
+ ASMJIT_INLINE FuncBuilder7() {
+ static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6) };
+ _setPrototype(T(RET), args, ASMJIT_ARRAY_SIZE(args));
+ }
+};
+
+//! Function prototype (8 arguments).
+template
+struct FuncBuilder8 : public FuncPrototype {
+ ASMJIT_INLINE FuncBuilder8() {
+ static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6), T(P7) };
+ _setPrototype(T(RET), args, ASMJIT_ARRAY_SIZE(args));
+ }
+};
+
+//! Function prototype (9 arguments).
+template
+struct FuncBuilder9 : public FuncPrototype {
+ ASMJIT_INLINE FuncBuilder9() {
+ static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6), T(P7), T(P8) };
+ _setPrototype(T(RET), args, ASMJIT_ARRAY_SIZE(args));
+ }
+};
+
+//! Function prototype (10 arguments).
+template
+struct FuncBuilder10 : public FuncPrototype {
+ ASMJIT_INLINE FuncBuilder10() {
+ static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6), T(P7), T(P8), T(P9) };
+ _setPrototype(T(RET), args, ASMJIT_ARRAY_SIZE(args));
+ }
+};
+
+#undef T
+
+// ============================================================================
+// [asmjit::FuncDecl]
+// ============================================================================
+
+//! Function declaration.
+struct FuncDecl {
+ // --------------------------------------------------------------------------
+ // [Accessors - Calling Convention]
+ // --------------------------------------------------------------------------
+
+ //! Get function calling convention, see `FuncConv`.
+ ASMJIT_INLINE uint32_t getConvention() const { return _convention; }
+
+ //! Get whether the callee pops the stack.
+ ASMJIT_INLINE uint32_t getCalleePopsStack() const { return _calleePopsStack; }
+
+ //! Get direction of arguments passed on the stack.
+ //!
+ //! Direction should be always `kFuncDirRtl`.
+ //!
+ //! \note This is related to used calling convention, it's not affected by
+ //! number of function arguments or their types.
+ ASMJIT_INLINE uint32_t getDirection() const { return _direction; }
+
+ //! Get stack size needed for function arguments passed on the stack.
+ ASMJIT_INLINE uint32_t getArgStackSize() const { return _argStackSize; }
+ //! Get size of "Red Zone".
+ ASMJIT_INLINE uint32_t getRedZoneSize() const { return _redZoneSize; }
+ //! Get size of "Spill Zone".
+ ASMJIT_INLINE uint32_t getSpillZoneSize() const { return _spillZoneSize; }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - Arguments and Return]
+ // --------------------------------------------------------------------------
+
+ //! Get whether the function has a return value.
+ ASMJIT_INLINE bool hasRet() const { return _retCount != 0; }
+ //! Get count of function return values.
+ ASMJIT_INLINE uint32_t getRetCount() const { return _retCount; }
+
+ //! Get function return value.
+ ASMJIT_INLINE FuncInOut& getRet(uint32_t index = kFuncRetLo) { return _retList[index]; }
+ //! Get function return value.
+ ASMJIT_INLINE const FuncInOut& getRet(uint32_t index = kFuncRetLo) const { return _retList[index]; }
+
+ //! Get count of function arguments.
+ ASMJIT_INLINE uint32_t getArgCount() const { return _argCount; }
+
+ //! Get function arguments array.
+ ASMJIT_INLINE FuncInOut* getArgList() { return _argList; }
+ //! Get function arguments array (const).
+ ASMJIT_INLINE const FuncInOut* getArgList() const { return _argList; }
+
+ //! Get function argument at index `index`.
+ ASMJIT_INLINE FuncInOut& getArg(size_t index) {
+ ASMJIT_ASSERT(index < kFuncArgCountLoHi);
+ return _argList[index];
+ }
+
+ //! Get function argument at index `index`.
+ ASMJIT_INLINE const FuncInOut& getArg(size_t index) const {
+ ASMJIT_ASSERT(index < kFuncArgCountLoHi);
+ return _argList[index];
+ }
+
+ ASMJIT_INLINE void resetArg(size_t index) {
+ ASMJIT_ASSERT(index < kFuncArgCountLoHi);
+ _argList[index].reset();
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Calling convention.
+ uint8_t _convention;
+ //! Whether a callee pops stack.
+ uint8_t _calleePopsStack : 1;
+ //! Direction for arguments passed on the stack, see `FuncDir`.
+ uint8_t _direction : 1;
+ //! Reserved #0 (alignment).
+ uint8_t _reserved0 : 6;
+
+ //! Count of arguments in `_argList`.
+ uint8_t _argCount;
+ //! Count of return value(s).
+ uint8_t _retCount;
+
+ //! Count of bytes consumed by arguments on the stack (aligned).
+ uint32_t _argStackSize;
+
+ //! Size of "Red Zone".
+ //!
+ //! \note Used by AMD64-ABI (128 bytes).
+ uint16_t _redZoneSize;
+
+ //! Size of "Spill Zone".
+ //!
+ //! \note Used by WIN64-ABI (32 bytes).
+ uint16_t _spillZoneSize;
+
+ //! Function arguments (including HI arguments) mapped to physical
+ //! registers and stack offset.
+ FuncInOut _argList[kFuncArgCountLoHi];
+
+ //! Function return value(s).
+ FuncInOut _retList[2];
+};
+
+// ============================================================================
+// [asmjit::Node]
+// ============================================================================
+
+//! Base node.
+//!
+//! `Every` node represents an abstract instruction, directive, label, or
+//! macro-instruction generated by compiler.
+struct Node {
+ ASMJIT_NO_COPY(Node)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create new `Node`.
+ //!
+ //! \note Always use compiler to create nodes.
+ ASMJIT_INLINE Node(Compiler* compiler, uint32_t type); // Defined-Later.
+
+ //! Destroy `Node`.
+ ASMJIT_INLINE ~Node() {}
+
+ // --------------------------------------------------------------------------
+ // [Accessors - List]
+ // --------------------------------------------------------------------------
+
+ //! Get previous node in the compiler stream.
+ ASMJIT_INLINE Node* getPrev() const {
+ return _prev;
+ }
+
+ //! Get next node in the compiler stream.
+ ASMJIT_INLINE Node* getNext() const {
+ return _next;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - Comment]
+ // --------------------------------------------------------------------------
+
+ //! Get comment string.
+ ASMJIT_INLINE const char* getComment() const {
+ return _comment;
+ }
+
+ //! Set comment string to `str`.
+ ASMJIT_INLINE void setComment(const char* comment) {
+ _comment = comment;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - Type and Flags]
+ // --------------------------------------------------------------------------
+
+ //! Get node type, see `NodeType`.
+ ASMJIT_INLINE uint32_t getType() const {
+ return _type;
+ }
+
+ //! Get node flags.
+ ASMJIT_INLINE uint32_t getFlags() const {
+ return _flags;
+ }
+
+ //! Get whether the instruction has flag `flag`.
+ ASMJIT_INLINE bool hasFlag(uint32_t flag) const {
+ return (static_cast(_flags) & flag) != 0;
+ }
+
+ //! Set node flags to `flags`.
+ ASMJIT_INLINE void setFlags(uint32_t flags) {
+ _flags = static_cast(flags);
+ }
+
+ //! Add instruction `flags`.
+ ASMJIT_INLINE void orFlags(uint32_t flags) {
+ _flags |= static_cast(flags);
+ }
+
+ //! And instruction `flags`.
+ ASMJIT_INLINE void andFlags(uint32_t flags) {
+ _flags &= static_cast(flags);
+ }
+
+ //! Clear instruction `flags`.
+ ASMJIT_INLINE void andNotFlags(uint32_t flags) {
+ _flags &= ~static_cast(flags);
+ }
+
+ //! Get whether the node has beed fetched.
+ ASMJIT_INLINE bool isFetched() const {
+ return _flowId != 0;
+ }
+
+ //! Get whether the node has been translated.
+ ASMJIT_INLINE bool isTranslated() const {
+ return hasFlag(kNodeFlagIsTranslated);
+ }
+
+ //! Get whether the node has been translated.
+ ASMJIT_INLINE bool isScheduled() const {
+ return hasFlag(kNodeFlagIsScheduled);
+ }
+
+ //! Get whether the node is informative only and can be safely removed after
+ //! translation.
+ //!
+ //! Informative nodes are comments and hints.
+ ASMJIT_INLINE bool isInformative() const {
+ return hasFlag(kNodeFlagIsInformative);
+ }
+
+ //! Whether the node is `InstNode` and unconditional jump.
+ ASMJIT_INLINE bool isJmp() const { return hasFlag(kNodeFlagIsJmp); }
+ //! Whether the node is `InstNode` and conditional jump.
+ ASMJIT_INLINE bool isJcc() const { return hasFlag(kNodeFlagIsJcc); }
+ //! Whether the node is `InstNode` and conditional/unconditional jump.
+ ASMJIT_INLINE bool isJmpOrJcc() const { return hasFlag(kNodeFlagIsJmp | kNodeFlagIsJcc); }
+ //! Whether the node is `InstNode` and return.
+ ASMJIT_INLINE bool isRet() const { return hasFlag(kNodeFlagIsRet); }
+
+ //! Get whether the node is `InstNode` and the instruction is special.
+ ASMJIT_INLINE bool isSpecial() const { return hasFlag(kNodeFlagIsSpecial); }
+ //! Get whether the node is `InstNode` and the instruction uses x87-FPU.
+ ASMJIT_INLINE bool isFp() const { return hasFlag(kNodeFlagIsFp); }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - FlowId]
+ // --------------------------------------------------------------------------
+
+ //! Get flow index.
+ ASMJIT_INLINE uint32_t getFlowId() const { return _flowId; }
+ //! Set flow index.
+ ASMJIT_INLINE void setFlowId(uint32_t flowId) { _flowId = flowId; }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - VarMap]
+ // --------------------------------------------------------------------------
+
+ //! Get whether node contains variable allocation instructions.
+ ASMJIT_INLINE bool hasMap() const {
+ return _map != NULL;
+ }
+
+ //! Get variable allocation instructions.
+ ASMJIT_INLINE VarMap* getMap() const {
+ return _map;
+ }
+
+ //! Get variable allocation instructions casted to `T*`.
+ template
+ ASMJIT_INLINE T* getMap() const {
+ return static_cast(_map);
+ }
+
+ //! Set variable allocation instructions.
+ ASMJIT_INLINE void setMap(VarMap* map) {
+ _map = map;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - VarState]
+ // --------------------------------------------------------------------------
+
+ //! Get node state.
+ ASMJIT_INLINE VarState* getState() const {
+ return _state;
+ }
+
+ //! Get node state casted to `T*`.
+ template
+ ASMJIT_INLINE T* getState() const {
+ return static_cast(_state);
+ }
+
+ //! Set node state.
+ ASMJIT_INLINE void setState(VarState* state) {
+ _state = state;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Accessors - Liveness]
+ // --------------------------------------------------------------------------
+
+ //! Get whether the node has variable liveness bits.
+ ASMJIT_INLINE bool hasLiveness() const {
+ return _liveness != NULL;
+ }
+
+ //! Get variable liveness bits.
+ ASMJIT_INLINE VarBits* getLiveness() const {
+ return _liveness;
+ }
+
+ //! Set variable liveness bits.
+ ASMJIT_INLINE void setLiveness(VarBits* liveness) {
+ _liveness = liveness;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Previous node.
+ Node* _prev;
+ //! Next node.
+ Node* _next;
+
+ //! Node type, see `NodeType`.
+ uint8_t _type;
+ //! Operands count (if the node has operands, otherwise zero).
+ uint8_t _opCount;
+ //! Node flags, different meaning for every node type.
+ uint16_t _flags;
+
+ //! Flow index.
+ uint32_t _flowId;
+
+ //! Inline comment string, initially set to NULL.
+ const char* _comment;
+
+ //! Variable mapping (VarAttr to VarData), initially NULL, filled during
+ //! fetch phase.
+ VarMap* _map;
+
+ //! Variable liveness bits (initially NULL, filled by analysis phase).
+ VarBits* _liveness;
+
+ //! Saved state.
+ //!
+ //! Initially NULL, not all nodes have saved state, only branch/flow control
+ //! nodes.
+ VarState* _state;
+};
+
+// ============================================================================
+// [asmjit::AlignNode]
+// ============================================================================
+
+//! Align node.
+struct AlignNode : public Node {
+ ASMJIT_NO_COPY(AlignNode)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `AlignNode` instance.
+ ASMJIT_INLINE AlignNode(Compiler* compiler, uint32_t mode, uint32_t offset) :
+ Node(compiler, kNodeTypeAlign) {
+
+ _mode = mode;
+ _offset = offset;
+ }
+
+ //! Destroy the `AlignNode` instance.
+ ASMJIT_INLINE ~AlignNode() {}
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get alignment mode.
+ ASMJIT_INLINE uint32_t getMode() const {
+ return _mode;
+ }
+
+ //! Set alignment mode.
+ ASMJIT_INLINE void setMode(uint32_t mode) {
+ _mode = mode;
+ }
+
+ //! Get align offset in bytes.
+ ASMJIT_INLINE uint32_t getOffset() const {
+ return _offset;
+ }
+
+ //! Set align offset in bytes to `offset`.
+ ASMJIT_INLINE void setOffset(uint32_t offset) {
+ _offset = offset;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Alignment mode, see \ref AlignMode.
+ uint32_t _mode;
+ //! Alignment offset in bytes.
+ uint32_t _offset;
+};
+
+// ============================================================================
+// [asmjit::EmbedNode]
+// ============================================================================
+
+//! Embed node.
+//!
+//! Embed node is used to embed data into final assembler stream. The data is
+//! considered to be RAW; No analysis is performed on RAW data.
+struct EmbedNode : public Node {
+ ASMJIT_NO_COPY(EmbedNode)
+
+ // --------------------------------------------------------------------------
+ // [Enums]
+ // --------------------------------------------------------------------------
+
+ enum { kInlineBufferSize = 8 };
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `EmbedNode` instance.
+ ASMJIT_INLINE EmbedNode(Compiler* compiler, void* data, uint32_t size) :
+ Node(compiler, kNodeTypeEmbed) {
+
+ _size = size;
+ if (size <= kInlineBufferSize) {
+ if (data != NULL)
+ ::memcpy(_data.buf, data, size);
+ }
+ else {
+ _data.ptr = static_cast(data);
+ }
+ }
+
+ //! Destroy the `EmbedNode` instance.
+ ASMJIT_INLINE ~EmbedNode() {}
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get pointer to data.
+ uint8_t* getData() { return getSize() <= kInlineBufferSize ? const_cast(_data.buf) : _data.ptr; }
+ //! Get size of data.
+ uint32_t getSize() const { return _size; }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Size of the embedded data.
+ uint32_t _size;
+
+ union {
+ //! data buffer.
+ uint8_t buf[kInlineBufferSize];
+ //! Data buffer.
+ uint8_t* ptr;
+ } _data;
+};
+
+// ============================================================================
+// [asmjit::CommentNode]
+// ============================================================================
+
+//! Comment node.
+//!
+//! Comments allows to comment your assembler stream for better debugging
+//! and visualization. Comments are usually ignored in release builds unless
+//! the logger is present.
+struct CommentNode : public Node {
+ ASMJIT_NO_COPY(CommentNode)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `CommentNode` instance.
+ ASMJIT_INLINE CommentNode(Compiler* compiler, const char* comment) : Node(compiler, kNodeTypeComment) {
+ orFlags(kNodeFlagIsInformative);
+ _comment = comment;
+ }
+
+ //! Destroy the `CommentNode` instance.
+ ASMJIT_INLINE ~CommentNode() {}
+};
+
+// ============================================================================
+// [asmjit::HintNode]
+// ============================================================================
+
+//! Hint node.
+struct HintNode : public Node {
+ ASMJIT_NO_COPY(HintNode)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `HintNode` instance.
+ ASMJIT_INLINE HintNode(Compiler* compiler, VarData* vd, uint32_t hint, uint32_t value) :
+ Node(compiler, kNodeTypeHint) {
+
+ orFlags(kNodeFlagIsInformative);
+ _vd = vd;
+ _hint = hint;
+ _value = value;
+ }
+
+ //! Destroy the `HintNode` instance.
+ ASMJIT_INLINE ~HintNode() {}
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get variable.
+ ASMJIT_INLINE VarData* getVd() const { return _vd; }
+
+ //! Get hint it (see `kVarHint)`.
+ ASMJIT_INLINE uint32_t getHint() const{ return _hint; }
+ //! Set hint it (see `kVarHint)`.
+ ASMJIT_INLINE void setHint(uint32_t hint) { _hint = hint; }
+
+ //! Get hint value.
+ ASMJIT_INLINE uint32_t getValue() const { return _value; }
+ //! Set hint value.
+ ASMJIT_INLINE void setValue(uint32_t value) { _value = value; }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Variable.
+ VarData* _vd;
+ //! Hint id.
+ uint32_t _hint;
+ //! Value.
+ uint32_t _value;
+};
+
+// ============================================================================
+// [asmjit::TargetNode]
+// ============================================================================
+
+//! label node.
+struct TargetNode : public Node {
+ ASMJIT_NO_COPY(TargetNode)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `TargetNode` instance.
+ ASMJIT_INLINE TargetNode(Compiler* compiler, uint32_t labelId) : Node(compiler, kNodeTypeTarget) {
+ _id = labelId;
+ _numRefs = 0;
+ _offset = -1;
+ _from = NULL;
+ }
+
+ //! Destroy the `TargetNode` instance.
+ ASMJIT_INLINE ~TargetNode() {}
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get target label.
+ ASMJIT_INLINE Label getLabel() const { return Label(_id); }
+ //! Get target label id.
+ ASMJIT_INLINE uint32_t getLabelId() const { return _id; }
+
+ //! Get first jmp instruction.
+ ASMJIT_INLINE JumpNode* getFrom() const { return _from; }
+
+ //! Get whether the node has assigned state.
+ ASMJIT_INLINE bool hasState() const { return _state != NULL; }
+ //! Get state for this target.
+ ASMJIT_INLINE VarState* getState() const { return _state; }
+ //! Set state for this target.
+ ASMJIT_INLINE void setState(VarState* state) { _state = state; }
+
+ //! Get number of jumps to this target.
+ ASMJIT_INLINE uint32_t getNumRefs() const { return _numRefs; }
+ //! Set number of jumps to this target.
+ ASMJIT_INLINE void setNumRefs(uint32_t i) { _numRefs = i; }
+
+ //! Add number of jumps to this target.
+ ASMJIT_INLINE void addNumRefs(uint32_t i = 1) { _numRefs += i; }
+ //! Subtract number of jumps to this target.
+ ASMJIT_INLINE void subNumRefs(uint32_t i = 1) { _numRefs -= i; }
+
+ //! Get the label offset.
+ //!
+ //! \note Only valid after the content has been serialized to the `Assembler`.
+ ASMJIT_INLINE intptr_t getOffset() const { return _offset; }
+
+ //! Set the label offset.
+ ASMJIT_INLINE void setOffset(intptr_t offset) { _offset = offset; }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Label id.
+ uint32_t _id;
+ //! Count of jumps here.
+ uint32_t _numRefs;
+
+ //! Label offset, after serialization.
+ intptr_t _offset;
+ //! First jump instruction that points to this target (label).
+ JumpNode* _from;
+};
+
+// ============================================================================
+// [asmjit::InstNode]
+// ============================================================================
+
+//! Instruction node.
+struct InstNode : public Node {
+ ASMJIT_NO_COPY(InstNode)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `InstNode` instance.
+ ASMJIT_INLINE InstNode(Compiler* compiler, uint32_t instId, uint32_t instOptions, Operand* opList, uint32_t opCount) :
+ Node(compiler, kNodeTypeInst) {
+
+ _instId = static_cast(instId);
+ _reserved = 0;
+ _instOptions = instOptions;
+
+ _opCount = static_cast(opCount);
+ _opList = opList;
+
+ _updateMemOp();
+ }
+
+ //! Destroy the `InstNode` instance.
+ ASMJIT_INLINE ~InstNode() {}
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get instruction ID, see `X86InstId`.
+ ASMJIT_INLINE uint32_t getInstId() const {
+ return _instId;
+ }
+
+ //! Set instruction ID to `instId`.
+ //!
+ //! Please do not modify instruction code if you don't know what are you
+ //! doing. Incorrect instruction code or operands can cause assertion failure.
+ ASMJIT_INLINE void setInstId(uint32_t instId) {
+ _instId = static_cast(instId);
+ }
+
+ //! Whether the instruction is an unconditional jump or whether the
+ //! instruction is a conditional jump which is likely to be taken.
+ ASMJIT_INLINE bool isTaken() const {
+ return hasFlag(kNodeFlagIsTaken);
+ }
+
+ //! Get emit options.
+ ASMJIT_INLINE uint32_t getOptions() const {
+ return _instOptions;
+ }
+ //! Set emit options.
+ ASMJIT_INLINE void setOptions(uint32_t options) {
+ _instOptions = options;
+ }
+ //! Add emit options.
+ ASMJIT_INLINE void addOptions(uint32_t options) {
+ _instOptions |= options;
+ }
+ //! Mask emit options.
+ ASMJIT_INLINE void andOptions(uint32_t options) {
+ _instOptions &= options;
+ }
+ //! Clear emit options.
+ ASMJIT_INLINE void delOptions(uint32_t options) {
+ _instOptions &= ~options;
+ }
+
+ //! Get operands list.
+ ASMJIT_INLINE Operand* getOpList() {
+ return _opList;
+ }
+ //! \overload
+ ASMJIT_INLINE const Operand* getOpList() const {
+ return _opList;
+ }
+
+ //! Get operands count.
+ ASMJIT_INLINE uint32_t getOpCount() const {
+ return _opCount;
+ }
+
+ //! Get whether the instruction contains a memory operand.
+ ASMJIT_INLINE bool hasMemOp() const {
+ return _memOpIndex != 0xFF;
+ }
+
+ //! Set memory operand index (in opList), 0xFF means that instruction
+ //! doesn't have a memory operand.
+ ASMJIT_INLINE void setMemOpIndex(uint32_t index) {
+ _memOpIndex = static_cast(index);
+ }
+ //! Reset memory operand index, setting it to 0xFF.
+ ASMJIT_INLINE void resetMemOpIndex() {
+ _memOpIndex = 0xFF;
+ }
+
+ //! Get memory operand.
+ //!
+ //! Can only be called if the instruction has such operand, see `hasMemOp()`.
+ ASMJIT_INLINE BaseMem* getMemOp() const {
+ ASMJIT_ASSERT(hasMemOp());
+ return static_cast(&_opList[_memOpIndex]);
+ }
+
+ //! \overload
+ template
+ ASMJIT_INLINE T* getMemOp() const {
+ ASMJIT_ASSERT(hasMemOp());
+ return static_cast(&_opList[_memOpIndex]);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Utils]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE void _updateMemOp() {
+ Operand* opList = getOpList();
+ uint32_t opCount = getOpCount();
+
+ uint32_t i;
+ for (i = 0; i < opCount; i++)
+ if (opList[i].isMem())
+ goto _Update;
+ i = 0xFF;
+
+_Update:
+ setMemOpIndex(i);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Instruction ID, see `InstId`.
+ uint16_t _instId;
+ //! \internal
+ uint8_t _memOpIndex;
+ //! \internal
+ uint8_t _reserved;
+ //! Instruction options, see `InstOptions`.
+ uint32_t _instOptions;
+
+ //! Operands list.
+ Operand* _opList;
+};
+
+// ============================================================================
+// [asmjit::JumpNode]
+// ============================================================================
+
+//! Jump node.
+struct JumpNode : public InstNode {
+ ASMJIT_NO_COPY(JumpNode)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE JumpNode(Compiler* compiler, uint32_t code, uint32_t options, Operand* opList, uint32_t opCount) :
+ InstNode(compiler, code, options, opList, opCount) {}
+ ASMJIT_INLINE ~JumpNode() {}
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE TargetNode* getTarget() const { return _target; }
+ ASMJIT_INLINE JumpNode* getJumpNext() const { return _jumpNext; }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Target node.
+ TargetNode* _target;
+ //! Next jump to the same target in a single linked-list.
+ JumpNode *_jumpNext;
+};
+
+// ============================================================================
+// [asmjit::FuncNode]
+// ============================================================================
+
+//! Function declaration node.
+//!
+//! Functions are base blocks for generating assembler output. Each generated
+//! assembler stream needs standard entry and leave sequences which are compatible
+//! with the operating system ABI.
+//!
+//! `FuncNode` can be used to generate function prolog and epilog which are
+//! compatible with a given function calling convention and to allocate and
+//! manage variables that can be allocated/spilled during compilation phase.
+struct FuncNode : public Node {
+ ASMJIT_NO_COPY(FuncNode)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `FuncNode` instance.
+ //!
+ //! Always use `Compiler::addFunc()` to create a `FuncNode` instance.
+ ASMJIT_INLINE FuncNode(Compiler* compiler) :
+ Node(compiler, kNodeTypeFunc),
+ _entryNode(NULL),
+ _exitNode(NULL),
+ _decl(NULL),
+ _end(NULL),
+ _argList(NULL),
+ _funcHints(IntUtil::mask(kFuncHintNaked)),
+ _funcFlags(0),
+ _expectedStackAlignment(0),
+ _requiredStackAlignment(0),
+ _redZoneSize(0),
+ _spillZoneSize(0),
+ _argStackSize(0),
+ _memStackSize(0),
+ _callStackSize(0) {}
+
+ //! Destroy the `FuncNode` instance.
+ ASMJIT_INLINE ~FuncNode() {}
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get function entry `TargetNode`.
+ ASMJIT_INLINE TargetNode* getEntryNode() const { return _entryNode; }
+ //! Get function exit `TargetNode`.
+ ASMJIT_INLINE TargetNode* getExitNode() const { return _exitNode; }
+
+ //! Get function entry label.
+ ASMJIT_INLINE Label getEntryLabel() const { return _entryNode->getLabel(); }
+ //! Get function exit label.
+ ASMJIT_INLINE Label getExitLabel() const { return _exitNode->getLabel(); }
+
+ //! Get function `EndNode`.
+ ASMJIT_INLINE EndNode* getEnd() const { return _end; }
+ //! Get function declaration.
+ ASMJIT_INLINE FuncDecl* getDecl() const { return _decl; }
+
+ //! Get arguments list.
+ ASMJIT_INLINE VarData** getArgList() const { return _argList; }
+ //! Get arguments count.
+ ASMJIT_INLINE uint32_t getArgCount() const { return _decl->getArgCount(); }
+
+ //! Get argument at `i`.
+ ASMJIT_INLINE VarData* getArg(uint32_t i) const {
+ ASMJIT_ASSERT(i < getArgCount());
+ return _argList[i];
+ }
+
+ //! Set argument at `i`.
+ ASMJIT_INLINE void setArg(uint32_t i, VarData* vd) {
+ ASMJIT_ASSERT(i < getArgCount());
+ _argList[i] = vd;
+ }
+
+ //! Reset argument at `i`.
+ ASMJIT_INLINE void resetArg(uint32_t i) {
+ ASMJIT_ASSERT(i < getArgCount());
+ _argList[i] = NULL;
+ }
+
+ //! Get function hints.
+ ASMJIT_INLINE uint32_t getFuncHints() const { return _funcHints; }
+ //! Get function flags.
+ ASMJIT_INLINE uint32_t getFuncFlags() const { return _funcFlags; }
+
+ //! Get whether the _funcFlags has `flag`
+ ASMJIT_INLINE bool hasFuncFlag(uint32_t flag) const { return (_funcFlags & flag) != 0; }
+ //! Set function `flag`.
+ ASMJIT_INLINE void addFuncFlags(uint32_t flags) { _funcFlags |= flags; }
+ //! Clear function `flag`.
+ ASMJIT_INLINE void clearFuncFlags(uint32_t flags) { _funcFlags &= ~flags; }
+
+ //! Get whether the function is naked.
+ ASMJIT_INLINE bool isNaked() const { return hasFuncFlag(kFuncFlagIsNaked); }
+ //! Get whether the function is also a caller.
+ ASMJIT_INLINE bool isCaller() const { return hasFuncFlag(kFuncFlagIsCaller); }
+ //! Get whether the required stack alignment is lower than expected one,
+ //! thus it has to be aligned manually.
+ ASMJIT_INLINE bool isStackMisaligned() const { return hasFuncFlag(kFuncFlagIsStackMisaligned); }
+ //! Get whether the stack pointer is adjusted inside function prolog/epilog.
+ ASMJIT_INLINE bool isStackAdjusted() const { return hasFuncFlag(kFuncFlagIsStackAdjusted); }
+
+ //! Get whether the function is finished.
+ ASMJIT_INLINE bool isFinished() const { return hasFuncFlag(kFuncFlagIsFinished); }
+
+ //! Get expected stack alignment.
+ ASMJIT_INLINE uint32_t getExpectedStackAlignment() const { return _expectedStackAlignment; }
+ //! Set expected stack alignment.
+ ASMJIT_INLINE void setExpectedStackAlignment(uint32_t alignment) { _expectedStackAlignment = alignment; }
+
+ //! Get required stack alignment.
+ ASMJIT_INLINE uint32_t getRequiredStackAlignment() const { return _requiredStackAlignment; }
+ //! Set required stack alignment.
+ ASMJIT_INLINE void setRequiredStackAlignment(uint32_t alignment) { _requiredStackAlignment = alignment; }
+
+ //! Update required stack alignment so it's not lower than expected
+ //! stack alignment.
+ ASMJIT_INLINE void updateRequiredStackAlignment() {
+ if (_requiredStackAlignment <= _expectedStackAlignment) {
+ _requiredStackAlignment = _expectedStackAlignment;
+ clearFuncFlags(kFuncFlagIsStackMisaligned);
+ }
+ else {
+ addFuncFlags(kFuncFlagIsStackMisaligned);
+ }
+ }
+
+ //! Set stack "Red Zone" size.
+ ASMJIT_INLINE uint32_t getRedZoneSize() const { return _redZoneSize; }
+ //! Get stack "Red Zone" size.
+ ASMJIT_INLINE void setRedZoneSize(uint32_t s) { _redZoneSize = static_cast(s); }
+
+ //! Set stack "Spill Zone" size.
+ ASMJIT_INLINE uint32_t getSpillZoneSize() const { return _spillZoneSize; }
+ //! Get stack "Spill Zone" size.
+ ASMJIT_INLINE void setSpillZoneSize(uint32_t s) { _spillZoneSize = static_cast(s); }
+
+ //! Get stack size used by function arguments.
+ ASMJIT_INLINE uint32_t getArgStackSize() const { return _argStackSize; }
+
+ //! Get stack size used by variables and memory allocated on the stack.
+ ASMJIT_INLINE uint32_t getMemStackSize() const { return _memStackSize; }
+
+ //! Get stack size used by function calls.
+ ASMJIT_INLINE uint32_t getCallStackSize() const { return _callStackSize; }
+ //! Merge stack size used by function call with `s`.
+ ASMJIT_INLINE void mergeCallStackSize(uint32_t s) { if (_callStackSize < s) _callStackSize = s; }
+
+ // --------------------------------------------------------------------------
+ // [Hints]
+ // --------------------------------------------------------------------------
+
+ //! Set function hint.
+ ASMJIT_INLINE void setHint(uint32_t hint, uint32_t value) {
+ ASMJIT_ASSERT(hint <= 31);
+ ASMJIT_ASSERT(value <= 1);
+
+ _funcHints &= ~(1 << hint);
+ _funcHints |= (value << hint);
+ }
+
+ //! Get function hint.
+ ASMJIT_INLINE uint32_t getHint(uint32_t hint) const {
+ ASMJIT_ASSERT(hint <= 31);
+ return (_funcHints >> hint) & 0x1;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Function entry.
+ TargetNode* _entryNode;
+ //! Function exit.
+ TargetNode* _exitNode;
+
+ //! Function declaration.
+ FuncDecl* _decl;
+ //! Function end.
+ EndNode* _end;
+
+ //! Arguments list as `VarData`.
+ VarData** _argList;
+
+ //! Function hints;
+ uint32_t _funcHints;
+ //! Function flags.
+ uint32_t _funcFlags;
+
+ //! Expected stack alignment (we depend on this value).
+ //!
+ //! \note It can be global alignment given by the OS or described by an
+ //! target platform ABI.
+ uint32_t _expectedStackAlignment;
+ //! Required stack alignment (usually for multimedia instructions).
+ uint32_t _requiredStackAlignment;
+
+ //! The "Red Zone" size - count of bytes which might be accessed without
+ //! adjusting the stack pointer.
+ uint16_t _redZoneSize;
+ //! Spill zone size (used by WIN64 ABI).
+ uint16_t _spillZoneSize;
+
+ //! Stack size needed for function arguments.
+ uint32_t _argStackSize;
+ //! Stack size needed for all variables and memory allocated on the stack.
+ uint32_t _memStackSize;
+ //! Stack size needed to call other functions.
+ uint32_t _callStackSize;
+};
+
+// ============================================================================
+// [asmjit::EndNode]
+// ============================================================================
+
+//! End of function/block node.
+struct EndNode : public Node {
+ ASMJIT_NO_COPY(EndNode)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `EndNode` instance.
+ ASMJIT_INLINE EndNode(Compiler* compiler) : Node(compiler, kNodeTypeEnd) {
+ _flags |= kNodeFlagIsRet;
+ }
+
+ //! Destroy the `EndNode` instance.
+ ASMJIT_INLINE ~EndNode() {}
+};
+
+// ============================================================================
+// [asmjit::RetNode]
+// ============================================================================
+
+//! Function return node.
+struct RetNode : public Node {
+ ASMJIT_NO_COPY(RetNode)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `RetNode` instance.
+ ASMJIT_INLINE RetNode(Compiler* compiler, const Operand& o0, const Operand& o1) : Node(compiler, kNodeTypeRet) {
+ _flags |= kNodeFlagIsRet;
+ _ret[0] = o0;
+ _ret[1] = o1;
+ }
+
+ //! Destroy the `RetNode` instance.
+ ASMJIT_INLINE ~RetNode() {}
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get the first return operand.
+ ASMJIT_INLINE Operand& getFirst() { return _ret[0]; }
+ //! \overload
+ ASMJIT_INLINE const Operand& getFirst() const { return _ret[0]; }
+
+ //! Get the second return operand.
+ ASMJIT_INLINE Operand& getSecond() { return _ret[1]; }
+ //! \overload
+ ASMJIT_INLINE const Operand& getSecond() const { return _ret[1]; }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Ret operand(s).
+ Operand _ret[2];
+};
+
+// ============================================================================
+// [asmjit::CallNode]
+// ============================================================================
+
+//! Function-call node.
+struct CallNode : public Node {
+ ASMJIT_NO_COPY(CallNode)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `CallNode` instance.
+ ASMJIT_INLINE CallNode(Compiler* compiler, const Operand& target) :
+ Node(compiler, kNodeTypeCall),
+ _decl(NULL),
+ _target(target),
+ _args(NULL) {}
+
+ //! Destroy the `CallNode` instance.
+ ASMJIT_INLINE ~CallNode() {}
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get function declaration.
+ ASMJIT_INLINE FuncDecl* getDecl() const { return _decl; }
+
+ //! Get target operand.
+ ASMJIT_INLINE Operand& getTarget() { return _target; }
+ //! \overload
+ ASMJIT_INLINE const Operand& getTarget() const { return _target; }
+
+ //! Get return at `i`.
+ ASMJIT_INLINE Operand& getRet(uint32_t i = 0) {
+ ASMJIT_ASSERT(i < 2);
+ return _ret[i];
+ }
+ //! \overload
+ ASMJIT_INLINE const Operand& getRet(uint32_t i = 0) const {
+ ASMJIT_ASSERT(i < 2);
+ return _ret[i];
+ }
+
+ //! Get argument at `i`.
+ ASMJIT_INLINE Operand& getArg(uint32_t i) {
+ ASMJIT_ASSERT(i < kFuncArgCountLoHi);
+ return _args[i];
+ }
+ //! \overload
+ ASMJIT_INLINE const Operand& getArg(uint32_t i) const {
+ ASMJIT_ASSERT(i < kFuncArgCountLoHi);
+ return _args[i];
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Function declaration.
+ FuncDecl* _decl;
+
+ //! Target (address of function, register, label, ...).
+ Operand _target;
+ //! Return.
+ Operand _ret[2];
+ //! Arguments.
+ Operand* _args;
+};
+
+// ============================================================================
+// [asmjit::SArgNode]
+// ============================================================================
+
+//! Function-call 'argument on the stack' node.
+struct SArgNode : public Node {
+ ASMJIT_NO_COPY(SArgNode)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `SArgNode` instance.
+ ASMJIT_INLINE SArgNode(Compiler* compiler, CallNode* call, VarData* sVd, VarData* cVd) :
+ Node(compiler, kNodeTypeSArg),
+ _call(call),
+ _sVd(sVd),
+ _cVd(cVd),
+ _args(0) {}
+
+ //! Destroy the `SArgNode` instance.
+ ASMJIT_INLINE ~SArgNode() {}
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get the associated function-call.
+ ASMJIT_INLINE CallNode* getCall() const { return _call; }
+ //! Get source variable.
+ ASMJIT_INLINE VarData* getSVd() const { return _sVd; }
+ //! Get conversion variable.
+ ASMJIT_INLINE VarData* getCVd() const { return _cVd; }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Associated `CallNode`.
+ CallNode* _call;
+ //! Source variable.
+ VarData* _sVd;
+ //! Temporary variable used for conversion (or NULL).
+ VarData* _cVd;
+
+ //! Affected arguments bit-array.
+ uint32_t _args;
+};
+
+//! \}
+
+// ============================================================================
+// [asmjit::Compiler]
+// ============================================================================
+
+//! \addtogroup asmjit_base_general
+//! \{
+
+//! Base compiler.
+//!
+//! \sa Assembler.
+struct ASMJIT_VCLASS Compiler : public CodeGen {
+ ASMJIT_NO_COPY(Compiler)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `Compiler` instance.
+ ASMJIT_API Compiler(Runtime* runtime);
+ //! Destroy the `Compiler` instance.
+ ASMJIT_API virtual ~Compiler();
+
+ // --------------------------------------------------------------------------
+ // [LookAhead]
+ // --------------------------------------------------------------------------
+
+ //! Get maximum look ahead.
+ ASMJIT_INLINE uint32_t getMaxLookAhead() const {
+ return _maxLookAhead;
+ }
+
+ //! Set maximum look ahead to `val`.
+ ASMJIT_INLINE void setMaxLookAhead(uint32_t val) {
+ _maxLookAhead = val;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Clear / Reset]
+ // --------------------------------------------------------------------------
+
+ //! Reset the compiler.
+ //!
+ //! If `releaseMemory` is true all buffers will be released to the system.
+ ASMJIT_API void reset(bool releaseMemory = false);
+
+ // --------------------------------------------------------------------------
+ // [Nodes]
+ // --------------------------------------------------------------------------
+
+ template
+ ASMJIT_INLINE T* newNode() {
+ void* p = _baseZone.alloc(sizeof(T));
+ return new(p) T(this);
+ }
+
+ template
+ ASMJIT_INLINE T* newNode(P0 p0) {
+ void* p = _baseZone.alloc(sizeof(T));
+ return new(p) T(this, p0);
+ }
+
+ template
+ ASMJIT_INLINE T* newNode(P0 p0, P1 p1) {
+ void* p = _baseZone.alloc(sizeof(T));
+ return new(p) T(this, p0, p1);
+ }
+
+ template
+ ASMJIT_INLINE T* newNode(P0 p0, P1 p1, P2 p2) {
+ void* p = _baseZone.alloc(sizeof(T));
+ return new(p) T(this, p0, p1, p2);
+ }
+
+ //! Get first node.
+ ASMJIT_INLINE Node* getFirstNode() const { return _firstNode; }
+ //! Get last node.
+ ASMJIT_INLINE Node* getLastNode() const { return _lastNode; }
+
+ //! Get current node.
+ //!
+ //! \note If this method returns `NULL` it means that nothing has been emitted
+ //! yet.
+ ASMJIT_INLINE Node* getCursor() const { return _cursor; }
+ //! Set the current node without returning the previous node (private).
+ ASMJIT_INLINE void _setCursor(Node* node) { _cursor = node; }
+ //! Set the current node to `node` and return the previous one.
+ ASMJIT_API Node* setCursor(Node* node);
+
+ //! Add node `node` after current and set current to `node`.
+ ASMJIT_API Node* addNode(Node* node);
+ //! Add node before `ref`.
+ ASMJIT_API Node* addNodeBefore(Node* node, Node* ref);
+ //! Add node after `ref`.
+ ASMJIT_API Node* addNodeAfter(Node* node, Node* ref);
+ //! Remove node `node`.
+ ASMJIT_API Node* removeNode(Node* node);
+ //! Remove multiple nodes.
+ ASMJIT_API void removeNodes(Node* first, Node* last);
+
+ // --------------------------------------------------------------------------
+ // [Func]
+ // --------------------------------------------------------------------------
+
+ //! Get current function.
+ ASMJIT_INLINE FuncNode* getFunc() const { return _func; }
+
+ // --------------------------------------------------------------------------
+ // [Align]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `AlignNode`.
+ ASMJIT_API AlignNode* newAlign(uint32_t mode, uint32_t offset);
+ //! Add a new `AlignNode`.
+ ASMJIT_API AlignNode* addAlign(uint32_t mode, uint32_t offset);
+
+ //! Align target buffer to `m` bytes.
+ //!
+ //! Typical usage of this is to align labels at start of the inner loops.
+ //!
+ //! Inserts `nop()` instructions or CPU optimized NOPs.
+ ASMJIT_INLINE AlignNode* align(uint32_t mode, uint32_t offset) {
+ return addAlign(mode, offset);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Target]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `TargetNode`.
+ ASMJIT_API TargetNode* newTarget();
+ //! Add a new `TargetNode`.
+ ASMJIT_API TargetNode* addTarget();
+
+ //! Get `TargetNode` by `id`.
+ ASMJIT_INLINE TargetNode* getTargetById(uint32_t id) {
+ ASMJIT_ASSERT(OperandUtil::isLabelId(id));
+ ASMJIT_ASSERT(id < _targetList.getLength());
+
+ return _targetList[id];
+ }
+
+ //! Get `TargetNode` by `label`.
+ ASMJIT_INLINE TargetNode* getTarget(const Label& label) {
+ return getTargetById(label.getId());
+ }
+
+ // --------------------------------------------------------------------------
+ // [Label]
+ // --------------------------------------------------------------------------
+
+ //! Get count of created labels.
+ ASMJIT_INLINE size_t getLabelsCount() const {
+ return _targetList.getLength();
+ }
+
+ //! Get whether `label` is created.
+ ASMJIT_INLINE bool isLabelValid(const Label& label) const {
+ return isLabelValid(label.getId());
+ }
+
+ //! \overload
+ ASMJIT_INLINE bool isLabelValid(uint32_t id) const {
+ return static_cast(id) < _targetList.getLength();
+ }
+
+ //! Get `TargetNode` by `label`.
+ ASMJIT_INLINE TargetNode* getTargetByLabel(const Label& label) {
+ return getTargetByLabel(label.getId());
+ }
+
+ //! \overload
+ ASMJIT_INLINE TargetNode* getTargetByLabel(uint32_t id) {
+ ASMJIT_ASSERT(isLabelValid(id));
+ return _targetList[id];
+ }
+
+ //! Get `label` offset or -1 if the label is not bound.
+ //!
+ //! This method can be only called after the code has been serialized to the
+ //! `Assembler`, otherwise the offset returned will be -1 (even if the label
+ //! has been bound).
+ ASMJIT_INLINE intptr_t getLabelOffset(const Label& label) const {
+ return getLabelOffset(label.getId());
+ }
+
+ //! \overload
+ ASMJIT_INLINE intptr_t getLabelOffset(uint32_t id) const {
+ ASMJIT_ASSERT(isLabelValid(id));
+ return _targetList[id]->getOffset();
+ }
+
+ //! \internal
+ //!
+ //! Create and initialize a new `Label`.
+ ASMJIT_API Error _newLabel(Label* dst);
+
+ //! Create and return a new `Label`.
+ ASMJIT_INLINE Label newLabel() {
+ Label result(NoInit);
+ _newLabel(&result);
+ return result;
+ }
+
+ //! Bind label to the current offset.
+ //!
+ //! \note Label can be bound only once!
+ ASMJIT_API Error bind(const Label& label);
+
+ // --------------------------------------------------------------------------
+ // [Embed]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `EmbedNode`.
+ ASMJIT_API EmbedNode* newEmbed(const void* data, uint32_t size);
+ //! Add a new `EmbedNode`.
+ ASMJIT_API EmbedNode* addEmbed(const void* data, uint32_t size);
+
+ //! Embed data.
+ ASMJIT_INLINE EmbedNode* embed(const void* data, uint32_t size) {
+ return addEmbed(data, size);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Comment]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `CommentNode`.
+ ASMJIT_API CommentNode* newComment(const char* str);
+ //! Add a new `CommentNode`.
+ ASMJIT_API CommentNode* addComment(const char* str);
+
+ //! Emit a single comment line.
+ ASMJIT_API CommentNode* comment(const char* fmt, ...);
+
+ // --------------------------------------------------------------------------
+ // [Hint]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `HintNode`.
+ ASMJIT_API HintNode* newHint(Var& var, uint32_t hint, uint32_t value);
+ //! Add a new `HintNode`.
+ ASMJIT_API HintNode* addHint(Var& var, uint32_t hint, uint32_t value);
+
+ // --------------------------------------------------------------------------
+ // [Vars]
+ // --------------------------------------------------------------------------
+
+ //! Get whether variable `var` is created.
+ ASMJIT_INLINE bool isVarValid(const Var& var) const {
+ return static_cast(var.getId() & kOperandIdNum) < _varList.getLength();
+ }
+
+ //! \internal
+ //!
+ //! Get `VarData` by `var`.
+ ASMJIT_INLINE VarData* getVd(const Var& var) const {
+ return getVdById(var.getId());
+ }
+
+ //! \internal
+ //!
+ //! Get `VarData` by `id`.
+ ASMJIT_INLINE VarData* getVdById(uint32_t id) const {
+ ASMJIT_ASSERT(id != kInvalidValue);
+ ASMJIT_ASSERT(static_cast(id & kOperandIdNum) < _varList.getLength());
+
+ return _varList[id & kOperandIdNum];
+ }
+
+ //! \internal
+ //!
+ //! Get an array of 'VarData*'.
+ ASMJIT_INLINE VarData** _getVdArray() const {
+ return const_cast(_varList.getData());
+ }
+
+ //! \internal
+ //!
+ //! Create a new `VarData`.
+ ASMJIT_API VarData* _newVd(uint32_t type, uint32_t size, uint32_t c, const char* name);
+
+ //! Create a new `Var`.
+ virtual Error _newVar(Var* var, uint32_t type, const char* name) = 0;
+
+ //! Alloc variable `var`.
+ ASMJIT_API void alloc(Var& var);
+ //! Alloc variable `var` using `regIndex` as a register index.
+ ASMJIT_API void alloc(Var& var, uint32_t regIndex);
+ //! Alloc variable `var` using `reg` as a register operand.
+ ASMJIT_API void alloc(Var& var, const Reg& reg);
+ //! Spill variable `var`.
+ ASMJIT_API void spill(Var& var);
+ //! Save variable `var` if the status is `modified` at this point.
+ ASMJIT_API void save(Var& var);
+ //! Unuse variable `var`.
+ ASMJIT_API void unuse(Var& var);
+
+ //! Alloc variable `var` (if initialized), but only if it's initialized.
+ ASMJIT_INLINE void allocUnsafe(Var& var) {
+ if (var.isInitialized())
+ alloc(var);
+ }
+
+ //! Alloc variable `var` (if initialized) using `regIndex` as a register index
+ ASMJIT_INLINE void allocUnsafe(Var& var, uint32_t regIndex) {
+ if (var.isInitialized())
+ alloc(var, regIndex);
+ }
+
+ //! Alloc variable `var` (if initialized) using `reg` as a register operand.
+ ASMJIT_INLINE void allocUnsafe(Var& var, const Reg& reg) {
+ if (var.isInitialized())
+ alloc(var, reg);
+ }
+
+ //! Spill variable `var` (if initialized).
+ ASMJIT_INLINE void spillUnsafe(Var& var) {
+ if (var.isInitialized())
+ spill(var);
+ }
+
+ //! Save variable `var` (if initialized) if the status is `modified` at this point.
+ ASMJIT_INLINE void saveUnsafe(Var& var) {
+ if (var.isInitialized())
+ save(var);
+ }
+
+ //! Unuse variable `var` (if initialized).
+ ASMJIT_INLINE void unuseUnsafe(Var& var) {
+ if (var.isInitialized())
+ unuse(var);
+ }
+
+ //! Get priority of variable `var`.
+ ASMJIT_API uint32_t getPriority(Var& var) const;
+ //! Set priority of variable `var` to `priority`.
+ ASMJIT_API void setPriority(Var& var, uint32_t priority);
+
+ //! Get save-on-unuse `var` property.
+ ASMJIT_API bool getSaveOnUnuse(Var& var) const;
+ //! Set save-on-unuse `var` property to `value`.
+ ASMJIT_API void setSaveOnUnuse(Var& var, bool value);
+
+ //! Rename variable `var` to `name`.
+ //!
+ //! \note Only new name will appear in the logger.
+ ASMJIT_API void rename(Var& var, const char* name);
+
+ // --------------------------------------------------------------------------
+ // [Stack]
+ // --------------------------------------------------------------------------
+
+ //! \internal
+ //!
+ //! Create a new memory chunk allocated on the current function's stack.
+ virtual Error _newStack(BaseMem* mem, uint32_t size, uint32_t alignment, const char* name) = 0;
+
+ // --------------------------------------------------------------------------
+ // [Const]
+ // --------------------------------------------------------------------------
+
+ //! \internal
+ //!
+ //! Put data to a constant-pool and get a memory reference to it.
+ virtual Error _newConst(BaseMem* mem, uint32_t scope, const void* data, size_t size) = 0;
+
+ // --------------------------------------------------------------------------
+ // [Assembler]
+ // --------------------------------------------------------------------------
+
+ //! Get an assembler instance that is associated with the compiler.
+ //!
+ //! \note One instance of `Assembler` is shared and has lifetime same as the
+ //! compiler, however, each call to `getAssembler()` resets the assembler so
+ //! new code can be serialized into it.
+ ASMJIT_API Assembler* getAssembler();
+
+ //! \internal
+ //!
+ //! Create a new `Assembler` instance associated with the compiler.
+ virtual Assembler* _newAssembler() = 0;
+
+ // --------------------------------------------------------------------------
+ // [Serialize]
+ // --------------------------------------------------------------------------
+
+ //! Serialize a compiled code to `assembler`.
+ virtual Error serialize(Assembler* assembler) = 0;
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Internal assembler.
+ Assembler* _assembler;
+
+ //! Flow id added to each node created (used only by `Context)`.
+ uint32_t _nodeFlowId;
+ //! Flags added to each node created (used only by `Context)`.
+ uint32_t _nodeFlags;
+
+ //! Maximum count of nodes to look ahead when allocating/spilling
+ //! registers.
+ uint32_t _maxLookAhead;
+
+ //! Variable mapping (translates incoming VarType into target).
+ const uint8_t* _targetVarMapping;
+
+ //! First node.
+ Node* _firstNode;
+ //! Last node.
+ Node* _lastNode;
+
+ //! Current node.
+ Node* _cursor;
+ //! Current function.
+ FuncNode* _func;
+
+ //! Variable zone.
+ Zone _varZone;
+ //! String/data zone.
+ Zone _stringZone;
+ //! Local constant pool zone.
+ Zone _localConstZone;
+
+ //! TargetNode list.
+ PodVector _targetList;
+ //! VarData list.
+ PodVector _varList;
+
+ //! Local constant pool, flushed at the end of each function.
+ ConstPool _localConstPool;
+ //! Global constant pool, flushed at the end of the compilation.
+ ConstPool _globalConstPool;
+
+ //! Label to start of the local constant pool.
+ Label _localConstPoolLabel;
+ //! Label to start of the global constant pool.
+ Label _globalConstPoolLabel;
+};
+
+//! \}
+
+// ============================================================================
+// [Defined-Later]
+// ============================================================================
+
+ASMJIT_INLINE Label::Label(Compiler& c) : Operand(NoInit) {
+ c._newLabel(this);
+}
+
+ASMJIT_INLINE Node::Node(Compiler* compiler, uint32_t type) {
+ _prev = NULL;
+ _next = NULL;
+ _type = static_cast(type);
+ _opCount = 0;
+ _flags = static_cast(compiler->_nodeFlags);
+ _flowId = compiler->_nodeFlowId;
+ _comment = NULL;
+ _map = NULL;
+ _liveness = NULL;
+ _state = NULL;
+}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
+
+// [Guard]
+#endif // !ASMJIT_DISABLE_COMPILER
+#endif // _ASMJIT_BASE_COMPILER_H
diff --git a/libraries/asmjit/base/constpool.cpp b/libraries/asmjit/base/constpool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cd7e6d7fb2fce6dbe92133e43b3bcaac973be6a2
--- /dev/null
+++ b/libraries/asmjit/base/constpool.cpp
@@ -0,0 +1,523 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Export]
+#define ASMJIT_EXPORTS
+
+// [Dependencies - AsmJit]
+#include "../base/constpool.h"
+#include "../base/intutil.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+// Binary tree code is based on Julienne Walker's "Andersson Binary Trees"
+// article and implementation. However, only three operations are implemented -
+// get, insert and traverse.
+
+// ============================================================================
+// [asmjit::ConstPoolTree - Ops]
+// ============================================================================
+
+//! \internal
+//!
+//! Remove left horizontal links.
+static ASMJIT_INLINE ConstPoolNode* ConstPoolTree_skewNode(ConstPoolNode* node) {
+ ConstPoolNode* link = node->_link[0];
+ uint32_t level = node->_level;
+
+ if (level != 0 && link != NULL && link->_level == level) {
+ node->_link[0] = link->_link[1];
+ link->_link[1] = node;
+
+ node = link;
+ }
+
+ return node;
+}
+
+//! \internal
+//!
+//! Remove consecutive horizontal links.
+static ASMJIT_INLINE ConstPoolNode* ConstPoolTree_splitNode(ConstPoolNode* node) {
+ ConstPoolNode* link = node->_link[1];
+ uint32_t level = node->_level;
+
+ if (level != 0 && link != NULL && link->_link[1] != NULL && link->_link[1]->_level == level) {
+ node->_link[1] = link->_link[0];
+ link->_link[0] = node;
+
+ node = link;
+ node->_level++;
+ }
+
+ return node;
+}
+
+ConstPoolNode* ConstPoolTree::get(const void* data) {
+ ConstPoolNode* node = _root;
+ size_t dataSize = _dataSize;
+
+ while (node != NULL) {
+ int c = ::memcmp(node->getData(), data, dataSize);
+ if (c == 0)
+ return node;
+ node = node->_link[c < 0];
+ }
+
+ return NULL;
+}
+
+void ConstPoolTree::put(ConstPoolNode* newNode) {
+ size_t dataSize = _dataSize;
+
+ _length++;
+ if (_root == NULL) {
+ _root = newNode;
+ return;
+ }
+
+ ConstPoolNode* node = _root;
+ ConstPoolNode* stack[kHeightLimit];
+
+ unsigned int top = 0;
+ unsigned int dir;
+
+ // Find a spot and save the stack.
+ for (;;) {
+ stack[top++] = node;
+ dir = ::memcmp(node->getData(), newNode->getData(), dataSize) < 0;
+
+ ConstPoolNode* link = node->_link[dir];
+ if (link == NULL)
+ break;
+
+ node = link;
+ }
+
+ // Link and rebalance.
+ node->_link[dir] = newNode;
+
+ while (top > 0) {
+ // Which child?
+ node = stack[--top];
+
+ if (top != 0) {
+ dir = stack[top - 1]->_link[1] == node;
+ }
+
+ node = ConstPoolTree_skewNode(node);
+ node = ConstPoolTree_splitNode(node);
+
+ // Fix the parent.
+ if (top != 0)
+ stack[top - 1]->_link[dir] = node;
+ else
+ _root = node;
+ }
+}
+
+// ============================================================================
+// [asmjit::ConstPool - Construction / Destruction]
+// ============================================================================
+
+ConstPool::ConstPool(Zone* zone) {
+ _zone = zone;
+
+ size_t dataSize = 1;
+ for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) {
+ _tree[i].setDataSize(dataSize);
+ _gaps[i] = NULL;
+ dataSize <<= 1;
+ }
+
+ _gapPool = NULL;
+ _size = 0;
+ _alignment = 0;
+}
+
+ConstPool::~ConstPool() {}
+
+// ============================================================================
+// [asmjit::ConstPool - Reset]
+// ============================================================================
+
+void ConstPool::reset() {
+ for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) {
+ _tree[i].reset();
+ _gaps[i] = NULL;
+ }
+
+ _gapPool = NULL;
+ _size = 0;
+ _alignment = 0;
+}
+
+// ============================================================================
+// [asmjit::ConstPool - Ops]
+// ============================================================================
+
+static ASMJIT_INLINE ConstPoolGap* ConstPool_allocGap(ConstPool* self) {
+ ConstPoolGap* gap = self->_gapPool;
+ if (gap == NULL)
+ return self->_zone->allocT();
+
+ self->_gapPool = gap->_next;
+ return gap;
+}
+
+static ASMJIT_INLINE void ConstPool_freeGap(ConstPool* self, ConstPoolGap* gap) {
+ gap->_next = self->_gapPool;
+ self->_gapPool = gap;
+}
+
+static void ConstPool_addGap(ConstPool* self, size_t offset, size_t length) {
+ ASMJIT_ASSERT(length > 0);
+
+ while (length > 0) {
+ size_t gapIndex;
+ size_t gapLength;
+
+ if (length >= 16 && IntUtil::isAligned(offset, 16)) {
+ gapIndex = ConstPool::kIndex16;
+ gapLength = 16;
+ }
+ else if (length >= 8 && IntUtil::isAligned(offset, 8)) {
+ gapIndex = ConstPool::kIndex8;
+ gapLength = 8;
+ }
+ else if (length >= 4 && IntUtil::isAligned(offset, 4)) {
+ gapIndex = ConstPool::kIndex4;
+ gapLength = 4;
+ }
+ else if (length >= 2 && IntUtil::isAligned(offset, 2)) {
+ gapIndex = ConstPool::kIndex2;
+ gapLength = 2;
+ }
+ else {
+ gapIndex = ConstPool::kIndex1;
+ gapLength = 1;
+ }
+
+ // We don't have to check for errors here, if this failed nothing really
+ // happened (just the gap won't be visible) and it will fail again at
+ // place where checking will cause kErrorNoHeapMemory.
+ ConstPoolGap* gap = ConstPool_allocGap(self);
+ if (gap == NULL)
+ return;
+
+ gap->_next = self->_gaps[gapIndex];
+ self->_gaps[gapIndex] = gap;
+
+ gap->_offset = offset;
+ gap->_length = gapLength;
+
+ offset += gapLength;
+ length -= gapLength;
+ }
+}
+
+Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) {
+ size_t treeIndex;
+
+ if (size == 32)
+ treeIndex = kIndex32;
+ else if (size == 16)
+ treeIndex = kIndex16;
+ else if (size == 8)
+ treeIndex = kIndex8;
+ else if (size == 4)
+ treeIndex = kIndex4;
+ else if (size == 2)
+ treeIndex = kIndex2;
+ else if (size == 1)
+ treeIndex = kIndex1;
+ else
+ return kErrorInvalidArgument;
+
+ ConstPoolNode* node = _tree[treeIndex].get(data);
+ if (node != NULL) {
+ dstOffset = node->_offset;
+ return kErrorOk;
+ }
+
+ // Before incrementing the current offset try if there is a gap that can
+ // be used for the requested data.
+ size_t offset = ~static_cast(0);
+ size_t gapIndex = treeIndex;
+
+ while (gapIndex != kIndexCount - 1) {
+ ConstPoolGap* gap = _gaps[treeIndex];
+
+ // Check if there is a gap.
+ if (gap != NULL) {
+ size_t gapOffset = gap->_offset;
+ size_t gapLength = gap->_length;
+
+ // Destroy the gap for now.
+ _gaps[treeIndex] = gap->_next;
+ ConstPool_freeGap(this, gap);
+
+ offset = gapOffset;
+ ASMJIT_ASSERT(IntUtil::isAligned(offset, size));
+
+ gapLength -= size;
+ if (gapLength > 0)
+ ConstPool_addGap(this, gapOffset, gapLength);
+ }
+
+ gapIndex++;
+ }
+
+ if (offset == ~static_cast(0)) {
+ // Get how many bytes have to be skipped so the address is aligned accordingly
+ // to the 'size'.
+ size_t deltaTo = IntUtil::deltaTo(_size, size);
+
+ if (deltaTo != 0) {
+ ConstPool_addGap(this, _size, deltaTo);
+ _size += deltaTo;
+ }
+
+ offset = _size;
+ _size += size;
+ }
+
+ // Add the initial node to the right index.
+ node = ConstPoolTree::_newNode(_zone, data, size, offset, false);
+ if (node == NULL)
+ return kErrorNoHeapMemory;
+
+ _tree[treeIndex].put(node);
+ _alignment = IntUtil::iMax(_alignment, size);
+
+ dstOffset = offset;
+
+ // Now create a bunch of shared constants that are based on the data pattern.
+ // We stop at size 4, it probably doesn't make sense to split constants down
+ // to 1 byte.
+ size_t pCount = 1;
+ while (size > 4) {
+ size >>= 1;
+ pCount <<= 1;
+
+ ASMJIT_ASSERT(treeIndex != 0);
+ treeIndex--;
+
+ const uint8_t* pData = static_cast(data);
+ for (size_t i = 0; i < pCount; i++, pData += size) {
+ node = _tree[treeIndex].get(pData);
+
+ if (node != NULL)
+ continue;
+
+ node = ConstPoolTree::_newNode(_zone, pData, size, offset + (i * size), true);
+ _tree[treeIndex].put(node);
+ }
+ }
+
+ return kErrorOk;
+}
+
+// ============================================================================
+// [asmjit::ConstPool - Reset]
+// ============================================================================
+
+struct ConstPoolFill {
+ ASMJIT_INLINE ConstPoolFill(uint8_t* dst, size_t dataSize) :
+ _dst(dst),
+ _dataSize(dataSize) {}
+
+ ASMJIT_INLINE void visit(const ConstPoolNode* node) {
+ if (!node->_shared)
+ ::memcpy(_dst + node->_offset, node->getData(), _dataSize);
+ }
+
+ uint8_t* _dst;
+ size_t _dataSize;
+};
+
+void ConstPool::fill(void* dst) {
+ // Clears possible gaps, asmjit should never emit garbage to the output.
+ ::memset(dst, 0, _size);
+
+ ConstPoolFill filler(static_cast(dst), 1);
+ for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) {
+ _tree[i].iterate(filler);
+ filler._dataSize <<= 1;
+ }
+}
+
+// ============================================================================
+// [asmjit::ConstPool - Test]
+// ============================================================================
+
+#if defined(ASMJIT_TEST)
+UNIT(base_constpool) {
+ Zone zone(32384 - kZoneOverhead);
+ ConstPool pool(&zone);
+
+ uint32_t i;
+ uint32_t kCount = 1000000;
+
+ INFO("Adding %u constants to the pool.", kCount);
+ {
+ size_t prevOffset;
+ size_t curOffset;
+ uint64_t c = ASMJIT_UINT64_C(0x0101010101010101);
+
+ EXPECT(pool.add(&c, 8, prevOffset) == kErrorOk,
+ "pool.add() - Returned error.");
+ EXPECT(prevOffset == 0,
+ "pool.add() - First constant should have zero offset.");
+
+ for (i = 1; i < kCount; i++) {
+ c++;
+ EXPECT(pool.add(&c, 8, curOffset) == kErrorOk,
+ "pool.add() - Returned error.");
+ EXPECT(prevOffset + 8 == curOffset,
+ "pool.add() - Returned incorrect curOffset.");
+ EXPECT(pool.getSize() == (i + 1) * 8,
+ "pool.getSize() - Reported incorrect size.");
+ prevOffset = curOffset;
+ }
+
+ EXPECT(pool.getAlignment() == 8,
+ "pool.getAlignment() - Expected 8-byte alignment.");
+ }
+
+ INFO("Retrieving %u constants from the pool.", kCount);
+ {
+ uint64_t c = ASMJIT_UINT64_C(0x0101010101010101);
+
+ for (i = 0; i < kCount; i++) {
+ size_t offset;
+ EXPECT(pool.add(&c, 8, offset) == kErrorOk,
+ "pool.add() - Returned error.");
+ EXPECT(offset == i * 8,
+ "pool.add() - Should have reused constant.");
+ c++;
+ }
+ }
+
+ INFO("Checking if the constants were split into 4-byte patterns.");
+ {
+ uint32_t c = 0x01010101;
+ for (i = 0; i < kCount; i++) {
+ size_t offset;
+ EXPECT(pool.add(&c, 4, offset) == kErrorOk,
+ "pool.add() - Returned error.");
+ EXPECT(offset == i * 8,
+ "pool.add() - Should reuse existing constant.");
+ c++;
+ }
+ }
+
+ INFO("Adding 2 byte constant to misalign the current offset.");
+ {
+ uint16_t c = 0xFFFF;
+ size_t offset;
+
+ EXPECT(pool.add(&c, 2, offset) == kErrorOk,
+ "pool.add() - Returned error.");
+ EXPECT(offset == kCount * 8,
+ "pool.add() - Didn't return expected position.");
+ EXPECT(pool.getAlignment() == 8,
+ "pool.getAlignment() - Expected 8-byte alignment.");
+ }
+
+ INFO("Adding 8 byte constant to check if pool gets aligned again.");
+ {
+ uint64_t c = ASMJIT_UINT64_C(0xFFFFFFFFFFFFFFFF);
+ size_t offset;
+
+ EXPECT(pool.add(&c, 8, offset) == kErrorOk,
+ "pool.add() - Returned error.");
+ EXPECT(offset == kCount * 8 + 8,
+ "pool.add() - Didn't return aligned offset.");
+ }
+
+ INFO("Adding 2 byte constant to verify the gap is filled.");
+ {
+ uint16_t c = 0xFFFE;
+ size_t offset;
+
+ EXPECT(pool.add(&c, 2, offset) == kErrorOk,
+ "pool.add() - Returned error.");
+ EXPECT(offset == kCount * 8 + 2,
+ "pool.add() - Didn't fill the gap.");
+ EXPECT(pool.getAlignment() == 8,
+ "pool.getAlignment() - Expected 8-byte alignment.");
+ }
+
+ INFO("Checking reset functionality.");
+ {
+ pool.reset();
+
+ EXPECT(pool.getSize() == 0,
+ "pool.getSize() - Expected pool size to be zero.");
+ EXPECT(pool.getAlignment() == 0,
+ "pool.getSize() - Expected pool alignment to be zero.");
+ }
+
+ INFO("Checking pool alignment when combined constants are added.");
+ {
+ uint8_t bytes[32] = { 0 };
+ size_t offset;
+
+ pool.add(bytes, 1, offset);
+
+ EXPECT(pool.getSize() == 1,
+ "pool.getSize() - Expected pool size to be 1 byte.");
+ EXPECT(pool.getAlignment() == 1,
+ "pool.getSize() - Expected pool alignment to be 1 byte.");
+ EXPECT(offset == 0,
+ "pool.getSize() - Expected offset returned to be zero.");
+
+ pool.add(bytes, 2, offset);
+
+ EXPECT(pool.getSize() == 4,
+ "pool.getSize() - Expected pool size to be 4 bytes.");
+ EXPECT(pool.getAlignment() == 2,
+ "pool.getSize() - Expected pool alignment to be 2 bytes.");
+ EXPECT(offset == 2,
+ "pool.getSize() - Expected offset returned to be 2.");
+
+ pool.add(bytes, 4, offset);
+
+ EXPECT(pool.getSize() == 8,
+ "pool.getSize() - Expected pool size to be 8 bytes.");
+ EXPECT(pool.getAlignment() == 4,
+ "pool.getSize() - Expected pool alignment to be 4 bytes.");
+ EXPECT(offset == 4,
+ "pool.getSize() - Expected offset returned to be 4.");
+
+ pool.add(bytes, 4, offset);
+
+ EXPECT(pool.getSize() == 8,
+ "pool.getSize() - Expected pool size to be 8 bytes.");
+ EXPECT(pool.getAlignment() == 4,
+ "pool.getSize() - Expected pool alignment to be 4 bytes.");
+ EXPECT(offset == 4,
+ "pool.getSize() - Expected offset returned to be 8.");
+
+ pool.add(bytes, 32, offset);
+ EXPECT(pool.getSize() == 64,
+ "pool.getSize() - Expected pool size to be 64 bytes.");
+ EXPECT(pool.getAlignment() == 32,
+ "pool.getSize() - Expected pool alignment to be 32 bytes.");
+ EXPECT(offset == 32,
+ "pool.getSize() - Expected offset returned to be 32.");
+ }
+}
+#endif // ASMJIT_TEST
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
diff --git a/libraries/asmjit/base/constpool.h b/libraries/asmjit/base/constpool.h
new file mode 100644
index 0000000000000000000000000000000000000000..8f66b8b6627a8423dfad7b6202d88d5e745cd6fa
--- /dev/null
+++ b/libraries/asmjit/base/constpool.h
@@ -0,0 +1,303 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Guard]
+#ifndef _ASMJIT_BASE_CONSTPOOL_H
+#define _ASMJIT_BASE_CONSTPOOL_H
+
+// [Dependencies - AsmJit]
+#include "../base/error.h"
+#include "../base/zone.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+//! \addtogroup asmjit_base_util
+//! \{
+
+// ============================================================================
+// [asmjit::ConstPoolNode]
+// ============================================================================
+
+//! \internal
+//!
+//! Zone-allocated constant-pool node.
+struct ConstPoolNode {
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE void* getData() const {
+ return static_cast(const_cast(this) + 1);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Left/Right nodes.
+ ConstPoolNode* _link[2];
+ //! Horizontal level for balance.
+ uint32_t _level : 31;
+ //! Whether this constant is shared with another.
+ uint32_t _shared : 1;
+ //! Data offset from the beginning of the pool.
+ uint32_t _offset;
+};
+
+// ============================================================================
+// [asmjit::ConstPoolTree]
+// ============================================================================
+
+//! \internal
+//!
+//! Zone-allocated constant-pool tree.
+struct ConstPoolTree {
+ enum {
+ //! Maximum tree height == log2(1 << 64).
+ kHeightLimit = 64
+ };
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE ConstPoolTree(size_t dataSize = 0) :
+ _root(NULL),
+ _length(0),
+ _dataSize(dataSize) {}
+ ASMJIT_INLINE ~ConstPoolTree() {}
+
+ // --------------------------------------------------------------------------
+ // [Reset]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE void reset() {
+ _root = NULL;
+ _length = 0;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE bool isEmpty() const {
+ return _length == 0;
+ }
+
+ ASMJIT_INLINE size_t getLength() const {
+ return _length;
+ }
+
+ ASMJIT_INLINE void setDataSize(size_t dataSize) {
+ ASMJIT_ASSERT(isEmpty());
+ _dataSize = dataSize;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Ops]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_API ConstPoolNode* get(const void* data);
+ ASMJIT_API void put(ConstPoolNode* node);
+
+ // --------------------------------------------------------------------------
+ // [Iterate]
+ // --------------------------------------------------------------------------
+
+ template
+ ASMJIT_INLINE void iterate(Visitor& visitor) const {
+ ConstPoolNode* node = const_cast(_root);
+ ConstPoolNode* link;
+
+ ConstPoolNode* stack[kHeightLimit];
+
+ if (node == NULL)
+ return;
+
+ size_t top = 0;
+
+ for (;;) {
+ link = node->_link[0];
+
+ if (link != NULL) {
+ ASMJIT_ASSERT(top != kHeightLimit);
+ stack[top++] = node;
+
+ node = link;
+ continue;
+ }
+
+_Visit:
+ visitor.visit(node);
+ link = node->_link[1];
+
+ if (link != NULL) {
+ node = link;
+ continue;
+ }
+
+ if (top == 0)
+ break;
+
+ node = stack[--top];
+ goto _Visit;
+ }
+ }
+
+ // --------------------------------------------------------------------------
+ // [Helpers]
+ // --------------------------------------------------------------------------
+
+ static ASMJIT_INLINE ConstPoolNode* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) {
+ ConstPoolNode* node = zone->allocT(sizeof(ConstPoolNode) + size);
+ if (node == NULL)
+ return NULL;
+
+ node->_link[0] = NULL;
+ node->_link[1] = NULL;
+ node->_level = 1;
+ node->_shared = shared;
+ node->_offset = static_cast(offset);
+
+ ::memcpy(node->getData(), data, size);
+ return node;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Root of the tree
+ ConstPoolNode* _root;
+ //! Length of the tree (count of nodes).
+ size_t _length;
+ //! Size of the data.
+ size_t _dataSize;
+};
+
+// ============================================================================
+// [asmjit::ConstPoolGap]
+// ============================================================================
+
+//! \internal
+//!
+//! Zone-allocated constant-pool gap.
+struct ConstPoolGap {
+ //! Link to the next gap
+ ConstPoolGap* _next;
+ //! Offset of the gap.
+ size_t _offset;
+ //! Remaining bytes of the gap (basically a gap size).
+ size_t _length;
+};
+
+// ============================================================================
+// [asmjit::ConstPool]
+// ============================================================================
+
+//! Constant pool.
+struct ConstPool {
+ ASMJIT_NO_COPY(ConstPool)
+
+ enum {
+ kIndex1 = 0,
+ kIndex2 = 1,
+ kIndex4 = 2,
+ kIndex8 = 3,
+ kIndex16 = 4,
+ kIndex32 = 5,
+ kIndexCount = 6
+ };
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_API ConstPool(Zone* zone);
+ ASMJIT_API ~ConstPool();
+
+ // --------------------------------------------------------------------------
+ // [Reset]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_API void reset();
+
+ // --------------------------------------------------------------------------
+ // [Ops]
+ // --------------------------------------------------------------------------
+
+ //! Get whether the constant-pool is empty.
+ ASMJIT_INLINE bool isEmpty() const {
+ return _size == 0;
+ }
+
+ //! Get the size of the constant-pool in bytes.
+ ASMJIT_INLINE size_t getSize() const {
+ return _size;
+ }
+
+ //! Get minimum alignment.
+ ASMJIT_INLINE size_t getAlignment() const {
+ return _alignment;
+ }
+
+ //! Add a constant to the constant pool.
+ //!
+ //! The constant must have known size, which is 1, 2, 4, 8, 16 or 32 bytes.
+ //! The constant is added to the pool only if it doesn't not exist, otherwise
+ //! cached value is returned.
+ //!
+ //! AsmJit is able to subdivide added constants, so for example if you add
+ //! 8-byte constant 0x1122334455667788 it will create the following slots:
+ //!
+ //! 8-byte: 0x1122334455667788
+ //! 4-byte: 0x11223344, 0x55667788
+ //!
+ //! The reason is that when combining MMX/SSE/AVX code some patterns are used
+ //! frequently. However, AsmJit is not able to reallocate a constant that has
+ //! been already added. For example if you try to add 4-byte constant and then
+ //! 8-byte constant having the same 4-byte pattern as the previous one, two
+ //! independent slots will be generated by the pool.
+ ASMJIT_API Error add(const void* data, size_t size, size_t& dstOffset);
+
+ // --------------------------------------------------------------------------
+ // [Fill]
+ // --------------------------------------------------------------------------
+
+ //! Fill the destination with the constants from the pool.
+ ASMJIT_API void fill(void* dst);
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Zone allocator.
+ Zone* _zone;
+ //! Tree per size.
+ ConstPoolTree _tree[kIndexCount];
+ //! Gaps per size.
+ ConstPoolGap* _gaps[kIndexCount];
+ //! Gaps pool
+ ConstPoolGap* _gapPool;
+
+ //! Size of the pool (in bytes).
+ size_t _size;
+ //! Alignemnt.
+ size_t _alignment;
+};
+
+//! \}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
+
+// [Guard]
+#endif // _ASMJIT_BASE_CONSTPOOL_H
diff --git a/libraries/asmjit/base/containers.cpp b/libraries/asmjit/base/containers.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b93181390832722f19cc77e1417c505a5d69d55b
--- /dev/null
+++ b/libraries/asmjit/base/containers.cpp
@@ -0,0 +1,116 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Export]
+#define ASMJIT_EXPORTS
+
+// [Dependencies - AsmJit]
+#include "../base/containers.h"
+#include "../base/intutil.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+// ============================================================================
+// [asmjit::PodVectorBase - NullData]
+// ============================================================================
+
+const PodVectorData PodVectorBase::_nullData = { 0, 0 };
+
+// ============================================================================
+// [asmjit::PodVectorBase - Reset]
+// ============================================================================
+
+//! Clear vector data and free internal buffer.
+void PodVectorBase::reset(bool releaseMemory) {
+ PodVectorData* d = _d;
+
+ if (d == &_nullData)
+ return;
+
+ if (releaseMemory) {
+ ASMJIT_FREE(d);
+ _d = const_cast(&_nullData);
+ return;
+ }
+
+ d->length = 0;
+}
+
+// ============================================================================
+// [asmjit::PodVectorBase - Helpers]
+// ============================================================================
+
+Error PodVectorBase::_grow(size_t n, size_t sizeOfT) {
+ PodVectorData* d = _d;
+
+ size_t threshold = kMemAllocGrowMax / sizeOfT;
+ size_t capacity = d->capacity;
+ size_t after = d->length;
+
+ if (IntUtil::maxUInt() - n < after)
+ return kErrorNoHeapMemory;
+
+ after += n;
+
+ if (capacity >= after)
+ return kErrorOk;
+
+ // PodVector is used as a linear array for some data structures used by
+ // AsmJit code generation. The purpose of this agressive growing schema
+ // is to minimize memory reallocations, because AsmJit code generation
+ // classes live short life and will be freed or reused soon.
+ if (capacity < 32)
+ capacity = 32;
+ else if (capacity < 128)
+ capacity = 128;
+ else if (capacity < 512)
+ capacity = 512;
+
+ while (capacity < after) {
+ if (capacity < threshold)
+ capacity *= 2;
+ else
+ capacity += threshold;
+ }
+
+ return _reserve(capacity, sizeOfT);
+}
+
+Error PodVectorBase::_reserve(size_t n, size_t sizeOfT) {
+ PodVectorData* d = _d;
+
+ if (d->capacity >= n)
+ return kErrorOk;
+
+ size_t nBytes = sizeof(PodVectorData) + n * sizeOfT;
+ if (nBytes < n)
+ return kErrorNoHeapMemory;
+
+ if (d == &_nullData) {
+ d = static_cast(ASMJIT_ALLOC(nBytes));
+ if (d == NULL)
+ return kErrorNoHeapMemory;
+ d->length = 0;
+ }
+ else {
+ d = static_cast(ASMJIT_REALLOC(d, nBytes));
+ if (d == NULL)
+ return kErrorNoHeapMemory;
+ }
+
+ d->capacity = n;
+ _d = d;
+
+ return kErrorOk;
+}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
diff --git a/libraries/asmjit/base/containers.h b/libraries/asmjit/base/containers.h
new file mode 100644
index 0000000000000000000000000000000000000000..c6dc70d4647a4251ac60dbaf46dd8fa58b64ef18
--- /dev/null
+++ b/libraries/asmjit/base/containers.h
@@ -0,0 +1,350 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Guard]
+#ifndef _ASMJIT_BASE_CONTAINERS_H
+#define _ASMJIT_BASE_CONTAINERS_H
+
+// [Dependencies - AsmJit]
+#include "../base/error.h"
+#include "../base/globals.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+//! \addtogroup asmjit_base_util
+//! \{
+
+// ============================================================================
+// [asmjit::PodVectorData]
+// ============================================================================
+
+//! \internal
+struct PodVectorData {
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get data.
+ ASMJIT_INLINE void* getData() const {
+ return (void*)(this + 1);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Capacity of the vector.
+ size_t capacity;
+ //! Length of the vector.
+ size_t length;
+};
+
+// ============================================================================
+// [asmjit::PodVectorBase]
+// ============================================================================
+
+//! \internal
+struct PodVectorBase {
+ static ASMJIT_API const PodVectorData _nullData;
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new instance of `PodVectorBase`.
+ ASMJIT_INLINE PodVectorBase() :
+ _d(const_cast(&_nullData)) {}
+
+ //! Destroy the `PodVectorBase` and data.
+ ASMJIT_INLINE ~PodVectorBase() {
+ reset(true);
+ }
+
+ // --------------------------------------------------------------------------
+ // [Reset]
+ // --------------------------------------------------------------------------
+
+ //! Reset the vector data and set its `length` to zero.
+ //!
+ //! If `releaseMemory` is true the vector buffer will be released to the
+ //! system.
+ ASMJIT_API void reset(bool releaseMemory = false);
+
+ // --------------------------------------------------------------------------
+ // [Grow / Reserve]
+ // --------------------------------------------------------------------------
+
+protected:
+ ASMJIT_API Error _grow(size_t n, size_t sizeOfT);
+ ASMJIT_API Error _reserve(size_t n, size_t sizeOfT);
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+public:
+ PodVectorData* _d;
+};
+
+// ============================================================================
+// [asmjit::PodVector]
+// ============================================================================
+
+//! Template used to store and manage array of POD data.
+//!
+//! This template has these adventages over other vector<> templates:
+//! - Non-copyable (designed to be non-copyable, we want it)
+//! - No copy-on-write (some implementations of stl can use it)
+//! - Optimized for working only with POD types
+//! - Uses ASMJIT_... memory management macros
+template
+struct PodVector : PodVectorBase {
+ ASMJIT_NO_COPY(PodVector)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new instance of `PodVector`.
+ ASMJIT_INLINE PodVector() {}
+ //! Destroy the `PodVector<>` and data.
+ ASMJIT_INLINE ~PodVector() {}
+
+ // --------------------------------------------------------------------------
+ // [Data]
+ // --------------------------------------------------------------------------
+
+ //! Get whether the vector is empty.
+ ASMJIT_INLINE bool isEmpty() const {
+ return _d->length == 0;
+ }
+
+ //! Get length.
+ ASMJIT_INLINE size_t getLength() const {
+ return _d->length;
+ }
+
+ //! Get capacity.
+ ASMJIT_INLINE size_t getCapacity() const {
+ return _d->capacity;
+ }
+
+ //! Get data.
+ ASMJIT_INLINE T* getData() {
+ return static_cast(_d->getData());
+ }
+
+ //! \overload
+ ASMJIT_INLINE const T* getData() const {
+ return static_cast(_d->getData());
+ }
+
+ // --------------------------------------------------------------------------
+ // [Grow / Reserve]
+ // --------------------------------------------------------------------------
+
+ //! Called to grow the buffer to fit at least `n` elements more.
+ ASMJIT_INLINE Error _grow(size_t n) {
+ return PodVectorBase::_grow(n, sizeof(T));
+ }
+
+ //! Realloc internal array to fit at least `n` items.
+ ASMJIT_INLINE Error _reserve(size_t n) {
+ return PodVectorBase::_reserve(n, sizeof(T));
+ }
+
+ // --------------------------------------------------------------------------
+ // [Ops]
+ // --------------------------------------------------------------------------
+
+ //! Prepend `item` to vector.
+ Error prepend(const T& item) {
+ PodVectorData* d = _d;
+
+ if (d->length == d->capacity) {
+ ASMJIT_PROPAGATE_ERROR(_grow(1));
+ _d = d;
+ }
+
+ ::memmove(static_cast(d->getData()) + 1, d->getData(), d->length * sizeof(T));
+ ::memcpy(d->getData(), &item, sizeof(T));
+
+ d->length++;
+ return kErrorOk;
+ }
+
+ //! Insert an `item` at the `index`.
+ Error insert(size_t index, const T& item) {
+ PodVectorData* d = _d;
+ ASMJIT_ASSERT(index <= d->length);
+
+ if (d->length == d->capacity) {
+ ASMJIT_PROPAGATE_ERROR(_grow(1));
+ d = _d;
+ }
+
+ T* dst = static_cast(d->getData()) + index;
+ ::memmove(dst + 1, dst, d->length - index);
+ ::memcpy(dst, &item, sizeof(T));
+
+ d->length++;
+ return kErrorOk;
+ }
+
+ //! Append `item` to vector.
+ Error append(const T& item) {
+ PodVectorData* d = _d;
+
+ if (d->length == d->capacity) {
+ ASMJIT_PROPAGATE_ERROR(_grow(1));
+ d = _d;
+ }
+
+ ::memcpy(static_cast(d->getData()) + d->length, &item, sizeof(T));
+
+ d->length++;
+ return kErrorOk;
+ }
+
+ //! Get index of `val` or `kInvalidIndex` if not found.
+ size_t indexOf(const T& val) const {
+ PodVectorData* d = _d;
+
+ const T* data = static_cast(d->getData());
+ size_t len = d->length;
+
+ for (size_t i = 0; i < len; i++)
+ if (data[i] == val)
+ return i;
+
+ return kInvalidIndex;
+ }
+
+ //! Remove item at index `i`.
+ void removeAt(size_t i) {
+ PodVectorData* d = _d;
+ ASMJIT_ASSERT(i < d->length);
+
+ T* data = static_cast(d->getData()) + i;
+ d->length--;
+ ::memmove(data, data + 1, d->length - i);
+ }
+
+ //! Swap this pod-vector with `other`.
+ void swap(PodVector& other) {
+ T* otherData = other._d;
+ other._d = _d;
+ _d = otherData;
+ }
+
+ //! Get item at index `i`.
+ ASMJIT_INLINE T& operator[](size_t i) {
+ ASMJIT_ASSERT(i < getLength());
+ return getData()[i];
+ }
+
+ //! Get item at index `i`.
+ ASMJIT_INLINE const T& operator[](size_t i) const {
+ ASMJIT_ASSERT(i < getLength());
+ return getData()[i];
+ }
+};
+
+// ============================================================================
+// [asmjit::PodList]
+// ============================================================================
+
+//! \internal
+template
+struct PodList {
+ ASMJIT_NO_COPY(PodList)
+
+ // --------------------------------------------------------------------------
+ // [Link]
+ // --------------------------------------------------------------------------
+
+ struct Link {
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get next node.
+ ASMJIT_INLINE Link* getNext() const { return _next; }
+
+ //! Get value.
+ ASMJIT_INLINE T getValue() const { return _value; }
+ //! Set value to `value`.
+ ASMJIT_INLINE void setValue(const T& value) { _value = value; }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ Link* _next;
+ T _value;
+ };
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE PodList() : _first(NULL), _last(NULL) {}
+ ASMJIT_INLINE ~PodList() {}
+
+ // --------------------------------------------------------------------------
+ // [Data]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE bool isEmpty() const { return _first != NULL; }
+
+ ASMJIT_INLINE Link* getFirst() const { return _first; }
+ ASMJIT_INLINE Link* getLast() const { return _last; }
+
+ // --------------------------------------------------------------------------
+ // [Ops]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE void reset() {
+ _first = NULL;
+ _last = NULL;
+ }
+
+ ASMJIT_INLINE void prepend(Link* link) {
+ link->_next = _first;
+ if (_first == NULL)
+ _last = link;
+ _first = link;
+ }
+
+ ASMJIT_INLINE void append(Link* link) {
+ link->_next = NULL;
+ if (_first == NULL)
+ _first = link;
+ else
+ _last->_next = link;
+ _last = link;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ Link* _first;
+ Link* _last;
+};
+
+//! \}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
+
+// [Guard]
+#endif // _ASMJIT_BASE_CONTAINERS_H
diff --git a/libraries/asmjit/base/context.cpp b/libraries/asmjit/base/context.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..aeadb245f440658077d1920f41be67b846d97bc5
--- /dev/null
+++ b/libraries/asmjit/base/context.cpp
@@ -0,0 +1,561 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Export]
+#define ASMJIT_EXPORTS
+
+// [Guard]
+#include "../build.h"
+#if !defined(ASMJIT_DISABLE_COMPILER)
+
+// [Dependencies - AsmJit]
+#include "../base/context_p.h"
+#include "../base/intutil.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+// ============================================================================
+// [asmjit::Context - Construction / Destruction]
+// ============================================================================
+
+Context::Context(Compiler* compiler) :
+ _compiler(compiler),
+ _baseZone(8192 - kZoneOverhead),
+ _varMapToVaListOffset(0) {
+
+ Context::reset();
+}
+
+Context::~Context() {}
+
+// ============================================================================
+// [asmjit::Context - Reset]
+// ============================================================================
+
+void Context::reset(bool releaseMemory) {
+ _baseZone.reset(releaseMemory);
+
+ _func = NULL;
+ _start = NULL;
+ _end = NULL;
+ _extraBlock = NULL;
+ _stop = NULL;
+
+ _unreachableList.reset();
+ _jccList.reset();
+ _contextVd.reset(releaseMemory);
+
+ _memVarCells = NULL;
+ _memStackCells = NULL;
+
+ _mem1ByteVarsUsed = 0;
+ _mem2ByteVarsUsed = 0;
+ _mem4ByteVarsUsed = 0;
+ _mem8ByteVarsUsed = 0;
+ _mem16ByteVarsUsed = 0;
+ _mem32ByteVarsUsed = 0;
+ _mem64ByteVarsUsed = 0;
+ _memStackCellsUsed = 0;
+
+ _memMaxAlign = 0;
+ _memVarTotal = 0;
+ _memStackTotal = 0;
+ _memAllTotal = 0;
+ _annotationLength = 12;
+
+ _state = NULL;
+}
+
+// ============================================================================
+// [asmjit::Context - Mem]
+// ============================================================================
+
+static ASMJIT_INLINE uint32_t BaseContext_getDefaultAlignment(uint32_t size) {
+ if (size > 32)
+ return 64;
+ else if (size > 16)
+ return 32;
+ else if (size > 8)
+ return 16;
+ else if (size > 4)
+ return 8;
+ else if (size > 2)
+ return 4;
+ else if (size > 1)
+ return 2;
+ else
+ return 1;
+}
+
+MemCell* Context::_newVarCell(VarData* vd) {
+ ASMJIT_ASSERT(vd->_memCell == NULL);
+
+ MemCell* cell;
+ uint32_t size = vd->getSize();
+
+ if (vd->isStack()) {
+ cell = _newStackCell(size, vd->getAlignment());
+
+ if (cell == NULL)
+ return NULL;
+ }
+ else {
+ cell = static_cast(_baseZone.alloc(sizeof(MemCell)));
+ if (cell == NULL)
+ goto _NoMemory;
+
+ cell->_next = _memVarCells;
+ _memVarCells = cell;
+
+ cell->_offset = 0;
+ cell->_size = size;
+ cell->_alignment = size;
+
+ _memMaxAlign = IntUtil::iMax(_memMaxAlign, size);
+ _memVarTotal += size;
+
+ switch (size) {
+ case 1: _mem1ByteVarsUsed++ ; break;
+ case 2: _mem2ByteVarsUsed++ ; break;
+ case 4: _mem4ByteVarsUsed++ ; break;
+ case 8: _mem8ByteVarsUsed++ ; break;
+ case 16: _mem16ByteVarsUsed++; break;
+ case 32: _mem32ByteVarsUsed++; break;
+ case 64: _mem64ByteVarsUsed++; break;
+ default: ASMJIT_ASSERT(!"Reached");
+ }
+ }
+
+ vd->_memCell = cell;
+ return cell;
+
+_NoMemory:
+ _compiler->setError(kErrorNoHeapMemory);
+ return NULL;
+}
+
+MemCell* Context::_newStackCell(uint32_t size, uint32_t alignment) {
+ MemCell* cell = static_cast(_baseZone.alloc(sizeof(MemCell)));
+ if (cell == NULL)
+ goto _NoMemory;
+
+ if (alignment == 0)
+ alignment = BaseContext_getDefaultAlignment(size);
+
+ if (alignment > 64)
+ alignment = 64;
+
+ ASMJIT_ASSERT(IntUtil::isPowerOf2(alignment));
+ size = IntUtil::alignTo(size, alignment);
+
+ // Insert it sorted according to the alignment and size.
+ {
+ MemCell** pPrev = &_memStackCells;
+ MemCell* cur = *pPrev;
+
+ for (cur = *pPrev; cur != NULL; cur = cur->_next) {
+ if (cur->getAlignment() > alignment)
+ continue;
+ if (cur->getAlignment() == alignment && cur->getSize() > size)
+ continue;
+ break;
+ }
+
+ cell->_next = cur;
+ cell->_offset = 0;
+ cell->_size = size;
+ cell->_alignment = alignment;
+
+ *pPrev = cell;
+ _memStackCellsUsed++;
+
+ _memMaxAlign = IntUtil::iMax(_memMaxAlign, alignment);
+ _memStackTotal += size;
+ }
+
+ return cell;
+
+_NoMemory:
+ _compiler->setError(kErrorNoHeapMemory);
+ return NULL;
+}
+
+Error Context::resolveCellOffsets() {
+ MemCell* varCell = _memVarCells;
+ MemCell* stackCell = _memStackCells;
+
+ uint32_t stackAlignment = 0;
+ if (stackCell != NULL)
+ stackAlignment = stackCell->getAlignment();
+
+ uint32_t pos64 = 0;
+ uint32_t pos32 = pos64 + _mem64ByteVarsUsed * 64;
+ uint32_t pos16 = pos32 + _mem32ByteVarsUsed * 32;
+ uint32_t pos8 = pos16 + _mem16ByteVarsUsed * 16;
+ uint32_t pos4 = pos8 + _mem8ByteVarsUsed * 8 ;
+ uint32_t pos2 = pos4 + _mem4ByteVarsUsed * 4 ;
+ uint32_t pos1 = pos2 + _mem2ByteVarsUsed * 2 ;
+
+ uint32_t stackPos = pos1 + _mem1ByteVarsUsed;
+
+ uint32_t gapAlignment = stackAlignment;
+ uint32_t gapSize = 0;
+
+ if (gapAlignment)
+ IntUtil::deltaTo(stackPos, gapAlignment);
+ stackPos += gapSize;
+
+ uint32_t gapPos = stackPos;
+ uint32_t allTotal = stackPos;
+
+ // Vars - Allocated according to alignment/width.
+ while (varCell != NULL) {
+ uint32_t size = varCell->getSize();
+ uint32_t offset = 0;
+
+ switch (size) {
+ case 1: offset = pos1 ; pos1 += 1 ; break;
+ case 2: offset = pos2 ; pos2 += 2 ; break;
+ case 4: offset = pos4 ; pos4 += 4 ; break;
+ case 8: offset = pos8 ; pos8 += 8 ; break;
+ case 16: offset = pos16; pos16 += 16; break;
+ case 32: offset = pos32; pos32 += 32; break;
+ case 64: offset = pos64; pos64 += 64; break;
+ default: ASMJIT_ASSERT(!"Reached");
+ }
+
+ varCell->setOffset(static_cast(offset));
+ varCell = varCell->_next;
+ }
+
+ // Stack - Allocated according to alignment/width.
+ while (stackCell != NULL) {
+ uint32_t size = stackCell->getSize();
+ uint32_t alignment = stackCell->getAlignment();
+ uint32_t offset;
+
+ // Try to fill the gap between variables/stack first.
+ if (size <= gapSize && alignment <= gapAlignment) {
+ offset = gapPos;
+
+ gapSize -= size;
+ gapPos -= size;
+
+ if (alignment < gapAlignment)
+ gapAlignment = alignment;
+ }
+ else {
+ offset = stackPos;
+
+ stackPos += size;
+ allTotal += size;
+ }
+
+ stackCell->setOffset(offset);
+ stackCell = stackCell->_next;
+ }
+
+ _memAllTotal = allTotal;
+ return kErrorOk;
+}
+
+// ============================================================================
+// [asmjit::Context - RemoveUnreachableCode]
+// ============================================================================
+
+Error Context::removeUnreachableCode() {
+ PodList::Link* link = _unreachableList.getFirst();
+ Node* stop = getStop();
+
+ while (link != NULL) {
+ Node* node = link->getValue();
+ if (node != NULL && node->getPrev() != NULL) {
+ // Locate all unreachable nodes.
+ Node* first = node;
+ do {
+ if (node->isFetched())
+ break;
+ node = node->getNext();
+ } while (node != stop);
+
+ // Remove.
+ if (node != first) {
+ Node* last = (node != NULL) ? node->getPrev() : getCompiler()->getLastNode();
+ getCompiler()->removeNodes(first, last);
+ }
+ }
+
+ link = link->getNext();
+ }
+
+ return kErrorOk;
+}
+
+// ============================================================================
+// [asmjit::Context - Liveness Analysis]
+// ============================================================================
+
+//! \internal
+struct LivenessTarget {
+ //! Previous target.
+ LivenessTarget* prev;
+
+ //! Target node.
+ TargetNode* node;
+ //! Jumped from.
+ JumpNode* from;
+};
+
+Error Context::livenessAnalysis() {
+ FuncNode* func = getFunc();
+ JumpNode* from = NULL;
+
+ Node* node = func->getEnd();
+ uint32_t bLen = static_cast(
+ ((_contextVd.getLength() + VarBits::kEntityBits - 1) / VarBits::kEntityBits));
+
+ LivenessTarget* ltCur = NULL;
+ LivenessTarget* ltUnused = NULL;
+
+ size_t varMapToVaListOffset = _varMapToVaListOffset;
+
+ // No variables.
+ if (bLen == 0)
+ return kErrorOk;
+
+ VarBits* bCur = newBits(bLen);
+ if (bCur == NULL)
+ goto _NoMemory;
+
+ // Allocate bits for code visited first time.
+_OnVisit:
+ for (;;) {
+ if (node->hasLiveness()) {
+ if (bCur->_addBitsDelSource(node->getLiveness(), bCur, bLen))
+ goto _OnPatch;
+ else
+ goto _OnDone;
+ }
+
+ VarBits* bTmp = copyBits(bCur, bLen);
+ if (bTmp == NULL)
+ goto _NoMemory;
+
+ node->setLiveness(bTmp);
+ VarMap* map = node->getMap();
+
+ if (map != NULL) {
+ uint32_t vaCount = map->getVaCount();
+ VarAttr* vaList = reinterpret_cast(((uint8_t*)map) + varMapToVaListOffset);
+
+ for (uint32_t i = 0; i < vaCount; i++) {
+ VarAttr* va = &vaList[i];
+ VarData* vd = va->getVd();
+
+ uint32_t flags = va->getFlags();
+ uint32_t ctxId = vd->getContextId();
+
+ if ((flags & kVarAttrOutAll) && !(flags & kVarAttrInAll)) {
+ // Write-Only.
+ bTmp->setBit(ctxId);
+ bCur->delBit(ctxId);
+ }
+ else {
+ // Read-Only or Read/Write.
+ bTmp->setBit(ctxId);
+ bCur->setBit(ctxId);
+ }
+ }
+ }
+
+ if (node->getType() == kNodeTypeTarget)
+ goto _OnTarget;
+
+ if (node == func)
+ goto _OnDone;
+
+ ASMJIT_ASSERT(node->getPrev());
+ node = node->getPrev();
+ }
+
+ // Patch already generated liveness bits.
+_OnPatch:
+ for (;;) {
+ ASMJIT_ASSERT(node->hasLiveness());
+ VarBits* bNode = node->getLiveness();
+
+ if (!bNode->_addBitsDelSource(bCur, bLen))
+ goto _OnDone;
+
+ if (node->getType() == kNodeTypeTarget)
+ goto _OnTarget;
+
+ if (node == func)
+ goto _OnDone;
+
+ node = node->getPrev();
+ }
+
+_OnTarget:
+ if (static_cast(node)->getNumRefs() != 0) {
+ // Push a new LivenessTarget onto the stack if needed.
+ if (ltCur == NULL || ltCur->node != node) {
+ // Allocate a new LivenessTarget object (from pool or zone).
+ LivenessTarget* ltTmp = ltUnused;
+
+ if (ltTmp != NULL) {
+ ltUnused = ltUnused->prev;
+ }
+ else {
+ ltTmp = _baseZone.allocT(
+ sizeof(LivenessTarget) - sizeof(VarBits) + bLen * sizeof(uintptr_t));
+
+ if (ltTmp == NULL)
+ goto _NoMemory;
+ }
+
+ // Initialize and make current - ltTmp->from will be set later on.
+ ltTmp->prev = ltCur;
+ ltTmp->node = static_cast(node);
+ ltCur = ltTmp;
+
+ from = static_cast(node)->getFrom();
+ ASMJIT_ASSERT(from != NULL);
+ }
+ else {
+ from = ltCur->from;
+ goto _OnJumpNext;
+ }
+
+ // Visit/Patch.
+ do {
+ ltCur->from = from;
+ bCur->copyBits(node->getLiveness(), bLen);
+
+ if (!from->hasLiveness()) {
+ node = from;
+ goto _OnVisit;
+ }
+
+ // Issue #25: Moved '_OnJumpNext' here since it's important to patch
+ // code again if there are more live variables than before.
+_OnJumpNext:
+ if (bCur->delBits(from->getLiveness(), bLen)) {
+ node = from;
+ goto _OnPatch;
+ }
+
+ from = from->getJumpNext();
+ } while (from != NULL);
+
+ // Pop the current LivenessTarget from the stack.
+ {
+ LivenessTarget* ltTmp = ltCur;
+
+ ltCur = ltCur->prev;
+ ltTmp->prev = ltUnused;
+ ltUnused = ltTmp;
+ }
+ }
+
+ bCur->copyBits(node->getLiveness(), bLen);
+ node = node->getPrev();
+
+ if (node->isJmp() || !node->isFetched())
+ goto _OnDone;
+
+ if (!node->hasLiveness())
+ goto _OnVisit;
+
+ if (bCur->delBits(node->getLiveness(), bLen))
+ goto _OnPatch;
+
+_OnDone:
+ if (ltCur != NULL) {
+ node = ltCur->node;
+ from = ltCur->from;
+
+ goto _OnJumpNext;
+ }
+ return kErrorOk;
+
+_NoMemory:
+ return setError(kErrorNoHeapMemory);
+}
+
+// ============================================================================
+// [asmjit::Context - Schedule]
+// ============================================================================
+
+Error Context::schedule() {
+ // By default there is no instruction scheduler implemented.
+ return kErrorOk;
+}
+
+// ============================================================================
+// [asmjit::Context - Cleanup]
+// ============================================================================
+
+void Context::cleanup() {
+ VarData** array = _contextVd.getData();
+ size_t length = _contextVd.getLength();
+
+ for (size_t i = 0; i < length; i++) {
+ VarData* vd = array[i];
+ vd->resetContextId();
+ vd->resetRegIndex();
+ }
+
+ _contextVd.reset(false);
+ _extraBlock = NULL;
+}
+
+// ============================================================================
+// [asmjit::Context - CompileFunc]
+// ============================================================================
+
+Error Context::compile(FuncNode* func) {
+ Node* end = func->getEnd();
+ Node* stop = end->getNext();
+
+ _func = func;
+ _stop = stop;
+ _extraBlock = end;
+
+ ASMJIT_PROPAGATE_ERROR(fetch());
+ ASMJIT_PROPAGATE_ERROR(removeUnreachableCode());
+ ASMJIT_PROPAGATE_ERROR(livenessAnalysis());
+
+ Compiler* compiler = getCompiler();
+
+#if !defined(ASMJIT_DISABLE_LOGGER)
+ if (compiler->hasLogger())
+ ASMJIT_PROPAGATE_ERROR(annotate());
+#endif // !ASMJIT_DISABLE_LOGGER
+
+ ASMJIT_PROPAGATE_ERROR(translate());
+
+ if (compiler->hasFeature(kCodeGenEnableScheduler))
+ ASMJIT_PROPAGATE_ERROR(schedule());
+
+ // We alter the compiler cursor, because it doesn't make sense to reference
+ // it after compilation - some nodes may disappear and it's forbidden to add
+ // new code after the compilation is done.
+ compiler->_setCursor(NULL);
+
+ return kErrorOk;
+}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
+
+// [Guard]
+#endif // !ASMJIT_DISABLE_COMPILER
diff --git a/libraries/asmjit/base/context_p.h b/libraries/asmjit/base/context_p.h
new file mode 100644
index 0000000000000000000000000000000000000000..bd235013eb5c08918ef13d5846bac8d1f91d8c87
--- /dev/null
+++ b/libraries/asmjit/base/context_p.h
@@ -0,0 +1,307 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Guard]
+#ifndef _ASMJIT_BASE_CONTEXT_P_H
+#define _ASMJIT_BASE_CONTEXT_P_H
+
+#include "../build.h"
+#if !defined(ASMJIT_DISABLE_COMPILER)
+
+// [Dependencies - AsmJit]
+#include "../base/compiler.h"
+#include "../base/zone.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+//! \addtogroup asmjit_base_compiler
+//! \{
+
+// ============================================================================
+// [asmjit::Context]
+// ============================================================================
+
+//! \internal
+//!
+//! Code generation context is the logic behind `Compiler`. The context is
+//! used to compile the code stored in `Compiler`.
+struct Context {
+ ASMJIT_NO_COPY(Context)
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ Context(Compiler* compiler);
+ virtual ~Context();
+
+ // --------------------------------------------------------------------------
+ // [Reset]
+ // --------------------------------------------------------------------------
+
+ //! Reset the whole context.
+ virtual void reset(bool releaseMemory = false);
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get compiler.
+ ASMJIT_INLINE Compiler* getCompiler() const { return _compiler; }
+
+ //! Get function.
+ ASMJIT_INLINE FuncNode* getFunc() const { return _func; }
+ //! Get stop node.
+ ASMJIT_INLINE Node* getStop() const { return _stop; }
+
+ //! Get start of the current scope.
+ ASMJIT_INLINE Node* getStart() const { return _start; }
+ //! Get end of the current scope.
+ ASMJIT_INLINE Node* getEnd() const { return _end; }
+
+ //! Get extra block.
+ ASMJIT_INLINE Node* getExtraBlock() const { return _extraBlock; }
+ //! Set extra block.
+ ASMJIT_INLINE void setExtraBlock(Node* node) { _extraBlock = node; }
+
+ // --------------------------------------------------------------------------
+ // [Error]
+ // --------------------------------------------------------------------------
+
+ //! Get the last error code.
+ ASMJIT_INLINE Error getError() const {
+ return getCompiler()->getError();
+ }
+
+ //! Set the last error code and propagate it through the error handler.
+ ASMJIT_INLINE Error setError(Error error, const char* message = NULL) {
+ return getCompiler()->setError(error, message);
+ }
+
+ // --------------------------------------------------------------------------
+ // [State]
+ // --------------------------------------------------------------------------
+
+ //! Get current state.
+ ASMJIT_INLINE VarState* getState() const {
+ return _state;
+ }
+
+ //! Load current state from `target` state.
+ virtual void loadState(VarState* src) = 0;
+
+ //! Save current state, returning new `VarState` instance.
+ virtual VarState* saveState() = 0;
+
+ //! Change the current state to `target` state.
+ virtual void switchState(VarState* src) = 0;
+
+ //! Change the current state to the intersection of two states `a` and `b`.
+ virtual void intersectStates(VarState* a, VarState* b) = 0;
+
+ // --------------------------------------------------------------------------
+ // [Context]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE Error _registerContextVar(VarData* vd) {
+ if (vd->hasContextId())
+ return kErrorOk;
+
+ uint32_t cid = static_cast(_contextVd.getLength());
+ ASMJIT_PROPAGATE_ERROR(_contextVd.append(vd));
+
+ vd->setContextId(cid);
+ return kErrorOk;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Mem]
+ // --------------------------------------------------------------------------
+
+ MemCell* _newVarCell(VarData* vd);
+ MemCell* _newStackCell(uint32_t size, uint32_t alignment);
+
+ ASMJIT_INLINE MemCell* getVarCell(VarData* vd) {
+ MemCell* cell = vd->getMemCell();
+ return cell ? cell : _newVarCell(vd);
+ }
+
+ virtual Error resolveCellOffsets();
+
+ // --------------------------------------------------------------------------
+ // [Bits]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE VarBits* newBits(uint32_t len) {
+ return static_cast(
+ _baseZone.allocZeroed(static_cast(len) * VarBits::kEntitySize));
+ }
+
+ ASMJIT_INLINE VarBits* copyBits(const VarBits* src, uint32_t len) {
+ return static_cast(
+ _baseZone.dup(src, static_cast(len) * VarBits::kEntitySize));
+ }
+
+ // --------------------------------------------------------------------------
+ // [Fetch]
+ // --------------------------------------------------------------------------
+
+ //! Fetch.
+ //!
+ //! Fetch iterates over all nodes and gathers information about all variables
+ //! used. The process generates information required by register allocator,
+ //! variable liveness analysis and translator.
+ virtual Error fetch() = 0;
+
+ // --------------------------------------------------------------------------
+ // [RemoveUnreachableCode]
+ // --------------------------------------------------------------------------
+
+ //! Remove unreachable code.
+ virtual Error removeUnreachableCode();
+
+ // --------------------------------------------------------------------------
+ // [Analyze]
+ // --------------------------------------------------------------------------
+
+ //! Perform variable liveness analysis.
+ //!
+ //! Analysis phase iterates over nodes in reverse order and generates a bit
+ //! array describing variables that are alive at every node in the function.
+ //! When the analysis start all variables are assumed dead. When a read or
+ //! read/write operations of a variable is detected the variable becomes
+ //! alive; when only write operation is detected the variable becomes dead.
+ //!
+ //! When a label is found all jumps to that label are followed and analysis
+ //! repeats until all variables are resolved.
+ virtual Error livenessAnalysis();
+
+ // --------------------------------------------------------------------------
+ // [Annotate]
+ // --------------------------------------------------------------------------
+
+ virtual Error annotate() = 0;
+
+ // --------------------------------------------------------------------------
+ // [Translate]
+ // --------------------------------------------------------------------------
+
+ //! Translate code by allocating registers and handling state changes.
+ virtual Error translate() = 0;
+
+ // --------------------------------------------------------------------------
+ // [Schedule]
+ // --------------------------------------------------------------------------
+
+ virtual Error schedule();
+
+ // --------------------------------------------------------------------------
+ // [Cleanup]
+ // --------------------------------------------------------------------------
+
+ virtual void cleanup();
+
+ // --------------------------------------------------------------------------
+ // [Compile]
+ // --------------------------------------------------------------------------
+
+ virtual Error compile(FuncNode* func);
+
+ // --------------------------------------------------------------------------
+ // [Serialize]
+ // --------------------------------------------------------------------------
+
+ virtual Error serialize(Assembler* assembler, Node* start, Node* stop) = 0;
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Compiler.
+ Compiler* _compiler;
+ //! Function.
+ FuncNode* _func;
+
+ //! Zone allocator.
+ Zone _baseZone;
+
+ //! \internal
+ //!
+ //! Offset (how many bytes to add) to `VarMap` to get `VarAttr` array. Used
+ //! by liveness analysis shared across all backends. This is needed because
+ //! `VarMap` is a base class for a specialized version that liveness analysis
+ //! doesn't use, it just needs `VarAttr` array.
+ uint32_t _varMapToVaListOffset;
+
+ //! Start of the current active scope.
+ Node* _start;
+ //! End of the current active scope.
+ Node* _end;
+
+ //! Node that is used to insert extra code after the function body.
+ Node* _extraBlock;
+ //! Stop node.
+ Node* _stop;
+
+ //! Unreachable nodes.
+ PodList _unreachableList;
+ //! Jump nodes.
+ PodList _jccList;
+
+ //! All variables used by the current function.
+ PodVector _contextVd;
+
+ //! Memory used to spill variables.
+ MemCell* _memVarCells;
+ //! Memory used to alloc memory on the stack.
+ MemCell* _memStackCells;
+
+ //! Count of 1-byte cells.
+ uint32_t _mem1ByteVarsUsed;
+ //! Count of 2-byte cells.
+ uint32_t _mem2ByteVarsUsed;
+ //! Count of 4-byte cells.
+ uint32_t _mem4ByteVarsUsed;
+ //! Count of 8-byte cells.
+ uint32_t _mem8ByteVarsUsed;
+ //! Count of 16-byte cells.
+ uint32_t _mem16ByteVarsUsed;
+ //! Count of 32-byte cells.
+ uint32_t _mem32ByteVarsUsed;
+ //! Count of 64-byte cells.
+ uint32_t _mem64ByteVarsUsed;
+ //! Count of stack memory cells.
+ uint32_t _memStackCellsUsed;
+
+ //! Maximum memory alignment used by the function.
+ uint32_t _memMaxAlign;
+ //! Count of bytes used by variables.
+ uint32_t _memVarTotal;
+ //! Count of bytes used by stack.
+ uint32_t _memStackTotal;
+ //! Count of bytes used by variables and stack after alignment.
+ uint32_t _memAllTotal;
+
+ //! Default lenght of annotated instruction.
+ uint32_t _annotationLength;
+
+ //! Current state (used by register allocator).
+ VarState* _state;
+};
+
+//! \}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
+
+// [Guard]
+#endif // !ASMJIT_DISABLE_COMPILER
+#endif // _ASMJIT_BASE_CONTEXT_P_H
diff --git a/libraries/asmjit/base/cpuinfo.cpp b/libraries/asmjit/base/cpuinfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1a6d7757c550fe722c088941307b14f7fb924729
--- /dev/null
+++ b/libraries/asmjit/base/cpuinfo.cpp
@@ -0,0 +1,79 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Export]
+#define ASMJIT_EXPORTS
+
+// [Dependencies - AsmJit]
+#include "../base/cpuinfo.h"
+
+#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64)
+#include "../x86/x86cpuinfo.h"
+#else
+// ?
+#endif
+
+// [Dependencies - Posix]
+#if defined(ASMJIT_OS_POSIX)
+# include
+# include
+# include
+# include
+#endif // ASMJIT_OS_POSIX
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+// ============================================================================
+// [asmjit::CpuInfo - DetectHwThreadsCount]
+// ============================================================================
+
+uint32_t CpuInfo::detectHwThreadsCount() {
+#if defined(ASMJIT_OS_WINDOWS)
+ SYSTEM_INFO info;
+ ::GetSystemInfo(&info);
+ return info.dwNumberOfProcessors;
+#elif defined(ASMJIT_OS_POSIX) && defined(_SC_NPROCESSORS_ONLN)
+ // It seems that sysconf returns the number of "logical" processors on both
+ // mac and linux. So we get the number of "online logical" processors.
+ long res = ::sysconf(_SC_NPROCESSORS_ONLN);
+ if (res == -1) return 1;
+
+ return static_cast(res);
+#else
+ return 1;
+#endif
+}
+
+// ============================================================================
+// [asmjit::CpuInfo - GetHost]
+// ============================================================================
+
+#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64)
+struct AutoX86CpuInfo : public X86CpuInfo {
+ ASMJIT_INLINE AutoX86CpuInfo() : X86CpuInfo() {
+ X86CpuUtil::detect(this);
+ }
+};
+#else
+#error "AsmJit - Unsupported CPU."
+#endif
+
+const CpuInfo* CpuInfo::getHost() {
+#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64)
+ static AutoX86CpuInfo cpuInfo;
+#else
+#error "AsmJit - Unsupported CPU."
+#endif
+ return &cpuInfo;
+}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
diff --git a/libraries/asmjit/base/cpuinfo.h b/libraries/asmjit/base/cpuinfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..04abb624e158345e50b547bc25648a5cf39fb0e7
--- /dev/null
+++ b/libraries/asmjit/base/cpuinfo.h
@@ -0,0 +1,147 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Guard]
+#ifndef _ASMJIT_BASE_CPUINFO_H
+#define _ASMJIT_BASE_CPUINFO_H
+
+// [Dependencies - AsmJit]
+#include "../base/globals.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+//! \addtogroup asmjit_base_general
+//! \{
+
+// ============================================================================
+// [asmjit::CpuVendor]
+// ============================================================================
+
+//! Cpu vendor ID.
+//!
+//! Vendor IDs are specific to AsmJit library. During the library initialization
+//! AsmJit checks host CPU and tries to identify the vendor based on the CPUID
+//! calls. Some manufacturers changed their vendor strings and AsmJit is aware
+//! of that - it checks multiple combinations and decides which vendor ID should
+//! be used.
+ASMJIT_ENUM(CpuVendor) {
+ //! No/Unknown vendor.
+ kCpuVendorNone = 0,
+
+ //! Intel vendor.
+ kCpuVendorIntel = 1,
+ //! AMD vendor.
+ kCpuVendorAmd = 2,
+ //! VIA vendor.
+ kCpuVendorVia = 3
+};
+
+// ============================================================================
+// [asmjit::CpuInfo]
+// ============================================================================
+
+//! Base cpu information.
+struct CpuInfo {
+ ASMJIT_NO_COPY(CpuInfo)
+
+ //! \internal
+ enum {
+ kFeaturesPerUInt32 = static_cast(sizeof(uint32_t)) * 8
+ };
+
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ ASMJIT_INLINE CpuInfo(uint32_t size) : _size(size) {}
+
+ // --------------------------------------------------------------------------
+ // [Accessors]
+ // --------------------------------------------------------------------------
+
+ //! Get CPU vendor string.
+ ASMJIT_INLINE const char* getVendorString() const { return _vendorString; }
+ //! Get CPU brand string.
+ ASMJIT_INLINE const char* getBrandString() const { return _brandString; }
+
+ //! Get CPU vendor ID.
+ ASMJIT_INLINE uint32_t getVendorId() const { return _vendorId; }
+ //! Get CPU family ID.
+ ASMJIT_INLINE uint32_t getFamily() const { return _family; }
+ //! Get CPU model ID.
+ ASMJIT_INLINE uint32_t getModel() const { return _model; }
+ //! Get CPU stepping.
+ ASMJIT_INLINE uint32_t getStepping() const { return _stepping; }
+
+ //! Get number of hardware threads available.
+ ASMJIT_INLINE uint32_t getHwThreadsCount() const { return _hwThreadsCount; }
+
+ //! Get whether CPU has a `feature`.
+ ASMJIT_INLINE bool hasFeature(uint32_t feature) const {
+ ASMJIT_ASSERT(feature < sizeof(_features) * 8);
+
+ return static_cast(
+ (_features[feature / kFeaturesPerUInt32] >> (feature % kFeaturesPerUInt32)) & 0x1);
+ }
+
+ //! Add a CPU `feature`.
+ ASMJIT_INLINE CpuInfo& addFeature(uint32_t feature) {
+ ASMJIT_ASSERT(feature < sizeof(_features) * 8);
+
+ _features[feature / kFeaturesPerUInt32] |= (1U << (feature % kFeaturesPerUInt32));
+ return *this;
+ }
+
+ // --------------------------------------------------------------------------
+ // [Statics]
+ // --------------------------------------------------------------------------
+
+ //! Detect the number of hardware threads.
+ static ASMJIT_API uint32_t detectHwThreadsCount();
+
+ //! Get host cpu.
+ static ASMJIT_API const CpuInfo* getHost();
+
+ // --------------------------------------------------------------------------
+ // [Members]
+ // --------------------------------------------------------------------------
+
+ //! Size of the structure in bytes.
+ uint32_t _size;
+
+ //! Cpu short vendor string.
+ char _vendorString[16];
+ //! Cpu long vendor string (brand).
+ char _brandString[64];
+
+ //! Cpu vendor id, see \ref CpuVendor.
+ uint32_t _vendorId;
+ //! Cpu family ID.
+ uint32_t _family;
+ //! Cpu model ID.
+ uint32_t _model;
+ //! Cpu stepping.
+ uint32_t _stepping;
+
+ //! Number of hardware threads.
+ uint32_t _hwThreadsCount;
+
+ //! Cpu features bitfield.
+ uint32_t _features[4];
+};
+
+//! \}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
+
+// [Guard]
+#endif // _ASMJIT_BASE_CPUINFO_H
diff --git a/libraries/asmjit/base/cputicks.cpp b/libraries/asmjit/base/cputicks.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0c503316edf102b9a23078e8665cd02c18232c26
--- /dev/null
+++ b/libraries/asmjit/base/cputicks.cpp
@@ -0,0 +1,131 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Export]
+#define ASMJIT_EXPORTS
+
+// [Dependencies - AsmJit]
+#include "../base/cputicks.h"
+
+// [Dependencies - Posix]
+#if defined(ASMJIT_OS_POSIX)
+# include
+# include
+#endif // ASMJIT_OS_POSIX
+
+// [Dependencies - Mac]
+#if defined(ASMJIT_OS_MAC)
+# include
+#endif // ASMJIT_OS_MAC
+
+// [Dependencies - Windows]
+#if defined(ASMJIT_OS_WINDOWS)
+// `_InterlockedCompareExchange` is only available as intrinsic (MS Compiler).
+# if defined(_MSC_VER) && _MSC_VER >= 1400
+# include
+# pragma intrinsic(_InterlockedCompareExchange)
+# else
+# define _InterlockedCompareExchange InterlockedCompareExchange
+# endif // _MSC_VER
+#endif // ASMJIT_OS_WINDOWS
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+// ============================================================================
+// [asmjit::CpuTicks - Windows]
+// ============================================================================
+
+#if defined(ASMJIT_OS_WINDOWS)
+static volatile uint32_t CpuTicks_hiResOk;
+static volatile double CpuTicks_hiResFreq;
+
+uint32_t CpuTicks::now() {
+ do {
+ uint32_t hiResOk = CpuTicks_hiResOk;
+
+ if (hiResOk == 1) {
+ LARGE_INTEGER now;
+ if (!::QueryPerformanceCounter(&now))
+ break;
+ return (int64_t)(double(now.QuadPart) / CpuTicks_hiResFreq);
+ }
+
+ if (hiResOk == 0) {
+ LARGE_INTEGER qpf;
+ if (!::QueryPerformanceFrequency(&qpf)) {
+ _InterlockedCompareExchange((LONG*)&CpuTicks_hiResOk, 0xFFFFFFFF, 0);
+ break;
+ }
+
+ LARGE_INTEGER now;
+ if (!::QueryPerformanceCounter(&now)) {
+ _InterlockedCompareExchange((LONG*)&CpuTicks_hiResOk, 0xFFFFFFFF, 0);
+ break;
+ }
+
+ double freqDouble = double(qpf.QuadPart) / 1000.0;
+
+ CpuTicks_hiResFreq = freqDouble;
+ _InterlockedCompareExchange((LONG*)&CpuTicks_hiResOk, 1, 0);
+
+ return static_cast(
+ static_cast(double(now.QuadPart) / freqDouble) & 0xFFFFFFFF);
+ }
+ } while (0);
+
+ // Bail to a less precise GetTickCount().
+ return ::GetTickCount();
+}
+
+// ============================================================================
+// [asmjit::CpuTicks - Mac]
+// ============================================================================
+
+#elif defined(ASMJIT_OS_MAC)
+static mach_timebase_info_data_t CpuTicks_machTime;
+
+uint32_t CpuTicks::now() {
+ // Initialize the first time CpuTicks::now() is called (See Apple's QA1398).
+ if (CpuTicks_machTime.denom == 0) {
+ if (mach_timebase_info(&CpuTicks_machTime) != KERN_SUCCESS);
+ return 0;
+ }
+
+ // mach_absolute_time() returns nanoseconds, we need just milliseconds.
+ uint64_t t = mach_absolute_time() / 1000000;
+
+ t = t * CpuTicks_machTime.numer / CpuTicks_machTime.denom;
+ return static_cast(t & 0xFFFFFFFFU);
+}
+
+// ============================================================================
+// [asmjit::CpuTicks - Posix]
+// ============================================================================
+
+#else
+uint32_t CpuTicks::now() {
+#if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
+ return 0;
+
+ uint64_t t = (uint64_t(ts.tv_sec ) * 1000) + (uint64_t(ts.tv_nsec) / 1000000);
+ return static_cast(t & 0xFFFFFFFFU);
+#else // _POSIX_MONOTONIC_CLOCK
+#error "AsmJit - Unsupported OS."
+ return 0;
+#endif // _POSIX_MONOTONIC_CLOCK
+}
+#endif // ASMJIT_OS
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
diff --git a/libraries/asmjit/base/cputicks.h b/libraries/asmjit/base/cputicks.h
new file mode 100644
index 0000000000000000000000000000000000000000..1732c2eb61f7c41636d90c9b32d094bc272c834f
--- /dev/null
+++ b/libraries/asmjit/base/cputicks.h
@@ -0,0 +1,40 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Guard]
+#ifndef _ASMJIT_BASE_CPUTICKS_H
+#define _ASMJIT_BASE_CPUTICKS_H
+
+// [Dependencies - AsmJit]
+#include "../base/globals.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+//! \addtogroup asmjit_base_util
+//! \{
+
+// ============================================================================
+// [asmjit::CpuTicks]
+// ============================================================================
+
+//! CPU ticks utilities.
+struct CpuTicks {
+ //! Get the current CPU ticks for benchmarking (1ms resolution).
+ static ASMJIT_API uint32_t now();
+};
+
+//! \}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
+
+// [Guard]
+#endif // _ASMJIT_BASE_CPUTICKS_H
diff --git a/libraries/asmjit/base/error.cpp b/libraries/asmjit/base/error.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..51516fba47ba8722dcf5eb88cd28974d2a99e385
--- /dev/null
+++ b/libraries/asmjit/base/error.cpp
@@ -0,0 +1,83 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Export]
+#define ASMJIT_EXPORTS
+
+// [Dependencies - AsmJit]
+#include "../base/error.h"
+#include "../base/intutil.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+// ============================================================================
+// [asmjit::ErrorHandler - Construction / Destruction]
+// ============================================================================
+
+ErrorHandler::ErrorHandler() {}
+ErrorHandler::~ErrorHandler() {}
+
+// ============================================================================
+// [asmjit::ErrorHandler - Interface]
+// ============================================================================
+
+ErrorHandler* ErrorHandler::addRef() const {
+ return const_cast(this);
+}
+
+void ErrorHandler::release() {}
+
+// ============================================================================
+// [asmjit::ErrorUtil - AsString]
+// ============================================================================
+
+#if !defined(ASMJIT_DISABLE_NAMES)
+static const char errorMessages[] = {
+ "Ok\0"
+ "No heap memory\0"
+ "No virtual memory\0"
+ "Invalid argument\0"
+ "Invalid state\0"
+ "No code generated\0"
+ "Code too large\0"
+ "Label already bound\0"
+ "Unknown instruction\0"
+ "Illegal instruction\0"
+ "Illegal addressing\0"
+ "Illegal displacement\0"
+ "Overlapped arguments\0"
+ "Unknown error\0"
+};
+
+static const char* findPackedString(const char* p, uint32_t id, uint32_t maxId) {
+ uint32_t i = 0;
+
+ if (id > maxId)
+ id = maxId;
+
+ while (i < id) {
+ while (p[0])
+ p++;
+
+ p++;
+ i++;
+ }
+
+ return p;
+}
+
+const char* ErrorUtil::asString(Error e) {
+ return findPackedString(errorMessages, e, kErrorCount);
+}
+#endif // ASMJIT_DISABLE_NAMES
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
diff --git a/libraries/asmjit/base/error.h b/libraries/asmjit/base/error.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f76934c076c4afc5d3c2b6667c4e77b277d41cf
--- /dev/null
+++ b/libraries/asmjit/base/error.h
@@ -0,0 +1,218 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Guard]
+#ifndef _ASMJIT_BASE_ERROR_H
+#define _ASMJIT_BASE_ERROR_H
+
+// [Dependencies - AsmJit]
+#include "../base/globals.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+//! \addtogroup asmjit_base_general
+//! \{
+
+// ============================================================================
+// [asmjit::ErrorCode]
+// ============================================================================
+
+//! AsmJit error codes.
+ASMJIT_ENUM(ErrorCode) {
+ //! No error (success).
+ //!
+ //! This is default state and state you want.
+ kErrorOk = 0,
+
+ //! Heap memory allocation failed.
+ kErrorNoHeapMemory = 1,
+
+ //! Virtual memory allocation failed.
+ kErrorNoVirtualMemory = 2,
+
+ //! Invalid argument.
+ kErrorInvalidArgument = 3,
+
+ //! Invalid state.
+ kErrorInvalidState = 4,
+
+ //! No code generated.
+ //!
+ //! Returned by runtime if the code-generator contains no code.
+ kErrorNoCodeGenerated = 5,
+
+ //! Code generated is too large to fit in memory reserved.
+ //!
+ //! Returned by `StaticRuntime` in case that the code generated is too large
+ //! to fit in the memory already reserved for it.
+ kErrorCodeTooLarge = 6,
+
+ //! Label is already bound.
+ kErrorLabelAlreadyBound = 7,
+
+ //! Unknown instruction (an instruction ID is out of bounds or instruction
+ //! name is invalid).
+ kErrorUnknownInst = 8,
+
+ //! Illegal instruction.
+ //!
+ //! This status code can also be returned in X64 mode if AH, BH, CH or DH
+ //! registers have been used together with a REX prefix. The instruction
+ //! is not encodable in such case.
+ //!
+ //! Example of raising `kErrorIllegalInst` error.
+ //!
+ //! ~~~
+ //! // Invalid address size.
+ //! a.mov(dword_ptr(eax), al);
+ //!
+ //! // Undecodable instruction - AH used with R10, however R10 can only be
+ //! // encoded by using REX prefix, which conflicts with AH.
+ //! a.mov(byte_ptr(r10), ah);
+ //! ~~~
+ //!
+ //! \note In debug mode assertion is raised instead of returning an error.
+ kErrorIllegalInst = 9,
+
+ //! Illegal (unencodable) addressing used.
+ kErrorIllegalAddresing = 10,
+
+ //! Illegal (unencodable) displacement used.
+ //!
+ //! X86/X64
+ //! -------
+ //!
+ //! Short form of jump instruction has been used, but the displacement is out
+ //! of bounds.
+ kErrorIllegalDisplacement = 11,
+
+ //! A variable has been assigned more than once to a function argument (Compiler).
+ kErrorOverlappedArgs = 12,
+
+ //! Count of AsmJit error codes.
+ kErrorCount = 13
+};
+
+// ============================================================================
+// [asmjit::Error]
+// ============================================================================
+
+//! AsmJit error type (unsigned integer).
+typedef uint32_t Error;
+
+// ============================================================================
+// [asmjit::ErrorHandler]
+// ============================================================================
+
+//! Error handler.
+//!
+//! Error handler can be used to override the default behavior of `CodeGen`
+//! error handling and propagation. See `handleError` on how to override it.
+//!
+//! Please note that `addRef` and `release` functions are used, but there is
+//! no reference counting implemented by default, reimplement to change the
+//! default behavior.
+struct ASMJIT_VCLASS ErrorHandler {
+ // --------------------------------------------------------------------------
+ // [Construction / Destruction]
+ // --------------------------------------------------------------------------
+
+ //! Create a new `ErrorHandler` instance.
+ ASMJIT_API ErrorHandler();
+ //! Destroy the `ErrorHandler` instance.
+ ASMJIT_API virtual ~ErrorHandler();
+
+ // --------------------------------------------------------------------------
+ // [Interface]
+ // --------------------------------------------------------------------------
+
+ //! Reference this error handler.
+ //!
+ //! \note This member function is provided for convenience. The default
+ //! implementation does nothing. If you are working in environment where
+ //! multiple `ErrorHandler` instances are used by a different code generators
+ //! you may provide your own functionality for reference counting. In that
+ //! case `addRef()` and `release()` functions should be overridden.
+ ASMJIT_API virtual ErrorHandler* addRef() const;
+
+ //! Release this error handler.
+ //!
+ //! \note This member function is provided for convenience. See `addRef()`
+ //! for more detailed information related to reference counting.
+ ASMJIT_API virtual void release();
+
+ //! Error handler (pure).
+ //!
+ //! Error handler is called when an error happened. An error can happen in
+ //! many places, but error handler is mostly used by `Assembler` and
+ //! `Compiler` classes to report anything that may cause incorrect code
+ //! generation. There are multiple ways how the error handler can be used
+ //! and each has it's pros/cons.
+ //!
+ //! AsmJit library doesn't use exceptions and can be compiled with or without
+ //! exception handling support. Even if the AsmJit library is compiled without
+ //! exceptions it is exception-safe and handleError() can report an incoming
+ //! error by throwing an exception of any type. It's guaranteed that the
+ //! exception won't be catched by AsmJit and will be propagated to the code
+ //! calling AsmJit `Assembler` or `Compiler` methods. Alternative to
+ //! throwing an exception is using `setjmp()` and `longjmp()` pair available
+ //! in the standard C library.
+ //!
+ //! If the exception or setjmp() / longjmp() mechanism is used, the state of
+ //! the `BaseAssember` or `Compiler` is unchanged and if it's possible the
+ //! execution (instruction serialization) can continue. However if the error
+ //! happened during any phase that translates or modifies the stored code
+ //! (for example relocation done by `Assembler` or analysis/translation
+ //! done by `Compiler`) the execution can't continue and the error will
+ //! be also stored in `Assembler` or `Compiler`.
+ //!
+ //! Finally, if no exceptions nor setjmp() / longjmp() mechanisms were used,
+ //! you can still implement a compatible handling by returning from your
+ //! error handler. Returning `true` means that error was reported and AsmJit
+ //! should continue execution, but `false` sets the rror immediately to the
+ //! `Assembler` or `Compiler` and execution shouldn't continue (this
+ //! is the default behavior in case no error handler is used).
+ virtual bool handleError(Error code, const char* message) = 0;
+};
+
+// ============================================================================
+// [asmjit::ErrorUtil]
+// ============================================================================
+
+//! Error utilities.
+struct ErrorUtil {
+#if !defined(ASMJIT_DISABLE_NAMES)
+ //! Get a printable version of AsmJit `Error` code.
+ static ASMJIT_API const char* asString(Error code);
+#endif // ASMJIT_DISABLE_NAMES
+};
+
+//! \}
+
+// ============================================================================
+// [ASMJIT_PROPAGATE_ERROR]
+// ============================================================================
+
+//! \internal
+//!
+//! Used by AsmJit to return the `_Exp_` result if it's an error.
+#define ASMJIT_PROPAGATE_ERROR(_Exp_) \
+ do { \
+ ::asmjit::Error errval_ = (_Exp_); \
+ if (errval_ != ::asmjit::kErrorOk) \
+ return errval_; \
+ } while (0)
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
+
+// [Guard]
+#endif // _ASMJIT_BASE_ERROR_H
diff --git a/libraries/asmjit/base/globals.cpp b/libraries/asmjit/base/globals.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2971e002bdcaf1d58bbeb8b3748a797c60d6c48c
--- /dev/null
+++ b/libraries/asmjit/base/globals.cpp
@@ -0,0 +1,30 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Export]
+#define ASMJIT_EXPORTS
+
+// [Dependencies - AsmJit]
+#include "../base/globals.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+// ============================================================================
+// [asmjit::Assert]
+// ============================================================================
+
+void assertionFailed(const char* exp, const char* file, int line) {
+ ::fprintf(stderr, "Assertion failed: %s\n, file %s, line %d\n", exp, file, line);
+ ::abort();
+}
+
+} // asmjit namespace
+
+// [Api-End]
+#include "../apiend.h"
diff --git a/libraries/asmjit/base/globals.h b/libraries/asmjit/base/globals.h
new file mode 100644
index 0000000000000000000000000000000000000000..5c1bcae3c7d13706c357c9257192f9fd2175e577
--- /dev/null
+++ b/libraries/asmjit/base/globals.h
@@ -0,0 +1,177 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Guard]
+#ifndef _ASMJIT_BASE_GLOBALS_H
+#define _ASMJIT_BASE_GLOBALS_H
+
+// [Dependencies - AsmJit]
+#include "../build.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+//! \addtogroup asmjit_base_general
+//! \{
+
+// ============================================================================
+// [asmjit::Ptr / SignedPtr]
+// ============================================================================
+
+//! 64-bit unsigned pointer, compatible with JIT and non-JIT generators.
+//!
+//! This is the preferred pointer type to use with AsmJit library. It has a
+//! capability to hold any pointer for any architecture making it an ideal
+//! candidate for cross-platform code generation.
+typedef uint64_t Ptr;
+
+//! 64-bit signed pointer, like \ref Ptr, but made signed.
+typedef int64_t SignedPtr;
+
+// ============================================================================
+// [asmjit::GlobalDefs]
+// ============================================================================
+
+//! Invalid index
+//!
+//! Invalid index is the last possible index that is never used in practice. In
+//! AsmJit it is used exclusively with strings to indicate the the length of the
+//! string is not known and has to be determined.
+static const size_t kInvalidIndex = ~static_cast(0);
+
+//! Invalid base address.
+static const Ptr kNoBaseAddress = static_cast(static_cast(-1));
+
+//! Global constants.
+ASMJIT_ENUM(GlobalDefs) {
+ //! Invalid value or operand id.
+ kInvalidValue = 0xFFFFFFFF,
+
+ //! Invalid register index.
+ kInvalidReg = 0xFF,
+ //! Invalid variable type.
+ kInvalidVar = 0xFF,
+
+ //! Host memory allocator overhead.
+ //!
+ //! The overhead is decremented from all zone allocators so the operating
+ //! system doesn't have allocate extra virtual page to keep tract of the
+ //! requested memory block.
+ //!
+ //! The number is actually a guess.
+ kMemAllocOverhead = sizeof(intptr_t) * 4,
+
+ //! Memory grow threshold.
+ //!
+ //! After the grow threshold is reached the capacity won't be doubled
+ //! anymore.
+ kMemAllocGrowMax = 8192 * 1024
+};
+
+// ============================================================================
+// [asmjit::ArchId]
+// ============================================================================
+
+//! CPU architecture identifier.
+ASMJIT_ENUM(ArchId) {
+ //! No/Unknown architecture.
+ kArchNone = 0,
+
+ //! X86 architecture.
+ kArchX86 = 1,
+ //! X64 architecture, also called AMD64.
+ kArchX64 = 2,
+
+ //! Arm architecture.
+ kArchArm = 4,
+
+#if defined(ASMJIT_ARCH_X86)
+ kArchHost = kArchX86,
+#endif // ASMJIT_ARCH_X86
+
+#if defined(ASMJIT_ARCH_X64)
+ kArchHost = kArchX64,
+#endif // ASMJIT_ARCH_X64
+
+#if defined(ASMJIT_ARCH_ARM)
+ kArchHost = kArchArm,
+#endif // ASMJIT_ARCH_ARM
+
+ //! Whether the host is 64-bit.
+ kArchHost64Bit = sizeof(intptr_t) >= 8
+};
+
+//! \}
+
+// ============================================================================
+// [asmjit::Init / NoInit]
+// ============================================================================
+
+#if !defined(ASMJIT_DOCGEN)
+struct _Init {};
+static const _Init Init = {};
+
+struct _NoInit {};
+static const _NoInit NoInit = {};
+#endif // !ASMJIT_DOCGEN
+
+// ============================================================================
+// [asmjit::Assert]
+// ============================================================================
+
+//! \addtogroup asmjit_base_general
+//! \{
+
+//! Called in debug build on assertion failure.
+//!
+//! \param exp Expression that failed.
+//! \param file Source file name where it happened.
+//! \param line Line in the source file.
+//!
+//! If you have problems with assertions put a breakpoint at assertionFailed()
+//! function (asmjit/base/globals.cpp) and check the call stack to locate the
+//! failing code.
+ASMJIT_API void assertionFailed(const char* exp, const char* file, int line);
+
+#if defined(ASMJIT_DEBUG)
+#define ASMJIT_ASSERT(_Exp_) \
+ do { \
+ if (!(_Exp_)) ::asmjit::assertionFailed(#_Exp_, __FILE__, __LINE__); \
+ } while (0)
+#else
+#define ASMJIT_ASSERT(_Exp_) ASMJIT_NOP()
+#endif // DEBUG
+
+//! \}
+
+} // asmjit namespace
+
+// ============================================================================
+// [asmjit_cast<>]
+// ============================================================================
+
+//! \addtogroup asmjit_base_util
+//! \{
+
+//! Cast used to cast pointer to function. It's like reinterpret_cast<>,
+//! but uses internally C style cast to work with MinGW.
+//!
+//! If you are using single compiler and `reinterpret_cast<>` works for you,
+//! there is no reason to use `asmjit_cast<>`. If you are writing
+//! cross-platform software with various compiler support, consider using
+//! `asmjit_cast<>` instead of `reinterpret_cast<>`.
+template
+static ASMJIT_INLINE T asmjit_cast(Z* p) { return (T)p; }
+
+//! \}
+
+// [Api-End]
+#include "../apiend.h"
+
+// [Guard]
+#endif // _ASMJIT_BASE_GLOBALS_H
diff --git a/libraries/asmjit/base/intutil.cpp b/libraries/asmjit/base/intutil.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3a811b66edddfd3258e5a7dda31f3d22e85dac77
--- /dev/null
+++ b/libraries/asmjit/base/intutil.cpp
@@ -0,0 +1,210 @@
+// [AsmJit]
+// Complete x86/x64 JIT and Remote Assembler for C++.
+//
+// [License]
+// Zlib - See LICENSE.md file in the package.
+
+// [Export]
+#define ASMJIT_EXPORTS
+
+// [Dependencies - AsmJit]
+#include "../base/intutil.h"
+
+// [Api-Begin]
+#include "../apibegin.h"
+
+namespace asmjit {
+
+#if defined(ASMJIT_TEST)
+UNIT(base_intutil) {
+ uint32_t i;
+
+ INFO("IntTraits<>.");
+ EXPECT(IntTraits::kIsSigned,
+ "IntTraits should report signed.");
+ EXPECT(IntTraits::kIsUnsigned,
+ "IntTraits should report unsigned.");
+
+ EXPECT(IntTraits::kIsSigned,
+ "IntTraits should report signed.");
+ EXPECT(IntTraits::kIsUnsigned,
+ "IntTraits should report unsigned.");
+
+ EXPECT(IntTraits::kIsSigned,
+ "IntTraits should report signed.");
+ EXPECT(IntTraits::kIsUnsigned,
+ "IntTraits should report unsigned.");
+
+ EXPECT(IntTraits::kIsSigned,
+ "IntTraits should report signed.");
+ EXPECT(IntTraits::kIsUnsigned,
+ "IntTraits should report unsigned.");
+
+ EXPECT(IntTraits::kIsSigned,
+ "IntTraits should report signed.");
+ EXPECT(IntTraits::kIsUnsigned,
+ "IntTraits should report unsigned.");
+
+ EXPECT(IntTraits::kIsIntPtr,
+ "IntTraits should report intptr_t type.");
+ EXPECT(IntTraits::kIsIntPtr,
+ "IntTraits should report intptr_t type.");
+
+ INFO("IntUtil::iMin()/iMax().");
+ EXPECT(IntUtil::iMin(0, -1) == -1,
+ "IntUtil::iMin should return a minimum value.");
+ EXPECT(IntUtil::iMin(-1, -2) == -2,
+ "IntUtil::iMin should return a minimum value.");
+ EXPECT(IntUtil::iMin(1, 2) == 1,
+ "IntUtil::iMin should return a minimum value.");
+
+ EXPECT(IntUtil::iMax(0, -1) == 0,
+ "IntUtil::iMax should return a maximum value.");
+ EXPECT(IntUtil::iMax(-1, -2) == -1,
+ "IntUtil::iMax should return a maximum value.");
+ EXPECT(IntUtil::iMax(1, 2) == 2,
+ "IntUtil::iMax should return a maximum value.");
+
+ INFO("IntUtil::inInterval().");
+ EXPECT(IntUtil::inInterval(11, 10, 20) == true,
+ "IntUtil::inInterval should return true if inside.");
+ EXPECT(IntUtil::inInterval(101, 10, 20) == false,
+ "IntUtil::inInterval should return false if outside.");
+
+ INFO("IntUtil::isInt8().");
+ EXPECT(IntUtil::isInt8(-128) == true,
+ "IntUtil::isInt8<> should return true if inside.");
+ EXPECT(IntUtil::isInt8(127) == true,
+ "IntUtil::isInt8<> should return true if inside.");
+ EXPECT(IntUtil::isInt8(-129) == false,
+ "IntUtil::isInt8<> should return false if outside.");
+ EXPECT(IntUtil::isInt8(128) == false,
+ "IntUtil::isInt8<> should return false if outside.");
+
+ INFO("IntUtil::isUInt8().");
+ EXPECT(IntUtil::isUInt8(255) == true,
+ "IntUtil::isUInt8<> should return true if inside.");
+ EXPECT(IntUtil::isUInt8(256) == false,
+ "IntUtil::isUInt8<> should return false if outside.");
+ EXPECT(IntUtil::isUInt8(-1) == false,
+ "IntUtil::isUInt8<> should return false if negative.");
+
+ INFO("IntUtil::isInt16().");
+ EXPECT(IntUtil::isInt16(-32768) == true,
+ "IntUtil::isInt16<> should return true if inside.");
+ EXPECT(IntUtil::isInt16(32767) == true,
+ "IntUtil::isInt16<> should return true if inside.");
+ EXPECT(IntUtil::isInt16(-32769) == false,
+ "IntUtil::isInt16<> should return false if outside.");
+ EXPECT(IntUtil::isInt16(32768) == false,
+ "IntUtil::isInt16<> should return false if outside.");
+
+ INFO("IntUtil::isUInt16().");
+ EXPECT(IntUtil::isUInt16(65535) == true,
+ "IntUtil::isUInt16<> should return true if inside.");
+ EXPECT(IntUtil::isUInt16(65536) == false,
+ "IntUtil::isUInt16<> should return false if outside.");
+ EXPECT(IntUtil::isUInt16(-1) == false,
+ "IntUtil::isUInt16<> should return false if negative.");
+
+ INFO("IntUtil::isInt32().");
+ EXPECT(IntUtil::isInt32(2147483647) == true,
+ "IntUtil::isInt32 should return true if inside.");
+ EXPECT(IntUtil::isInt32(-2147483647 - 1) == true,
+ "IntUtil::isInt32 should return true if inside.");
+ EXPECT(IntUtil::isInt32(ASMJIT_UINT64_C(2147483648)) == false,
+ "IntUtil::isInt32 should return false if outside.");
+ EXPECT(IntUtil::isInt32(ASMJIT_UINT64_C(0xFFFFFFFF)) == false,
+ "IntUtil::isInt32 should return false if outside.");
+ EXPECT(IntUtil::isInt32(ASMJIT_UINT64_C(0xFFFFFFFF) + 1) == false,
+ "IntUtil::isInt32 should return false if outside.");
+
+ INFO("IntUtil::isUInt32().");
+ EXPECT(IntUtil::isUInt32(ASMJIT_UINT64_C(0xFFFFFFFF)) == true,
+ "IntUtil::isUInt32 should return true if inside.");
+ EXPECT(IntUtil::isUInt32(ASMJIT_UINT64_C(0xFFFFFFFF) + 1) == false,
+ "IntUtil::isUInt32 should return false if outside.");
+ EXPECT(IntUtil::isUInt32(-1) == false,
+ "IntUtil::isUInt32 should return false if negative.");
+
+ INFO("IntUtil::isPower2().");
+ for (i = 0; i < 64; i++) {
+ EXPECT(IntUtil::isPowerOf2(static_cast(1) << i) == true,
+ "IntUtil::isPower2() didn't report power of 2.");
+ EXPECT(IntUtil::isPowerOf2((static_cast(1) << i) ^ 0x001101) == false,
+ "IntUtil::isPower2() didn't report not power of 2.");
+ }
+
+ INFO("IntUtil::mask().");
+ for (i = 0; i < 32; i++) {
+ EXPECT(IntUtil::mask(i) == (1 << i),
+ "IntUtil::mask(%u) should return %X.", i, (1 << i));
+ }
+
+ INFO("IntUtil::bits().");
+ for (i = 0; i < 32; i++) {
+ uint32_t expectedBits = 0;
+
+ for (uint32_t b = 0; b < i; b++)
+ expectedBits |= static_cast(1) << b;
+
+ EXPECT(IntUtil::bits(i) == expectedBits,
+ "IntUtil::bits(%u) should return %X.", i, expectedBits);
+ }
+
+ INFO("IntUtil::hasBit().");
+ for (i = 0; i < 32; i++) {
+ EXPECT(IntUtil::hasBit((1 << i), i) == true,
+ "IntUtil::hasBit(%X, %u) should return true.", (1 << i), i);
+ }
+
+ INFO("IntUtil::bitCount().");
+ for (i = 0; i < 32; i++) {
+ EXPECT(IntUtil::bitCount((1 << i)) == 1,
+ "IntUtil::bitCount(%X) should return true.", (1 << i));
+ }
+ EXPECT(IntUtil::bitCount(0x000000F0) == 4, "");
+ EXPECT(IntUtil::bitCount(0x10101010) == 4, "");
+ EXPECT(IntUtil::bitCount(0xFF000000) == 8, "");
+ EXPECT(IntUtil::bitCount(0xFFFFFFF7) == 31, "");
+ EXPECT(IntUtil::bitCount(0x7FFFFFFF) == 31, "");
+
+ INFO("IntUtil::findFirstBit().");
+ for (i = 0; i < 32; i++) {
+ EXPECT(IntUtil::findFirstBit((1 << i)) == i,
+ "IntUtil::findFirstBit(%X) should return %u.", (1 << i), i);
+ }
+
+ INFO("IntUtil::isAligned().");
+ EXPECT(IntUtil::isAligned(0xFFFF, 4) == false, "");
+ EXPECT(IntUtil::isAligned(0xFFF4, 4) == true , "");
+ EXPECT(IntUtil::isAligned