mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-17 04:24:37 +03:00
Initial.
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
build_*
|
||||
292
CMakeLists.txt
Normal file
292
CMakeLists.txt
Normal file
@@ -0,0 +1,292 @@
|
||||
# =============================================================================
|
||||
# [AsmJit - CMakeLists.txt]
|
||||
# =============================================================================
|
||||
|
||||
CMake_Minimum_Required(VERSION 2.8.12)
|
||||
|
||||
# =============================================================================
|
||||
# [AsmJit - Configuration]
|
||||
# =============================================================================
|
||||
|
||||
# Whether to build static library (default FALSE).
|
||||
# Set(ASMJIT_STATIC FALSE)
|
||||
|
||||
# Whether to build samples (default FALSE).
|
||||
# Set(ASMJIT_BUILD_SAMPLES FALSE)
|
||||
|
||||
# =============================================================================
|
||||
# [AsmJit - Build]
|
||||
# =============================================================================
|
||||
|
||||
If(NOT CMAKE_PROJECT_NAME)
|
||||
Project(asmjit C CXX)
|
||||
Set(ASMJIT_PROJECT_STR "Project")
|
||||
Else()
|
||||
# Do not create a project if this CMakeLists.txt is included by a different
|
||||
# project. This allows easy static library build including debugger support.
|
||||
Set(ASMJIT_PROJECT_STR "Include")
|
||||
EndIf()
|
||||
|
||||
If(ASMJIT_STATIC)
|
||||
Set(ASMJIT_PROJECT_STR "${ASMJIT_PROJECT_STR}|Static")
|
||||
Else()
|
||||
Set(ASMJIT_PROJECT_STR "${ASMJIT_PROJECT_STR}|Shared")
|
||||
EndIf()
|
||||
|
||||
Message("")
|
||||
Message("== ====================================================")
|
||||
Message("== [AsmJit ${ASMJIT_PROJECT_STR}]")
|
||||
Message("== ====================================================")
|
||||
Message("")
|
||||
|
||||
# =============================================================================
|
||||
# [AsmJit - Directories]
|
||||
# =============================================================================
|
||||
|
||||
If(NOT ASMJIT_DIR)
|
||||
Set(ASMJIT_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
Message("-- Initializing ASMJIT_DIR=${ASMJIT_DIR}")
|
||||
Else()
|
||||
Message("-- Using Custom ASMJIT_DIR=${ASMJIT_DIR}")
|
||||
EndIf()
|
||||
|
||||
Set(ASMJIT_SRC_DIR "${ASMJIT_DIR}/src")
|
||||
Set(ASMJIT_INC_DIR "${ASMJIT_SRC_DIR}")
|
||||
|
||||
Include_Directories(${ASMJIT_SRC_DIR})
|
||||
|
||||
# =============================================================================
|
||||
# [AsmJit - Flags/Deps]
|
||||
# =============================================================================
|
||||
|
||||
Set(ASMJIT_DEPS)
|
||||
Set(ASMJIT_LFLAGS)
|
||||
|
||||
Set(ASMJIT_CDEFS)
|
||||
Set(ASMJIT_CDEFS_DBG ASMJIT_DEBUG)
|
||||
Set(ASMJIT_CDEFS_REL ASMJIT_RELEASE)
|
||||
|
||||
Set(ASMJIT_CFLAGS)
|
||||
Set(ASMJIT_CFLAGS_DBG)
|
||||
Set(ASMJIT_CFLAGS_REL)
|
||||
|
||||
If(MSVC)
|
||||
Set(ASMJIT_LFLAGS "/OPT:REF /OPT:ICF")
|
||||
Set(ASMJIT_CFLAGS /GF)
|
||||
Set(ASMJIT_CFLAGS_DBG /GS /GR-)
|
||||
Set(ASMJIT_CFLAGS_REL /Oi /Oy /GS- /GR-)
|
||||
EndIf()
|
||||
|
||||
If(CMAKE_COMPILER_IS_GNUCXX)
|
||||
Set(ASMJIT_CFLAGS -fno-exceptions)
|
||||
Set(ASMJIT_CFLAGS_DBG -O0
|
||||
-fno-inline-functions)
|
||||
Set(ASMJIT_CFLAGS_REL -O2
|
||||
-finline-functions
|
||||
-fomit-frame-pointer
|
||||
-fmerge-all-constants
|
||||
-fno-keep-static-consts)
|
||||
EndIf()
|
||||
|
||||
If(WIN32)
|
||||
List(APPEND ASMJIT_CDEFS _UNICODE)
|
||||
Else()
|
||||
List(APPEND ASMJIT_DEPS pthread)
|
||||
EndIf()
|
||||
|
||||
Set(ASMJIT_CFLAGS_DBG ${ASMJIT_CFLAGS} ${ASMJIT_CFLAGS_DBG})
|
||||
Set(ASMJIT_CFLAGS_REL ${ASMJIT_CFLAGS} ${ASMJIT_CFLAGS_REL})
|
||||
|
||||
# =============================================================================
|
||||
# [AsmJit - Macros]
|
||||
# =============================================================================
|
||||
|
||||
Macro(AsmJit_AddSource DST BASE_PATH)
|
||||
Set(__list "")
|
||||
Set(__path "${ASMJIT_SRC_DIR}/${BASE_PATH}")
|
||||
|
||||
ForEach(__name ${ARGN})
|
||||
Set(__file "${__path}/${__name}")
|
||||
Set(__cflags ${ASMJIT_CFLAGS})
|
||||
|
||||
If(__name MATCHES "\\.cpp|\\.h")
|
||||
If(${__cflags})
|
||||
Set_Source_Files_Properties(${__name} PROPERTIES COMPILE_FLAGS ${__cflags})
|
||||
EndIf()
|
||||
List(APPEND __list ${__file})
|
||||
EndIf()
|
||||
EndForEach()
|
||||
|
||||
List(APPEND "${DST}" ${__list})
|
||||
Source_Group(${BASE_PATH} FILES ${__list})
|
||||
EndMacro()
|
||||
|
||||
Macro(AsmJit_AddLibrary NAME SRC DEPS CDEFS_DBG CDEFS_REL CFLAGS_DBG CFLAGS_REL)
|
||||
If(NOT ASMJIT_STATIC)
|
||||
Set(__type "SHARED")
|
||||
Else()
|
||||
Set(__type "STATIC")
|
||||
EndIf()
|
||||
|
||||
Add_Library(${NAME} ${__type} ${SRC})
|
||||
|
||||
# Dependencies.
|
||||
Target_Link_Libraries(${NAME} ${DEPS})
|
||||
|
||||
# Compiler Flags.
|
||||
If(${CMAKE_BUILD_TYPE})
|
||||
If(${CMAKE_BUILD_TYPE} MATCHES "Debug")
|
||||
Set_Target_Properties(${NAME} PROPERTIES COMPILE_DEFINITIONS ${ASMJIT_CDEFS_DBG})
|
||||
Set_Target_Properties(${NAME} PROPERTIES COMPILE_FLAGS ${ASMJIT_CFLAGS_DBG})
|
||||
Else()
|
||||
Set_Target_Properties(${NAME} PROPERTIES COMPILE_DEFINITIONS ${ASMJIT_CDEFS_REL})
|
||||
Set_Target_Properties(${NAME} PROPERTIES COMPILE_FLAGS ${ASMJIT_CFLAGS_REL})
|
||||
EndIf()
|
||||
Else()
|
||||
Target_Compile_Definitions(${NAME} PUBLIC
|
||||
$<$<CONFIG:Debug>:${CDEFS_DBG}>$<$<NOT:$<CONFIG:Debug>>:${CDEFS_REL}>)
|
||||
|
||||
Target_Compile_Options(${NAME} PUBLIC
|
||||
$<$<CONFIG:Debug>:${CFLAGS_DBG}>$<$<NOT:$<CONFIG:Debug>>:${CFLAGS_REL}>)
|
||||
EndIf()
|
||||
|
||||
# Linker Flags.
|
||||
Set_Target_Properties(${NAME} PROPERTIES LINK_FLAGS "${ASMJIT_LFLAGS}")
|
||||
|
||||
# Install Instructions.
|
||||
If(NOT ASMJIT_STATIC)
|
||||
Install(TARGETS ${NAME} DESTINATION lib)
|
||||
EndIf()
|
||||
|
||||
Unset(__type)
|
||||
EndMacro()
|
||||
|
||||
# =============================================================================
|
||||
# [AsmJit - Source]
|
||||
# =============================================================================
|
||||
|
||||
Set(ASMJIT_SRC "")
|
||||
|
||||
AsmJit_AddSource(ASMJIT_SRC asmjit
|
||||
asmjit.h
|
||||
base.h
|
||||
build.h
|
||||
config.h
|
||||
contrib.h
|
||||
host.h
|
||||
x86.h
|
||||
)
|
||||
|
||||
AsmJit_AddSource(ASMJIT_SRC asmjit/base
|
||||
apibegin.h
|
||||
apiend.h
|
||||
|
||||
assembler.cpp
|
||||
assembler.h
|
||||
assert.cpp
|
||||
assert.h
|
||||
codegen.cpp
|
||||
codegen.h
|
||||
compiler.cpp
|
||||
compiler.h
|
||||
context.cpp
|
||||
context_p.h
|
||||
cpu.cpp
|
||||
cpu.h
|
||||
defs.cpp
|
||||
defs.h
|
||||
error.cpp
|
||||
error.h
|
||||
func.cpp
|
||||
func.h
|
||||
globals.h
|
||||
intutil.h
|
||||
lock.h
|
||||
logger.cpp
|
||||
logger.h
|
||||
memorymanager.cpp
|
||||
memorymanager.h
|
||||
podlist.h
|
||||
podvector.cpp
|
||||
podvector.h
|
||||
runtime.cpp
|
||||
runtime.h
|
||||
string.cpp
|
||||
string.h
|
||||
vectypes.h
|
||||
vmem.cpp
|
||||
vmem.h
|
||||
zone.cpp
|
||||
zone.h
|
||||
)
|
||||
|
||||
AsmJit_AddSource(ASMJIT_SRC asmjit/x86
|
||||
x86assembler.cpp
|
||||
x86assembler.h
|
||||
x86compiler.cpp
|
||||
x86compiler.h
|
||||
x86context.cpp
|
||||
x86context_p.h
|
||||
x86cpu.cpp
|
||||
x86cpu.h
|
||||
x86defs.cpp
|
||||
x86defs.h
|
||||
x86func.cpp
|
||||
x86func.h
|
||||
)
|
||||
|
||||
AsmJit_AddSource(ASMJIT_SRC asmjit/contrib
|
||||
winremoteruntime.cpp
|
||||
winremoteruntime.h
|
||||
)
|
||||
|
||||
# =============================================================================
|
||||
# [AsmJit - Headers]
|
||||
# =============================================================================
|
||||
|
||||
If(NOT ASMJIT_STATIC)
|
||||
ForEach(i ${ASMJIT_SRC})
|
||||
Get_Filename_Component(path ${i} PATH)
|
||||
Get_Filename_Component(name ${i} NAME)
|
||||
String(REGEX REPLACE "^${ASMJIT_SRC_DIR}/" "" targetpath "${path}")
|
||||
If(${name} MATCHES ".h$")
|
||||
If(NOT "${name}" MATCHES "_p.h$")
|
||||
Install(FILES ${i} DESTINATION "include/${targetpath}")
|
||||
EndIf()
|
||||
EndIf()
|
||||
EndForEach()
|
||||
EndIf()
|
||||
|
||||
# =============================================================================
|
||||
# [Asmjit - Library]
|
||||
# =============================================================================
|
||||
|
||||
AsmJit_AddLibrary(asmjit
|
||||
"${ASMJIT_SRC}"
|
||||
"${ASMJIT_DEPS}"
|
||||
"${ASMJIT_CDEFS_DBG}"
|
||||
"${ASMJIT_CDEFS_REL}"
|
||||
"${ASMJIT_CFLAGS_DBG}"
|
||||
"${ASMJIT_CFLAGS_REL}"
|
||||
)
|
||||
|
||||
# =============================================================================
|
||||
# [Asmjit - Samples]
|
||||
# =============================================================================
|
||||
|
||||
If(ASMJIT_BUILD_SAMPLES)
|
||||
Set(ASMJIT_SRC_SAMPLES
|
||||
benchx86
|
||||
testcpu
|
||||
testdummy
|
||||
testmem
|
||||
testopcode
|
||||
testsizeof
|
||||
testx86
|
||||
)
|
||||
|
||||
ForEach(file ${ASMJIT_SRC_SAMPLES})
|
||||
Add_Executable(${file} src/app/test/${file}.cpp)
|
||||
Target_Link_Libraries(${file} asmjit ${ASMJIT_DEPS})
|
||||
EndForEach(file)
|
||||
EndIf()
|
||||
18
LICENSE.md
Normal file
18
LICENSE.md
Normal file
@@ -0,0 +1,18 @@
|
||||
AsmJit - Complete x86/x64 JIT and Remote Assembler for C++
|
||||
Copyright (c) 2008-2014, Petr Kobalicek <kobalicek.petr@gmail.com>
|
||||
|
||||
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.
|
||||
129
README.md
Normal file
129
README.md
Normal file
@@ -0,0 +1,129 @@
|
||||
AsmJit - Complete x86/x64 JIT and Remote Assembler for C++
|
||||
==========================================================
|
||||
|
||||
Official Repository: https://github.com/kobalicekp/asmjit
|
||||
|
||||
Support the Project: [](
|
||||
https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=QDRM6SRNG7378&lc=EN;&item_name=asmjit¤cy_code=EUR)
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
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.
|
||||
|
||||
Features
|
||||
========
|
||||
|
||||
- Complete x86/x64 instruction set - MMX, SSE, AVX, BMI, XOP, FMA...,
|
||||
- Low-level and high-level code generation,
|
||||
- Built-in CPU detection,
|
||||
- Virtual Memory management,
|
||||
- Pretty logging and error handling,
|
||||
- Small and embeddable, around 150kB compiled,
|
||||
- Zero dependencies, not even STL or RTTI.
|
||||
|
||||
Supported Environments
|
||||
======================
|
||||
|
||||
## Operating Systems
|
||||
|
||||
- BSDs
|
||||
- Linux
|
||||
- Mac
|
||||
- Windows
|
||||
|
||||
## C++ Compilers
|
||||
|
||||
- BorlandC++
|
||||
- GNU (3.4.X+, 4.0+, MinGW)
|
||||
- MSVC (VS2005, VS2008, VS2010)
|
||||
- Other compilers require testing
|
||||
|
||||
## Backends
|
||||
|
||||
- X86
|
||||
- X64
|
||||
|
||||
Project Organization
|
||||
====================
|
||||
|
||||
- project root /
|
||||
- extras - Documentation and addons
|
||||
- contrib - Contributions (not official, but included)
|
||||
- doc - Documentation generator files
|
||||
- msvs - MS Visual Studio additions
|
||||
- scripts - Scripts to generate project files and regenerate defs
|
||||
- src - Source code
|
||||
- asmjit - Public header files (always include from here)
|
||||
- base - Base files, used by the AsmJit and all backends
|
||||
- x86 - X86/X64 specific files, used only by X86/X64 backend
|
||||
|
||||
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.
|
||||
|
||||
Configuring/Building
|
||||
====================
|
||||
|
||||
AsmJit is designed to be easy embeddable in any project. However, it has some compile-time flags that can be used to build a specific version of AsmJit including or omitting certain features:
|
||||
|
||||
## Debugging
|
||||
|
||||
- *ASMJIT_DEBUG* - Define to always turn debugging on (regardless of build-mode).
|
||||
- *ASMJIT_RELEASE* - Define to always turn debugging off (regardless of build-mode).
|
||||
|
||||
- By default none of these is defined, AsmJit detects mode based on compile-time macros (useful when using IDE that has switches for Debug/Release/etc...).
|
||||
|
||||
## Library
|
||||
|
||||
- *ASMJIT_STATIC* - Define when building AsmJit as a static library. No symbols will be exported by AsmJit by default.
|
||||
- *ASMJIT_API* - This is AsmJit API decorator that is used in all functions that has to be exported. It can be redefined, however it's not a recommended way.
|
||||
|
||||
- By default AsmJit build is configured as a shared library and *ASMJIT_API* contains compiler specific attributes to import/export AsmJit symbols.
|
||||
|
||||
## Backends
|
||||
|
||||
- *ASMJIT_BUILD_X86* - Always build x86 backend regardless of host architecture.
|
||||
- *ASMJIT_BUILD_X64* - Always build x64 backend regardless of host architecture.
|
||||
- *ASMJIT_BUILD_HOST* - Always build host backand, if only *ASMJIT_BUILD_HOST* is used only the host architecture detected at compile-time will be included.
|
||||
|
||||
- By default only *ASMJIT_BUILD_HOST* is defined.
|
||||
|
||||
To build AsmJit please use cmake <http://www.cmake.org> that will generate project files for your favorite IDE and platform. If you don't use cmake and you still want to include AsmJit in your project it's perfectly fine by just including it there, probably defining *ASMJIT_STATIC* to prevent AsmJit trying to export the API.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Comprehensive test suite can be found at src/app/test directory in AsmJit package. It can be used as a starting point before using AsmJit.
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
AsmJit can be distributed under zlib license:
|
||||
|
||||
* <http://www.opensource.org/licenses/zlib-license.php>
|
||||
|
||||
Google Groups & Mailing Lists
|
||||
=============================
|
||||
|
||||
AsmJit google group:
|
||||
|
||||
* http://groups.google.com/group/asmjit-dev
|
||||
|
||||
AsmJit mailing list:
|
||||
|
||||
* asmjit-dev@googlegroups.com
|
||||
|
||||
Contact Authors & Maintainers
|
||||
=============================
|
||||
|
||||
* Petr Kobalicek <kobalicek.petr@gmail.com>
|
||||
113
src/app/test/benchx86.cpp
Normal file
113
src/app/test/benchx86.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include <asmjit/asmjit.h>
|
||||
|
||||
// [Dependencies - Test]
|
||||
#include "genblend.h"
|
||||
#include "genopcode.h"
|
||||
|
||||
// [Dependencies - C]
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// ============================================================================
|
||||
// [Performance]
|
||||
// ============================================================================
|
||||
|
||||
struct Performance {
|
||||
static inline uint32_t now() {
|
||||
#if defined(ASMJIT_OS_WINDOWS)
|
||||
return ::GetTickCount();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void reset() {
|
||||
tick = 0;
|
||||
best = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
inline uint32_t start() {
|
||||
return (tick = now());
|
||||
}
|
||||
|
||||
inline uint32_t diff() const {
|
||||
return now() - tick;
|
||||
}
|
||||
|
||||
inline uint32_t end() {
|
||||
tick = diff();
|
||||
if (best > tick)
|
||||
best = tick;
|
||||
return tick;
|
||||
}
|
||||
|
||||
uint32_t tick;
|
||||
uint32_t best;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [Main]
|
||||
// ============================================================================
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using namespace asmjit;
|
||||
using namespace asmjit::host;
|
||||
|
||||
Performance perf;
|
||||
uint32_t kNumRepeats = 10;
|
||||
uint32_t kNumIterations = 100000;
|
||||
|
||||
JitRuntime runtime;
|
||||
Assembler a(&runtime);
|
||||
Compiler c(&runtime);
|
||||
|
||||
uint32_t r, i;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Bench - Opcode]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
perf.reset();
|
||||
for (r = 0; r < kNumRepeats; r++) {
|
||||
perf.start();
|
||||
for (i = 0; i < kNumIterations; i++) {
|
||||
asmgen::opcode(a);
|
||||
|
||||
void *p = a.make();
|
||||
runtime.release(p);
|
||||
|
||||
a.clear();
|
||||
}
|
||||
perf.end();
|
||||
}
|
||||
printf("Opcode | Time: %u [ms]\n", perf.best);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Bench - Blend]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
perf.reset();
|
||||
for (r = 0; r < kNumRepeats; r++) {
|
||||
perf.start();
|
||||
for (i = 0; i < kNumIterations; i++) {
|
||||
asmgen::blend(c);
|
||||
|
||||
void* p = c.make();
|
||||
runtime.release(p);
|
||||
|
||||
c.clear();
|
||||
}
|
||||
perf.end();
|
||||
}
|
||||
printf("Blend | Time: %u [ms]\n", perf.best);
|
||||
|
||||
return 0;
|
||||
}
|
||||
178
src/app/test/genblend.h
Normal file
178
src/app/test/genblend.h
Normal file
@@ -0,0 +1,178 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _GENBLEND_H
|
||||
#define _GENBLEND_H
|
||||
|
||||
// [Dependencies]
|
||||
#include <asmjit/asmjit.h>
|
||||
|
||||
namespace asmgen {
|
||||
|
||||
// Generate a typical alpha blend function using SSE2 instruction set. Used
|
||||
// for benchmarking and also in test86. The generated code should be stable
|
||||
// and can be tested.
|
||||
static void blend(asmjit::host::Compiler& c) {
|
||||
using namespace asmjit;
|
||||
using namespace asmjit::host;
|
||||
|
||||
GpVar dst(c, kVarTypeIntPtr, "dst");
|
||||
GpVar src(c, kVarTypeIntPtr, "src");
|
||||
|
||||
GpVar i(c, kVarTypeIntPtr, "i");
|
||||
GpVar j(c, kVarTypeIntPtr, "j");
|
||||
GpVar t(c, kVarTypeIntPtr, "t");
|
||||
|
||||
XmmVar cZero(c, kVarTypeXmm, "cZero");
|
||||
XmmVar cMul255A(c, kVarTypeXmm, "cMul255A");
|
||||
XmmVar cMul255M(c, kVarTypeXmm, "cMul255M");
|
||||
|
||||
XmmVar x0(c, kVarTypeXmm, "x0");
|
||||
XmmVar x1(c, kVarTypeXmm, "x1");
|
||||
XmmVar y0(c, kVarTypeXmm, "y0");
|
||||
XmmVar a0(c, kVarTypeXmm, "a0");
|
||||
XmmVar a1(c, kVarTypeXmm, "a1");
|
||||
|
||||
Label L_SmallLoop(c);
|
||||
Label L_SmallEnd(c);
|
||||
|
||||
Label L_LargeLoop(c);
|
||||
Label L_LargeEnd(c);
|
||||
|
||||
Label L_Data(c);
|
||||
|
||||
c.addFunc(kFuncConvHost, FuncBuilder3<FnVoid, void*, const void*, size_t>());
|
||||
|
||||
c.setArg(0, dst);
|
||||
c.setArg(1, src);
|
||||
c.setArg(2, i);
|
||||
|
||||
c.alloc(dst);
|
||||
c.alloc(src);
|
||||
c.alloc(i);
|
||||
|
||||
// How many pixels we have to process to align the loop.
|
||||
c.lea(t, ptr(L_Data));
|
||||
c.xor_(j, j);
|
||||
c.xorps(cZero, cZero);
|
||||
|
||||
c.sub(j, dst);
|
||||
c.movaps(cMul255A, ptr(t, 0));
|
||||
|
||||
c.and_(j, 15);
|
||||
c.movaps(cMul255M, ptr(t, 16));
|
||||
|
||||
c.shr(j, 2);
|
||||
c.jz(L_SmallEnd);
|
||||
|
||||
// j = min(i, j).
|
||||
c.cmp(j, i);
|
||||
c.cmovg(j, i);
|
||||
|
||||
// i -= j.
|
||||
c.sub(i, j);
|
||||
|
||||
// Small loop.
|
||||
c.bind(L_SmallLoop);
|
||||
|
||||
c.pcmpeqb(a0, a0);
|
||||
c.movd(y0, ptr(src));
|
||||
|
||||
c.pxor(a0, y0);
|
||||
c.movd(x0, ptr(dst));
|
||||
|
||||
c.psrlw(a0, 8);
|
||||
c.punpcklbw(x0, cZero);
|
||||
|
||||
c.pshuflw(a0, a0, mm_shuffle(1, 1, 1, 1));
|
||||
c.punpcklbw(y0, cZero);
|
||||
|
||||
c.pmullw(x0, a0);
|
||||
c.paddsw(x0, cMul255A);
|
||||
c.pmulhuw(x0, cMul255M);
|
||||
|
||||
c.paddw(x0, y0);
|
||||
c.packuswb(x0, x0);
|
||||
|
||||
c.movd(ptr(dst), x0);
|
||||
|
||||
c.add(dst, 4);
|
||||
c.add(src, 4);
|
||||
|
||||
c.dec(j);
|
||||
c.jnz(L_SmallLoop);
|
||||
|
||||
// Second section, prepare for an aligned loop.
|
||||
c.bind(L_SmallEnd);
|
||||
|
||||
c.test(i, i);
|
||||
c.mov(j, i);
|
||||
c.jz(c.getFunc()->getExitLabel());
|
||||
|
||||
c.and_(j, 3);
|
||||
c.shr(i, 2);
|
||||
c.jz(L_LargeEnd);
|
||||
|
||||
// Aligned loop.
|
||||
c.bind(L_LargeLoop);
|
||||
|
||||
c.movups(y0, ptr(src));
|
||||
c.pcmpeqb(a0, a0);
|
||||
c.movaps(x0, ptr(dst));
|
||||
|
||||
c.xorps(a0, y0);
|
||||
c.movaps(x1, x0);
|
||||
|
||||
c.psrlw(a0, 8);
|
||||
c.punpcklbw(x0, cZero);
|
||||
|
||||
c.movaps(a1, a0);
|
||||
c.punpcklwd(a0, a0);
|
||||
|
||||
c.punpckhbw(x1, cZero);
|
||||
c.punpckhwd(a1, a1);
|
||||
|
||||
c.pshufd(a0, a0, mm_shuffle(3, 3, 1, 1));
|
||||
c.pshufd(a1, a1, mm_shuffle(3, 3, 1, 1));
|
||||
|
||||
c.pmullw(x0, a0);
|
||||
c.pmullw(x1, a1);
|
||||
|
||||
c.paddsw(x0, cMul255A);
|
||||
c.paddsw(x1, cMul255A);
|
||||
|
||||
c.pmulhuw(x0, cMul255M);
|
||||
c.pmulhuw(x1, cMul255M);
|
||||
|
||||
c.add(src, 16);
|
||||
c.packuswb(x0, x1);
|
||||
|
||||
c.paddw(x0, y0);
|
||||
c.movaps(ptr(dst), x0);
|
||||
|
||||
c.add(dst, 16);
|
||||
|
||||
c.dec(i);
|
||||
c.jnz(L_LargeLoop);
|
||||
|
||||
c.bind(L_LargeEnd);
|
||||
c.test(j, j);
|
||||
c.jnz(L_SmallLoop);
|
||||
|
||||
c.endFunc();
|
||||
|
||||
// Data.
|
||||
c.align(16);
|
||||
c.bind(L_Data);
|
||||
c.dxmm(XmmData::fromSw(0x0080));
|
||||
c.dxmm(XmmData::fromSw(0x0101));
|
||||
}
|
||||
|
||||
} // asmgen namespace
|
||||
|
||||
// [Guard]
|
||||
#endif // _GENBLEND_H
|
||||
2296
src/app/test/genopcode.h
Normal file
2296
src/app/test/genopcode.h
Normal file
File diff suppressed because it is too large
Load Diff
114
src/app/test/testcpu.cpp
Normal file
114
src/app/test/testcpu.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include <asmjit/asmjit.h>
|
||||
|
||||
// [Dependencies - C]
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
struct CpuFeature {
|
||||
uint32_t feature;
|
||||
const char* description;
|
||||
};
|
||||
|
||||
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
|
||||
static const CpuFeature x86x64Features[] = {
|
||||
{ x86x64::kCpuFeatureMultithreading , "Multithreading" },
|
||||
{ x86x64::kCpuFeatureExecuteDisableBit , "Execute-Disable Bit" },
|
||||
{ x86x64::kCpuFeatureRdtsc , "Rdtsc" },
|
||||
{ x86x64::kCpuFeatureRdtscp , "Rdtscp" },
|
||||
{ x86x64::kCpuFeatureCmov , "Cmov" },
|
||||
{ x86x64::kCpuFeatureCmpXchg8B , "Cmpxchg8b" },
|
||||
{ x86x64::kCpuFeatureCmpXchg16B , "Cmpxchg16b" },
|
||||
{ x86x64::kCpuFeatureClflush , "Clflush" },
|
||||
{ x86x64::kCpuFeaturePrefetch , "Prefetch" },
|
||||
{ x86x64::kCpuFeatureLahfSahf , "Lahf/Sahf" },
|
||||
{ x86x64::kCpuFeatureFxsr , "Fxsave/Fxrstor" },
|
||||
{ x86x64::kCpuFeatureFfxsr , "Fxsave/Fxrstor Opt." },
|
||||
{ x86x64::kCpuFeatureMmx , "Mmx" },
|
||||
{ x86x64::kCpuFeatureMmxExt , "MmxExt" },
|
||||
{ x86x64::kCpuFeature3dNow , "3dnow" },
|
||||
{ x86x64::kCpuFeature3dNowExt , "3dnowExt" },
|
||||
{ x86x64::kCpuFeatureSse , "Sse" },
|
||||
{ x86x64::kCpuFeatureSse2 , "Sse2" },
|
||||
{ x86x64::kCpuFeatureSse3 , "Sse3" },
|
||||
{ x86x64::kCpuFeatureSsse3 , "Ssse3" },
|
||||
{ x86x64::kCpuFeatureSse4A , "Sse4a" },
|
||||
{ x86x64::kCpuFeatureSse41 , "Sse4.1" },
|
||||
{ x86x64::kCpuFeatureSse42 , "Sse4.2" },
|
||||
{ x86x64::kCpuFeatureMsse , "Misaligned SSE" },
|
||||
{ x86x64::kCpuFeatureMonitorMWait , "Monitor/MWait" },
|
||||
{ x86x64::kCpuFeatureMovbe , "Movbe" },
|
||||
{ x86x64::kCpuFeaturePopcnt , "Popcnt" },
|
||||
{ x86x64::kCpuFeatureLzcnt , "Lzcnt" },
|
||||
{ x86x64::kCpuFeatureAesni , "AesNI" },
|
||||
{ x86x64::kCpuFeaturePclmulqdq , "Pclmulqdq" },
|
||||
{ x86x64::kCpuFeatureRdrand , "Rdrand" },
|
||||
{ x86x64::kCpuFeatureAvx , "Avx" },
|
||||
{ x86x64::kCpuFeatureAvx2 , "Avx2" },
|
||||
{ x86x64::kCpuFeatureF16C , "F16C" },
|
||||
{ x86x64::kCpuFeatureFma3 , "Fma3" },
|
||||
{ x86x64::kCpuFeatureFma4 , "Fma4" },
|
||||
{ x86x64::kCpuFeatureXop , "Xop" },
|
||||
{ x86x64::kCpuFeatureBmi , "Bmi" },
|
||||
{ x86x64::kCpuFeatureBmi2 , "Bmi2" },
|
||||
{ x86x64::kCpuFeatureHle , "Hle" },
|
||||
{ x86x64::kCpuFeatureRtm , "Rtm" },
|
||||
{ x86x64::kCpuFeatureFsGsBase , "FsGsBase" },
|
||||
{ x86x64::kCpuFeatureRepMovsbStosbExt , "RepMovsbStosbExt" }
|
||||
};
|
||||
#endif // ASMJIT_HOST || ASMJIT_HOST_X64
|
||||
|
||||
static void printFeatures(const char* prefix, const BaseCpu* cpu, const CpuFeature* data) {
|
||||
for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(x86x64Features); i++) {
|
||||
if (cpu->hasFeature(data[i].feature)) {
|
||||
printf("%s%s\n", prefix, data[i].description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
const BaseCpu* cpu_ = BaseCpu::getHost();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Core Features]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
printf("Host CPU\n");
|
||||
printf("========\n");
|
||||
|
||||
printf("\nBasic info\n");
|
||||
printf(" Vendor string : %s\n", cpu_->getVendorString());
|
||||
printf(" Brand string : %s\n", cpu_->getBrandString());
|
||||
printf(" Family : %u\n", cpu_->getFamily());
|
||||
printf(" Model : %u\n", cpu_->getModel());
|
||||
printf(" Stepping : %u\n", cpu_->getStepping());
|
||||
printf(" Cores Count : %u\n", cpu_->getCoresCount());
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [X86 Features]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
|
||||
const x86x64::Cpu* cpu = static_cast<const x86x64::Cpu*>(cpu_);
|
||||
|
||||
printf("\nX86/X64 Extended Info:\n");
|
||||
printf(" Processor Type : %u\n", cpu->getProcessorType());
|
||||
printf(" Brand Index : %u\n", cpu->getBrandIndex());
|
||||
printf(" CL Flush Cache Line : %u\n", cpu->getFlushCacheLineSize());
|
||||
printf(" Max logical Processors: %u\n", cpu->getMaxLogicalProcessors());
|
||||
|
||||
printf("\nX86/X64 Features:\n");
|
||||
printFeatures(" ", cpu, x86x64Features);
|
||||
#endif // ASMJIT_HOST || ASMJIT_HOST_X64
|
||||
|
||||
return 0;
|
||||
}
|
||||
66
src/app/test/testdummy.cpp
Normal file
66
src/app/test/testdummy.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// This file is used as a dummy test. It's changed during development.
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include <asmjit/asmjit.h>
|
||||
|
||||
// [Dependencies - C]
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef void (*MyFunc)(void);
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using namespace asmjit;
|
||||
using namespace asmjit::host;
|
||||
|
||||
JitRuntime runtime;
|
||||
FileLogger logger(stderr);
|
||||
logger.setOption(kLoggerOptionBinaryForm, true);
|
||||
|
||||
Compiler c(&runtime);
|
||||
c.setLogger(&logger);
|
||||
|
||||
c.addFunc(kFuncConvHost, FuncBuilder0<void>());
|
||||
|
||||
Label L_1(c);
|
||||
Label L_2(c);
|
||||
Label L_3(c);
|
||||
Label L_4(c);
|
||||
Label L_5(c);
|
||||
Label L_6(c);
|
||||
Label L_7(c);
|
||||
|
||||
GpVar v1(c);
|
||||
GpVar v2(c);
|
||||
|
||||
c.bind(L_2);
|
||||
c.bind(L_3);
|
||||
|
||||
c.jmp(L_1);
|
||||
c.bind(L_5);
|
||||
c.mov(v1, 0);
|
||||
c.bind(L_6);
|
||||
c.jmp(L_3);
|
||||
c.mov(v2, 1);
|
||||
c.jmp(L_1);
|
||||
c.bind(L_4);
|
||||
c.jmp(L_2);
|
||||
c.bind(L_7);
|
||||
c.add(v1, v2);
|
||||
|
||||
c.bind(L_1);
|
||||
c.ret();
|
||||
c.endFunc();
|
||||
|
||||
MyFunc func = asmjit_cast<MyFunc>(c.make());
|
||||
runtime.release((void*)func);
|
||||
|
||||
return 0;
|
||||
}
|
||||
173
src/app/test/testmem.cpp
Normal file
173
src/app/test/testmem.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include <asmjit/asmjit.h>
|
||||
|
||||
// [Dependencies - C]
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
static int problems = 0;
|
||||
|
||||
static void gen(void* a, void* b, int i) {
|
||||
int pattern = rand() % 256;
|
||||
*(int *)a = i;
|
||||
*(int *)b = i;
|
||||
::memset((char*)a + sizeof(int), pattern, i - sizeof(int));
|
||||
::memset((char*)b + sizeof(int), pattern, i - sizeof(int));
|
||||
}
|
||||
|
||||
static void verify(void* a, void* b) {
|
||||
int ai = *(int*)a;
|
||||
int bi = *(int*)b;
|
||||
if (ai != bi || memcmp(a, b, ai) != 0)
|
||||
{
|
||||
printf("Failed to verify %p\n", a);
|
||||
problems++;
|
||||
}
|
||||
}
|
||||
|
||||
static void die() {
|
||||
printf("Couldn't allocate virtual memory, this test needs at least 100MB of free virtual memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void stats(MemoryManager* memmgr) {
|
||||
printf("-- Used: %d\n", (int)memmgr->getUsedBytes());
|
||||
printf("-- Allocated: %d\n", (int)memmgr->getAllocatedBytes());
|
||||
}
|
||||
|
||||
static void shuffle(void **a, void **b, size_t count) {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
size_t si = (size_t)rand() % count;
|
||||
|
||||
void *ta = a[i];
|
||||
void *tb = b[i];
|
||||
|
||||
a[i] = a[si];
|
||||
b[i] = b[si];
|
||||
|
||||
a[si] = ta;
|
||||
b[si] = tb;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
MemoryManager* memmgr = MemoryManager::getGlobal();
|
||||
|
||||
size_t i;
|
||||
size_t count = 200000;
|
||||
|
||||
printf("Memory alloc/free test - %d allocations\n\n", (int)count);
|
||||
|
||||
void** a = (void**)::malloc(sizeof(void*) * count);
|
||||
void** b = (void**)::malloc(sizeof(void*) * count);
|
||||
if (!a || !b) die();
|
||||
|
||||
srand(100);
|
||||
printf("Allocating virtual memory...");
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
int r = (rand() % 1000) + 4;
|
||||
|
||||
a[i] = memmgr->alloc(r);
|
||||
if (a[i] == NULL) die();
|
||||
|
||||
::memset(a[i], 0, r);
|
||||
}
|
||||
|
||||
printf("done\n");
|
||||
stats(memmgr);
|
||||
|
||||
printf("\n");
|
||||
printf("Freeing virtual memory...");
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (memmgr->release(a[i]) != kErrorOk) {
|
||||
printf("Failed to free %p\n", b[i]);
|
||||
problems++;
|
||||
}
|
||||
}
|
||||
|
||||
printf("done\n");
|
||||
stats(memmgr);
|
||||
|
||||
printf("\n");
|
||||
printf("Verified alloc/free test - %d allocations\n\n", (int)count);
|
||||
|
||||
printf("Alloc...");
|
||||
for (i = 0; i < count; i++) {
|
||||
int r = (rand() % 1000) + 4;
|
||||
|
||||
a[i] = memmgr->alloc(r);
|
||||
b[i] = ::malloc(r);
|
||||
if (a[i] == NULL || b[i] == NULL) die();
|
||||
|
||||
gen(a[i], b[i], r);
|
||||
}
|
||||
printf("done\n");
|
||||
stats(memmgr);
|
||||
|
||||
printf("\n");
|
||||
printf("Shuffling...");
|
||||
shuffle(a, b, count);
|
||||
printf("done\n");
|
||||
|
||||
printf("\n");
|
||||
printf("Verify and free...");
|
||||
for (i = 0; i < count / 2; i++) {
|
||||
verify(a[i], b[i]);
|
||||
if (memmgr->release(a[i]) != kErrorOk) {
|
||||
printf("Failed to free %p\n", a[i]);
|
||||
problems++;
|
||||
}
|
||||
free(b[i]);
|
||||
}
|
||||
printf("done\n");
|
||||
stats(memmgr);
|
||||
|
||||
printf("\n");
|
||||
printf("Alloc...");
|
||||
for (i = 0; i < count / 2; i++) {
|
||||
int r = (rand() % 1000) + 4;
|
||||
|
||||
a[i] = memmgr->alloc(r);
|
||||
b[i] = ::malloc(r);
|
||||
if (a[i] == NULL || b[i] == NULL) die();
|
||||
|
||||
gen(a[i], b[i], r);
|
||||
}
|
||||
printf("done\n");
|
||||
stats(memmgr);
|
||||
|
||||
printf("\n");
|
||||
printf("Verify and free...");
|
||||
for (i = 0; i < count; i++) {
|
||||
verify(a[i], b[i]);
|
||||
if (memmgr->release(a[i]) != kErrorOk) {
|
||||
printf("Failed to free %p\n", a[i]);
|
||||
problems++;
|
||||
}
|
||||
free(b[i]);
|
||||
}
|
||||
printf("done\n");
|
||||
stats(memmgr);
|
||||
|
||||
printf("\n");
|
||||
if (problems)
|
||||
printf("Status: Failure: %d problems found\n", problems);
|
||||
else
|
||||
printf("Status: Success\n");
|
||||
|
||||
::free(a);
|
||||
::free(b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
42
src/app/test/testopcode.cpp
Normal file
42
src/app/test/testopcode.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// This file is used to test opcodes generated by AsmJit. Output can be
|
||||
// disassembled in your IDE or by your favourite disassembler. Instructions
|
||||
// are sorted alphabetically.
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include <asmjit/asmjit.h>
|
||||
|
||||
// [Dependencies - Test]
|
||||
#include "genopcode.h"
|
||||
|
||||
// [Dependencies - C]
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef void (*VoidFunc)(void);
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using namespace asmjit;
|
||||
using namespace asmjit::host;
|
||||
|
||||
FileLogger logger(stdout);
|
||||
logger.setOption(kLoggerOptionBinaryForm, true);
|
||||
|
||||
JitRuntime runtime;
|
||||
Assembler a(&runtime);
|
||||
|
||||
a.setLogger(&logger);
|
||||
asmgen::opcode(a);
|
||||
|
||||
VoidFunc p = asmjit_cast<VoidFunc>(a.make());
|
||||
p();
|
||||
runtime.release((void*)p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
106
src/app/test/testsizeof.cpp
Normal file
106
src/app/test/testsizeof.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include <asmjit/base.h>
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
|
||||
#include <asmjit/x86.h>
|
||||
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
|
||||
|
||||
// [Dependencies - C]
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Runtime]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
printf("Sizeof[Runtime]:\n");
|
||||
printf(" int8_t : %u\n", static_cast<uint32_t>(sizeof(int8_t)));
|
||||
printf(" int16_t : %u\n", static_cast<uint32_t>(sizeof(int16_t)));
|
||||
printf(" int32_t : %u\n", static_cast<uint32_t>(sizeof(int32_t)));
|
||||
printf(" int64_t : %u\n", static_cast<uint32_t>(sizeof(int64_t)));
|
||||
printf(" long : %u\n", static_cast<uint32_t>(sizeof(long)));
|
||||
printf(" size_t : %u\n", static_cast<uint32_t>(sizeof(size_t)));
|
||||
printf(" intptr_t : %u\n", static_cast<uint32_t>(sizeof(intptr_t)));
|
||||
printf(" float : %u\n", static_cast<uint32_t>(sizeof(float)));
|
||||
printf(" double : %u\n", static_cast<uint32_t>(sizeof(double)));
|
||||
printf(" void* : %u\n", static_cast<uint32_t>(sizeof(void*)));
|
||||
printf("\n");
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Core]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
printf("Sizeof[Base]:\n");
|
||||
printf(" asmjit::CodeGen : %u\n", static_cast<uint32_t>(sizeof(CodeGen)));
|
||||
printf(" asmjit::BaseAssembler : %u\n", static_cast<uint32_t>(sizeof(BaseAssembler)));
|
||||
printf(" asmjit::BaseCompiler : %u\n", static_cast<uint32_t>(sizeof(BaseCompiler)));
|
||||
printf(" asmjit::BaseRuntime : %u\n", static_cast<uint32_t>(sizeof(BaseRuntime)));
|
||||
printf("\n");
|
||||
printf(" asmjit::Operand : %u\n", static_cast<uint32_t>(sizeof(Operand)));
|
||||
printf(" asmjit::BaseReg : %u\n", static_cast<uint32_t>(sizeof(BaseReg)));
|
||||
printf(" asmjit::BaseVar : %u\n", static_cast<uint32_t>(sizeof(BaseVar)));
|
||||
printf(" asmjit::BaseMem : %u\n", static_cast<uint32_t>(sizeof(BaseMem)));
|
||||
printf(" asmjit::Imm : %u\n", static_cast<uint32_t>(sizeof(Imm)));
|
||||
printf(" asmjit::Label : %u\n", static_cast<uint32_t>(sizeof(Label)));
|
||||
printf("\n");
|
||||
printf(" asmjit::Ptr : %u\n", static_cast<uint32_t>(sizeof(Ptr)));
|
||||
printf(" asmjit::SignedPtr : %u\n", static_cast<uint32_t>(sizeof(SignedPtr)));
|
||||
printf("\n");
|
||||
printf(" asmjit::LabelData : %u\n", static_cast<uint32_t>(sizeof(LabelData)));
|
||||
printf(" asmjit::RelocData : %u\n", static_cast<uint32_t>(sizeof(RelocData)));
|
||||
printf("\n");
|
||||
printf(" asmjit::BaseNode : %u\n", static_cast<uint32_t>(sizeof(BaseNode)));
|
||||
printf(" asmjit::AlignNode : %u\n", static_cast<uint32_t>(sizeof(AlignNode)));
|
||||
printf(" asmjit::CallNode : %u\n", static_cast<uint32_t>(sizeof(CallNode)));
|
||||
printf(" asmjit::CommentNode : %u\n", static_cast<uint32_t>(sizeof(CommentNode)));
|
||||
printf(" asmjit::EmbedNode : %u\n", static_cast<uint32_t>(sizeof(EmbedNode)));
|
||||
printf(" asmjit::FuncNode : %u\n", static_cast<uint32_t>(sizeof(FuncNode)));
|
||||
printf(" asmjit::EndNode : %u\n", static_cast<uint32_t>(sizeof(EndNode)));
|
||||
printf(" asmjit::InstNode : %u\n", static_cast<uint32_t>(sizeof(InstNode)));
|
||||
printf(" asmjit::JumpNode : %u\n", static_cast<uint32_t>(sizeof(JumpNode)));
|
||||
printf(" asmjit::TargetNode : %u\n", static_cast<uint32_t>(sizeof(TargetNode)));
|
||||
printf("\n");
|
||||
printf(" asmjit::FuncDecl : %u\n", static_cast<uint32_t>(sizeof(FuncDecl)));
|
||||
printf(" asmjit::FuncInOut : %u\n", static_cast<uint32_t>(sizeof(FuncInOut)));
|
||||
printf(" asmjit::FuncPrototype : %u\n", static_cast<uint32_t>(sizeof(FuncPrototype)));
|
||||
printf("\n");
|
||||
printf(" asmjit::VarAttr : %u\n", static_cast<uint32_t>(sizeof(VarAttr)));
|
||||
printf(" asmjit::VarData : %u\n", static_cast<uint32_t>(sizeof(VarData)));
|
||||
printf(" asmjit::BaseVarInst : %u\n", static_cast<uint32_t>(sizeof(BaseVarInst)));
|
||||
printf(" asmjit::BaseVarState : %u\n", static_cast<uint32_t>(sizeof(BaseVarState)));
|
||||
printf("\n");
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [X86/X64]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
|
||||
printf("Sizeof[X86/X64]:\n");
|
||||
printf(" asmjit::x86x64::X86X64Assembler: %u\n", static_cast<uint32_t>(sizeof(x86x64::X86X64Assembler)));
|
||||
printf(" asmjit::x86x64::X86X64Compiler : %u\n", static_cast<uint32_t>(sizeof(x86x64::X86X64Compiler)));
|
||||
printf("\n");
|
||||
printf(" asmjit::x86x64::X86X64CallNode : %u\n", static_cast<uint32_t>(sizeof(x86x64::X86X64CallNode)));
|
||||
printf(" asmjit::x86x64::X86X64FuncNode : %u\n", static_cast<uint32_t>(sizeof(x86x64::X86X64FuncNode)));
|
||||
printf("\n");
|
||||
printf(" asmjit::x86x64::X86X64FuncDecl : %u\n", static_cast<uint32_t>(sizeof(x86x64::X86X64FuncDecl)));
|
||||
printf("\n");
|
||||
printf(" asmjit::x86x64::VarInst : %u\n", static_cast<uint32_t>(sizeof(x86x64::VarInst)));
|
||||
printf(" asmjit::x86x64::VarState : %u\n", static_cast<uint32_t>(sizeof(x86x64::VarState)));
|
||||
printf("\n");
|
||||
printf(" asmjit::x86x64::InstInfo : %u\n", static_cast<uint32_t>(sizeof(x86x64::InstInfo)));
|
||||
printf(" asmjit::x86x64::VarInfo : %u\n", static_cast<uint32_t>(sizeof(x86x64::VarInfo)));
|
||||
printf("\n");
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
return 0;
|
||||
}
|
||||
1805
src/app/test/testx86.cpp
Normal file
1805
src/app/test/testx86.cpp
Normal file
File diff suppressed because it is too large
Load Diff
323
src/asmjit/asmjit.h
Normal file
323
src/asmjit/asmjit.h
Normal file
@@ -0,0 +1,323 @@
|
||||
// [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
|
||||
|
||||
//! @mainpage
|
||||
//!
|
||||
//! @brief AsmJit is a complete x86/x64 JIT Assembler for C++ language.
|
||||
//!
|
||||
//! It supports FPU, MMX, 3dNow, SSE, SSE2, SSE3 and SSE4 intrinsics, powerful
|
||||
//! compiler that helps to write portable functions for 32-bit (x86) and 64-bit
|
||||
//! (x64) architectures. AsmJit can be used to create functions at runtime that
|
||||
//! can be called from existing (but also generated) C/C++ code.
|
||||
//!
|
||||
//! AsmJit is a cross-platform library that supports various compilers and
|
||||
//! operating systems. Currently only limitation is x86 (32-bit) or x64 (64-bit)
|
||||
//! processor. Currently tested operating systems are Windows (32-bit and 64-bit),
|
||||
//! Linux (32-bit and 64-bit) and MacOSX (32-bit and 64-bit).
|
||||
//!
|
||||
//! @section AsmJit_Main_Introduction Introduction
|
||||
//!
|
||||
//! AsmJit library contains two main classes for code generation with different
|
||||
//! goals. First main code generation class is called @c asmjit::Assembler and
|
||||
//! contains low level API that can be used to generate JIT binary code. It
|
||||
//! directly emits binary stream that represents encoded x86/x64 assembler
|
||||
//! opcodes. Together with operands and labels it can be used to generate
|
||||
//! complete code. For details look to @ref asmjit_base and @ref asmjit_compiler
|
||||
//! sections.
|
||||
//!
|
||||
//! There is also class named @c asmjit::BaseCompiler that allows to develop
|
||||
//! cross-platform assembler code without worring about function calling
|
||||
//! conventions and registers allocation. It can be also used to write 32-bit
|
||||
//! and 64-bit portable code. Compiler is a recommended concept to use for code
|
||||
//! generation.
|
||||
//!
|
||||
//! Everything in AsmJit library is in @c asmjit namespace.
|
||||
//!
|
||||
//! @section AsmJit_Main_CodeGeneration Code Generation
|
||||
//!
|
||||
//! - @ref asmjit_base "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_Configuration Configuration, Definitions and Utilities
|
||||
//!
|
||||
//! - @ref asmjit_config "Configuration" - Macros used to configure AsmJit.
|
||||
//!
|
||||
//! @section AsmJit_Main_HomePage AsmJit Homepage
|
||||
//!
|
||||
//! - http://code.google.com/p/asmjit/
|
||||
//!
|
||||
//! @section AsmJit_Main_ResourcesX86 External X86/X64 Assembler Resources
|
||||
//! - http://www.agner.org/optimize/
|
||||
//! - http://www.mark.masmcode.com/ (Assembler Tips)
|
||||
//! - http://avisynth.org/mediawiki/Filter_SDK/Assembler_optimizing (Optimizing)
|
||||
//! - http://www.ragestorm.net/distorm/ (Disassembling)
|
||||
//!
|
||||
//! @section AsmJit_Main_Terminology Terminology
|
||||
//!
|
||||
//! - <b>Non-volatile (preserved) register</b> - Register that can't be changed
|
||||
//! by callee (callee must save and restore it if it want to use it inside).
|
||||
//!
|
||||
//! - <b>Volatile (non-preserved) register</b> - The opossite. Register that can
|
||||
//! be freely used by callee. The caller must free all registers before calling
|
||||
//! other function.
|
||||
|
||||
//! @defgroup asmjit_base Platform neutral API, abstract classes and operands.
|
||||
//!
|
||||
//! Contains all AsmJit classes and helper functions that are neutral or
|
||||
//! abstract. All abstract classes are reimplemented for every supported
|
||||
//! architecture.
|
||||
//!
|
||||
//! - See @c asmjit::Assembler class for low level code generation
|
||||
//! documentation.
|
||||
//! - See @c asmjit::Operand for AsmJit operand's overview.
|
||||
//!
|
||||
//! @section AsmJit_Core_Registers Registers
|
||||
//!
|
||||
//! There are static objects that represents X86 and X64 registers. They can
|
||||
//! be used directly (like @c eax, @c mm, @c xmm, ...) or created through
|
||||
//! these functions:
|
||||
//!
|
||||
//! - @c asmjit::gpb_lo() - Get Gpb-lo register.
|
||||
//! - @c asmjit::gpb_hi() - Get Gpb-hi register.
|
||||
//! - @c asmjit::gpw() - Get Gpw register.
|
||||
//! - @c asmjit::gpd() - Get Gpd register.
|
||||
//! - @c asmjit::gpq() - Get Gpq Gp register.
|
||||
//! - @c asmjit::gpz() - Get Gpd/Gpq register.
|
||||
//! - @c asmjit::fp() - Get Fp register.
|
||||
//! - @c asmjit::mm() - Get Mm register.
|
||||
//! - @c asmjit::xmm() - Get Xmm register.
|
||||
//! - @c asmjit::ymm() - Get Ymm register.
|
||||
//!
|
||||
//! @section AsmJit_Core_Addressing Addressing
|
||||
//!
|
||||
//! X86 and x64 architectures contains several addressing modes and most ones
|
||||
//! are possible with AsmJit library. Memory represents are represented by
|
||||
//! @c asmjit::BaseMem class. These functions are used to make operands that
|
||||
//! represents memory addresses:
|
||||
//!
|
||||
//! - @c asmjit::ptr()
|
||||
//! - @c asmjit::byte_ptr()
|
||||
//! - @c asmjit::word_ptr()
|
||||
//! - @c asmjit::dword_ptr()
|
||||
//! - @c asmjit::qword_ptr()
|
||||
//! - @c asmjit::tword_ptr()
|
||||
//! - @c asmjit::oword_ptr()
|
||||
//! - @c asmjit::yword_ptr()
|
||||
//! - @c asmjit::intptr_ptr()
|
||||
//!
|
||||
//! Most useful function to make pointer should be @c 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 @c asmjit::ptr()
|
||||
//! can't be used with @c asmjit::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 (register + displacement) and complex
|
||||
//! address forms (register + (register << shift) + displacement).
|
||||
//!
|
||||
//! @section AsmJit_Core_Immediates Immediates
|
||||
//!
|
||||
//! Immediate values are constants thats passed directly after instruction
|
||||
//! opcode. To create such value use @c asmjit::imm() or @c asmjit::imm_u()
|
||||
//! methods to create signed or unsigned immediate value.
|
||||
//!
|
||||
//! @sa @c asmjit::BaseCompiler.
|
||||
|
||||
//! @defgroup asmjit_compiler Compiler (high-level code generation).
|
||||
//!
|
||||
//! Contains classes related to @c asmjit::Compiler that can be used
|
||||
//! to generate code using high-level constructs.
|
||||
//!
|
||||
//! - See @c Compiler class for high level code generation
|
||||
//! documentation - calling conventions, function declaration
|
||||
//! and variables management.
|
||||
|
||||
//! @defgroup asmjit_config Configuration.
|
||||
//!
|
||||
//! Contains macros that can be redefined to fit into any project.
|
||||
|
||||
//! @defgroup asmjit_cpuinfo CPU information.
|
||||
//!
|
||||
//! X86 or x64 cpuid instruction allows to get information about processor
|
||||
//! vendor and it's features. It's always used to detect features like MMX,
|
||||
//! SSE and other newer ones.
|
||||
//!
|
||||
//! AsmJit library supports low level cpuid call implemented internally as
|
||||
//! C++ function using inline assembler or intrinsics and also higher level
|
||||
//! CPU features detection. The low level function (also used by higher level
|
||||
//! one) is @c asmjit::cpuid().
|
||||
//!
|
||||
//! AsmJit library also contains higher level function @c asmjit::getCpu()
|
||||
//! that returns features detected by the library. The detection process is
|
||||
//! done only once and the returned object is always the same. @c asmjit::BaseCpu
|
||||
//! structure not contains only information through @c asmjit::cpuid(), but
|
||||
//! there is also small multiplatform code to detect number of processors
|
||||
//! (or cores) through operating system API.
|
||||
//!
|
||||
//! It's recommended to use @c asmjit::cpuInfo to detect and check for
|
||||
//! host processor features.
|
||||
//!
|
||||
//! Example how to use asmjit::cpuid():
|
||||
//!
|
||||
//! @code
|
||||
//! // All functions and structures are in asmjit namesapce.
|
||||
//! using namespace asmjit;
|
||||
//!
|
||||
//! // Here will be retrieved result of cpuid call.
|
||||
//! CpuId out;
|
||||
//!
|
||||
//! // Use cpuid function to do the job.
|
||||
//! cpuid(0 /* eax */, &out /* eax, ebx, ecx, edx */);
|
||||
//!
|
||||
//! // If eax argument to cpuid is 0, ebx, ecx and edx registers
|
||||
//! // are filled with cpu vendor.
|
||||
//! char vendor[13];
|
||||
//! memcpy(i->vendor, &out.ebx, 4);
|
||||
//! memcpy(i->vendor + 4, &out.edx, 4);
|
||||
//! memcpy(i->vendor + 8, &out.ecx, 4);
|
||||
//! vendor[12] = '\0';
|
||||
//!
|
||||
//! // Print vendor
|
||||
//! puts(vendor);
|
||||
//! @endcode
|
||||
//!
|
||||
//! If the high-level interface of asmjit::BaseCpu is not enough, you can use
|
||||
//! low-level asmjit::cpuid() when running on x86/x64 host, but please read
|
||||
//! processor manuals provided by Intel, AMD or other manufacturer for cpuid
|
||||
//! details.
|
||||
//!
|
||||
//! Example of using @c asmjit::BaseCpu::getHost():
|
||||
//!
|
||||
//! @code
|
||||
//! // All functions and structures are in asmjit namesapce.
|
||||
//! using namespace asmjit;
|
||||
//!
|
||||
//! // Call to cpuInfo return BaseCpu structure that shouldn't be modified.
|
||||
//! // Make it const by default.
|
||||
//! const BaseCpu* cpu = BaseCpu::getHost();
|
||||
//!
|
||||
//! // Now you are able to get specific features.
|
||||
//!
|
||||
//! // Processor has SSE2
|
||||
//! if (cpu->features & kCpuFeatureSse2) {
|
||||
//! // your code...
|
||||
//! }
|
||||
//! // Processor has MMX
|
||||
//! else if (cpu->features & kCpuFeature_MMX) {
|
||||
//! // your code...
|
||||
//! }
|
||||
//! // Processor is old, no SSE2 or MMX support.
|
||||
//! else {
|
||||
//! // your code...
|
||||
//! }
|
||||
//! @endcode
|
||||
//!
|
||||
//! Better example is in app/test/testcpu.cpp file.
|
||||
|
||||
|
||||
//! @defgroup asmjit_logging Logging and error handling.
|
||||
//!
|
||||
//! Contains classes related to loging. Currently logging is implemented in
|
||||
//! @ref asmjit::BaseLogger class. The function @ref asmjit::BaseLogger::log()
|
||||
//! can be overridden to redirect logging into any user-defined stream.
|
||||
//!
|
||||
//! To log your assembler output to FILE stream use this code:
|
||||
//!
|
||||
//! @code
|
||||
//! // Create assembler
|
||||
//! Assembler a;
|
||||
//!
|
||||
//! // Create and set file based logger
|
||||
//! FileLogger logger(stderr);
|
||||
//! a.setLogger(&logger);
|
||||
//! @endcode
|
||||
//!
|
||||
//! You can see that logging goes through @c Assembler. If you are using
|
||||
//! @c Compiler and you want to log messages in correct assembler order,
|
||||
//! you should look at @ref Compiler::comment() method. It allows you to
|
||||
//! insert text message into items stream so the @c Compiler is able to
|
||||
//! send messages to @ref Assembler in correct order.
|
||||
//!
|
||||
//! @sa @c asmjit::BaseLogger, @c asmjit::FileLogger.
|
||||
|
||||
|
||||
//! @defgroup AsmJit_MemoryManagement Virtual memory management.
|
||||
//!
|
||||
//! Using @c asmjit::Assembler or @c asmjit::Compiler to generate machine
|
||||
//! code is not final step. Each generated code needs to run in memory
|
||||
//! that is not protected against code execution. To alloc this code it's
|
||||
//! needed to use operating system functions provided to enable execution
|
||||
//! code in specified memory block or to allocate memory that is not
|
||||
//! protected. The solution is always to use @c See asmjit::Assembler::make()
|
||||
//! and @c asmjit::Compiler::make() functions that can allocate memory and
|
||||
//! relocate code for you. But AsmJit also contains classes for manual memory
|
||||
//! management thats internally used by AsmJit but can be used by programmers
|
||||
//! too.
|
||||
//!
|
||||
//! Memory management contains low level and high level classes related to
|
||||
//! allocating and freeing virtual memory. Low level class is
|
||||
//! @c asmjit::VMem that can allocate and free full pages of virtual memory
|
||||
//! provided by operating system. Higher level class is @c asmjit::MemoryManager
|
||||
//! that is able to manage complete allocation and free mechanism. It
|
||||
//! internally uses larger chunks of memory to make allocation fast and
|
||||
//! effective.
|
||||
//!
|
||||
//! Using @c asmjit::VMem::alloc() is cross-platform way how to allocate this
|
||||
//! kind of memory without worrying about operating system and it's API. Each
|
||||
//! memory block that is no longer needed should be released by @ref
|
||||
//! asmjit::VMem::release() method. Higher-level interface for virtual memory
|
||||
//! allocation can be found at asmjit::MemoryManager class.
|
||||
//!
|
||||
//! @sa @c asmjit::VMem, @ asmjit::MemoryManager.
|
||||
|
||||
|
||||
//! @addtogroup asmjit_config
|
||||
//! @{
|
||||
|
||||
//! @def ASMJIT_OS_WINDOWS
|
||||
//! @brief Macro that is declared if AsmJit is compiled for Windows.
|
||||
|
||||
//! @def ASMJIT_OS_POSIX
|
||||
//! @brief Macro that is declared if AsmJit is compiled for unix like
|
||||
//! operating system.
|
||||
|
||||
//! @def ASMJIT_API
|
||||
//! @brief Attribute that's added to classes that can be exported if AsmJit
|
||||
//! is compiled as a dll library.
|
||||
|
||||
//! @def ASMJIT_ASSERT
|
||||
//! @brief Assertion macro. Default implementation calls
|
||||
//! @c asmjit::assertionFailed() function.
|
||||
|
||||
//! @}
|
||||
|
||||
|
||||
//! @namespace asmjit
|
||||
//! @brief Main AsmJit library namespace.
|
||||
//!
|
||||
//! There are not other namespaces used in AsmJit library.
|
||||
|
||||
// [Dependencies - Core]
|
||||
#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
|
||||
35
src/asmjit/base.h
Normal file
35
src/asmjit/base.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// [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/assert.h"
|
||||
#include "base/codegen.h"
|
||||
#include "base/compiler.h"
|
||||
#include "base/cpu.h"
|
||||
#include "base/defs.h"
|
||||
#include "base/error.h"
|
||||
#include "base/func.h"
|
||||
#include "base/globals.h"
|
||||
#include "base/intutil.h"
|
||||
#include "base/lock.h"
|
||||
#include "base/logger.h"
|
||||
#include "base/memorymanager.h"
|
||||
#include "base/podlist.h"
|
||||
#include "base/podvector.h"
|
||||
#include "base/string.h"
|
||||
#include "base/vectypes.h"
|
||||
#include "base/vmem.h"
|
||||
#include "base/zone.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_H
|
||||
54
src/asmjit/base/apibegin.h
Normal file
54
src/asmjit/base/apibegin.h
Normal file
@@ -0,0 +1,54 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
#if !defined(_ASMJIT_BUILD_H)
|
||||
#include "../build.h"
|
||||
#endif // !_ASMJIT_BUILD_H
|
||||
|
||||
// ============================================================================
|
||||
// [MSVC]
|
||||
// ============================================================================
|
||||
|
||||
#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_DEFINED_VSNPRINTF
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif // !vsnprintf
|
||||
|
||||
#if !defined(snprintf)
|
||||
#define ASMJIT_DEFINED_SNPRINTF
|
||||
#define snprintf _snprintf
|
||||
#endif // !snprintf
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
// ============================================================================
|
||||
// [GNUC]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(__GNUC__)
|
||||
// GCC warnings fix: I can't understand why GCC has no interface to push/pop
|
||||
// specific warnings.
|
||||
// # if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 402001
|
||||
// # pragma GCC diagnostic ignored "-w"
|
||||
// # endif
|
||||
#endif // __GNUC__
|
||||
34
src/asmjit/base/apiend.h
Normal file
34
src/asmjit/base/apiend.h
Normal file
@@ -0,0 +1,34 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// ============================================================================
|
||||
// [MSVC]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
// Pop disabled warnings by ApiBegin.h
|
||||
#pragma warning(pop)
|
||||
|
||||
// Rename symbols back.
|
||||
#if defined(ASMJIT_DEFINED_VSNPRINTF)
|
||||
#undef ASMJIT_DEFINED_VSNPRINTF
|
||||
#undef vsnprintf
|
||||
#endif // ASMJIT_DEFINED_VSNPRINTF
|
||||
|
||||
#if defined(ASMJIT_DEFINED_SNPRINTF)
|
||||
#undef ASMJIT_DEFINED_SNPRINTF
|
||||
#undef snprintf
|
||||
#endif // ASMJIT_DEFINED_SNPRINTF
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
// ============================================================================
|
||||
// [GNUC]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#endif // __GNUC__
|
||||
286
src/asmjit/base/assembler.cpp
Normal file
286
src/asmjit/base/assembler.cpp
Normal file
@@ -0,0 +1,286 @@
|
||||
// [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/memorymanager.h"
|
||||
|
||||
// [Dependenceis - C]
|
||||
#include <stdarg.h>
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseAssembler - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
BaseAssembler::BaseAssembler(BaseRuntime* runtime) :
|
||||
CodeGen(runtime),
|
||||
_buffer(NULL),
|
||||
_end(NULL),
|
||||
_cursor(NULL),
|
||||
_trampolineSize(0),
|
||||
_comment(NULL),
|
||||
_unusedLinks(NULL) {}
|
||||
|
||||
BaseAssembler::~BaseAssembler() {
|
||||
if (_buffer != NULL)
|
||||
::free(_buffer);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseAssembler - Clear / Reset]
|
||||
// ============================================================================
|
||||
|
||||
void BaseAssembler::clear() {
|
||||
_purge();
|
||||
}
|
||||
|
||||
void BaseAssembler::reset() {
|
||||
_purge();
|
||||
_zoneAllocator.reset();
|
||||
|
||||
if (_buffer != NULL) {
|
||||
::free(_buffer);
|
||||
|
||||
_buffer = NULL;
|
||||
_end = NULL;
|
||||
_cursor = NULL;
|
||||
}
|
||||
|
||||
_labels.reset();
|
||||
_relocData.reset();
|
||||
}
|
||||
|
||||
void BaseAssembler::_purge() {
|
||||
_zoneAllocator.clear();
|
||||
_cursor = _buffer;
|
||||
|
||||
_options = 0;
|
||||
_trampolineSize = 0;
|
||||
|
||||
_comment = NULL;
|
||||
_unusedLinks = NULL;
|
||||
|
||||
_labels.clear();
|
||||
_relocData.clear();
|
||||
|
||||
clearError();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseAssembler - Buffer]
|
||||
// ============================================================================
|
||||
|
||||
Error BaseAssembler::_grow(size_t n) {
|
||||
size_t capacity = getCapacity();
|
||||
size_t after = getOffset() + n;
|
||||
|
||||
// Overflow.
|
||||
if (n > IntUtil::maxUInt<uintptr_t>() - 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 BaseAssembler::_reserve(size_t n) {
|
||||
size_t capacity = getCapacity();
|
||||
if (n <= capacity)
|
||||
return kErrorOk;
|
||||
|
||||
uint8_t* newBuffer;
|
||||
if (_buffer == NULL)
|
||||
newBuffer = static_cast<uint8_t*>(::malloc(n));
|
||||
else
|
||||
newBuffer = static_cast<uint8_t*>(::realloc(_buffer, n));
|
||||
|
||||
if (newBuffer == NULL)
|
||||
return setError(kErrorNoHeapMemory);
|
||||
|
||||
size_t offset = getOffset();
|
||||
|
||||
_buffer = newBuffer;
|
||||
_end = _buffer + n;
|
||||
_cursor = newBuffer + offset;
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseAssembler - Label]
|
||||
// ============================================================================
|
||||
|
||||
Error BaseAssembler::_registerIndexedLabels(size_t index) {
|
||||
size_t i = _labels.getLength();
|
||||
if (index < i)
|
||||
return kErrorOk;
|
||||
|
||||
if (_labels._grow(index - i) != kErrorOk)
|
||||
return setError(kErrorNoHeapMemory);
|
||||
|
||||
LabelData data;
|
||||
data.offset = -1;
|
||||
data.links = NULL;
|
||||
|
||||
do {
|
||||
_labels.append(data);
|
||||
} while (++i < index);
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error BaseAssembler::_newLabel(Label* dst) {
|
||||
dst->_label.op = kOperandTypeLabel;
|
||||
dst->_label.size = 0;
|
||||
dst->_label.id = OperandUtil::makeLabelId(static_cast<uint32_t>(_labels.getLength()));
|
||||
|
||||
LabelData data;
|
||||
data.offset = -1;
|
||||
data.links = NULL;
|
||||
|
||||
if (_labels.append(data) != kErrorOk)
|
||||
goto _NoMemory;
|
||||
return kErrorOk;
|
||||
|
||||
_NoMemory:
|
||||
dst->_label.id = kInvalidValue;
|
||||
return setError(kErrorNoHeapMemory);
|
||||
}
|
||||
|
||||
LabelLink* BaseAssembler::_newLabelLink() {
|
||||
LabelLink* link = _unusedLinks;
|
||||
|
||||
if (link) {
|
||||
_unusedLinks = link->prev;
|
||||
}
|
||||
else {
|
||||
link = _zoneAllocator.allocT<LabelLink>();
|
||||
if (link == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
link->prev = NULL;
|
||||
link->offset = 0;
|
||||
link->displacement = 0;
|
||||
link->relocId = -1;
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseAssembler - Embed]
|
||||
// ============================================================================
|
||||
|
||||
Error BaseAssembler::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 (_logger)
|
||||
_logger->logBinary(kLoggerStyleData, data, size);
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseAssembler - Make]
|
||||
// ============================================================================
|
||||
|
||||
void* BaseAssembler::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::BaseAssembler - Emit (Helpers)]
|
||||
// ============================================================================
|
||||
|
||||
#define no noOperand
|
||||
|
||||
Error BaseAssembler::emit(uint32_t code) {
|
||||
return _emit(code, no, no, no, no);
|
||||
}
|
||||
|
||||
Error BaseAssembler::emit(uint32_t code, const Operand& o0) {
|
||||
return _emit(code, o0, no, no, no);
|
||||
}
|
||||
|
||||
Error BaseAssembler::emit(uint32_t code, const Operand& o0, const Operand& o1) {
|
||||
return _emit(code, o0, o1, no, no);
|
||||
}
|
||||
|
||||
Error BaseAssembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) {
|
||||
return _emit(code, o0, o1, o2, no);
|
||||
}
|
||||
|
||||
Error BaseAssembler::emit(uint32_t code, int o0_) {
|
||||
return _emit(code, Imm(o0_), no, no, no);
|
||||
}
|
||||
|
||||
Error BaseAssembler::emit(uint32_t code, const Operand& o0, int o1_) {
|
||||
return _emit(code, o0, Imm(o1_), no, no);
|
||||
}
|
||||
|
||||
Error BaseAssembler::emit(uint32_t code, const Operand& o0, const Operand& o1, int o2_) {
|
||||
return _emit(code, o0, o1, Imm(o2_), no);
|
||||
}
|
||||
|
||||
Error BaseAssembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int o3_) {
|
||||
return _emit(code, o0, o1, o2, Imm(o3_));
|
||||
}
|
||||
|
||||
#undef no
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
459
src/asmjit/base/assembler.h
Normal file
459
src/asmjit/base/assembler.h
Normal file
@@ -0,0 +1,459 @@
|
||||
// [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/defs.h"
|
||||
#include "../base/error.h"
|
||||
#include "../base/logger.h"
|
||||
#include "../base/podlist.h"
|
||||
#include "../base/podvector.h"
|
||||
#include "../base/runtime.h"
|
||||
#include "../base/zone.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_base
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::LabelLink]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Data structure used to link linked-labels.
|
||||
struct LabelLink {
|
||||
//! @brief Previous link.
|
||||
LabelLink* prev;
|
||||
//! @brief Offset.
|
||||
intptr_t offset;
|
||||
//! @brief Inlined displacement.
|
||||
intptr_t displacement;
|
||||
//! @brief RelocId if link must be absolute when relocated.
|
||||
intptr_t relocId;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::LabelData]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Label data.
|
||||
struct LabelData {
|
||||
//! @brief Label offset.
|
||||
intptr_t offset;
|
||||
//! @brief Label links chain.
|
||||
LabelLink* links;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::RelocData]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief 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 {
|
||||
//! @brief Type of relocation.
|
||||
uint32_t type;
|
||||
//! @brief Size of relocation (4 or 8 bytes).
|
||||
uint32_t size;
|
||||
|
||||
//! @brief Offset from code begin address.
|
||||
Ptr from;
|
||||
|
||||
//! @brief Relative displacement from code begin address (not to @c offset)
|
||||
//! or absolute address.
|
||||
Ptr data;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseAssembler]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Base assembler.
|
||||
//!
|
||||
//! This class implements core setialization API only. The platform specific
|
||||
//! methods and intrinsics is implemented by derived classes.
|
||||
//!
|
||||
//! @sa BaseCompiler.
|
||||
struct BaseAssembler : public CodeGen {
|
||||
ASMJIT_NO_COPY(BaseAssembler)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create a new @ref BaseAssembler instance.
|
||||
ASMJIT_API BaseAssembler(BaseRuntime* runtime);
|
||||
//! @brief Destroy the @ref BaseAssembler instance.
|
||||
ASMJIT_API virtual ~BaseAssembler();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Clear / Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Clear everything, but not deallocate buffers.
|
||||
ASMJIT_API void clear();
|
||||
//! @brief Reset everything (means also to free all buffers).
|
||||
ASMJIT_API void reset();
|
||||
//! @brief Called by clear() and reset() to clear all data related to derived
|
||||
//! class implementation.
|
||||
ASMJIT_API virtual void _purge();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Buffer]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get capacity of the code buffer.
|
||||
ASMJIT_INLINE size_t getCapacity() const {
|
||||
return (size_t)(_end - _buffer);
|
||||
}
|
||||
|
||||
//! @brief 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);
|
||||
}
|
||||
|
||||
//! @brief Get buffer.
|
||||
ASMJIT_INLINE uint8_t* getBuffer() const {
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
//! @brief Get the end of the buffer (points to the first byte that is outside).
|
||||
ASMJIT_INLINE uint8_t* getEnd() const {
|
||||
return _end;
|
||||
}
|
||||
|
||||
//! @brief Get the current position in the buffer.
|
||||
ASMJIT_INLINE uint8_t* getCursor() const {
|
||||
return _cursor;
|
||||
}
|
||||
|
||||
//! @brief Set the current position in the buffer.
|
||||
ASMJIT_INLINE void setCursor(uint8_t* cursor) {
|
||||
ASMJIT_ASSERT(cursor >= _buffer && cursor <= _end);
|
||||
_cursor = cursor;
|
||||
}
|
||||
|
||||
//! @brief Get the current offset in the buffer (<code>_cursor - _buffer</code>).
|
||||
ASMJIT_INLINE size_t getOffset() const {
|
||||
return (size_t)(_cursor - _buffer);
|
||||
}
|
||||
|
||||
//! @brief Set the current offset in the buffer to @a 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;
|
||||
}
|
||||
|
||||
//! @brief Grow the internal buffer.
|
||||
//!
|
||||
//! The internal buffer will grow at least by @a n bytes so @a n bytes
|
||||
//! can be added to it. If @a n is zero or <code>getOffset() + n</code>
|
||||
//! is not greater than the current capacity of the buffer this function
|
||||
//! won't do anything.
|
||||
ASMJIT_API Error _grow(size_t n);
|
||||
|
||||
//! @brief Reserve the internal buffer to at least @a n bytes.
|
||||
ASMJIT_API Error _reserve(size_t n);
|
||||
|
||||
//! @brief Set byte at position @a pos.
|
||||
ASMJIT_INLINE uint8_t getByteAt(size_t pos) const {
|
||||
ASMJIT_ASSERT(pos + 1 <= (size_t)(_end - _buffer));
|
||||
return *reinterpret_cast<const uint8_t*>(_buffer + pos);
|
||||
}
|
||||
|
||||
//! @brief Set word at position @a pos.
|
||||
ASMJIT_INLINE uint16_t getWordAt(size_t pos) const {
|
||||
ASMJIT_ASSERT(pos + 2 <= (size_t)(_end - _buffer));
|
||||
return *reinterpret_cast<const uint16_t*>(_buffer + pos);
|
||||
}
|
||||
|
||||
//! @brief Set dword at position @a pos.
|
||||
ASMJIT_INLINE uint32_t getDWordAt(size_t pos) const {
|
||||
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
|
||||
return *reinterpret_cast<const uint32_t*>(_buffer + pos);
|
||||
}
|
||||
|
||||
//! @brief Set qword at position @a pos.
|
||||
ASMJIT_INLINE uint64_t getQWordAt(size_t pos) const {
|
||||
ASMJIT_ASSERT(pos + 8 <= (size_t)(_end - _buffer));
|
||||
return *reinterpret_cast<const uint64_t*>(_buffer + pos);
|
||||
}
|
||||
|
||||
//! @brief Set int32_t at position @a pos.
|
||||
ASMJIT_INLINE int32_t getInt32At(size_t pos) const {
|
||||
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
|
||||
return *reinterpret_cast<const int32_t*>(_buffer + pos);
|
||||
}
|
||||
|
||||
//! @brief Set uint32_t at position @a pos.
|
||||
ASMJIT_INLINE uint32_t getUInt32At(size_t pos) const {
|
||||
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
|
||||
return *reinterpret_cast<const uint32_t*>(_buffer + pos);
|
||||
}
|
||||
|
||||
//! @brief Set byte at position @a pos.
|
||||
ASMJIT_INLINE void setByteAt(size_t pos, uint8_t x) {
|
||||
ASMJIT_ASSERT(pos + 1 <= (size_t)(_end - _buffer));
|
||||
*reinterpret_cast<uint8_t*>(_buffer + pos) = x;
|
||||
}
|
||||
|
||||
//! @brief Set word at position @a pos.
|
||||
ASMJIT_INLINE void setWordAt(size_t pos, uint16_t x) {
|
||||
ASMJIT_ASSERT(pos + 2 <= (size_t)(_end - _buffer));
|
||||
*reinterpret_cast<uint16_t*>(_buffer + pos) = x;
|
||||
}
|
||||
|
||||
//! @brief Set dword at position @a pos.
|
||||
ASMJIT_INLINE void setDWordAt(size_t pos, uint32_t x) {
|
||||
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
|
||||
*reinterpret_cast<uint32_t*>(_buffer + pos) = x;
|
||||
}
|
||||
|
||||
//! @brief Set qword at position @a pos.
|
||||
ASMJIT_INLINE void setQWordAt(size_t pos, uint64_t x) {
|
||||
ASMJIT_ASSERT(pos + 8 <= (size_t)(_end - _buffer));
|
||||
*reinterpret_cast<uint64_t*>(_buffer + pos) = x;
|
||||
}
|
||||
|
||||
//! @brief Set int32_t at position @a pos.
|
||||
ASMJIT_INLINE void setInt32At(size_t pos, int32_t x) {
|
||||
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
|
||||
*reinterpret_cast<int32_t*>(_buffer + pos) = x;
|
||||
}
|
||||
|
||||
//! @brief Set uint32_t at position @a pos.
|
||||
ASMJIT_INLINE void setUInt32At(size_t pos, uint32_t x) {
|
||||
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
|
||||
*reinterpret_cast<uint32_t*>(_buffer + pos) = x;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [GetCodeSize]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get current offset in buffer (same as <code>getOffset() + getTramplineSize()</code>).
|
||||
ASMJIT_INLINE size_t getCodeSize() const {
|
||||
return getOffset() + getTrampolineSize();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [GetTrampolineSize]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get size of all possible trampolines 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]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get count of labels created.
|
||||
ASMJIT_INLINE size_t getLabelsCount() const {
|
||||
return _labels.getLength();
|
||||
}
|
||||
|
||||
//! @brief Get whether @a label is created.
|
||||
ASMJIT_INLINE bool isLabelCreated(const Label& label) const {
|
||||
return static_cast<size_t>(label.getId()) < _labels.getLength();
|
||||
}
|
||||
|
||||
//! @internal
|
||||
//!
|
||||
//! @brief Register labels for other code generator (@ref Compiler).
|
||||
ASMJIT_API Error _registerIndexedLabels(size_t index);
|
||||
|
||||
//! @internal
|
||||
//!
|
||||
//! @brief Create and initialize a new label.
|
||||
ASMJIT_API Error _newLabel(Label* dst);
|
||||
|
||||
//! @internal
|
||||
//!
|
||||
//! @brief New LabelLink instance.
|
||||
ASMJIT_API LabelLink* _newLabelLink();
|
||||
|
||||
//! @brief Create and return new label.
|
||||
ASMJIT_INLINE Label newLabel() {
|
||||
Label result(DontInitialize);
|
||||
_newLabel(&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
//! @brief Bind label to the current offset (virtual).
|
||||
virtual void _bind(const Label& label) = 0;
|
||||
|
||||
//! @brief Bind label to the current offset (virtual).
|
||||
//!
|
||||
//! @note Label can be bound only once!
|
||||
ASMJIT_INLINE void bind(const Label& label) {
|
||||
_bind(label);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Embed]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Embed data into the code buffer.
|
||||
ASMJIT_API Error embed(const void* data, uint32_t size);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Align]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Align target buffer to @a m bytes.
|
||||
//!
|
||||
//! Typical usage of this is to align labels at start of the inner loops.
|
||||
//!
|
||||
//! Inserts @c nop() instructions or CPU optimized NOPs.
|
||||
ASMJIT_INLINE Error align(uint32_t m) {
|
||||
return _align(m);
|
||||
}
|
||||
|
||||
//! @brief Align target buffer to @a m bytes (virtual).
|
||||
virtual Error _align(uint32_t m) = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Reloc]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Simplifed version of @c relocCode() method designed for JIT.
|
||||
//!
|
||||
//! @overload
|
||||
ASMJIT_INLINE size_t relocCode(void* dst) const {
|
||||
return _relocCode(dst, static_cast<Ptr>((uintptr_t)dst));
|
||||
}
|
||||
|
||||
//! @brief Relocate code to a given address @a dst.
|
||||
//!
|
||||
//! @param dst Where the relocated code should me stored. The pointer can be
|
||||
//! address returned by virtual memory allocator or your own address if you
|
||||
//! want only to store the code for later reuse (or load, etc...).
|
||||
//! @param addressBase Base address used for relocation. When using JIT code
|
||||
//! generation, this will be the same as @a dst, only casted to system
|
||||
//! integer type. But when generating code for remote process then the value
|
||||
//! can be different.
|
||||
//!
|
||||
//! @retval The bytes used. Code-generator can create trampolines which are
|
||||
//! used when calling other functions inside the JIT code. However, these
|
||||
//! trampolines can be unused so the relocCode() returns the exact size needed
|
||||
//! for the function.
|
||||
//!
|
||||
//! A given buffer will be overwritten, to get number of bytes required use
|
||||
//! @c getCodeSize().
|
||||
ASMJIT_INLINE size_t relocCode(void* dst, Ptr base) const {
|
||||
return _relocCode(dst, base);
|
||||
}
|
||||
|
||||
//! @brief Reloc code (virtual).
|
||||
virtual size_t _relocCode(void* dst, Ptr base) const = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Make]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API void* make();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Emit]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief 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);
|
||||
}
|
||||
|
||||
//! @brief 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);
|
||||
|
||||
//! @brief Emit an instruction (virtual).
|
||||
virtual Error _emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief 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 @c _cursor member.
|
||||
uint8_t* _buffer;
|
||||
//! @brief The end of the buffer (points to the first invalid byte).
|
||||
//!
|
||||
//! The end of the buffer is calculated as <code>_buffer + size</code>.
|
||||
uint8_t* _end;
|
||||
//! @brief The current position in code @c _buffer.
|
||||
uint8_t* _cursor;
|
||||
|
||||
//! @brief Size of possible trampolines.
|
||||
uint32_t _trampolineSize;
|
||||
|
||||
//! @brief Inline comment that will be logged by the next instruction and
|
||||
//! set to NULL.
|
||||
const char* _comment;
|
||||
//! @brief Linked list of unused links (@c LabelLink* structures)
|
||||
LabelLink* _unusedLinks;
|
||||
|
||||
//! @brief Labels data.
|
||||
PodVector<LabelData> _labels;
|
||||
//! @brief Relocations data.
|
||||
PodVector<RelocData> _relocData;
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
// ============================================================================
|
||||
// [Defined-Later]
|
||||
// ============================================================================
|
||||
|
||||
ASMJIT_INLINE Label::Label(BaseAssembler& a) : Operand(DontInitialize) {
|
||||
a._newLabel(this);
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_ASSEMBLER_H
|
||||
31
src/asmjit/base/assert.cpp
Normal file
31
src/asmjit/base/assert.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// [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/assert.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
// helpers
|
||||
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 "../base/apiend.h"
|
||||
65
src/asmjit/base/assert.h
Normal file
65
src/asmjit/base/assert.h
Normal file
@@ -0,0 +1,65 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_ASSERT_H
|
||||
#define _ASMJIT_BASE_ASSERT_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../build.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_base
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Assert]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief 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/assert.cpp) to see what happened.
|
||||
ASMJIT_API void assertionFailed(const char* exp, const char* file, int line);
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_ASSERT]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(ASMJIT_DEBUG)
|
||||
|
||||
#if !defined(ASMJIT_ASSERT)
|
||||
#define ASMJIT_ASSERT(_Exp_) \
|
||||
do { \
|
||||
if (!(_Exp_)) ::asmjit::assertionFailed(#_Exp_, __FILE__, __LINE__); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#if !defined(ASMJIT_ASSERT)
|
||||
#define ASMJIT_ASSERT(_Exp_) ASMJIT_NOP()
|
||||
#endif
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
//! @}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_ASSERT_H
|
||||
118
src/asmjit/base/codegen.cpp
Normal file
118
src/asmjit/base/codegen.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
// [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 "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeGen - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
CodeGen::CodeGen(BaseRuntime* runtime) :
|
||||
_runtime(runtime),
|
||||
_logger(NULL),
|
||||
_errorHandler(NULL),
|
||||
_arch(kArchNone),
|
||||
_regSize(0),
|
||||
_error(kErrorOk),
|
||||
_features(IntUtil::mask(kCodeGenOptimizedAlign)),
|
||||
_options(0),
|
||||
_zoneAllocator(16384 - sizeof(Zone::Chunk) - kMemAllocOverhead) {}
|
||||
|
||||
CodeGen::~CodeGen() {
|
||||
if (_errorHandler != NULL)
|
||||
_errorHandler->release();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeGen - Logging]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeGen::setLogger(BaseLogger* logger) {
|
||||
_logger = logger;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeGen - Error]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeGen::setError(Error error, const char* message) {
|
||||
if (error == kErrorOk) {
|
||||
_error = kErrorOk;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
if (message == NULL)
|
||||
message = ErrorUtil::asString(error);
|
||||
|
||||
// Error handler is called before logger so logging can be skipped if error
|
||||
// has been handled.
|
||||
ErrorHandler* handler = _errorHandler;
|
||||
if (handler != NULL && handler->handleError(error, message))
|
||||
return error;
|
||||
|
||||
BaseLogger* logger = _logger;
|
||||
if (logger != NULL) {
|
||||
logger->logFormat(kLoggerStyleComment,
|
||||
"*** ERROR: %s (%u).\n", message, static_cast<unsigned int>(error));
|
||||
}
|
||||
|
||||
// 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::CodeGen - Features]
|
||||
// ============================================================================
|
||||
|
||||
bool CodeGen::hasFeature(uint32_t feature) const {
|
||||
if (feature >= sizeof(_features) * 8)
|
||||
return false;
|
||||
|
||||
feature = 1 << feature;
|
||||
return (_features & feature) != 0;
|
||||
}
|
||||
|
||||
Error CodeGen::setFeature(uint32_t feature, bool value) {
|
||||
if (feature >= sizeof(_features) * 8)
|
||||
return setError(kErrorInvalidArgument);
|
||||
|
||||
feature = static_cast<uint32_t>(value) << feature;
|
||||
_features = static_cast<uint8_t>((static_cast<uint32_t>(_features) & ~feature) | feature);
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
204
src/asmjit/base/codegen.h
Normal file
204
src/asmjit/base/codegen.h
Normal file
@@ -0,0 +1,204 @@
|
||||
// [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/defs.h"
|
||||
#include "../base/error.h"
|
||||
#include "../base/logger.h"
|
||||
#include "../base/runtime.h"
|
||||
#include "../base/zone.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_base
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kCodeGen]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief @ref CodeGen features.
|
||||
ASMJIT_ENUM(kCodeGen) {
|
||||
//! @brief Emit optimized code-alignment sequences.
|
||||
//!
|
||||
//! 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 @ref x86x64::Compiler
|
||||
//! is used, it may add rex prefixes into the code to make some instructions
|
||||
//! larger so no alignment sequences are needed.
|
||||
//!
|
||||
//! @default true.
|
||||
kCodeGenOptimizedAlign = 0,
|
||||
|
||||
//! @brief Emit jump-prediction hints.
|
||||
//!
|
||||
//! 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.
|
||||
//!
|
||||
//! @default true.
|
||||
kCodeGenPredictedJumps = 1
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeGen]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Abstract class inherited by @ref Assembler and @ref Compiler.
|
||||
struct CodeGen {
|
||||
ASMJIT_NO_COPY(CodeGen)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create a new @ref CodeGen instance.
|
||||
ASMJIT_API CodeGen(BaseRuntime* runtime);
|
||||
//! @brief Destroy the @ref CodeGen instance.
|
||||
ASMJIT_API virtual ~CodeGen();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Runtime]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get runtime.
|
||||
ASMJIT_INLINE BaseRuntime* getRuntime() const { return _runtime; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Logger]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get whether the code generator has a logger.
|
||||
ASMJIT_INLINE bool hasLogger() const { return _logger != NULL; }
|
||||
//! @brief Get logger.
|
||||
ASMJIT_INLINE BaseLogger* getLogger() const { return _logger; }
|
||||
//! @brief Set logger to @a logger.
|
||||
ASMJIT_API Error setLogger(BaseLogger* logger);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Arch]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get target architecture.
|
||||
ASMJIT_INLINE uint32_t getArch() const { return _arch; }
|
||||
|
||||
//! @brief Get default register size (4 or 8 bytes).
|
||||
ASMJIT_INLINE uint32_t getRegSize() const { return _regSize; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Error]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get last error code.
|
||||
ASMJIT_INLINE Error getError() const { return _error; }
|
||||
//! @brief Set last error code and propagate it through the error handler.
|
||||
ASMJIT_API Error setError(Error error, const char* message = NULL);
|
||||
//! @brief Clear the last error code.
|
||||
ASMJIT_INLINE void clearError() { _error = kErrorOk; }
|
||||
|
||||
//! @brief Get error handler.
|
||||
ASMJIT_INLINE ErrorHandler* getErrorHandler() const { return _errorHandler; }
|
||||
//! @brief Set error handler.
|
||||
ASMJIT_API Error setErrorHandler(ErrorHandler* handler);
|
||||
//! @brief Clear error handler.
|
||||
ASMJIT_INLINE Error clearErrorHandler() { return setErrorHandler(NULL); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Features]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get code-generator @a feature.
|
||||
ASMJIT_API bool hasFeature(uint32_t feature) const;
|
||||
//! @brief Set code-generator @a feature to @a value.
|
||||
ASMJIT_API Error setFeature(uint32_t feature, bool value);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Options]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get options.
|
||||
ASMJIT_INLINE uint32_t getOptions() const { return _options; }
|
||||
//! @brief Set options.
|
||||
ASMJIT_INLINE void setOptions(uint32_t options) { _options = options; }
|
||||
|
||||
//! @brief Get options and clear them.
|
||||
ASMJIT_INLINE uint32_t getOptionsAndClear() {
|
||||
uint32_t options = _options;
|
||||
_options = 0;
|
||||
return options;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Purge]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Called by clear() and reset() to clear all data used by the code
|
||||
//! generator.
|
||||
virtual void _purge() = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Make]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Make is a convenience method to make and relocate the current code
|
||||
//! into 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() @c NULL is returned
|
||||
//! and the last error code can be obtained by calling @ref getError().
|
||||
virtual void* make() = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Runtime.
|
||||
BaseRuntime* _runtime;
|
||||
//! @brief Logger.
|
||||
BaseLogger* _logger;
|
||||
//! @brief Error handler, called by @ref setError().
|
||||
ErrorHandler* _errorHandler;
|
||||
|
||||
//! @brief Target architecture.
|
||||
uint8_t _arch;
|
||||
//! @brief Get the default register size of the architecture (4 or 8 bytes).
|
||||
uint8_t _regSize;
|
||||
//! @brief Last error code.
|
||||
uint8_t _error;
|
||||
//! @brief Target features.
|
||||
uint8_t _features;
|
||||
//! @brief Options for the next generated instruction (only 8-bits used).
|
||||
uint32_t _options;
|
||||
|
||||
//! @brief Zone memory allocator.
|
||||
Zone _zoneAllocator;
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_CODEGEN_H
|
||||
549
src/asmjit/base/compiler.cpp
Normal file
549
src/asmjit/base/compiler.cpp
Normal file
@@ -0,0 +1,549 @@
|
||||
// [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/compiler.h"
|
||||
#include "../base/context_p.h"
|
||||
#include "../base/cpu.h"
|
||||
#include "../base/intutil.h"
|
||||
#include "../base/logger.h"
|
||||
|
||||
// [Dependencies - C]
|
||||
#include <stdarg.h>
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [Constants]
|
||||
// ============================================================================
|
||||
|
||||
static const char noName[1] = { '\0' };
|
||||
enum { kBaseCompilerDefaultLookAhead = 64 };
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseCompiler - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
BaseCompiler::BaseCompiler(BaseRuntime* runtime) :
|
||||
CodeGen(runtime),
|
||||
_nodeFlowId(0),
|
||||
_nodeFlags(0),
|
||||
_maxLookAhead(kBaseCompilerDefaultLookAhead),
|
||||
_targetVarMapping(NULL),
|
||||
_firstNode(NULL),
|
||||
_lastNode(NULL),
|
||||
_cursor(NULL),
|
||||
_func(NULL),
|
||||
_varAllocator(4096 - kMemAllocOverhead),
|
||||
_stringAllocator(4096 - kMemAllocOverhead) {}
|
||||
|
||||
BaseCompiler::~BaseCompiler() {
|
||||
reset();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseCompiler - Clear / Reset]
|
||||
// ============================================================================
|
||||
|
||||
void BaseCompiler::clear() {
|
||||
_purge();
|
||||
}
|
||||
|
||||
void BaseCompiler::reset() {
|
||||
_purge();
|
||||
_zoneAllocator.reset();
|
||||
|
||||
_varAllocator.reset();
|
||||
_stringAllocator.reset();
|
||||
|
||||
_targets.reset();
|
||||
_vars.reset();
|
||||
}
|
||||
|
||||
void BaseCompiler::_purge() {
|
||||
_zoneAllocator.clear();
|
||||
|
||||
_varAllocator.clear();
|
||||
_stringAllocator.clear();
|
||||
|
||||
_options = 0;
|
||||
|
||||
_firstNode = NULL;
|
||||
_lastNode = NULL;
|
||||
|
||||
_cursor = NULL;
|
||||
_func = NULL;
|
||||
|
||||
_targets.clear();
|
||||
_vars.clear();
|
||||
|
||||
clearError();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseCompiler - Node Management]
|
||||
// ============================================================================
|
||||
|
||||
BaseNode* BaseCompiler::setCursor(BaseNode* node) {
|
||||
BaseNode* old = _cursor;
|
||||
_cursor = node;
|
||||
return old;
|
||||
}
|
||||
|
||||
BaseNode* BaseCompiler::addNode(BaseNode* 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 {
|
||||
BaseNode* prev = _cursor;
|
||||
BaseNode* next = _cursor->_next;
|
||||
|
||||
node->_prev = prev;
|
||||
node->_next = next;
|
||||
|
||||
prev->_next = node;
|
||||
if (next)
|
||||
next->_prev = node;
|
||||
else
|
||||
_lastNode = node;
|
||||
}
|
||||
|
||||
_cursor = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
BaseNode* BaseCompiler::addNodeBefore(BaseNode* node, BaseNode* ref) {
|
||||
ASMJIT_ASSERT(node != NULL);
|
||||
ASMJIT_ASSERT(node->_prev == NULL);
|
||||
ASMJIT_ASSERT(node->_next == NULL);
|
||||
ASMJIT_ASSERT(ref != NULL);
|
||||
|
||||
BaseNode* prev = ref->_prev;
|
||||
BaseNode* next = ref;
|
||||
|
||||
node->_prev = prev;
|
||||
node->_next = next;
|
||||
|
||||
next->_prev = node;
|
||||
if (prev)
|
||||
prev->_next = node;
|
||||
else
|
||||
_firstNode = node;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
BaseNode* BaseCompiler::addNodeAfter(BaseNode* node, BaseNode* ref) {
|
||||
ASMJIT_ASSERT(node != NULL);
|
||||
ASMJIT_ASSERT(node->_prev == NULL);
|
||||
ASMJIT_ASSERT(node->_next == NULL);
|
||||
ASMJIT_ASSERT(ref != NULL);
|
||||
|
||||
BaseNode* prev = ref;
|
||||
BaseNode* next = ref->_next;
|
||||
|
||||
node->_prev = prev;
|
||||
node->_next = next;
|
||||
|
||||
prev->_next = node;
|
||||
if (next)
|
||||
next->_prev = node;
|
||||
else
|
||||
_lastNode = node;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
BaseNode* BaseCompiler::removeNode(BaseNode* node) {
|
||||
BaseNode* prev = node->_prev;
|
||||
BaseNode* 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;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void BaseCompiler::removeNodes(BaseNode* first, BaseNode* last) {
|
||||
if (first == last) {
|
||||
removeNode(first);
|
||||
return;
|
||||
}
|
||||
|
||||
BaseNode* prev = first->_prev;
|
||||
BaseNode* next = last->_next;
|
||||
|
||||
if (_firstNode == first)
|
||||
_firstNode = next;
|
||||
else
|
||||
prev->_next = next;
|
||||
|
||||
if (_lastNode == last)
|
||||
_lastNode = prev;
|
||||
else
|
||||
next->_prev = prev;
|
||||
|
||||
BaseNode* node = first;
|
||||
for (;;) {
|
||||
BaseNode* next = node->getNext();
|
||||
ASMJIT_ASSERT(next != NULL);
|
||||
|
||||
node->_prev = NULL;
|
||||
node->_next = NULL;
|
||||
|
||||
if (_cursor == node)
|
||||
_cursor = prev;
|
||||
|
||||
if (node == last)
|
||||
break;
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseCompiler - Align]
|
||||
// ============================================================================
|
||||
|
||||
AlignNode* BaseCompiler::newAlign(uint32_t m) {
|
||||
AlignNode* node = newNode<AlignNode>(m);
|
||||
if (node == NULL)
|
||||
goto _NoMemory;
|
||||
return node;
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AlignNode* BaseCompiler::addAlign(uint32_t m) {
|
||||
AlignNode* node = newAlign(m);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
return static_cast<AlignNode*>(addNode(node));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseCompiler - Target]
|
||||
// ============================================================================
|
||||
|
||||
TargetNode* BaseCompiler::newTarget() {
|
||||
TargetNode* node = newNode<TargetNode>(
|
||||
OperandUtil::makeLabelId(static_cast<uint32_t>(_targets.getLength())));
|
||||
|
||||
if (node == NULL || _targets.append(node) != kErrorOk)
|
||||
goto _NoMemory;
|
||||
return node;
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TargetNode* BaseCompiler::addTarget() {
|
||||
TargetNode* node = newTarget();
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
return static_cast<TargetNode*>(addNode(node));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseCompiler - Label]
|
||||
// ============================================================================
|
||||
|
||||
Error BaseCompiler::_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);
|
||||
}
|
||||
|
||||
void BaseCompiler::bind(const Label& label) {
|
||||
uint32_t index = label.getId();
|
||||
ASMJIT_ASSERT(index < _targets.getLength());
|
||||
|
||||
addNode(_targets[index]);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseCompiler - Embed]
|
||||
// ============================================================================
|
||||
|
||||
EmbedNode* BaseCompiler::newEmbed(const void* data, uint32_t size) {
|
||||
EmbedNode* node;
|
||||
|
||||
if (size > EmbedNode::kInlineBufferSize) {
|
||||
void* clonedData = _stringAllocator.alloc(size);
|
||||
if (clonedData == NULL)
|
||||
goto _NoMemory;
|
||||
|
||||
::memcpy(clonedData, data, size);
|
||||
data = clonedData;
|
||||
}
|
||||
|
||||
node = newNode<EmbedNode>(const_cast<void*>(data), size);
|
||||
if (node == NULL)
|
||||
goto _NoMemory;
|
||||
return node;
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EmbedNode* BaseCompiler::addEmbed(const void* data, uint32_t size) {
|
||||
EmbedNode* node = newEmbed(data, size);
|
||||
if (node == NULL)
|
||||
return node;
|
||||
return static_cast<EmbedNode*>(addNode(node));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseCompiler - Comment]
|
||||
// ============================================================================
|
||||
|
||||
CommentNode* BaseCompiler::newComment(const char* str) {
|
||||
CommentNode* node;
|
||||
|
||||
if (str != NULL && str[0]) {
|
||||
str = _stringAllocator.sdup(str);
|
||||
if (str == NULL)
|
||||
goto _NoMemory;
|
||||
}
|
||||
|
||||
node = newNode<CommentNode>(str);
|
||||
if (node == NULL)
|
||||
goto _NoMemory;
|
||||
return node;
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CommentNode* BaseCompiler::addComment(const char* str) {
|
||||
CommentNode* node = newComment(str);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
return static_cast<CommentNode*>(addNode(node));
|
||||
}
|
||||
|
||||
CommentNode* BaseCompiler::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::BaseCompiler - Hint]
|
||||
// ============================================================================
|
||||
|
||||
HintNode* BaseCompiler::newHint(BaseVar& var, uint32_t hint, uint32_t value) {
|
||||
if (var.getId() == kInvalidValue)
|
||||
return NULL;
|
||||
VarData* vd = getVd(var);
|
||||
|
||||
HintNode* node = newNode<HintNode>(vd, hint, value);
|
||||
if (node == NULL)
|
||||
goto _NoMemory;
|
||||
return node;
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HintNode* BaseCompiler::addHint(BaseVar& 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<HintNode*>(addNode(node));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseCompiler - Vars]
|
||||
// ============================================================================
|
||||
|
||||
VarData* BaseCompiler:: _newVd(uint32_t type, uint32_t size, uint32_t c, const char* name) {
|
||||
VarData* vd = reinterpret_cast<VarData*>(_varAllocator.alloc(sizeof(VarData)));
|
||||
if (vd == NULL)
|
||||
goto _NoMemory;
|
||||
|
||||
vd->_name = noName;
|
||||
vd->_id = OperandUtil::makeVarId(static_cast<uint32_t>(_vars.getLength()));
|
||||
vd->_contextId = kInvalidValue;
|
||||
|
||||
if (name != NULL && name[0] != '\0') {
|
||||
vd->_name = _stringAllocator.sdup(name);
|
||||
}
|
||||
|
||||
vd->_type = static_cast<uint8_t>(type);
|
||||
vd->_class = static_cast<uint8_t>(c);
|
||||
vd->_flags = 0;
|
||||
vd->_priority = 10;
|
||||
|
||||
vd->_state = kVarStateUnused;
|
||||
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<uint8_t>(IntUtil::iMin<uint32_t>(size, 64));
|
||||
|
||||
vd->_size = size;
|
||||
|
||||
vd->_memOffset = 0;
|
||||
vd->_memCell = NULL;
|
||||
|
||||
vd->rReadCount = 0;
|
||||
vd->rWriteCount = 0;
|
||||
vd->mReadCount = 0;
|
||||
vd->mWriteCount = 0;
|
||||
|
||||
vd->_va = NULL;
|
||||
|
||||
if (_vars.append(vd) != kErrorOk)
|
||||
goto _NoMemory;
|
||||
return vd;
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void BaseCompiler::alloc(BaseVar& var) {
|
||||
addHint(var, kVarHintAlloc, kInvalidValue);
|
||||
}
|
||||
|
||||
void BaseCompiler::alloc(BaseVar& var, uint32_t regIndex) {
|
||||
addHint(var, kVarHintAlloc, regIndex);
|
||||
}
|
||||
|
||||
void BaseCompiler::alloc(BaseVar& var, const BaseReg& reg) {
|
||||
addHint(var, kVarHintAlloc, reg.getRegIndex());
|
||||
}
|
||||
|
||||
void BaseCompiler::save(BaseVar& var) {
|
||||
addHint(var, kVarHintSave, kInvalidValue);
|
||||
}
|
||||
|
||||
void BaseCompiler::spill(BaseVar& var) {
|
||||
addHint(var, kVarHintSpill, kInvalidValue);
|
||||
}
|
||||
|
||||
void BaseCompiler::unuse(BaseVar& var) {
|
||||
addHint(var, kVarHintUnuse, kInvalidValue);
|
||||
}
|
||||
|
||||
uint32_t BaseCompiler::getPriority(BaseVar& var) const {
|
||||
if (var.getId() == kInvalidValue)
|
||||
return kInvalidValue;
|
||||
|
||||
VarData* vd = getVdById(var.getId());
|
||||
return vd->getPriority();
|
||||
}
|
||||
|
||||
void BaseCompiler::setPriority(BaseVar& var, uint32_t priority) {
|
||||
if (var.getId() == kInvalidValue)
|
||||
return;
|
||||
|
||||
if (priority > 255)
|
||||
priority = 255;
|
||||
|
||||
VarData* vd = getVdById(var.getId());
|
||||
vd->_priority = static_cast<uint8_t>(priority);
|
||||
}
|
||||
|
||||
bool BaseCompiler::getSaveOnUnuse(BaseVar& var) const {
|
||||
if (var.getId() == kInvalidValue)
|
||||
return false;
|
||||
|
||||
VarData* vd = getVdById(var.getId());
|
||||
return static_cast<bool>(vd->_saveOnUnuse);
|
||||
}
|
||||
|
||||
void BaseCompiler::setSaveOnUnuse(BaseVar& var, bool value) {
|
||||
if (var.getId() == kInvalidValue)
|
||||
return;
|
||||
|
||||
VarData* vd = getVdById(var.getId());
|
||||
vd->_saveOnUnuse = value;
|
||||
}
|
||||
|
||||
void BaseCompiler::rename(BaseVar& 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 = _stringAllocator.sdup(name);
|
||||
}
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
1984
src/asmjit/base/compiler.h
Normal file
1984
src/asmjit/base/compiler.h
Normal file
File diff suppressed because it is too large
Load Diff
343
src/asmjit/base/context.cpp
Normal file
343
src/asmjit/base/context.cpp
Normal file
@@ -0,0 +1,343 @@
|
||||
// [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/context_p.h"
|
||||
#include "../base/intutil.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseContext - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
BaseContext::BaseContext(BaseCompiler* compiler) :
|
||||
_compiler(compiler),
|
||||
_zoneAllocator(8192 - sizeof(Zone::Chunk) - kMemAllocOverhead) {
|
||||
|
||||
BaseContext::reset();
|
||||
}
|
||||
|
||||
BaseContext::~BaseContext() {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseContext - Reset]
|
||||
// ============================================================================
|
||||
|
||||
void BaseContext::reset() {
|
||||
_zoneAllocator.clear();
|
||||
|
||||
_func = NULL;
|
||||
_start = NULL;
|
||||
_end = NULL;
|
||||
_extraBlock = NULL;
|
||||
_stop = NULL;
|
||||
|
||||
_unreachableList.reset();
|
||||
_jccList.reset();
|
||||
_contextVd.clear();
|
||||
|
||||
_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;
|
||||
|
||||
_state = NULL;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseContext - 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* BaseContext::_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<MemCell*>(_zoneAllocator.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<uint32_t>(_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* BaseContext::_newStackCell(uint32_t size, uint32_t alignment) {
|
||||
MemCell* cell = static_cast<MemCell*>(_zoneAllocator.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<uint32_t>(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<uint32_t>(_memMaxAlign, alignment);
|
||||
_memStackTotal += size;
|
||||
}
|
||||
|
||||
return cell;
|
||||
|
||||
_NoMemory:
|
||||
_compiler->setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Error BaseContext::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;
|
||||
|
||||
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<int32_t>(offset));
|
||||
varCell = varCell->_next;
|
||||
}
|
||||
|
||||
// Stack - Allocated according to alignment and 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::BaseContext - RemoveUnreachableCode]
|
||||
// ============================================================================
|
||||
|
||||
Error BaseContext::removeUnreachableCode() {
|
||||
PodList<BaseNode*>::Link* link = _unreachableList.getFirst();
|
||||
BaseNode* stop = getStop();
|
||||
|
||||
while (link != NULL) {
|
||||
BaseNode* node = link->getValue();
|
||||
if (node != NULL) {
|
||||
// Locate all unreachable nodes.
|
||||
BaseNode* first = node;
|
||||
do {
|
||||
if (node->isFetched() || (node->getType() == kNodeTypeTarget && static_cast<TargetNode*>(node)->getNumRefs() > 0))
|
||||
break;
|
||||
node = node->getNext();
|
||||
} while (node != stop);
|
||||
|
||||
// Remove.
|
||||
if (node != first) {
|
||||
BaseNode* last = (node != NULL) ? node->getPrev() : getCompiler()->getLastNode();
|
||||
getCompiler()->removeNodes(first, last);
|
||||
}
|
||||
}
|
||||
|
||||
link = link->getNext();
|
||||
}
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseContext - Cleanup]
|
||||
// ============================================================================
|
||||
|
||||
//! @internal
|
||||
//!
|
||||
//! @brief Translate the given function @a func.
|
||||
void BaseContext::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.clear();
|
||||
_extraBlock = NULL;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseContext - CompileFunc]
|
||||
// ============================================================================
|
||||
|
||||
Error BaseContext::compile(FuncNode* func) {
|
||||
BaseNode* end = func->getEnd();
|
||||
BaseNode* stop = end->getNext();
|
||||
|
||||
_func = func;
|
||||
_stop = stop;
|
||||
_extraBlock = end;
|
||||
|
||||
ASMJIT_PROPAGATE_ERROR(fetch());
|
||||
ASMJIT_PROPAGATE_ERROR(removeUnreachableCode());
|
||||
ASMJIT_PROPAGATE_ERROR(analyze());
|
||||
ASMJIT_PROPAGATE_ERROR(translate());
|
||||
|
||||
// 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 "../base/apiend.h"
|
||||
254
src/asmjit/base/context_p.h
Normal file
254
src/asmjit/base/context_p.h
Normal file
@@ -0,0 +1,254 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_CONTEXT_H
|
||||
#define _ASMJIT_BASE_CONTEXT_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/compiler.h"
|
||||
#include "../base/zone.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseContext]
|
||||
// ============================================================================
|
||||
|
||||
struct BaseContext {
|
||||
ASMJIT_NO_COPY(BaseContext)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
BaseContext(BaseCompiler* compiler);
|
||||
virtual ~BaseContext();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Reset the whole context.
|
||||
virtual void reset();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get compiler.
|
||||
ASMJIT_INLINE BaseCompiler* getCompiler() const { return _compiler; }
|
||||
|
||||
//! @brief Get function.
|
||||
ASMJIT_INLINE FuncNode* getFunc() const { return _func; }
|
||||
//! @brief Get stop node.
|
||||
ASMJIT_INLINE BaseNode* getStop() const { return _stop; }
|
||||
|
||||
//! @brief Get start of the current scope.
|
||||
ASMJIT_INLINE BaseNode* getStart() const { return _start; }
|
||||
//! @brief Get end of the current scope.
|
||||
ASMJIT_INLINE BaseNode* getEnd() const { return _end; }
|
||||
|
||||
//! @brief Get extra block.
|
||||
ASMJIT_INLINE BaseNode* getExtraBlock() const { return _extraBlock; }
|
||||
//! @brief Set extra block.
|
||||
ASMJIT_INLINE void setExtraBlock(BaseNode* node) { _extraBlock = node; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Error]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get the last error code.
|
||||
ASMJIT_INLINE Error getError() const {
|
||||
return getCompiler()->getError();
|
||||
}
|
||||
|
||||
//! @brief 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]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get current state.
|
||||
ASMJIT_INLINE BaseVarState* getState() const { return _state; }
|
||||
|
||||
//! @brief Load current state from @a target state.
|
||||
virtual void loadState(BaseVarState* src) = 0;
|
||||
//! @brief Save current state, returning new @ref BaseVarState instance.
|
||||
virtual BaseVarState* saveState() = 0;
|
||||
|
||||
//! @brief Change the current state to @a target state.
|
||||
virtual void switchState(BaseVarState* src) = 0;
|
||||
|
||||
//! @brief Change the current state to the intersection of two states @a a
|
||||
//! and @a b.
|
||||
virtual void intersectStates(BaseVarState* a, BaseVarState* b) = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [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<VarBits*>(
|
||||
_zoneAllocator.calloc(static_cast<size_t>(len) * VarBits::kEntitySize));
|
||||
}
|
||||
|
||||
ASMJIT_INLINE VarBits* copyBits(const VarBits* src, uint32_t len) {
|
||||
return static_cast<VarBits*>(
|
||||
_zoneAllocator.dup(src, static_cast<size_t>(len) * VarBits::kEntitySize));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Fetch]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief 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]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Remove unreachable code.
|
||||
virtual Error removeUnreachableCode();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Analyze]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Preform 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 analyze() = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Translate]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Translate code by allocating registers and handling state changes.
|
||||
virtual Error translate() = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Cleanup]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
virtual void cleanup();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Compile]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
virtual Error compile(FuncNode* func);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Serialize]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
virtual Error serialize(BaseAssembler* assembler, BaseNode* start, BaseNode* stop) = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Compiler.
|
||||
BaseCompiler* _compiler;
|
||||
//! @brief Function.
|
||||
FuncNode* _func;
|
||||
|
||||
//! @brief Zone allocator.
|
||||
Zone _zoneAllocator;
|
||||
|
||||
//! @brief Start of the current active scope.
|
||||
BaseNode* _start;
|
||||
//! @brief End of the current active scope.
|
||||
BaseNode* _end;
|
||||
|
||||
//! @brief Node that is used to insert extra code after the function body.
|
||||
BaseNode* _extraBlock;
|
||||
//! @brief Stop node.
|
||||
BaseNode* _stop;
|
||||
|
||||
//! @brief Unreachable nodes.
|
||||
PodList<BaseNode*> _unreachableList;
|
||||
//! @brief Jump nodes.
|
||||
PodList<BaseNode*> _jccList;
|
||||
|
||||
//! @brief All variables used by the current function.
|
||||
PodVector<VarData*> _contextVd;
|
||||
|
||||
//! @brief Memory used to spill variables.
|
||||
MemCell* _memVarCells;
|
||||
//! @brief Memory used to alloc memory on the stack.
|
||||
MemCell* _memStackCells;
|
||||
|
||||
//! @brief Count of 1-byte cells.
|
||||
uint32_t _mem1ByteVarsUsed;
|
||||
//! @brief Count of 2-byte cells.
|
||||
uint32_t _mem2ByteVarsUsed;
|
||||
//! @brief Count of 4-byte cells.
|
||||
uint32_t _mem4ByteVarsUsed;
|
||||
//! @brief Count of 8-byte cells.
|
||||
uint32_t _mem8ByteVarsUsed;
|
||||
//! @brief Count of 16-byte cells.
|
||||
uint32_t _mem16ByteVarsUsed;
|
||||
//! @brief Count of 32-byte cells.
|
||||
uint32_t _mem32ByteVarsUsed;
|
||||
//! @brief Count of 64-byte cells.
|
||||
uint32_t _mem64ByteVarsUsed;
|
||||
//! @brief Count of stack memory cells.
|
||||
uint32_t _memStackCellsUsed;
|
||||
|
||||
//! @brief Maximum memory alignment used by the function.
|
||||
uint32_t _memMaxAlign;
|
||||
//! @brief Count of bytes used by variables.
|
||||
uint32_t _memVarTotal;
|
||||
//! @brief Count of bytes used by stack.
|
||||
uint32_t _memStackTotal;
|
||||
//! @brief Count of bytes used by variables and stack after alignment.
|
||||
uint32_t _memAllTotal;
|
||||
|
||||
//! @brief Current state (used by register allocator).
|
||||
BaseVarState* _state;
|
||||
};
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_CONTEXT_H
|
||||
83
src/asmjit/base/cpu.cpp
Normal file
83
src/asmjit/base/cpu.cpp
Normal file
@@ -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/cpu.h"
|
||||
|
||||
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
|
||||
#include "../x86/x86cpu.h"
|
||||
#else
|
||||
// ?
|
||||
#endif // ASMJIT_HOST || ASMJIT_HOST_X64
|
||||
|
||||
// [Dependencies - Windows]
|
||||
#if defined(ASMJIT_OS_WINDOWS)
|
||||
# include <windows.h>
|
||||
#endif // ASMJIT_OS_WINDOWS
|
||||
|
||||
// [Dependencies - Posix]
|
||||
#if defined(ASMJIT_OS_POSIX)
|
||||
# include <errno.h>
|
||||
# include <sys/statvfs.h>
|
||||
# include <sys/utsname.h>
|
||||
# include <unistd.h>
|
||||
#endif // ASMJIT_OS_POSIX
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseCpu - DetectNumberOfCores]
|
||||
// ============================================================================
|
||||
|
||||
uint32_t BaseCpu::detectNumberOfCores() {
|
||||
#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<uint32_t>(res);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseCpu - GetHost]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
|
||||
struct HostCpu : public x86x64::Cpu {
|
||||
ASMJIT_INLINE HostCpu() : Cpu() { hostCpuDetect(this); }
|
||||
};
|
||||
#else
|
||||
#error "asmjit/base/cpu.cpp - Unsupported CPU."
|
||||
#endif // ASMJIT_HOST || ASMJIT_HOST_X64
|
||||
|
||||
const BaseCpu* BaseCpu::getHost()
|
||||
{
|
||||
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
|
||||
static HostCpu cpu;
|
||||
#else
|
||||
#error "asmjit/base/cpu.cpp - Unsupported CPU."
|
||||
#endif // ASMJIT_HOST || ASMJIT_HOST_X64
|
||||
return &cpu;
|
||||
}
|
||||
|
||||
} // AsmJit
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
141
src/asmjit/base/cpu.h
Normal file
141
src/asmjit/base/cpu.h
Normal file
@@ -0,0 +1,141 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_CPU_H
|
||||
#define _ASMJIT_BASE_CPU_H
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
#include "../base/assert.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_base
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kCpuVendor]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Cpu vendor IDs.
|
||||
//!
|
||||
//! Cpu vendor IDs are specific for AsmJit library. Vendor ID is not directly
|
||||
//! read from cpuid result, instead it's based on CPU vendor string.
|
||||
ASMJIT_ENUM(kCpuVendor) {
|
||||
//! @brief Unknown CPU vendor.
|
||||
kCpuVendorUnknown = 0,
|
||||
|
||||
//! @brief Intel CPU vendor.
|
||||
kCpuVendorIntel = 1,
|
||||
//! @brief AMD CPU vendor.
|
||||
kCpuVendorAmd = 2,
|
||||
//! @brief National Semiconductor CPU vendor (applies also to Cyrix processors).
|
||||
kCpuVendorNSM = 3,
|
||||
//! @brief Transmeta CPU vendor.
|
||||
kCpuVendorTransmeta = 4,
|
||||
//! @brief VIA CPU vendor.
|
||||
kCpuVendorVia = 5
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseCpu]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Base cpu information.
|
||||
struct BaseCpu {
|
||||
ASMJIT_NO_COPY(BaseCpu)
|
||||
|
||||
enum { kFeaturesPerUInt32 = static_cast<int>(sizeof(uint32_t)) * 8 };
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE BaseCpu(uint32_t size = sizeof(BaseCpu)) : _size(size) {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get CPU vendor string.
|
||||
ASMJIT_INLINE const char* getVendorString() const { return _vendorString; }
|
||||
//! @brief Get CPU brand string.
|
||||
ASMJIT_INLINE const char* getBrandString() const { return _brandString; }
|
||||
|
||||
//! @brief Get CPU vendor ID.
|
||||
ASMJIT_INLINE uint32_t getVendorId() const { return _vendorId; }
|
||||
//! @brief Get CPU family ID.
|
||||
ASMJIT_INLINE uint32_t getFamily() const { return _family; }
|
||||
//! @brief Get CPU model ID.
|
||||
ASMJIT_INLINE uint32_t getModel() const { return _model; }
|
||||
//! @brief Get CPU stepping.
|
||||
ASMJIT_INLINE uint32_t getStepping() const { return _stepping; }
|
||||
//! @brief Get CPU cores count (or sum of all cores of all procesors).
|
||||
ASMJIT_INLINE uint32_t getCoresCount() const { return _coresCount; }
|
||||
|
||||
//! @brief Get whether CPU has a @a feature.
|
||||
ASMJIT_INLINE bool hasFeature(uint32_t feature) const {
|
||||
ASMJIT_ASSERT(feature < sizeof(_features) * 8);
|
||||
|
||||
return static_cast<bool>(
|
||||
(_features[feature / kFeaturesPerUInt32] >> (feature % kFeaturesPerUInt32)) & 0x1);
|
||||
}
|
||||
|
||||
//! @brief Add CPU @a feature.
|
||||
ASMJIT_INLINE BaseCpu& addFeature(uint32_t feature) {
|
||||
ASMJIT_ASSERT(feature < sizeof(_features) * 8);
|
||||
|
||||
_features[feature / kFeaturesPerUInt32] |= (1U << (feature % kFeaturesPerUInt32));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Statics]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Detect number of cores (or sum of all cores of all processors).
|
||||
static ASMJIT_API uint32_t detectNumberOfCores();
|
||||
|
||||
//! @brief Get host cpu.
|
||||
static ASMJIT_API const BaseCpu* getHost();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Size of the structure in bytes.
|
||||
uint32_t _size;
|
||||
|
||||
//! @brief Cpu short vendor string.
|
||||
char _vendorString[16];
|
||||
//! @brief Cpu long vendor string (brand).
|
||||
char _brandString[64];
|
||||
|
||||
//! @brief Cpu vendor id (see @c asmjit::kCpuVendor enum).
|
||||
uint32_t _vendorId;
|
||||
//! @brief Cpu family ID.
|
||||
uint32_t _family;
|
||||
//! @brief Cpu model ID.
|
||||
uint32_t _model;
|
||||
//! @brief Cpu stepping.
|
||||
uint32_t _stepping;
|
||||
//! @brief Cpu cores count (or sum of all CPU cores of all processors).
|
||||
uint32_t _coresCount;
|
||||
|
||||
//! @brief Cpu features bitfield.
|
||||
uint32_t _features[4];
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_CPU_H
|
||||
27
src/asmjit/base/defs.cpp
Normal file
27
src/asmjit/base/defs.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// [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/defs.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Operand]
|
||||
// ============================================================================
|
||||
|
||||
const Operand noOperand;
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
1154
src/asmjit/base/defs.h
Normal file
1154
src/asmjit/base/defs.h
Normal file
File diff suppressed because it is too large
Load Diff
69
src/asmjit/base/error.cpp
Normal file
69
src/asmjit/base/error.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
// [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 "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ErrorHandler - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
ErrorHandler::ErrorHandler() {}
|
||||
ErrorHandler::~ErrorHandler() {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ErrorHandler - Interface]
|
||||
// ============================================================================
|
||||
|
||||
ErrorHandler* ErrorHandler::addRef() const { return const_cast<ErrorHandler*>(this); }
|
||||
void ErrorHandler::release() {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ErrorUtil - AsString]
|
||||
// ============================================================================
|
||||
|
||||
static const char* errorMessages[] = {
|
||||
"Ok",
|
||||
|
||||
"No heap memory",
|
||||
"No virtual memory",
|
||||
|
||||
"Invalid argument",
|
||||
"Invalid state",
|
||||
|
||||
"Unknown instruction",
|
||||
"Illegal instruction",
|
||||
"Illegal addressing",
|
||||
"Illegal short jump",
|
||||
|
||||
"No function defined",
|
||||
"Incomplete function",
|
||||
"Overlapped arguments",
|
||||
"No registers",
|
||||
"Overlapped registers",
|
||||
"Incompatible argument",
|
||||
"Incompatible return",
|
||||
|
||||
"Unknown error"
|
||||
};
|
||||
|
||||
const char* ErrorUtil::asString(Error err) {
|
||||
return errorMessages[IntUtil::iMin<Error>(err, kErrorCount)];
|
||||
}
|
||||
|
||||
} // AsmJit
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
196
src/asmjit/base/error.h
Normal file
196
src/asmjit/base/error.h
Normal file
@@ -0,0 +1,196 @@
|
||||
// [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
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_base
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kError]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief AsmJit error codes.
|
||||
ASMJIT_ENUM(kError) {
|
||||
//! @brief No error (success).
|
||||
//!
|
||||
//! This is default state and state you want.
|
||||
kErrorOk = 0,
|
||||
|
||||
//! @brief Heap memory allocation failed.
|
||||
kErrorNoHeapMemory = 1,
|
||||
//! @brief Virtual memory allocation failed.
|
||||
kErrorNoVirtualMemory = 2,
|
||||
|
||||
//! @brief Invalid argument.
|
||||
kErrorInvalidArgument = 3,
|
||||
//! @brief Invalid state.
|
||||
kErrorInvalidState = 4,
|
||||
|
||||
//! @brief Unknown instruction. This happens only if instruction code is
|
||||
//! out of bounds. Shouldn't happen.
|
||||
kErrorAssemblerUnknownInst = 5,
|
||||
//! @brief Illegal instruction, usually generated by asmjit::Assembler
|
||||
//! class when emitting instruction opcode. If this error is generated the
|
||||
//! target buffer is not affected by this invalid instruction.
|
||||
//!
|
||||
//! You can also get this status code if you are under x64 (64-bit x86) and
|
||||
//! you tried to decode instruction using AH, BH, CH or DH register with REX
|
||||
//! prefix. These registers can't be accessed if REX prefix is used and AsmJit
|
||||
//! didn't check for this situation in intrinsics (@c Compiler takes care of
|
||||
//! this and rearrange registers if needed).
|
||||
//!
|
||||
//! Examples that will raise @c kErrorAssemblerIllegalInst error (a is
|
||||
//! @c Assembler instance):
|
||||
//!
|
||||
//! @code
|
||||
//! a.mov(dword_ptr(eax), al); // Invalid address size.
|
||||
//! a.mov(byte_ptr(r10), ah); // Undecodable instruction (AH used with r10
|
||||
//! // that can be encoded by using REX prefix only)
|
||||
//! @endcode
|
||||
//!
|
||||
//! @note In debug mode you get assertion failure instead of setting error
|
||||
//! code.
|
||||
kErrorAssemblerIllegalInst = 6,
|
||||
//! @brief Illegal addressing used (unencodable).
|
||||
kErrorAssemblerIllegalAddr = 7,
|
||||
//! @brief Short jump instruction used, but displacement is out of bounds.
|
||||
kErrorAssemblerIllegalShortJump = 8,
|
||||
|
||||
//! @brief No function defined.
|
||||
kErrorCompilerNoFunc = 9,
|
||||
//! @brief Function generation is not finished by using @c Compiler::endFunc()
|
||||
//! or something bad happened during generation related to function. This can
|
||||
//! be missing compiler node, etc...
|
||||
kErrorCompilerIncompleteFunc = 10,
|
||||
//! @brief Tried to generate a function with overlapped arguments.
|
||||
kErrorCompilerOverlappedArgs = 11,
|
||||
|
||||
//! @brief Compiler can't allocate registers.
|
||||
kErrorCompilerNoRegs = 12,
|
||||
//! @brief Compiler can't allocate registers, because they overlap.
|
||||
kErrorCompilerOverlappedRegs = 13,
|
||||
|
||||
//! @brief Tried to call function with an incompatible argument.
|
||||
kErrorCompilerIncompatibleArg = 14,
|
||||
//! @brief Incompatible return value.
|
||||
kErrorCompilerIncompatibleRet = 15,
|
||||
|
||||
//! @brief Count of AsmJit status codes. Can grow in future.
|
||||
kErrorCount = 16
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Error]
|
||||
// ============================================================================
|
||||
|
||||
typedef uint32_t Error;
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ErrorHandler]
|
||||
// ============================================================================
|
||||
|
||||
struct ErrorHandler {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create a new @ref ErrorHandler.
|
||||
ASMJIT_API ErrorHandler();
|
||||
//! @brief Destroy the @ref ErrorHandler.
|
||||
ASMJIT_API virtual ~ErrorHandler();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Interface]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief 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 @ref ErrorHandler instances are used in different @ref Assembler
|
||||
//! and @ref Compiler instances (or in multithreaded environment) you might
|
||||
//! want to provide your own functionality for reference counting. In that
|
||||
//! case override @ref addRef() and @ref release() functions to inc/dec your
|
||||
//! reference count value.
|
||||
ASMJIT_API virtual ErrorHandler* addRef() const;
|
||||
|
||||
//! @brief Release this error handler.
|
||||
//!
|
||||
//! @note This member function is provided for convenience. See @ref addRef()
|
||||
//! for more detailed information related to reference counting.
|
||||
ASMJIT_API virtual void release();
|
||||
|
||||
//! @brief 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 @ref Assembler and
|
||||
//! @ref Compiler classes to report anything that may prevent correct 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 feature 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 @ref Assembler or @ref Compiler. Alternative to throwing
|
||||
//! exception is using setjmp() / longjmp() pair from the standard C library.
|
||||
//!
|
||||
//! If the exception or setjmp() / longjmp() mechanism is used, the state of
|
||||
//! the @ref Assember or @ref 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 @ref Assembler or analysis/translation
|
||||
//! done by @ref Compiler) the execution can't continue and the error will
|
||||
//! be also stored in @ref Assembler or @ref Compiler.
|
||||
//!
|
||||
//! Finally, if exceptions nor setjmp() / longjmp() mechanisms were used,
|
||||
//! you can still implement a compatible design by returning from your error
|
||||
//! handler. Returning @c true means that error was reported and AsmJit
|
||||
//! should continue execution. When @c false is returned, AsmJit sets the
|
||||
//! error immediately to the @ref Assembler or @ref 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]
|
||||
// ============================================================================
|
||||
|
||||
struct ErrorUtil {
|
||||
//! @brief Get printable version of AsmJit @ref kError code.
|
||||
static ASMJIT_API const char* asString(Error code);
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_PROPAGATE_ERROR]
|
||||
// ============================================================================
|
||||
|
||||
#define ASMJIT_PROPAGATE_ERROR(_Exp_) \
|
||||
do { \
|
||||
::asmjit::Error errval_ = (_Exp_); \
|
||||
if (errval_ != ::asmjit::kErrorOk) \
|
||||
return errval_; \
|
||||
} while (0)
|
||||
|
||||
//! @}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_ERROR_H
|
||||
20
src/asmjit/base/func.cpp
Normal file
20
src/asmjit/base/func.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
// [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/func.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
} // AsmJit
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
629
src/asmjit/base/func.h
Normal file
629
src/asmjit/base/func.h
Normal file
@@ -0,0 +1,629 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_FUNC_H
|
||||
#define _ASMJIT_BASE_FUNC_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/assert.h"
|
||||
#include "../base/defs.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [Forward Declarations]
|
||||
// ============================================================================
|
||||
|
||||
template<typename T>
|
||||
struct FnTypeId;
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kFuncConv]
|
||||
// ============================================================================
|
||||
|
||||
ASMJIT_ENUM(kFuncConv) {
|
||||
//! @brief Calling convention is invalid (can't be used).
|
||||
kFuncConvNone = 0
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kFuncHint]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Function hints.
|
||||
ASMJIT_ENUM(kFuncHint) {
|
||||
//! @brief Make a naked function (default true).
|
||||
//!
|
||||
//! Naked function is function without using standard prolog/epilog sequence).
|
||||
//!
|
||||
//! @section X86/X64
|
||||
//!
|
||||
//! Standard prolog sequence is:
|
||||
//!
|
||||
//! "push zbp"
|
||||
//! "mov zsp, zbp"
|
||||
//! "sub zsp, StackAdjustment"
|
||||
//!
|
||||
//! which is equal to:
|
||||
//!
|
||||
//! "enter StackAdjustment, 0"
|
||||
//!
|
||||
//! Standard epilog sequence is:
|
||||
//!
|
||||
//! "mov zsp, zbp"
|
||||
//! "pop zbp"
|
||||
//! "ret"
|
||||
//!
|
||||
//! which is equal to:
|
||||
//!
|
||||
//! "leave"
|
||||
//! "ret"
|
||||
//!
|
||||
//! 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,
|
||||
|
||||
//! @brief Generate compact function prolog/epilog if possible.
|
||||
//!
|
||||
//! @section X86/X64
|
||||
//!
|
||||
//! Use shorter, but possible slower prolog/epilog sequence to save/restore
|
||||
//! registers.
|
||||
kFuncHintCompact = 1
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kFuncFlags]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Function flags.
|
||||
ASMJIT_ENUM(kFuncFlags) {
|
||||
//! @brief Whether the function is using naked (minimal) prolog / epilog.
|
||||
kFuncFlagIsNaked = 0x00000001,
|
||||
|
||||
//! @brief Whether an another function is called from this function.
|
||||
kFuncFlagIsCaller = 0x00000002,
|
||||
|
||||
//! @brief Whether the stack is not aligned to the required stack alignment,
|
||||
//! thus it has to be aligned manually.
|
||||
kFuncFlagIsStackMisaligned = 0x00000004,
|
||||
|
||||
//! @brief Whether the stack pointer is adjusted by the stack size needed
|
||||
//! to save registers and function variables.
|
||||
//!
|
||||
//! @section X86/X64
|
||||
//!
|
||||
//! 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,
|
||||
|
||||
//! @brief Whether the function is finished using @c Compiler::endFunc().
|
||||
kFuncFlagIsFinished = 0x80000000
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kFuncDir]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Function arguments direction.
|
||||
ASMJIT_ENUM(kFuncDir) {
|
||||
//! @brief Arguments are passed left to right.
|
||||
//!
|
||||
//! This arguments direction is unusual to C programming, it's used by pascal
|
||||
//! compilers and in some calling conventions by Borland compiler).
|
||||
kFuncDirLtr = 0,
|
||||
//! @brief Arguments are passed right ro left
|
||||
//!
|
||||
//! This is default argument direction in C programming.
|
||||
kFuncDirRtl = 1
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kFuncStackInvalid]
|
||||
// ============================================================================
|
||||
|
||||
enum {
|
||||
//! @brief Invalid stack offset in function or function parameter.
|
||||
kFuncStackInvalid = -1
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kFuncArg]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Function argument (lo/hi) specification.
|
||||
ASMJIT_ENUM(kFuncArg) {
|
||||
//! @brief Maxumum number of function arguments supported by AsmJit.
|
||||
kFuncArgCount = 16,
|
||||
//! @brief Extended maximum number of arguments (used internally).
|
||||
kFuncArgCountLoHi = kFuncArgCount * 2,
|
||||
|
||||
//! @brief 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,
|
||||
//! @brief 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::kFuncRet]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Function return value (lo/hi) specification.
|
||||
ASMJIT_ENUM(kFuncRet) {
|
||||
//! @brief Index to the LO part of function return value.
|
||||
kFuncRetLo = 0,
|
||||
//! @brief Index to the HI part of function return value.
|
||||
kFuncRetHi = 1
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FnTypeId]
|
||||
// ============================================================================
|
||||
|
||||
//! @internal
|
||||
#define ASMJIT_DECLARE_TYPE_CORE(_PtrId_) \
|
||||
template<typename T> \
|
||||
struct TypeId { enum { kId = static_cast<int>(::asmjit::kVarTypeInvalid) }; }; \
|
||||
\
|
||||
template<typename T> \
|
||||
struct TypeId<T*> { enum { kId = _PtrId_ }; }
|
||||
|
||||
//! @internal
|
||||
//!
|
||||
//! @brief Declare C/C++ type-id mapped to @c asmjit::kVarType.
|
||||
#define ASMJIT_DECLARE_TYPE_ID(_T_, _Id_) \
|
||||
template<> \
|
||||
struct TypeId<_T_> { enum { kId = _Id_ }; }
|
||||
|
||||
//! @brief Function builder 'void' type.
|
||||
struct FnVoid {};
|
||||
|
||||
//! @brief Function builder 'int8_t' type.
|
||||
struct FnInt8 {};
|
||||
//! @brief Function builder 'uint8_t' type.
|
||||
struct FnUInt8 {};
|
||||
|
||||
//! @brief Function builder 'int16_t' type.
|
||||
struct FnInt16 {};
|
||||
//! @brief Function builder 'uint16_t' type.
|
||||
struct FnUInt16 {};
|
||||
|
||||
//! @brief Function builder 'int32_t' type.
|
||||
struct FnInt32 {};
|
||||
//! @brief Function builder 'uint32_t' type.
|
||||
struct FnUInt32 {};
|
||||
|
||||
//! @brief Function builder 'int64_t' type.
|
||||
struct FnInt64 {};
|
||||
//! @brief Function builder 'uint64_t' type.
|
||||
struct FnUInt64 {};
|
||||
|
||||
//! @brief Function builder 'intptr_t' type.
|
||||
struct FnIntPtr {};
|
||||
//! @brief Function builder 'uintptr_t' type.
|
||||
struct FnUIntPtr {};
|
||||
|
||||
//! @brief Function builder 'float' type.
|
||||
struct FnFloat {};
|
||||
//! @brief Function builder 'double' type.
|
||||
struct FnDouble {};
|
||||
|
||||
ASMJIT_DECLARE_TYPE_CORE(kVarTypeIntPtr);
|
||||
|
||||
ASMJIT_DECLARE_TYPE_ID(void, kVarTypeInvalid);
|
||||
ASMJIT_DECLARE_TYPE_ID(FnVoid, kVarTypeInvalid);
|
||||
|
||||
ASMJIT_DECLARE_TYPE_ID(int8_t, kVarTypeInt8);
|
||||
ASMJIT_DECLARE_TYPE_ID(FnInt8, kVarTypeInt8);
|
||||
|
||||
ASMJIT_DECLARE_TYPE_ID(uint8_t, kVarTypeUInt8);
|
||||
ASMJIT_DECLARE_TYPE_ID(FnUInt8, kVarTypeUInt8);
|
||||
|
||||
ASMJIT_DECLARE_TYPE_ID(int16_t, kVarTypeInt16);
|
||||
ASMJIT_DECLARE_TYPE_ID(FnInt16, kVarTypeInt16);
|
||||
|
||||
ASMJIT_DECLARE_TYPE_ID(uint16_t, kVarTypeUInt8);
|
||||
ASMJIT_DECLARE_TYPE_ID(FnUInt16, kVarTypeUInt8);
|
||||
|
||||
ASMJIT_DECLARE_TYPE_ID(int32_t, kVarTypeInt32);
|
||||
ASMJIT_DECLARE_TYPE_ID(FnInt32, kVarTypeUInt8);
|
||||
|
||||
ASMJIT_DECLARE_TYPE_ID(uint32_t, kVarTypeUInt32);
|
||||
ASMJIT_DECLARE_TYPE_ID(FnUInt32, kVarTypeUInt8);
|
||||
|
||||
ASMJIT_DECLARE_TYPE_ID(int64_t, kVarTypeInt64);
|
||||
ASMJIT_DECLARE_TYPE_ID(FnInt64, kVarTypeUInt8);
|
||||
|
||||
ASMJIT_DECLARE_TYPE_ID(uint64_t, kVarTypeUInt64);
|
||||
ASMJIT_DECLARE_TYPE_ID(FnUInt64, kVarTypeUInt8);
|
||||
|
||||
ASMJIT_DECLARE_TYPE_ID(float, kVarTypeFp32);
|
||||
ASMJIT_DECLARE_TYPE_ID(FnFloat, kVarTypeFp32);
|
||||
|
||||
ASMJIT_DECLARE_TYPE_ID(double, kVarTypeFp64);
|
||||
ASMJIT_DECLARE_TYPE_ID(FnDouble, kVarTypeFp64);
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FuncInOut]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Function in/out (argument or a return value).
|
||||
//!
|
||||
//! This class contains function argument or return value translated from the
|
||||
//! @ref 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<int32_t>(_stackOffset); }
|
||||
|
||||
//! @brief Get whether the argument / return value is assigned.
|
||||
ASMJIT_INLINE bool isSet() const {
|
||||
return (_regIndex != kInvalidReg) | (_stackOffset != kFuncStackInvalid);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Reset the function argument to "unassigned state".
|
||||
ASMJIT_INLINE void reset() { _packed = 0xFFFFFFFF; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
union {
|
||||
struct {
|
||||
//! @brief Variable type, see @c kVarType.
|
||||
uint8_t _varType;
|
||||
//! @brief Register index if argument / return value is a register.
|
||||
uint8_t _regIndex;
|
||||
//! @brief Stack offset if argument / return value is on the stack.
|
||||
int16_t _stackOffset;
|
||||
};
|
||||
|
||||
//! @brief All members packed into single 32-bit integer.
|
||||
uint32_t _packed;
|
||||
};
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FuncPrototype]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief 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 @ref FuncDecl.
|
||||
struct FuncPrototype {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get function return value.
|
||||
ASMJIT_INLINE uint32_t getRet() const { return _ret; }
|
||||
|
||||
//! @brief Get function arguments' IDs.
|
||||
ASMJIT_INLINE const uint32_t* getArgList() const { return _argList; }
|
||||
//! @brief Get count of function arguments.
|
||||
ASMJIT_INLINE uint32_t getArgCount() const { return _argCount; }
|
||||
|
||||
//! @brief Get argument at index @a id.
|
||||
ASMJIT_INLINE uint32_t getArg(uint32_t id) const {
|
||||
ASMJIT_ASSERT(id < _argCount);
|
||||
return _argList[id];
|
||||
}
|
||||
|
||||
//! @brief 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::FuncDecl]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Function declaration.
|
||||
struct FuncDecl {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors - Calling Convention]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get function calling convention, see @c kFuncConv.
|
||||
ASMJIT_INLINE uint32_t getConvention() const { return _convention; }
|
||||
|
||||
//! @brief Get whether the callee pops the stack.
|
||||
ASMJIT_INLINE uint32_t getCalleePopsStack() const { return _calleePopsStack; }
|
||||
|
||||
//! @brief Get direction of arguments passed on the stack.
|
||||
//!
|
||||
//! Direction should be always @c 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; }
|
||||
|
||||
//! @brief Get stack size needed for function arguments passed on the stack.
|
||||
ASMJIT_INLINE uint32_t getArgStackSize() const { return _argStackSize; }
|
||||
//! @brief Get size of "Red Zone".
|
||||
ASMJIT_INLINE uint32_t getRedZoneSize() const { return _redZoneSize; }
|
||||
//! @brief Get size of "Spill Zone".
|
||||
ASMJIT_INLINE uint32_t getSpillZoneSize() const { return _spillZoneSize; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors - Arguments and Return]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get whether the function has a return value.
|
||||
ASMJIT_INLINE bool hasRet() const { return _retCount != 0; }
|
||||
//! @brief Get count of function return values.
|
||||
ASMJIT_INLINE uint32_t getRetCount() const { return _retCount; }
|
||||
|
||||
//! @brief Get function return value.
|
||||
ASMJIT_INLINE FuncInOut& getRet(uint32_t index = kFuncRetLo) { return _retList[index]; }
|
||||
//! @brief Get function return value.
|
||||
ASMJIT_INLINE const FuncInOut& getRet(uint32_t index = kFuncRetLo) const { return _retList[index]; }
|
||||
|
||||
//! @brief Get count of function arguments.
|
||||
ASMJIT_INLINE uint32_t getArgCount() const { return _argCount; }
|
||||
|
||||
//! @brief Get function arguments array.
|
||||
ASMJIT_INLINE FuncInOut* getArgList() { return _argList; }
|
||||
//! @brief Get function arguments array (const).
|
||||
ASMJIT_INLINE const FuncInOut* getArgList() const { return _argList; }
|
||||
|
||||
//! @brief Get function argument at index @a index.
|
||||
ASMJIT_INLINE FuncInOut& getArg(size_t index) {
|
||||
ASMJIT_ASSERT(index < kFuncArgCountLoHi);
|
||||
return _argList[index];
|
||||
}
|
||||
|
||||
//! @brief Get function argument at index @a 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]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Calling convention.
|
||||
uint8_t _convention;
|
||||
//! @brief Whether a callee pops stack.
|
||||
uint8_t _calleePopsStack : 1;
|
||||
//! @brief Direction for arguments passed on the stack, see @c kFuncDir.
|
||||
uint8_t _direction : 1;
|
||||
//! @brief Reserved #0 (alignment).
|
||||
uint8_t _reserved0 : 6;
|
||||
|
||||
//! @brief Count of arguments (in @c _argList).
|
||||
uint8_t _argCount;
|
||||
//! @brief Count of return value(s).
|
||||
uint8_t _retCount;
|
||||
|
||||
//! @brief Count of bytes consumed by arguments on the stack (aligned).
|
||||
uint32_t _argStackSize;
|
||||
|
||||
//! @brief Size of "Red Zone".
|
||||
//!
|
||||
//! @note Used by AMD64-ABI (128 bytes).
|
||||
uint16_t _redZoneSize;
|
||||
|
||||
//! @brief Size of "Spill Zone".
|
||||
//!
|
||||
//! @note Used by WIN64-ABI (32 bytes).
|
||||
uint16_t _spillZoneSize;
|
||||
|
||||
//! @brief Function arguments (including HI arguments) mapped to physical
|
||||
//! registers and stack offset.
|
||||
FuncInOut _argList[kFuncArgCountLoHi];
|
||||
|
||||
//! @brief Function return value(s).
|
||||
FuncInOut _retList[2];
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FuncBuilderX]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Custom function builder for up to 32 function arguments.
|
||||
struct FuncBuilderX : public FuncPrototype {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE FuncBuilderX() {
|
||||
_setPrototype(kVarTypeInvalid, _builderArgList, 0);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Set return type to @a 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<typename T>
|
||||
ASMJIT_INLINE void setRetT()
|
||||
{ setRet(TypeId<T>::kId); }
|
||||
|
||||
template<typename T>
|
||||
ASMJIT_INLINE void setArgT(uint32_t id)
|
||||
{ setArg(id, TypeId<T>::kId); }
|
||||
|
||||
template<typename T>
|
||||
ASMJIT_INLINE void addArgT()
|
||||
{ addArg(TypeId<T>::kId); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
uint32_t _builderArgList[kFuncArgCount];
|
||||
};
|
||||
|
||||
#define _TID(_T_) TypeId<_T_>::kId
|
||||
|
||||
//! @brief Function builder (no args).
|
||||
template<typename RET>
|
||||
struct FuncBuilder0 : public FuncPrototype {
|
||||
ASMJIT_INLINE FuncBuilder0() {
|
||||
_setPrototype(_TID(RET), NULL, 0);
|
||||
}
|
||||
};
|
||||
|
||||
//! @brief Function builder (1 argument).
|
||||
template<typename RET, typename P0>
|
||||
struct FuncBuilder1 : public FuncPrototype {
|
||||
ASMJIT_INLINE FuncBuilder1() {
|
||||
static const uint32_t args[] = { _TID(P0) };
|
||||
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
|
||||
}
|
||||
};
|
||||
|
||||
//! @brief Function builder (2 arguments).
|
||||
template<typename RET, typename P0, typename P1>
|
||||
struct FuncBuilder2 : public FuncPrototype {
|
||||
ASMJIT_INLINE FuncBuilder2() {
|
||||
static const uint32_t args[] = { _TID(P0), _TID(P1) };
|
||||
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
|
||||
}
|
||||
};
|
||||
|
||||
//! @brief Function builder (3 arguments).
|
||||
template<typename RET, typename P0, typename P1, typename P2>
|
||||
struct FuncBuilder3 : public FuncPrototype {
|
||||
ASMJIT_INLINE FuncBuilder3() {
|
||||
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2) };
|
||||
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
|
||||
}
|
||||
};
|
||||
|
||||
//! @brief Function builder (4 arguments).
|
||||
template<typename RET, typename P0, typename P1, typename P2, typename P3>
|
||||
struct FuncBuilder4 : public FuncPrototype {
|
||||
ASMJIT_INLINE FuncBuilder4() {
|
||||
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2), _TID(P3) };
|
||||
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
|
||||
}
|
||||
};
|
||||
|
||||
//! @brief Function builder (5 arguments).
|
||||
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4>
|
||||
struct FuncBuilder5 : public FuncPrototype {
|
||||
ASMJIT_INLINE FuncBuilder5() {
|
||||
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2), _TID(P3), _TID(P4) };
|
||||
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
|
||||
}
|
||||
};
|
||||
|
||||
//! @brief Function builder (6 arguments).
|
||||
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
|
||||
struct FuncBuilder6 : public FuncPrototype {
|
||||
ASMJIT_INLINE FuncBuilder6() {
|
||||
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2), _TID(P3), _TID(P4), _TID(P5) };
|
||||
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
|
||||
}
|
||||
};
|
||||
|
||||
//! @brief Function builder (7 arguments).
|
||||
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
|
||||
struct FuncBuilder7 : public FuncPrototype {
|
||||
ASMJIT_INLINE FuncBuilder7() {
|
||||
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2), _TID(P3), _TID(P4), _TID(P5), _TID(P6) };
|
||||
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
|
||||
}
|
||||
};
|
||||
|
||||
//! @brief Function builder (8 arguments).
|
||||
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
|
||||
struct FuncBuilder8 : public FuncPrototype {
|
||||
ASMJIT_INLINE FuncBuilder8() {
|
||||
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2),_TID(P3), _TID(P4), _TID(P5), _TID(P6), _TID(P7) };
|
||||
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
|
||||
}
|
||||
};
|
||||
|
||||
//! @brief Function builder (9 arguments).
|
||||
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
|
||||
struct FuncBuilder9 : public FuncPrototype {
|
||||
ASMJIT_INLINE FuncBuilder9() {
|
||||
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2), _TID(P3), _TID(P4), _TID(P5), _TID(P6), _TID(P7), _TID(P8) };
|
||||
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
|
||||
}
|
||||
};
|
||||
|
||||
//! @brief Function builder (10 arguments).
|
||||
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9>
|
||||
struct FuncBuilder10 : public FuncPrototype {
|
||||
ASMJIT_INLINE FuncBuilder10() {
|
||||
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2), _TID(P3), _TID(P4), _TID(P5), _TID(P6), _TID(P7), _TID(P8), _TID(P9) };
|
||||
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
|
||||
}
|
||||
};
|
||||
|
||||
#undef _TID
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_FUNC_H
|
||||
124
src/asmjit/base/globals.h
Normal file
124
src/asmjit/base/globals.h
Normal file
@@ -0,0 +1,124 @@
|
||||
// [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 "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_base
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kGlobal]
|
||||
// ============================================================================
|
||||
|
||||
ASMJIT_ENUM(kGlobal) {
|
||||
//! @brief Invalid operand id.
|
||||
kInvalidValue = 0xFFFFFFFF,
|
||||
|
||||
//! @brief Invalid register index.
|
||||
kInvalidReg = 0xFF,
|
||||
|
||||
//! @brief Minimum reserved bytes in @ref Buffer.
|
||||
kBufferGrow = 32U,
|
||||
|
||||
//! @brief Minimum size of assembler/compiler code buffer.
|
||||
kMemAllocMinimum = 4096,
|
||||
|
||||
//! @brief Memory grow threshold.
|
||||
//!
|
||||
//! If the grow threshold is reached capacity is not doubled anymore.
|
||||
kMemAllocGrowMax = 8192 * 1024,
|
||||
|
||||
//! @brief An overhead of the host memory allocator.
|
||||
//!
|
||||
//! We decrement the overhead from our pools so the host operating system
|
||||
//! doesn't need allocate an extra virtual page to put the data it needs
|
||||
//! to manage the requested memory block (for example if a single virtual
|
||||
//! page is 4096 and we require the same memory size we decrease our
|
||||
//! requirement by kMemAllocOverhead).
|
||||
kMemAllocOverhead = sizeof(intptr_t) * 4,
|
||||
};
|
||||
|
||||
static const size_t kInvalidIndex = ~static_cast<size_t>(0);
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kArch]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Architecture.
|
||||
ASMJIT_ENUM(kArch) {
|
||||
//! @brief No/Unknown architecture.
|
||||
kArchNone = 0,
|
||||
|
||||
//! @brief X86 architecture.
|
||||
kArchX86 = 1,
|
||||
//! @brief X64 architecture, also called AMD64.
|
||||
kArchX64 = 2,
|
||||
//! @brief Arm architecture.
|
||||
kArchArm = 3,
|
||||
|
||||
#if defined(ASMJIT_HOST_X86)
|
||||
kArchHost = kArchX86,
|
||||
#endif // ASMJIT_HOST
|
||||
|
||||
#if defined(ASMJIT_HOST_X64)
|
||||
kArchHost = kArchX86,
|
||||
#endif // ASMJIT_HOST
|
||||
|
||||
#if defined(ASMJIT_HOST_ARM)
|
||||
kArchHost = kArchArm,
|
||||
#endif // ASMJIT_HOST_ARM
|
||||
|
||||
//! @brief Whether the host is 64-bit.
|
||||
kArchHost64Bit = sizeof(intptr_t) >= 8
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::_Initialize]
|
||||
// ============================================================================
|
||||
|
||||
struct _Initialize {};
|
||||
static const _Initialize Initialize = {};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::_DontInitialize]
|
||||
// ============================================================================
|
||||
|
||||
struct _DontInitialize {};
|
||||
static const _DontInitialize DontInitialize = {};
|
||||
|
||||
//! @}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit_cast<>]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief 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 @c reinterpret_cast<> works for you,
|
||||
//! there is no reason to use @c asmjit_cast<>. If you are writing
|
||||
//! cross-platform software with various compiler support, consider using
|
||||
//! @c asmjit_cast<> instead of @c reinterpret_cast<>.
|
||||
template<typename T, typename Z>
|
||||
static ASMJIT_INLINE T asmjit_cast(Z* p) { return (T)p; }
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_GLOBALS_H
|
||||
693
src/asmjit/base/intutil.h
Normal file
693
src/asmjit/base/intutil.h
Normal file
@@ -0,0 +1,693 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_INTUTIL_H
|
||||
#define _ASMJIT_BASE_INTUTIL_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/assert.h"
|
||||
#include "../base/globals.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma intrinsic(_BitScanForward)
|
||||
#endif // ASMJIT_OS_WINDOWS
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_base
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::IntTraits]
|
||||
// ============================================================================
|
||||
|
||||
template<typename T>
|
||||
struct IntTraits {
|
||||
enum {
|
||||
kIsSigned = (~static_cast<T>(0)) < static_cast<T>(0),
|
||||
kIsUnsigned = !kIsSigned,
|
||||
|
||||
kIs8Bit = sizeof(T) == 1,
|
||||
kIs16Bit = sizeof(T) == 2,
|
||||
kIs32Bit = sizeof(T) == 4,
|
||||
kIs64Bit = sizeof(T) == 8,
|
||||
|
||||
kIsIntPtr = sizeof(T) == sizeof(intptr_t)
|
||||
};
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::IntUtil]
|
||||
// ============================================================================
|
||||
|
||||
struct IntUtil {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Float <-> Int]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
union Float {
|
||||
int32_t i;
|
||||
float f;
|
||||
};
|
||||
|
||||
union Double {
|
||||
int64_t i;
|
||||
double d;
|
||||
};
|
||||
|
||||
static ASMJIT_INLINE int32_t floatAsInt(float f) { Float m; m.f = f; return m.i; }
|
||||
static ASMJIT_INLINE float intAsFloat(int32_t i) { Float m; m.i = i; return m.f; }
|
||||
|
||||
static ASMJIT_INLINE int64_t doubleAsInt(double d) { Double m; m.d = d; return m.i; }
|
||||
static ASMJIT_INLINE double intAsDouble(int64_t i) { Double m; m.i = i; return m.d; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - Pack / Unpack]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
static ASMJIT_INLINE uint32_t pack32_2x8_1x16(uint32_t u0, uint32_t u1, uint32_t w2) {
|
||||
#if defined(ASMJIT_HOST_LE)
|
||||
return u0 + (u1 << 8) + (w2 << 16);
|
||||
#else
|
||||
return (u0 << 24) + (u1 << 16) + (w2);
|
||||
#endif // ASMJIT_HOST
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE uint32_t pack32_4x8(uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3) {
|
||||
#if defined(ASMJIT_HOST_LE)
|
||||
return u0 + (u1 << 8) + (u2 << 16) + (u3 << 24);
|
||||
#else
|
||||
return (u0 << 24) + (u1 << 16) + (u2 << 8) + u3;
|
||||
#endif // ASMJIT_HOST
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE uint64_t pack64_2x32(uint32_t u0, uint32_t u1) {
|
||||
#if defined(ASMJIT_HOST_LE)
|
||||
return (static_cast<uint64_t>(u1) << 32) + u0;
|
||||
#else
|
||||
return (static_cast<uint64_t>(u0) << 32) + u1;
|
||||
#endif // ASMJIT_HOST
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - Min/Max]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// NOTE: Because some environments declare min() and max() as macros, it has
|
||||
// been decided to use different name so we never collide with them.
|
||||
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE T iMin(const T& a, const T& b) { return a < b ? a : b; }
|
||||
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE T iMax(const T& a, const T& b) { return a > b ? a : b; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - MaxUInt]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE T maxUInt() { return ~T(0); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - InInterval]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE bool inInterval(const T& x, const T& start, const T& end)
|
||||
{ return x >= start && x <= end; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - IsInt/IsUInt]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get whether the given integer @a x can be casted to a signed 8-bit
|
||||
//! integer.
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE bool isInt8(T x) {
|
||||
if (IntTraits<T>::kIsSigned)
|
||||
return sizeof(T) <= sizeof(int8_t) ? true : x >= T(-128) && x <= T(127);
|
||||
else
|
||||
return x <= T(127);
|
||||
}
|
||||
|
||||
//! @brief Get whether the given integer @a x can be casted to an unsigned 8-bit
|
||||
//! integer.
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE bool isUInt8(T x) {
|
||||
if (IntTraits<T>::kIsSigned)
|
||||
return x >= T(0) && (sizeof(T) <= sizeof(uint8_t) ? true : x <= T(255));
|
||||
else
|
||||
return sizeof(T) <= sizeof(uint8_t) ? true : x <= T(255);
|
||||
}
|
||||
|
||||
//! @brief Get whether the given integer @a x can be casted to a signed 16-bit
|
||||
//! integer.
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE bool isInt16(T x) {
|
||||
if (IntTraits<T>::kIsSigned)
|
||||
return sizeof(T) <= sizeof(int16_t) ? true : x >= T(-32768) && x <= T(32767);
|
||||
else
|
||||
return x >= T(0) && (sizeof(T) <= sizeof(int16_t) ? true : x <= T(32767));
|
||||
}
|
||||
|
||||
//! @brief Get whether the given integer @a x can be casted to an unsigned 16-bit
|
||||
//! integer.
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE bool isUInt16(T x) {
|
||||
if (IntTraits<T>::kIsSigned)
|
||||
return x >= T(0) && (sizeof(T) <= sizeof(uint16_t) ? true : x <= T(65535));
|
||||
else
|
||||
return sizeof(T) <= sizeof(uint16_t) ? true : x <= T(65535);
|
||||
}
|
||||
|
||||
//! @brief Get whether the given integer @a x can be casted to a signed 32-bit
|
||||
//! integer.
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE bool isInt32(T x) {
|
||||
if (IntTraits<T>::kIsSigned)
|
||||
return sizeof(T) <= sizeof(int32_t) ? true : x >= T(-32768) && x <= T(32767);
|
||||
else
|
||||
return x >= T(0) && (sizeof(T) <= sizeof(int32_t) ? true : x <= T(2147483647));
|
||||
}
|
||||
|
||||
//! @brief Get whether the given integer @a x can be casted to an unsigned 32-bit
|
||||
//! integer.
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE bool isUInt32(T x) {
|
||||
if (IntTraits<T>::kIsSigned)
|
||||
return x >= T(0) && (sizeof(T) <= sizeof(uint32_t) ? true : x <= T(4294967295U));
|
||||
else
|
||||
return sizeof(T) <= sizeof(uint32_t) ? true : x <= T(4294967295U);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - IsPowerOf2]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE bool isPowerOf2(T n) {
|
||||
return n != 0 && (n & (n - 1)) == 0;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - Mask]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
static ASMJIT_INLINE uint32_t mask(uint32_t x) {
|
||||
ASMJIT_ASSERT(x < 32);
|
||||
return (1U << x);
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1) {
|
||||
return mask(x0) | mask(x1);
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2) {
|
||||
return mask(x0) | mask(x1) | mask(x2);
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) {
|
||||
return mask(x0) | mask(x1) | mask(x2) | mask(x3);
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4) {
|
||||
return mask(x0) | mask(x1) | mask(x2) | mask(x3) |
|
||||
mask(x4) ;
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5) {
|
||||
return mask(x0) | mask(x1) | mask(x2) | mask(x3) |
|
||||
mask(x4) | mask(x5) ;
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6) {
|
||||
return mask(x0) | mask(x1) | mask(x2) | mask(x3) |
|
||||
mask(x4) | mask(x5) | mask(x6) ;
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7) {
|
||||
return mask(x0) | mask(x1) | mask(x2) | mask(x3) |
|
||||
mask(x4) | mask(x5) | mask(x6) | mask(x7) ;
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8) {
|
||||
return mask(x0) | mask(x1) | mask(x2) | mask(x3) |
|
||||
mask(x4) | mask(x5) | mask(x6) | mask(x7) |
|
||||
mask(x8) ;
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8, uint32_t x9) {
|
||||
return mask(x0) | mask(x1) | mask(x2) | mask(x3) |
|
||||
mask(x4) | mask(x5) | mask(x6) | mask(x7) |
|
||||
mask(x8) | mask(x9) ;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - Bits]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
static ASMJIT_INLINE uint32_t bits(uint32_t x) {
|
||||
// Shifting more bits that the type has has undefined behavior. Everything
|
||||
// we need is that application shouldn't crash because of that, but the
|
||||
// content of register after shift is not defined. So in case that the
|
||||
// requested shift is too large for the type we correct this undefined
|
||||
// behavior by setting all bits to ones (this is why we generate an overflow
|
||||
// mask).
|
||||
uint32_t overflow = static_cast<uint32_t>(
|
||||
-static_cast<int32_t>(x >= sizeof(uint32_t) * 8));
|
||||
|
||||
return ((static_cast<uint32_t>(1) << x) - 1U) | overflow;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - HasBit]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
static ASMJIT_INLINE bool hasBit(uint32_t x, uint32_t n)
|
||||
{ return static_cast<bool>((x >> n) & 0x1); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - BitCount]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// From http://graphics.stanford.edu/~seander/bithacks.html .
|
||||
static ASMJIT_INLINE uint32_t bitCount(uint32_t x) {
|
||||
x = x - ((x >> 1) & 0x55555555U);
|
||||
x = (x & 0x33333333U) + ((x >> 2) & 0x33333333U);
|
||||
return (((x + (x >> 4)) & 0x0F0F0F0FU) * 0x01010101U) >> 24;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - FindFirstBit]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
static ASMJIT_INLINE uint32_t findFirstBitSlow(uint32_t mask) {
|
||||
// This is a reference (slow) implementation of findFirstBit(), used when
|
||||
// we don't have compiler support for this task. The implementation speed
|
||||
// has been improved to check for 2 bits per iteration.
|
||||
uint32_t i = 1;
|
||||
|
||||
while (mask != 0) {
|
||||
uint32_t two = mask & 0x3;
|
||||
if (two != 0x0)
|
||||
return i - (two & 0x1);
|
||||
|
||||
i += 2;
|
||||
mask >>= 2;
|
||||
}
|
||||
|
||||
return 0xFFFFFFFFU;
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE uint32_t findFirstBit(uint32_t mask) {
|
||||
#if defined(_MSC_VER)
|
||||
DWORD i;
|
||||
if (_BitScanForward(&i, mask))
|
||||
{
|
||||
ASMJIT_ASSERT(findFirstBitSlow(mask) == i);
|
||||
return static_cast<uint32_t>(i);
|
||||
}
|
||||
return 0xFFFFFFFFU;
|
||||
#else
|
||||
return findFirstBitSlow(mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - Misc]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
static ASMJIT_INLINE uint32_t keepNOnesFromRight(uint32_t mask, uint32_t nBits) {
|
||||
uint32_t m = 0x1;
|
||||
|
||||
do {
|
||||
nBits -= (mask & m) == 0;
|
||||
m <<= 1;
|
||||
if (nBits == 0) {
|
||||
m -= 1;
|
||||
mask &= m;
|
||||
break;
|
||||
}
|
||||
} while (m);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE uint32_t indexNOnesFromRight(uint8_t* dst, uint32_t mask, uint32_t nBits) {
|
||||
uint32_t totalBits = nBits;
|
||||
uint8_t i = 0;
|
||||
uint32_t m = 0x1;
|
||||
|
||||
do {
|
||||
if (mask & m) {
|
||||
*dst++ = i;
|
||||
if (--nBits == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
m <<= 1;
|
||||
i++;
|
||||
} while (m);
|
||||
|
||||
return totalBits - nBits;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - Alignment]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE bool isAligned(T base, T alignment)
|
||||
{ return (base % alignment) == 0; }
|
||||
|
||||
//! @brief Align @a base to @a alignment.
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE T alignTo(T base, T alignment)
|
||||
{ return (base + (alignment - 1)) & ~(alignment - 1); }
|
||||
|
||||
//! @brief Get delta required to align @a base to @a alignment.
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE T deltaTo(T base, T alignment)
|
||||
{ return alignTo(base, alignment) - base; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [AsmJit - Round]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE T roundUp(T base, T alignment) {
|
||||
T over = base % alignment;
|
||||
return base + (over > 0 ? alignment - over : 0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static ASMJIT_INLINE T roundUpToPowerOf2(T base) {
|
||||
// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
|
||||
// figure 3-3, page 48, where the function is called clp2.
|
||||
base -= 1;
|
||||
|
||||
// I'm trying to make this portable and MSVC strikes me the warning C4293:
|
||||
// "Shift count negative or too big, undefined behavior"
|
||||
// Fixing...
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4293)
|
||||
#endif // _MSC_VER
|
||||
|
||||
base = base | (base >> 1);
|
||||
base = base | (base >> 2);
|
||||
base = base | (base >> 4);
|
||||
|
||||
// 8/16/32 constants are multiplied by the condition to prevent a compiler
|
||||
// complaining about the 'shift count >= type width' (GCC).
|
||||
if (sizeof(T) >= 2) base = base | (base >> ( 8 * (sizeof(T) >= 2))); // Base >> 8.
|
||||
if (sizeof(T) >= 4) base = base | (base >> (16 * (sizeof(T) >= 4))); // Base >> 16.
|
||||
if (sizeof(T) >= 8) base = base | (base >> (32 * (sizeof(T) >= 8))); // Base >> 32.
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
|
||||
return base + 1;
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::UInt64]
|
||||
// ============================================================================
|
||||
|
||||
union UInt64 {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE UInt64 fromUInt64(uint64_t val) {
|
||||
UInt64 data;
|
||||
data.setUInt64(val);
|
||||
return data;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE UInt64 fromUInt64(const UInt64& val) {
|
||||
UInt64 data;
|
||||
data.setUInt64(val);
|
||||
return data;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE void reset() {
|
||||
if (kArchHost64Bit) {
|
||||
u64 = 0;
|
||||
}
|
||||
else {
|
||||
u32[0] = 0;
|
||||
u32[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE uint64_t getUInt64() const {
|
||||
return u64;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE UInt64& setUInt64(uint64_t val) {
|
||||
u64 = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE UInt64& setUInt64(const UInt64& val) {
|
||||
if (kArchHost64Bit) {
|
||||
u64 = val.u64;
|
||||
}
|
||||
else {
|
||||
u32[0] = val.u32[0];
|
||||
u32[1] = val.u32[1];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE UInt64& setPacked_2x32(uint32_t u0, uint32_t u1) {
|
||||
if (kArchHost64Bit) {
|
||||
u64 = IntUtil::pack64_2x32(u0, u1);
|
||||
}
|
||||
else {
|
||||
u32[0] = u0;
|
||||
u32[1] = u1;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Add]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE UInt64& add(uint64_t val) {
|
||||
u64 += val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE UInt64& add(const UInt64& val) {
|
||||
if (kArchHost64Bit) {
|
||||
u64 += val.u64;
|
||||
}
|
||||
else {
|
||||
u32[0] += val.u32[0];
|
||||
u32[1] += val.u32[1];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Sub]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE UInt64& sub(uint64_t val) {
|
||||
u64 -= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE UInt64& sub(const UInt64& val) {
|
||||
if (kArchHost64Bit) {
|
||||
u64 -= val.u64;
|
||||
}
|
||||
else {
|
||||
u32[0] -= val.u32[0];
|
||||
u32[1] -= val.u32[1];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [And]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE UInt64& and_(uint64_t val) {
|
||||
u64 &= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE UInt64& and_(const UInt64& val) {
|
||||
if (kArchHost64Bit) {
|
||||
u64 &= val.u64;
|
||||
}
|
||||
else {
|
||||
u32[0] &= val.u32[0];
|
||||
u32[1] &= val.u32[1];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Or]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE UInt64& or_(uint64_t val) {
|
||||
u64 |= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE UInt64& or_(const UInt64& val) {
|
||||
if (kArchHost64Bit) {
|
||||
u64 |= val.u64;
|
||||
}
|
||||
else {
|
||||
u32[0] |= val.u32[0];
|
||||
u32[1] |= val.u32[1];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Xor]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE UInt64& xor_(uint64_t val) {
|
||||
u64 ^= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE UInt64& xor_(const UInt64& val) {
|
||||
if (kArchHost64Bit) {
|
||||
u64 ^= val.u64;
|
||||
}
|
||||
else {
|
||||
u32[0] ^= val.u32[0];
|
||||
u32[1] ^= val.u32[1];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Del]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE UInt64& del(uint64_t val) {
|
||||
u64 &= ~val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE UInt64& del(const UInt64& val) {
|
||||
if (kArchHost64Bit) {
|
||||
u64 &= ~val.u64;
|
||||
}
|
||||
else {
|
||||
u32[0] &= ~val.u32[0];
|
||||
u32[1] &= ~val.u32[1];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Eq]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE bool isZero() const
|
||||
{ return kArchHost64Bit ? u64 == 0 : (u32[0] | u32[1]) == 0; }
|
||||
|
||||
ASMJIT_INLINE bool isNonZero() const
|
||||
{ return kArchHost64Bit ? u64 != 0 : (u32[0] | u32[1]) != 0; }
|
||||
|
||||
ASMJIT_INLINE bool eq(uint64_t val) const
|
||||
{ return u64 == val; }
|
||||
|
||||
ASMJIT_INLINE bool eq(const UInt64& val) const
|
||||
{ return kArchHost64Bit ? u64 == val.u64 : (u32[0] == val.u32[0]) & (u32[1] == val.u32[1]); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Operator Overload]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE UInt64& operator+=(uint64_t val) { return add(val); }
|
||||
ASMJIT_INLINE UInt64& operator+=(const UInt64& val) { return add(val); }
|
||||
|
||||
ASMJIT_INLINE UInt64& operator-=(uint64_t val) { return sub(val); }
|
||||
ASMJIT_INLINE UInt64& operator-=(const UInt64& val) { return sub(val); }
|
||||
|
||||
ASMJIT_INLINE UInt64& operator&=(uint64_t val) { return and_(val); }
|
||||
ASMJIT_INLINE UInt64& operator&=(const UInt64& val) { return and_(val); }
|
||||
|
||||
ASMJIT_INLINE UInt64& operator|=(uint64_t val) { return or_(val); }
|
||||
ASMJIT_INLINE UInt64& operator|=(const UInt64& val) { return or_(val); }
|
||||
|
||||
ASMJIT_INLINE UInt64& operator^=(uint64_t val) { return xor_(val); }
|
||||
ASMJIT_INLINE UInt64& operator^=(const UInt64& val) { return xor_(val); }
|
||||
|
||||
ASMJIT_INLINE bool operator==(uint64_t val) const { return eq(val); }
|
||||
ASMJIT_INLINE bool operator==(const UInt64& val) const { return eq(val); }
|
||||
|
||||
ASMJIT_INLINE bool operator!=(uint64_t val) const { return !eq(val); }
|
||||
ASMJIT_INLINE bool operator!=(const UInt64& val) const { return !eq(val); }
|
||||
|
||||
ASMJIT_INLINE bool operator<(uint64_t val) const { return u64 < val; }
|
||||
ASMJIT_INLINE bool operator<(const UInt64& val) const { return u64 < val.u64; }
|
||||
|
||||
ASMJIT_INLINE bool operator<=(uint64_t val) const { return u64 <= val; }
|
||||
ASMJIT_INLINE bool operator<=(const UInt64& val) const { return u64 <= val.u64; }
|
||||
|
||||
ASMJIT_INLINE bool operator>(uint64_t val) const { return u64 > val; }
|
||||
ASMJIT_INLINE bool operator>(const UInt64& val) const { return u64 > val.u64; }
|
||||
|
||||
ASMJIT_INLINE bool operator>=(uint64_t val) const { return u64 >= val; }
|
||||
ASMJIT_INLINE bool operator>=(const UInt64& val) const { return u64 >= val.u64; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
uint64_t u64;
|
||||
|
||||
uint32_t u32[2];
|
||||
uint16_t u16[4];
|
||||
uint8_t u8[8];
|
||||
|
||||
struct {
|
||||
#if defined(ASMJIT_HOST_LE)
|
||||
uint32_t lo, hi;
|
||||
#else
|
||||
uint32_t hi, lo;
|
||||
#endif // ASMJIT_HOST_LE
|
||||
};
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_INTUTIL_H
|
||||
132
src/asmjit/base/lock.h
Normal file
132
src/asmjit/base/lock.h
Normal file
@@ -0,0 +1,132 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_LOCK_H
|
||||
#define _ASMJIT_BASE_LOCK_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../build.h"
|
||||
|
||||
// [Dependencies - Windows]
|
||||
#if defined(ASMJIT_OS_WINDOWS)
|
||||
# include <windows.h>
|
||||
#endif // ASMJIT_OS_WINDOWS
|
||||
|
||||
// [Dependencies - Posix]
|
||||
#if defined(ASMJIT_OS_POSIX)
|
||||
# include <pthread.h>
|
||||
#endif // ASMJIT_OS_POSIX
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_base
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Lock]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Lock - used in thread-safe code for locking.
|
||||
struct Lock {
|
||||
ASMJIT_NO_COPY(Lock)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Windows]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if defined(ASMJIT_OS_WINDOWS)
|
||||
typedef CRITICAL_SECTION Handle;
|
||||
|
||||
//! @brief Create a new @ref Lock instance.
|
||||
ASMJIT_INLINE Lock() { InitializeCriticalSection(&_handle); }
|
||||
//! @brief Destroy the @ref Lock instance.
|
||||
ASMJIT_INLINE ~Lock() { DeleteCriticalSection(&_handle); }
|
||||
|
||||
//! @brief Lock.
|
||||
ASMJIT_INLINE void lock() { EnterCriticalSection(&_handle); }
|
||||
//! @brief Unlock.
|
||||
ASMJIT_INLINE void unlock() { LeaveCriticalSection(&_handle); }
|
||||
|
||||
#endif // ASMJIT_OS_WINDOWS
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Posix]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if defined(ASMJIT_OS_POSIX)
|
||||
typedef pthread_mutex_t Handle;
|
||||
|
||||
//! @brief Create a new @ref Lock instance.
|
||||
ASMJIT_INLINE Lock() { pthread_mutex_init(&_handle, NULL); }
|
||||
//! @brief Destroy the @ref Lock instance.
|
||||
ASMJIT_INLINE ~Lock() { pthread_mutex_destroy(&_handle); }
|
||||
|
||||
//! @brief Lock.
|
||||
ASMJIT_INLINE void lock() { pthread_mutex_lock(&_handle); }
|
||||
//! @brief Unlock.
|
||||
ASMJIT_INLINE void unlock() { pthread_mutex_unlock(&_handle); }
|
||||
#endif // ASMJIT_OS_POSIX
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get handle.
|
||||
ASMJIT_INLINE Handle& getHandle() { return _handle; }
|
||||
//! @overload
|
||||
ASMJIT_INLINE const Handle& getHandle() const { return _handle; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Handle.
|
||||
Handle _handle;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::AutoLock]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Scope auto locker.
|
||||
struct AutoLock {
|
||||
ASMJIT_NO_COPY(AutoLock)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Locks @a target.
|
||||
ASMJIT_INLINE AutoLock(Lock& target) : _target(target) {
|
||||
_target.lock();
|
||||
}
|
||||
|
||||
//! @brief Unlocks target.
|
||||
ASMJIT_INLINE ~AutoLock() {
|
||||
_target.unlock();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Pointer to target (lock).
|
||||
Lock& _target;
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_LOCK_H
|
||||
160
src/asmjit/base/logger.cpp
Normal file
160
src/asmjit/base/logger.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
// [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"
|
||||
#include "../base/logger.h"
|
||||
#include "../base/string.h"
|
||||
|
||||
// [Dependencies - C]
|
||||
#include <stdarg.h>
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseLogger - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
BaseLogger::BaseLogger() {
|
||||
_options = 0;
|
||||
::memset(_indentation, 0, ASMJIT_ARRAY_SIZE(_indentation));
|
||||
}
|
||||
|
||||
BaseLogger::~BaseLogger() {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseLogger - Logging]
|
||||
// ============================================================================
|
||||
|
||||
void BaseLogger::logFormat(uint32_t style, const char* fmt, ...) {
|
||||
char buf[1024];
|
||||
size_t len;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(buf, 1023, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
logString(style, buf, len);
|
||||
}
|
||||
|
||||
void BaseLogger::logBinary(uint32_t style, const void* data, size_t size) {
|
||||
static const char prefix[] = ".data ";
|
||||
static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
||||
const uint8_t* s = static_cast<const uint8_t*>(data);
|
||||
size_t i = size;
|
||||
|
||||
char buffer[128];
|
||||
::memcpy(buffer, prefix, ASMJIT_ARRAY_SIZE(prefix) - 1);
|
||||
|
||||
while (i) {
|
||||
uint32_t n = static_cast<uint32_t>(IntUtil::iMax<size_t>(i, 16));
|
||||
char* p = buffer + ASMJIT_ARRAY_SIZE(prefix) - 1;
|
||||
|
||||
i -= n;
|
||||
do {
|
||||
uint32_t c = s[0];
|
||||
|
||||
p[0] = hex[c >> 4];
|
||||
p[1] = hex[c & 15];
|
||||
|
||||
p += 2;
|
||||
s += 1;
|
||||
} while (--n);
|
||||
|
||||
*p++ = '\n';
|
||||
logString(style, buffer, (size_t)(p - buffer));
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseLogger - LogBinary]
|
||||
// ============================================================================
|
||||
|
||||
void BaseLogger::setOption(uint32_t id, bool value) {
|
||||
if (id >= kLoggerOptionCount)
|
||||
return;
|
||||
|
||||
uint32_t mask = 1 << id;
|
||||
|
||||
if (value)
|
||||
_options |= mask;
|
||||
else
|
||||
_options &= ~mask;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseLogger - Indentation]
|
||||
// ============================================================================
|
||||
|
||||
void BaseLogger::setIndentation(const char* indentation) {
|
||||
::memset(_indentation, 0, ASMJIT_ARRAY_SIZE(_indentation));
|
||||
if (!indentation)
|
||||
return;
|
||||
|
||||
size_t length = StringUtil::nlen(indentation, ASMJIT_ARRAY_SIZE(_indentation) - 1);
|
||||
::memcpy(_indentation, indentation, length);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FileLogger - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
FileLogger::FileLogger(FILE* stream) : _stream(NULL) {
|
||||
setStream(stream);
|
||||
}
|
||||
|
||||
FileLogger::~FileLogger() {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FileLogger - Accessors]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Set file stream.
|
||||
void FileLogger::setStream(FILE* stream) {
|
||||
_stream = stream;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FileLogger - Logging]
|
||||
// ============================================================================
|
||||
|
||||
void FileLogger::logString(uint32_t style, const char* buf, size_t len) {
|
||||
if (!_stream)
|
||||
return;
|
||||
|
||||
if (len == kInvalidIndex)
|
||||
len = strlen(buf);
|
||||
|
||||
fwrite(buf, 1, len, _stream);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::StringLogger - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
StringLogger::StringLogger() {}
|
||||
StringLogger::~StringLogger() {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::StringLogger - Logging]
|
||||
// ============================================================================
|
||||
|
||||
void StringLogger::logString(uint32_t style, const char* buf, size_t len) {
|
||||
_stringBuilder.appendString(buf, len);
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
238
src/asmjit/base/logger.h
Normal file
238
src/asmjit/base/logger.h
Normal file
@@ -0,0 +1,238 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_LOGGER_H
|
||||
#define _ASMJIT_BASE_LOGGER_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/defs.h"
|
||||
#include "../base/string.h"
|
||||
|
||||
// [Dependencies - C]
|
||||
#include <stdarg.h>
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_logging
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kLoggerOption]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Logger options.
|
||||
ASMJIT_ENUM(kLoggerOption) {
|
||||
//! @brief Whether to output instructions also in binary form.
|
||||
kLoggerOptionBinaryForm = 0,
|
||||
|
||||
//! @brief Whether to output immediates as hexadecimal numbers.
|
||||
kLoggerOptionHexImmediate = 1,
|
||||
//! @brief Whether to output displacements as hexadecimal numbers.
|
||||
kLoggerOptionHexDisplacement = 2,
|
||||
|
||||
//! @brief Count of logger options.
|
||||
kLoggerOptionCount = 3
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kLoggerStyle]
|
||||
// ============================================================================
|
||||
|
||||
ASMJIT_ENUM(kLoggerStyle) {
|
||||
kLoggerStyleDefault = 0,
|
||||
kLoggerStyleDirective = 1,
|
||||
kLoggerStyleLabel = 2,
|
||||
kLoggerStyleData = 3,
|
||||
kLoggerStyleComment = 4,
|
||||
|
||||
kLoggerStyleCount = 5
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Logger]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Abstract logging class.
|
||||
//!
|
||||
//! This class can be inherited and reimplemented to fit into your logging
|
||||
//! subsystem. When reimplementing use @c asmjit::Logger::log() method to
|
||||
//! log into your stream.
|
||||
//!
|
||||
//! This class also contain @c _enabled member that can be used to enable
|
||||
//! or disable logging.
|
||||
struct BaseLogger {
|
||||
ASMJIT_NO_COPY(BaseLogger)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create a @ref BaseLogger instance.
|
||||
ASMJIT_API BaseLogger();
|
||||
//! @brief Destroy the @ref BaseLogger instance.
|
||||
ASMJIT_API virtual ~BaseLogger();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Logging]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Abstract method to log output.
|
||||
//!
|
||||
//! Default implementation that is in @c asmjit::Logger is to do nothing.
|
||||
//! It's virtual to fit to your logging system.
|
||||
virtual void logString(uint32_t style, const char* buf, size_t len = kInvalidIndex) = 0;
|
||||
|
||||
//! @brief Log formatter message (like sprintf) sending output to @c logString() method.
|
||||
ASMJIT_API void logFormat(uint32_t style, const char* fmt, ...);
|
||||
//! @brief Log binary data.
|
||||
ASMJIT_API void logBinary(uint32_t style, const void* data, size_t size);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Options]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get all logger options as a single integer.
|
||||
ASMJIT_INLINE uint32_t getOptions() const
|
||||
{ return _options; }
|
||||
|
||||
//! @brief Get the given logger option.
|
||||
ASMJIT_INLINE bool getOption(uint32_t id) const {
|
||||
ASMJIT_ASSERT(id < kLoggerOptionCount);
|
||||
return static_cast<bool>((_options >> id) & 0x1);
|
||||
}
|
||||
|
||||
//! @brief Set the given logger option.
|
||||
ASMJIT_API void setOption(uint32_t id, bool value);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Indentation]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get indentation.
|
||||
ASMJIT_INLINE const char* getIndentation() const { return _indentation; }
|
||||
//! @brief Set indentation.
|
||||
ASMJIT_API void setIndentation(const char* indentation);
|
||||
//! @brief Reset indentation.
|
||||
ASMJIT_INLINE void resetIndentation() { setIndentation(NULL); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Options, see @ref kLoggerOption.
|
||||
uint32_t _options;
|
||||
|
||||
//! @brief Indentation.
|
||||
char _indentation[12];
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FileLogger]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Logger that can log to standard C @c FILE* stream.
|
||||
struct FileLogger : public BaseLogger {
|
||||
ASMJIT_NO_COPY(FileLogger)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create a new @c FileLogger.
|
||||
//! @param stream FILE stream where logging will be sent (can be @c NULL
|
||||
//! to disable logging).
|
||||
ASMJIT_API FileLogger(FILE* stream = NULL);
|
||||
|
||||
//! @brief Destroy the @ref FileLogger.
|
||||
ASMJIT_API virtual ~FileLogger();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get @c FILE* stream.
|
||||
//!
|
||||
//! @note Return value can be @c NULL.
|
||||
ASMJIT_INLINE FILE* getStream() const { return _stream; }
|
||||
|
||||
//! @brief Set @c FILE* stream.
|
||||
//!
|
||||
//! @param stream @c FILE stream where to log output (can be @c NULL to
|
||||
//! disable logging).
|
||||
ASMJIT_API void setStream(FILE* stream);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Logging]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API virtual void logString(uint32_t style, const char* buf, size_t len = kInvalidIndex);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief C file stream.
|
||||
FILE* _stream;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::StringLogger]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief String logger.
|
||||
struct StringLogger : public BaseLogger {
|
||||
ASMJIT_NO_COPY(StringLogger)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create new @ref StringLogger.
|
||||
ASMJIT_API StringLogger();
|
||||
|
||||
//! @brief Destroy the @ref StringLogger.
|
||||
ASMJIT_API virtual ~StringLogger();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get <code>char*</code> pointer which represents the resulting
|
||||
//! string.
|
||||
//!
|
||||
//! The pointer is owned by @ref StringLogger, it can't be modified or freed.
|
||||
ASMJIT_INLINE const char* getString() const { return _stringBuilder.getData(); }
|
||||
|
||||
//! @brief Clear the resulting string.
|
||||
ASMJIT_INLINE void clearString() { _stringBuilder.clear(); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Logging]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API virtual void logString(uint32_t style, const char* buf, size_t len = kInvalidIndex);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Output.
|
||||
StringBuilder _stringBuilder;
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_LOGGER_H
|
||||
1047
src/asmjit/base/memorymanager.cpp
Normal file
1047
src/asmjit/base/memorymanager.cpp
Normal file
File diff suppressed because it is too large
Load Diff
170
src/asmjit/base/memorymanager.h
Normal file
170
src/asmjit/base/memorymanager.h
Normal file
@@ -0,0 +1,170 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_MEMORYMANAGER_H
|
||||
#define _ASMJIT_BASE_MEMORYMANAGER_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/defs.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup AsmJit_MemoryManagement
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kVirtualAlloc]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Type of virtual memory allocation, see @c asmjit::MemoryManager::alloc().
|
||||
ASMJIT_ENUM(kVirtualAlloc) {
|
||||
//! @brief Normal memory allocation, allocated memory can be free by calling
|
||||
//! @ref asmjit::MemoryManager::free()
|
||||
//! method.
|
||||
kVirtualAllocFreeable = 0,
|
||||
//! @brief Allocate permanent memory that will be never freed.
|
||||
kVirtualAllocPermanent = 1
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::MemoryManager]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Virtual memory manager interface.
|
||||
//!
|
||||
//! This class is pure virtual. You can get default virtual memory manager using
|
||||
//! @c getGlobal() method. If you want to create more memory managers with same
|
||||
//! functionality as global memory manager use @c VirtualMemoryManager class.
|
||||
struct MemoryManager {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create memory manager instance.
|
||||
ASMJIT_API MemoryManager();
|
||||
//! @brief Destroy memory manager instance, this means also to free all memory
|
||||
//! blocks.
|
||||
ASMJIT_API virtual ~MemoryManager();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Interface]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Free all allocated memory.
|
||||
virtual void reset() = 0;
|
||||
|
||||
//! @brief Allocate a @a size bytes of virtual memory.
|
||||
//!
|
||||
//! Note that if you are implementing your own virtual memory manager then you
|
||||
//! can quitly ignore type of allocation. This is mainly for AsmJit to memory
|
||||
//! manager that allocated memory will be never freed.
|
||||
virtual void* alloc(size_t size, uint32_t type = kVirtualAllocFreeable) = 0;
|
||||
//! @brief Free previously allocated memory at a given @a address.
|
||||
virtual Error release(void* address) = 0;
|
||||
//! @brief Free some tail memory.
|
||||
virtual Error shrink(void* address, size_t used) = 0;
|
||||
|
||||
//! @brief Get how many bytes are currently used.
|
||||
virtual size_t getUsedBytes() = 0;
|
||||
//! @brief Get how many bytes are currently allocated.
|
||||
virtual size_t getAllocatedBytes() = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Statics]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get global memory manager instance.
|
||||
//!
|
||||
//! Global instance is instance of @c VirtualMemoryManager class. Global memory
|
||||
//! manager is used by default by @ref Assembler::make() and @ref Compiler::make()
|
||||
//! methods.
|
||||
static ASMJIT_API MemoryManager* getGlobal();
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::VirtualMemoryManager]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Reference implementation of memory manager that uses @ref asmjit::VMem
|
||||
//! class to allocate chunks of virtual memory and bit arrays to manage it.
|
||||
struct VirtualMemoryManager : public MemoryManager {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create a @c VirtualMemoryManager instance.
|
||||
ASMJIT_API VirtualMemoryManager();
|
||||
|
||||
#if defined(ASMJIT_OS_WINDOWS)
|
||||
//! @brief Create a @c VirtualMemoryManager instance for process @a hProcess.
|
||||
//!
|
||||
//! This is specialized version of constructor available only for windows and
|
||||
//! usable to alloc/free memory of different process.
|
||||
ASMJIT_API VirtualMemoryManager(HANDLE hProcess);
|
||||
#endif // ASMJIT_OS_WINDOWS
|
||||
|
||||
//! @brief Destroy the @c VirtualMemoryManager instance, this means also to
|
||||
//! free all blocks.
|
||||
ASMJIT_API virtual ~VirtualMemoryManager();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Interface]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API virtual void reset();
|
||||
|
||||
ASMJIT_API virtual void* alloc(size_t size, uint32_t type = kVirtualAllocFreeable);
|
||||
ASMJIT_API virtual Error release(void* address);
|
||||
ASMJIT_API virtual Error shrink(void* address, size_t used);
|
||||
|
||||
ASMJIT_API virtual size_t getUsedBytes();
|
||||
ASMJIT_API virtual size_t getAllocatedBytes();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Virtual Memory Manager Specific]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get whether to keep allocated memory after memory manager is
|
||||
//! destroyed.
|
||||
//!
|
||||
//! @sa @c setKeepVirtualMemory().
|
||||
ASMJIT_API bool getKeepVirtualMemory() const;
|
||||
|
||||
//! @brief Set whether to keep allocated memory after memory manager is
|
||||
//! destroyed.
|
||||
//!
|
||||
//! This method is usable when patching code of remote process. You need to
|
||||
//! allocate process memory, store generated assembler into it and patch the
|
||||
//! method you want to redirect (into your code). This method affects only
|
||||
//! VirtualMemoryManager destructor. After destruction all internal
|
||||
//! structures are freed, only the process virtual memory remains.
|
||||
//!
|
||||
//! @note Memory allocated with kVirtualAllocPermanent is always kept.
|
||||
//!
|
||||
//! @sa @c getKeepVirtualMemory().
|
||||
ASMJIT_API void setKeepVirtualMemory(bool keepVirtualMemory);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Pointer to private data hidden out of the public API.
|
||||
void* _d;
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_MEMORYMANAGER_H
|
||||
116
src/asmjit/base/podlist.h
Normal file
116
src/asmjit/base/podlist.h
Normal file
@@ -0,0 +1,116 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_PODLIST_H
|
||||
#define _ASMJIT_BASE_PODLIST_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/assert.h"
|
||||
#include "../base/defs.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_base
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::PodList<T>]
|
||||
// ============================================================================
|
||||
|
||||
template <typename T>
|
||||
struct PodList {
|
||||
ASMJIT_NO_COPY(PodList<T>)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Link]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
struct Link {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get next node.
|
||||
ASMJIT_INLINE Link* getNext() const { return _next; }
|
||||
|
||||
//! @brief Get value.
|
||||
ASMJIT_INLINE T getValue() const { return _value; }
|
||||
//! @brief Set value to @a 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 clear() {
|
||||
reset();
|
||||
}
|
||||
|
||||
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 "../base/apiend.h"
|
||||
|
||||
#endif // _ASMJIT_BASE_PODLIST_H
|
||||
96
src/asmjit/base/podvector.cpp
Normal file
96
src/asmjit/base/podvector.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
// [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"
|
||||
#include "../base/podvector.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::PodVectorBase - NullData]
|
||||
// ============================================================================
|
||||
|
||||
const PodVectorData PodVectorBase::_nullData = { 0, 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<size_t>() - 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<PodVectorData*>(::malloc(nBytes));
|
||||
if (d == NULL)
|
||||
return kErrorNoHeapMemory;
|
||||
d->length = 0;
|
||||
}
|
||||
else {
|
||||
d = static_cast<PodVectorData*>(::realloc(d, nBytes));
|
||||
if (d == NULL)
|
||||
return kErrorNoHeapMemory;
|
||||
}
|
||||
|
||||
d->capacity = n;
|
||||
_d = d;
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
262
src/asmjit/base/podvector.h
Normal file
262
src/asmjit/base/podvector.h
Normal file
@@ -0,0 +1,262 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_PODVECTOR_H
|
||||
#define _ASMJIT_BASE_PODVECTOR_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/assert.h"
|
||||
#include "../base/defs.h"
|
||||
#include "../base/error.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_base
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::PodVectorData]
|
||||
// ============================================================================
|
||||
|
||||
struct PodVectorData {
|
||||
//! @brief Get data.
|
||||
ASMJIT_INLINE void* getData() const { return (void*)(this + 1); }
|
||||
|
||||
//! @brief Capacity of the vector.
|
||||
size_t capacity;
|
||||
//! @brief Length of the vector.
|
||||
size_t length;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::PodVectorBase]
|
||||
// ============================================================================
|
||||
|
||||
struct PodVectorBase {
|
||||
static ASMJIT_API const PodVectorData _nullData;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create a new instance of @ref PodVectorBase.
|
||||
ASMJIT_INLINE PodVectorBase() :
|
||||
_d(const_cast<PodVectorData*>(&_nullData)) {}
|
||||
|
||||
//! @brief Destroy the @ref PodVectorBase and data.
|
||||
ASMJIT_INLINE ~PodVectorBase() {
|
||||
if (_d != &_nullData)
|
||||
::free(_d);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [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<T>]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief 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 <typename T>
|
||||
struct PodVector : PodVectorBase {
|
||||
ASMJIT_NO_COPY(PodVector<T>)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create new instance of @ref PodVector<>.
|
||||
ASMJIT_INLINE PodVector() {}
|
||||
//! @brief Destroy the @ref PodVector<> and data.
|
||||
ASMJIT_INLINE ~PodVector() {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Data]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get whether the vector is empty.
|
||||
ASMJIT_INLINE bool isEmpty() const { return _d->length == 0; }
|
||||
//! @brief Get length.
|
||||
ASMJIT_INLINE size_t getLength() const { return _d->length; }
|
||||
//! @brief Get capacity.
|
||||
ASMJIT_INLINE size_t getCapacity() const { return _d->capacity; }
|
||||
|
||||
//! @brief Get data.
|
||||
ASMJIT_INLINE T* getData() { return static_cast<T*>(_d->getData()); }
|
||||
//! @overload
|
||||
ASMJIT_INLINE const T* getData() const { return static_cast<const T*>(_d->getData()); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Clear / Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Clear vector data, but don't free an internal buffer.
|
||||
ASMJIT_INLINE void clear() {
|
||||
if (_d != &_nullData)
|
||||
_d->length = 0;
|
||||
}
|
||||
|
||||
//! @brief Clear vector data and free internal buffer.
|
||||
ASMJIT_INLINE void reset() {
|
||||
if (_d != &_nullData) {
|
||||
::free(_d);
|
||||
_d = const_cast<PodVectorData*>(&_nullData);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Grow / Reserve]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Called to grow the buffer to fit at least @a n elements more.
|
||||
ASMJIT_INLINE Error _grow(size_t n)
|
||||
{ return PodVectorBase::_grow(n, sizeof(T)); }
|
||||
|
||||
//! @brief Realloc internal array to fit at least @a to items.
|
||||
ASMJIT_INLINE Error _reserve(size_t n)
|
||||
{ return PodVectorBase::_reserve(n, sizeof(T)); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Ops]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Prepend @a 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<T*>(d->getData()) + 1, d->getData(), d->length * sizeof(T));
|
||||
::memcpy(d->getData(), &item, sizeof(T));
|
||||
|
||||
d->length++;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
//! @brief Insert an @a item at the @a 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<T*>(d->getData()) + index;
|
||||
::memmove(dst + 1, dst, d->length - index);
|
||||
::memcpy(dst, &item, sizeof(T));
|
||||
|
||||
d->length++;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
//! @brief Append @a 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<T*>(d->getData()) + d->length, &item, sizeof(T));
|
||||
|
||||
d->length++;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
//! @brief Get index of @a val or kInvalidIndex if not found.
|
||||
size_t indexOf(const T& val) const {
|
||||
PodVectorData* d = _d;
|
||||
|
||||
const T* data = static_cast<const T*>(d->getData());
|
||||
size_t len = d->length;
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
if (data[i] == val)
|
||||
return i;
|
||||
|
||||
return kInvalidIndex;
|
||||
}
|
||||
|
||||
//! @brief Remove item at index @a i.
|
||||
void removeAt(size_t i) {
|
||||
PodVectorData* d = _d;
|
||||
ASMJIT_ASSERT(i < d->length);
|
||||
|
||||
T* data = static_cast<T*>(d->getData()) + i;
|
||||
d->length--;
|
||||
::memmove(data, data + 1, d->length - i);
|
||||
}
|
||||
|
||||
//! @brief Swap this pod-vector with @a other.
|
||||
void swap(PodVector<T>& other) {
|
||||
T* otherData = other._d;
|
||||
other._d = _d;
|
||||
_d = otherData;
|
||||
}
|
||||
|
||||
//! @brief Get item at index @a i.
|
||||
ASMJIT_INLINE T& operator[](size_t i) {
|
||||
ASMJIT_ASSERT(i < getLength());
|
||||
return getData()[i];
|
||||
}
|
||||
|
||||
//! @brief Get item at index @a i.
|
||||
ASMJIT_INLINE const T& operator[](size_t i) const {
|
||||
ASMJIT_ASSERT(i < getLength());
|
||||
return getData()[i];
|
||||
}
|
||||
|
||||
//! @brief Allocate and append a new item and return its address.
|
||||
T* newElement() {
|
||||
PodVectorData* d = _d;
|
||||
|
||||
if (d->length == d->capacity) {
|
||||
if (!_grow(1))
|
||||
return NULL;
|
||||
d = _d;
|
||||
}
|
||||
|
||||
return static_cast<T*>(d->getData()) + (d->length++);
|
||||
}
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
#endif // _ASMJIT_BASE_PODVECTOR_H
|
||||
113
src/asmjit/base/runtime.cpp
Normal file
113
src/asmjit/base/runtime.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
// [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/cpu.h"
|
||||
#include "../base/defs.h"
|
||||
#include "../base/error.h"
|
||||
#include "../base/memorymanager.h"
|
||||
#include "../base/runtime.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseRuntime - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
BaseRuntime::BaseRuntime() {}
|
||||
BaseRuntime::~BaseRuntime() {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::JitRuntime - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
JitRuntime::JitRuntime(MemoryManager* memmgr) :
|
||||
_memoryManager(memmgr ? memmgr : MemoryManager::getGlobal()),
|
||||
_allocType(kVirtualAllocFreeable) {}
|
||||
|
||||
JitRuntime::~JitRuntime() {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::JitRuntime - Get]
|
||||
// ============================================================================
|
||||
|
||||
uint32_t JitRuntime::getStackAlignment() {
|
||||
uint32_t alignment = sizeof(intptr_t);
|
||||
|
||||
#if defined(ASMJIT_HOST_X86)
|
||||
// Modern Linux, APPLE and UNIX guarantees 16-byte stack alignment, but I'm
|
||||
// not sure about all other UNIX operating systems, because 16-byte alignment
|
||||
// is addition to an older specification.
|
||||
#if (defined(__linux__) || \
|
||||
defined(__linux) || \
|
||||
defined(__unix__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__DARWIN__) || \
|
||||
defined(__APPLE__) )
|
||||
alignment = 16;
|
||||
#endif
|
||||
#elif defined(ASMJIT_HOST_X64)
|
||||
alignment = 16;
|
||||
#endif
|
||||
|
||||
return alignment;
|
||||
}
|
||||
|
||||
const BaseCpu* JitRuntime::getCpu() {
|
||||
return BaseCpu::getHost();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::JitRuntime - Add]
|
||||
// ============================================================================
|
||||
|
||||
Error JitRuntime::add(void** dst, BaseAssembler* assembler) {
|
||||
// Disallow empty code generation.
|
||||
size_t codeSize = assembler->getCodeSize();
|
||||
|
||||
if (codeSize == 0) {
|
||||
*dst = NULL;
|
||||
return kErrorCompilerNoFunc;
|
||||
}
|
||||
|
||||
MemoryManager* memmgr = getMemoryManager();
|
||||
void* p = memmgr->alloc(codeSize, getAllocType());
|
||||
|
||||
if (p == NULL) {
|
||||
*dst = NULL;
|
||||
return kErrorNoVirtualMemory;
|
||||
}
|
||||
|
||||
// Relocate the code.
|
||||
size_t relocSize = assembler->relocCode(p);
|
||||
|
||||
// Return unused memory to MemoryManager.
|
||||
if (relocSize < codeSize)
|
||||
memmgr->shrink(p, relocSize);
|
||||
|
||||
// Return the code.
|
||||
*dst = p;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error JitRuntime::release(void* p) {
|
||||
MemoryManager* memmgr = getMemoryManager();
|
||||
return memmgr->release(p);
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
132
src/asmjit/base/runtime.h
Normal file
132
src/asmjit/base/runtime.h
Normal file
@@ -0,0 +1,132 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_RUNTIME_H
|
||||
#define _ASMJIT_BASE_RUNTIME_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/error.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [Forward Declarations]
|
||||
// ============================================================================
|
||||
|
||||
struct BaseAssembler;
|
||||
struct BaseCpu;
|
||||
struct MemoryManager;
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::BaseRuntime]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Base runtime.
|
||||
struct BaseRuntime {
|
||||
ASMJIT_NO_COPY(BaseRuntime)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create a @ref BaseRuntime instance.
|
||||
ASMJIT_API BaseRuntime();
|
||||
//! @brief Destroy the @ref BaseRuntime instance.
|
||||
ASMJIT_API virtual ~BaseRuntime();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Interface]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get stack alignment of target runtime.
|
||||
virtual uint32_t getStackAlignment() = 0;
|
||||
|
||||
//! @brief Get CPU information.
|
||||
virtual const BaseCpu* getCpu() = 0;
|
||||
|
||||
//! @brief Allocate memory for code generated in @a assembler and reloc it
|
||||
//! to the target location.
|
||||
//!
|
||||
//! This method is universal allowing any preprocessing / postprocessing
|
||||
//! with code generated by @ref BaseAssembler or @ref BaseCompiler. Because
|
||||
//! @ref BaseCompiler always uses @ref BaseAssembler it's allowed to access
|
||||
//! only the @ref BaseAssembler instance.
|
||||
//!
|
||||
//! This method is always last step when using code generation. You can use
|
||||
//! it to allocate memory for JIT code, saving code to remote process or a
|
||||
//! file.
|
||||
//!
|
||||
//! @retrurn Status code, see @ref kError.
|
||||
virtual Error add(void** dst, BaseAssembler* assembler) = 0;
|
||||
|
||||
//! @brief Release memory allocated by add.
|
||||
virtual Error release(void* p) = 0;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::JitRuntime]
|
||||
// ============================================================================
|
||||
|
||||
struct JitRuntime : public BaseRuntime {
|
||||
ASMJIT_NO_COPY(JitRuntime)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create a @c JitRuntime instance.
|
||||
ASMJIT_API JitRuntime(MemoryManager* memmgr = NULL);
|
||||
//! @brief Destroy the @c JitRuntime instance.
|
||||
ASMJIT_API virtual ~JitRuntime();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Memory Manager and Alloc Type]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Note: These members can be ignored by all derived classes. They are here
|
||||
// only to privide default implementation. All other implementations (remote
|
||||
// code patching or making dynamic loadable libraries/executables) ignore
|
||||
// members accessed by these accessors.
|
||||
|
||||
//! @brief Get the @c MemoryManager instance.
|
||||
ASMJIT_INLINE MemoryManager* getMemoryManager() const { return _memoryManager; }
|
||||
|
||||
//! @brief Get the type of allocation.
|
||||
ASMJIT_INLINE uint32_t getAllocType() const { return _allocType; }
|
||||
//! @brief Set the type of allocation.
|
||||
ASMJIT_INLINE void setAllocType(uint32_t allocType) { _allocType = allocType; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Interface]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API virtual uint32_t getStackAlignment();
|
||||
ASMJIT_API virtual const BaseCpu* getCpu();
|
||||
|
||||
ASMJIT_API virtual Error add(void** dst, BaseAssembler* assembler);
|
||||
ASMJIT_API virtual Error release(void* p);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Memory manager.
|
||||
MemoryManager* _memoryManager;
|
||||
//! @brief Type of allocation.
|
||||
uint32_t _allocType;
|
||||
};
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_RUNTIME_H
|
||||
375
src/asmjit/base/string.cpp
Normal file
375
src/asmjit/base/string.cpp
Normal file
@@ -0,0 +1,375 @@
|
||||
// [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/defs.h"
|
||||
#include "../base/intutil.h"
|
||||
#include "../base/string.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// Should be placed in read-only memory.
|
||||
static const char StringBuilder_empty[4] = { 0 };
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::StringBuilder - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
StringBuilder::StringBuilder() :
|
||||
_data(const_cast<char*>(StringBuilder_empty)),
|
||||
_length(0),
|
||||
_capacity(0),
|
||||
_canFree(false) {}
|
||||
|
||||
StringBuilder::~StringBuilder() {
|
||||
if (_canFree)
|
||||
::free(_data);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::StringBuilder - Prepare / Reserve]
|
||||
// ============================================================================
|
||||
|
||||
char* StringBuilder::prepare(uint32_t op, size_t len) {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Set]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
if (op == kStringOpSet) {
|
||||
// We don't care here, but we can't return a NULL pointer since it indicates
|
||||
// failure in memory allocation.
|
||||
if (len == 0) {
|
||||
if (_data != StringBuilder_empty)
|
||||
_data[0] = 0;
|
||||
|
||||
_length = 0;
|
||||
return _data;
|
||||
}
|
||||
|
||||
if (_capacity < len) {
|
||||
if (len >= IntUtil::maxUInt<size_t>() - sizeof(intptr_t) * 2)
|
||||
return NULL;
|
||||
|
||||
size_t to = IntUtil::alignTo<size_t>(len, sizeof(intptr_t));
|
||||
if (to < 256 - sizeof(intptr_t))
|
||||
to = 256 - sizeof(intptr_t);
|
||||
|
||||
char* newData = static_cast<char*>(::malloc(to + sizeof(intptr_t)));
|
||||
if (newData == NULL) {
|
||||
clear();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_canFree)
|
||||
::free(_data);
|
||||
|
||||
_data = newData;
|
||||
_capacity = to + sizeof(intptr_t) - 1;
|
||||
_canFree = true;
|
||||
}
|
||||
|
||||
_data[len] = 0;
|
||||
_length = len;
|
||||
|
||||
ASMJIT_ASSERT(_length <= _capacity);
|
||||
return _data;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Append]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
else {
|
||||
// We don't care here, but we can't return a NULL pointer since it indicates
|
||||
// failure in memory allocation.
|
||||
if (len == 0)
|
||||
return _data + _length;
|
||||
|
||||
// Overflow.
|
||||
if (IntUtil::maxUInt<size_t>() - sizeof(intptr_t) * 2 - _length < len)
|
||||
return NULL;
|
||||
|
||||
size_t after = _length + len;
|
||||
if (_capacity < after) {
|
||||
size_t to = _capacity;
|
||||
|
||||
if (to < 256)
|
||||
to = 256;
|
||||
|
||||
while (to < 1024 * 1024 && to < after)
|
||||
to *= 2;
|
||||
|
||||
if (to < after) {
|
||||
to = after;
|
||||
if (to < (IntUtil::maxUInt<size_t>() - 1024 * 32))
|
||||
to = IntUtil::alignTo<size_t>(to, 1024 * 32);
|
||||
}
|
||||
|
||||
to = IntUtil::alignTo<size_t>(to, sizeof(intptr_t));
|
||||
char* newData = static_cast<char*>(::malloc(to + sizeof(intptr_t)));
|
||||
|
||||
if (newData == NULL)
|
||||
return NULL;
|
||||
|
||||
::memcpy(newData, _data, _length);
|
||||
if (_canFree)
|
||||
::free(_data);
|
||||
|
||||
_data = newData;
|
||||
_capacity = to + sizeof(intptr_t) - 1;
|
||||
_canFree = true;
|
||||
}
|
||||
|
||||
char* ret = _data + _length;
|
||||
_data[after] = 0;
|
||||
_length = after;
|
||||
|
||||
ASMJIT_ASSERT(_length <= _capacity);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
bool StringBuilder::reserve(size_t to) {
|
||||
if (_capacity >= to)
|
||||
return true;
|
||||
|
||||
if (to >= IntUtil::maxUInt<size_t>() - sizeof(intptr_t) * 2)
|
||||
return false;
|
||||
|
||||
to = IntUtil::alignTo<size_t>(to, sizeof(intptr_t));
|
||||
|
||||
char* newData = static_cast<char*>(::malloc(to + sizeof(intptr_t)));
|
||||
if (newData == NULL)
|
||||
return false;
|
||||
|
||||
::memcpy(newData, _data, _length + 1);
|
||||
if (_canFree)
|
||||
::free(_data);
|
||||
|
||||
_data = newData;
|
||||
_capacity = to + sizeof(intptr_t) - 1;
|
||||
_canFree = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::StringBuilder - Clear]
|
||||
// ============================================================================
|
||||
|
||||
void StringBuilder::clear() {
|
||||
if (_data != StringBuilder_empty)
|
||||
_data[0] = 0;
|
||||
_length = 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::StringBuilder - Methods]
|
||||
// ============================================================================
|
||||
|
||||
bool StringBuilder::_opString(uint32_t op, const char* str, size_t len) {
|
||||
if (len == kInvalidIndex)
|
||||
len = str != NULL ? ::strlen(str) : static_cast<size_t>(0);
|
||||
|
||||
char* p = prepare(op, len);
|
||||
if (p == NULL)
|
||||
return false;
|
||||
|
||||
::memcpy(p, str, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StringBuilder::_opChar(uint32_t op, char c) {
|
||||
char* p = prepare(op, 1);
|
||||
if (p == NULL)
|
||||
return false;
|
||||
|
||||
*p = c;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StringBuilder::_opChars(uint32_t op, char c, size_t len) {
|
||||
char* p = prepare(op, len);
|
||||
if (p == NULL)
|
||||
return false;
|
||||
|
||||
::memset(p, c, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char StringBuilder_numbers[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
bool StringBuilder::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, uint32_t flags) {
|
||||
if (base < 2 || base > 36)
|
||||
base = 10;
|
||||
|
||||
char buf[128];
|
||||
char* p = buf + ASMJIT_ARRAY_SIZE(buf);
|
||||
|
||||
uint64_t orig = i;
|
||||
char sign = '\0';
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Sign]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
if ((flags & kStringFormatSigned) != 0 && static_cast<int64_t>(i) < 0) {
|
||||
i = static_cast<uint64_t>(-static_cast<int64_t>(i));
|
||||
sign = '-';
|
||||
}
|
||||
else if ((flags & kStringFormatShowSign) != 0) {
|
||||
sign = '+';
|
||||
}
|
||||
else if ((flags & kStringFormatShowSpace) != 0) {
|
||||
sign = ' ';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Number]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
do {
|
||||
uint64_t d = i / base;
|
||||
uint64_t r = i % base;
|
||||
|
||||
*--p = StringBuilder_numbers[r];
|
||||
i = d;
|
||||
} while (i);
|
||||
|
||||
size_t numberLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Alternate Form]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
if ((flags & kStringFormatAlternate) != 0) {
|
||||
if (base == 8) {
|
||||
if (orig != 0)
|
||||
*--p = '0';
|
||||
}
|
||||
if (base == 16) {
|
||||
*--p = 'x';
|
||||
*--p = '0';
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Width]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
if (sign != 0)
|
||||
*--p = sign;
|
||||
|
||||
if (width > 256)
|
||||
width = 256;
|
||||
|
||||
if (width <= numberLength)
|
||||
width = 0;
|
||||
else
|
||||
width -= numberLength;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Write]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
size_t prefixLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p) - numberLength;
|
||||
char* data = prepare(op, prefixLength + width + numberLength);
|
||||
|
||||
if (data == NULL)
|
||||
return false;
|
||||
|
||||
::memcpy(data, p, prefixLength);
|
||||
data += prefixLength;
|
||||
|
||||
::memset(data, '0', width);
|
||||
data += width;
|
||||
|
||||
::memcpy(data, p + prefixLength, numberLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StringBuilder::_opHex(uint32_t op, const void* data, size_t len) {
|
||||
if (len >= IntUtil::maxUInt<size_t>() / 2)
|
||||
return false;
|
||||
|
||||
char* dst = prepare(op, len * 2);
|
||||
if (dst == NULL)
|
||||
return false;
|
||||
|
||||
const char* src = static_cast<const char*>(data);
|
||||
for (size_t i = 0; i < len; i++, dst += 2, src += 1)
|
||||
{
|
||||
dst[0] = StringBuilder_numbers[(src[0] >> 4) & 0xF];
|
||||
dst[1] = StringBuilder_numbers[(src[0] ) & 0xF];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StringBuilder::_opVFormat(uint32_t op, const char* fmt, va_list ap) {
|
||||
char buf[1024];
|
||||
|
||||
vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap);
|
||||
buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0';
|
||||
|
||||
return _opString(op, buf);
|
||||
}
|
||||
|
||||
bool StringBuilder::setFormat(const char* fmt, ...) {
|
||||
bool result;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
result = _opVFormat(kStringOpSet, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool StringBuilder::appendFormat(const char* fmt, ...) {
|
||||
bool result;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
result = _opVFormat(kStringOpAppend, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool StringBuilder::eq(const char* str, size_t len) const {
|
||||
const char* aData = _data;
|
||||
const char* bData = str;
|
||||
|
||||
size_t aLength = _length;
|
||||
size_t bLength = len;
|
||||
|
||||
if (bLength == kInvalidIndex) {
|
||||
size_t i;
|
||||
for (i = 0; i < aLength; i++) {
|
||||
if (aData[i] != bData[i] || bData[i] == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return bData[i] == 0;
|
||||
}
|
||||
else {
|
||||
if (aLength != bLength)
|
||||
return false;
|
||||
|
||||
return ::memcmp(aData, bData, aLength) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
350
src/asmjit/base/string.h
Normal file
350
src/asmjit/base/string.h
Normal file
@@ -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_STRING_H
|
||||
#define _ASMJIT_BASE_STRING_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/assert.h"
|
||||
#include "../base/defs.h"
|
||||
|
||||
// [Dependencies - C]
|
||||
#include <stdarg.h>
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_base
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kStringOp]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief String operation.
|
||||
ASMJIT_ENUM(kStringOp) {
|
||||
//! @brief Replace the current string by a given content.
|
||||
kStringOpSet = 0,
|
||||
//! @brief Append a given content to the current string.
|
||||
kStringOpAppend = 1
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::kStringFormat]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief String format flags.
|
||||
ASMJIT_ENUM(kStringFormat) {
|
||||
kStringFormatShowSign = 0x00000001,
|
||||
kStringFormatShowSpace = 0x00000002,
|
||||
kStringFormatAlternate = 0x00000004,
|
||||
kStringFormatSigned = 0x80000000
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::StringUtil]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief String utilities.
|
||||
struct StringUtil {
|
||||
static ASMJIT_INLINE size_t nlen(const char* s, size_t maxlen) {
|
||||
size_t i;
|
||||
for (i = 0; i < maxlen; i++)
|
||||
if (!s[i])
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::StringBuilder]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief String builder.
|
||||
//!
|
||||
//! String builder was designed to be able to build a string using append like
|
||||
//! operation to append numbers, other strings, or signle characters. It can
|
||||
//! allocate it's own buffer or use a buffer created on the stack.
|
||||
//!
|
||||
//! String builder contains method specific to AsmJit functionality, used for
|
||||
//! logging or HTML output.
|
||||
struct StringBuilder {
|
||||
ASMJIT_NO_COPY(StringBuilder)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API StringBuilder();
|
||||
ASMJIT_API ~StringBuilder();
|
||||
|
||||
ASMJIT_INLINE StringBuilder(const _DontInitialize&) {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get string builder capacity.
|
||||
ASMJIT_INLINE size_t getCapacity() const { return _capacity; }
|
||||
//! @brief Get length.
|
||||
ASMJIT_INLINE size_t getLength() const { return _length; }
|
||||
|
||||
//! @brief Get null-terminated string data.
|
||||
ASMJIT_INLINE char* getData() { return _data; }
|
||||
//! @brief Get null-terminated string data (const).
|
||||
ASMJIT_INLINE const char* getData() const { return _data; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Prepare / Reserve]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Prepare to set/append.
|
||||
ASMJIT_API char* prepare(uint32_t op, size_t len);
|
||||
|
||||
//! @brief Reserve @a to bytes in string builder.
|
||||
ASMJIT_API bool reserve(size_t to);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Clear]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Clear the content in String builder.
|
||||
ASMJIT_API void clear();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Op]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API bool _opString(uint32_t op, const char* str, size_t len = kInvalidIndex);
|
||||
ASMJIT_API bool _opVFormat(uint32_t op, const char* fmt, va_list ap);
|
||||
ASMJIT_API bool _opChar(uint32_t op, char c);
|
||||
ASMJIT_API bool _opChars(uint32_t op, char c, size_t len);
|
||||
ASMJIT_API bool _opNumber(uint32_t op, uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0);
|
||||
ASMJIT_API bool _opHex(uint32_t op, const void* data, size_t len);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Set]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Replace the current content by @a str of @a len.
|
||||
ASMJIT_INLINE bool setString(const char* str, size_t len = kInvalidIndex)
|
||||
{ return _opString(kStringOpSet, str, len); }
|
||||
|
||||
//! @brief Replace the current content by formatted string @a fmt.
|
||||
ASMJIT_INLINE bool setVFormat(const char* fmt, va_list ap)
|
||||
{ return _opVFormat(kStringOpSet, fmt, ap); }
|
||||
|
||||
//! @brief Replace the current content by formatted string @a fmt.
|
||||
ASMJIT_API bool setFormat(const char* fmt, ...);
|
||||
|
||||
//! @brief Replace the current content by @a c character.
|
||||
ASMJIT_INLINE bool setChar(char c)
|
||||
{ return _opChar(kStringOpSet, c); }
|
||||
|
||||
//! @brief Replace the current content by @a c of @a len.
|
||||
ASMJIT_INLINE bool setChars(char c, size_t len)
|
||||
{ return _opChars(kStringOpSet, c, len); }
|
||||
|
||||
//! @brief Replace the current content by @a i..
|
||||
ASMJIT_INLINE bool setInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0)
|
||||
{ return _opNumber(kStringOpSet, i, base, width, flags | kStringFormatSigned); }
|
||||
|
||||
//! @brief Replace the current content by @a i..
|
||||
ASMJIT_INLINE bool setUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0)
|
||||
{ return _opNumber(kStringOpSet, i, base, width, flags); }
|
||||
|
||||
//! @brief Replace the current content by the given @a data converted to a HEX string.
|
||||
ASMJIT_INLINE bool setHex(const void* data, size_t len)
|
||||
{ return _opHex(kStringOpSet, data, len); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Append]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Append @a str of @a len.
|
||||
ASMJIT_INLINE bool appendString(const char* str, size_t len = kInvalidIndex)
|
||||
{ return _opString(kStringOpAppend, str, len); }
|
||||
|
||||
//! @brief Append a formatted string @a fmt to the current content.
|
||||
ASMJIT_INLINE bool appendVFormat(const char* fmt, va_list ap)
|
||||
{ return _opVFormat(kStringOpAppend, fmt, ap); }
|
||||
|
||||
//! @brief Append a formatted string @a fmt to the current content.
|
||||
ASMJIT_API bool appendFormat(const char* fmt, ...);
|
||||
|
||||
//! @brief Append @a c character.
|
||||
ASMJIT_INLINE bool appendChar(char c)
|
||||
{ return _opChar(kStringOpAppend, c); }
|
||||
|
||||
//! @brief Append @a c of @a len.
|
||||
ASMJIT_INLINE bool appendChars(char c, size_t len)
|
||||
{ return _opChars(kStringOpAppend, c, len); }
|
||||
|
||||
//! @brief Append @a i.
|
||||
ASMJIT_INLINE bool appendInt(int64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0)
|
||||
{ return _opNumber(kStringOpAppend, static_cast<uint64_t>(i), base, width, flags | kStringFormatSigned); }
|
||||
|
||||
//! @brief Append @a i.
|
||||
ASMJIT_INLINE bool appendUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0)
|
||||
{ return _opNumber(kStringOpAppend, i, base, width, flags); }
|
||||
|
||||
//! @brief Append the given @a data converted to a HEX string.
|
||||
ASMJIT_INLINE bool appendHex(const void* data, size_t len)
|
||||
{ return _opHex(kStringOpAppend, data, len); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [_Append]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Append @a str of @a len (inlined, without buffer overflow check).
|
||||
ASMJIT_INLINE void _appendString(const char* str, size_t len = kInvalidIndex) {
|
||||
// len should be a constant if we are inlining.
|
||||
if (len == kInvalidIndex) {
|
||||
char* p = &_data[_length];
|
||||
|
||||
while (*str) {
|
||||
ASMJIT_ASSERT(p < _data + _capacity);
|
||||
*p++ = *str++;
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
_length = (size_t)(p - _data);
|
||||
}
|
||||
else {
|
||||
ASMJIT_ASSERT(_capacity - _length >= len);
|
||||
|
||||
char* p = &_data[_length];
|
||||
char* pEnd = p + len;
|
||||
|
||||
while (p < pEnd)
|
||||
*p++ = *str++;
|
||||
|
||||
*p = '\0';
|
||||
_length += len;
|
||||
}
|
||||
}
|
||||
|
||||
//! @brief Append @a c character (inlined, without buffer overflow check).
|
||||
ASMJIT_INLINE void _appendChar(char c) {
|
||||
ASMJIT_ASSERT(_capacity - _length >= 1);
|
||||
|
||||
_data[_length] = c;
|
||||
_length++;
|
||||
_data[_length] = '\0';
|
||||
}
|
||||
|
||||
//! @brief Append @a c of @a len (inlined, without buffer overflow check).
|
||||
ASMJIT_INLINE void _appendChars(char c, size_t len) {
|
||||
ASMJIT_ASSERT(_capacity - _length >= len);
|
||||
|
||||
char* p = &_data[_length];
|
||||
char* pEnd = p + len;
|
||||
|
||||
while (p < pEnd)
|
||||
*p++ = c;
|
||||
|
||||
*p = '\0';
|
||||
_length += len;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE void _appendUInt32(uint32_t i) {
|
||||
char buf_[32];
|
||||
|
||||
char* pEnd = buf_ + ASMJIT_ARRAY_SIZE(buf_);
|
||||
char* pBuf = pEnd;
|
||||
|
||||
do {
|
||||
uint32_t d = i / 10;
|
||||
uint32_t r = i % 10;
|
||||
|
||||
*--pBuf = static_cast<uint8_t>(r + '0');
|
||||
i = d;
|
||||
} while (i);
|
||||
|
||||
ASMJIT_ASSERT(_capacity - _length >= (size_t)(pEnd - pBuf));
|
||||
char* p = &_data[_length];
|
||||
|
||||
do {
|
||||
*p++ = *pBuf;
|
||||
} while (++pBuf != pEnd);
|
||||
|
||||
*p = '\0';
|
||||
_length = (size_t)(p - _data);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Eq]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Check for equality with other @a str.
|
||||
ASMJIT_API bool eq(const char* str, size_t len = kInvalidIndex) const;
|
||||
//! @brief Check for equality with StringBuilder @a other.
|
||||
ASMJIT_INLINE bool eq(const StringBuilder& other) const { return eq(other._data); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Operator Overload]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE bool operator==(const StringBuilder& other) const { return eq(other); }
|
||||
ASMJIT_INLINE bool operator!=(const StringBuilder& other) const { return !eq(other); }
|
||||
|
||||
ASMJIT_INLINE bool operator==(const char* str) const { return eq(str); }
|
||||
ASMJIT_INLINE bool operator!=(const char* str) const { return !eq(str); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief String data.
|
||||
char* _data;
|
||||
//! @brief Length.
|
||||
size_t _length;
|
||||
//! @brief Capacity.
|
||||
size_t _capacity;
|
||||
//! @brief Whether the string can be freed.
|
||||
size_t _canFree;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::StringBuilderT]
|
||||
// ============================================================================
|
||||
|
||||
template<size_t N>
|
||||
struct StringBuilderT : public StringBuilder {
|
||||
ASMJIT_NO_COPY(StringBuilderT<N>)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE StringBuilderT() : StringBuilder(DontInitialize) {
|
||||
_data = _embeddedData;
|
||||
_data[0] = 0;
|
||||
|
||||
_length = 0;
|
||||
_capacity = N;
|
||||
_canFree = false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Embedded data.
|
||||
char _embeddedData[static_cast<size_t>(N + 1 + sizeof(intptr_t)) & ~static_cast<size_t>(sizeof(intptr_t) - 1)];
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
#endif // _ASMJIT_BASE_STRING_H
|
||||
1248
src/asmjit/base/vectypes.h
Normal file
1248
src/asmjit/base/vectypes.h
Normal file
File diff suppressed because it is too large
Load Diff
145
src/asmjit/base/vmem.cpp
Normal file
145
src/asmjit/base/vmem.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
// [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"
|
||||
#include "../base/vmem.h"
|
||||
|
||||
// [Dependencies - Windows]
|
||||
#if defined(ASMJIT_OS_WINDOWS)
|
||||
# include <windows.h>
|
||||
#endif // ASMJIT_OS_WINDOWS
|
||||
|
||||
// [Dependencies - Posix]
|
||||
#if defined(ASMJIT_OS_POSIX)
|
||||
# include <sys/types.h>
|
||||
# include <sys/mman.h>
|
||||
# include <unistd.h>
|
||||
#endif // ASMJIT_OS_POSIX
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::VMem - Windows]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(ASMJIT_OS_WINDOWS)
|
||||
struct VMemLocal {
|
||||
VMemLocal() {
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
|
||||
alignment = info.dwAllocationGranularity;
|
||||
pageSize = IntUtil::roundUpToPowerOf2<uint32_t>(info.dwPageSize);
|
||||
}
|
||||
|
||||
size_t alignment;
|
||||
size_t pageSize;
|
||||
};
|
||||
|
||||
static VMemLocal& vm() {
|
||||
static VMemLocal vm;
|
||||
return vm;
|
||||
};
|
||||
|
||||
void* VMem::alloc(size_t length, size_t* allocated, bool canExecute) {
|
||||
return allocProcessMemory(GetCurrentProcess(), length, allocated, canExecute);
|
||||
}
|
||||
|
||||
void VMem::release(void* addr, size_t length) {
|
||||
return releaseProcessMemory(GetCurrentProcess(), addr, length);
|
||||
}
|
||||
|
||||
void* VMem::allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, bool canExecute) {
|
||||
// VirtualAlloc rounds allocated size to page size automatically.
|
||||
size_t msize = IntUtil::roundUp(length, vm().pageSize);
|
||||
|
||||
// Windows XP SP2 / Vista allow Data Excution Prevention (DEP).
|
||||
WORD protect = canExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
|
||||
LPVOID mbase = VirtualAllocEx(hProcess, NULL, msize, MEM_COMMIT | MEM_RESERVE, protect);
|
||||
if (mbase == NULL) return NULL;
|
||||
|
||||
ASMJIT_ASSERT(IntUtil::isAligned<size_t>(reinterpret_cast<size_t>(mbase), vm().alignment));
|
||||
|
||||
if (allocated != NULL)
|
||||
*allocated = msize;
|
||||
return mbase;
|
||||
}
|
||||
|
||||
void VMem::releaseProcessMemory(HANDLE hProcess, void* addr, size_t /* length */) {
|
||||
VirtualFreeEx(hProcess, addr, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
size_t VMem::getAlignment() {
|
||||
return vm().alignment;
|
||||
}
|
||||
|
||||
size_t VMem::getPageSize() {
|
||||
return vm().pageSize;
|
||||
}
|
||||
#endif // ASMJIT_OS_WINDOWS
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::VMem - Posix]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(ASMJIT_OS_POSIX)
|
||||
|
||||
// MacOS uses MAP_ANON instead of MAP_ANONYMOUS.
|
||||
#if !defined(MAP_ANONYMOUS)
|
||||
# define MAP_ANONYMOUS MAP_ANON
|
||||
#endif // MAP_ANONYMOUS
|
||||
|
||||
struct VMemLocal {
|
||||
VMemLocal() {
|
||||
alignment = pageSize = ::getpagesize();
|
||||
}
|
||||
|
||||
size_t alignment;
|
||||
size_t pageSize;
|
||||
};
|
||||
|
||||
static VMemLocal& vm() {
|
||||
static VMemLocal vm;
|
||||
return vm;
|
||||
}
|
||||
|
||||
void* VMem::alloc(size_t length, size_t* allocated, bool canExecute) {
|
||||
size_t msize = IntUtil::roundUp<size_t>(length, vm().pageSize);
|
||||
int protection = PROT_READ | PROT_WRITE | (canExecute ? PROT_EXEC : 0);
|
||||
|
||||
void* mbase = ::mmap(NULL, msize, protection, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (mbase == MAP_FAILED)
|
||||
return NULL;
|
||||
|
||||
if (allocated != NULL)
|
||||
*allocated = msize;
|
||||
return mbase;
|
||||
}
|
||||
|
||||
void VMem::release(void* addr, size_t length) {
|
||||
munmap(addr, length);
|
||||
}
|
||||
|
||||
size_t VMem::getAlignment() {
|
||||
return vm().alignment;
|
||||
}
|
||||
|
||||
size_t VMem::getPageSize() {
|
||||
return vm().pageSize;
|
||||
}
|
||||
#endif // ASMJIT_OS_POSIX
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
76
src/asmjit/base/vmem.h
Normal file
76
src/asmjit/base/vmem.h
Normal file
@@ -0,0 +1,76 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_VMEM_H
|
||||
#define _ASMJIT_BASE_VMEM_H
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_base
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::VMem]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Class that helps with allocating memory for executing code
|
||||
//! generated by JIT compiler.
|
||||
//!
|
||||
//! There are defined functions that provides facility to allocate and free
|
||||
//! memory where can be executed code. If processor and operating system
|
||||
//! supports execution protection then you can't run code from normally
|
||||
//! malloc()'ed memory.
|
||||
//!
|
||||
//! Functions are internally implemented by operating system dependent way.
|
||||
//! VirtualAlloc() function is used for Windows operating system and mmap()
|
||||
//! for posix ones. If you want to study or create your own functions, look
|
||||
//! at VirtualAlloc() or mmap() documentation (depends on you target OS).
|
||||
//!
|
||||
//! Under posix operating systems is also useable mprotect() function, that
|
||||
//! can enable execution protection to malloc()'ed memory block.
|
||||
struct VMem {
|
||||
//! @brief Allocate virtual memory.
|
||||
//!
|
||||
//! Pages are readable/writeable, but they are not guaranteed to be
|
||||
//! executable unless 'canExecute' is true. Returns the address of
|
||||
//! allocated memory, or NULL on failure.
|
||||
static ASMJIT_API void* alloc(size_t length, size_t* allocated, bool canExecute);
|
||||
|
||||
//! @brief Free memory allocated by @c alloc()
|
||||
static ASMJIT_API void release(void* addr, size_t length);
|
||||
|
||||
#if defined(ASMJIT_OS_WINDOWS)
|
||||
//! @brief Allocate virtual memory of @a hProcess.
|
||||
//!
|
||||
//! @note This function is Windows specific.
|
||||
static ASMJIT_API void* allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, bool canExecute);
|
||||
|
||||
//! @brief Free virtual memory of @a hProcess.
|
||||
//!
|
||||
//! @note This function is Windows specific.
|
||||
static ASMJIT_API void releaseProcessMemory(HANDLE hProcess, void* addr, size_t length);
|
||||
#endif // ASMJIT_OS_WINDOWS
|
||||
|
||||
//! @brief Get the alignment guaranteed by alloc().
|
||||
static ASMJIT_API size_t getAlignment();
|
||||
|
||||
//! @brief Get size of the single page.
|
||||
static ASMJIT_API size_t getPageSize();
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_VMEM_H
|
||||
163
src/asmjit/base/zone.cpp
Normal file
163
src/asmjit/base/zone.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
// [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/defs.h"
|
||||
#include "../base/intutil.h"
|
||||
#include "../base/zone.h"
|
||||
|
||||
// [Dependencies - C]
|
||||
#include <stdarg.h>
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Zone - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
Zone::Zone(size_t chunkSize) {
|
||||
_chunks = NULL;
|
||||
_chunkSize = chunkSize;
|
||||
}
|
||||
|
||||
Zone::~Zone() {
|
||||
reset();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Zone - Clear / Reset]
|
||||
// ============================================================================
|
||||
|
||||
void Zone::clear() {
|
||||
Chunk* cur = _chunks;
|
||||
|
||||
if (cur == NULL)
|
||||
return;
|
||||
|
||||
cur = cur->prev;
|
||||
while (cur != NULL) {
|
||||
Chunk* prev = cur->prev;
|
||||
::free(cur);
|
||||
cur = prev;
|
||||
}
|
||||
|
||||
_chunks->pos = 0;
|
||||
_chunks->prev = NULL;
|
||||
}
|
||||
|
||||
void Zone::reset() {
|
||||
Chunk* cur = _chunks;
|
||||
_chunks = NULL;
|
||||
|
||||
while (cur != NULL) {
|
||||
Chunk* prev = cur->prev;
|
||||
::free(cur);
|
||||
cur = prev;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Zone - Alloc]
|
||||
// ============================================================================
|
||||
|
||||
void* Zone::_alloc(size_t size) {
|
||||
Chunk* cur = _chunks;
|
||||
ASMJIT_ASSERT(cur == NULL || cur->getRemainingSize() < size);
|
||||
|
||||
size_t chunkSize = _chunkSize;
|
||||
if (chunkSize < size)
|
||||
chunkSize = size;
|
||||
|
||||
cur = static_cast<Chunk*>(::malloc(sizeof(Chunk) - sizeof(void*) + chunkSize));
|
||||
if (cur == NULL)
|
||||
return NULL;
|
||||
|
||||
cur->prev = _chunks;
|
||||
cur->pos = 0;
|
||||
cur->size = chunkSize;
|
||||
|
||||
_chunks = cur;
|
||||
|
||||
uint8_t* p = cur->data + cur->pos;
|
||||
cur->pos += size;
|
||||
|
||||
ASMJIT_ASSERT(cur->pos <= cur->size);
|
||||
return (void*)p;
|
||||
}
|
||||
|
||||
void* Zone::_calloc(size_t size) {
|
||||
void* p = _alloc(size);
|
||||
|
||||
if (p != NULL)
|
||||
::memset(p, 0, size);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void* Zone::dup(const void* data, size_t size) {
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
void* m = alloc(size);
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
|
||||
::memcpy(m, data, size);
|
||||
return m;
|
||||
}
|
||||
|
||||
char* Zone::sdup(const char* str) {
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
size_t len = strlen(str);
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
|
||||
// Include NULL terminator and limit string length.
|
||||
if (++len > 256)
|
||||
len = 256;
|
||||
|
||||
char* m = static_cast<char*>(alloc(len));
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
|
||||
::memcpy(m, str, len);
|
||||
m[len - 1] = '\0';
|
||||
return m;
|
||||
}
|
||||
|
||||
char* Zone::sformat(const char* fmt, ...) {
|
||||
if (fmt == NULL)
|
||||
return NULL;
|
||||
|
||||
char buf[256];
|
||||
size_t len;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(buf, 256, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
len = IntUtil::iMin<size_t>(len, 255);
|
||||
buf[len++] = 0;
|
||||
|
||||
return static_cast<char*>(dup(buf, len));
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
191
src/asmjit/base/zone.h
Normal file
191
src/asmjit/base/zone.h
Normal file
@@ -0,0 +1,191 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_ZONE_H
|
||||
#define _ASMJIT_BASE_ZONE_H
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! @addtogroup asmjit_base
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Zone]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Fast incremental memory allocator.
|
||||
//!
|
||||
//! Memory allocator designed to allocate small objects that will be invalidated
|
||||
//! (free) all at once.
|
||||
struct Zone {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Chunk]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @internal
|
||||
//!
|
||||
//! @brief One allocated chunk of memory.
|
||||
struct Chunk {
|
||||
//! @brief Get count of remaining (unused) bytes in chunk.
|
||||
ASMJIT_INLINE size_t getRemainingSize() const { return size - pos; }
|
||||
|
||||
//! @brief Link to previous chunk.
|
||||
Chunk* prev;
|
||||
//! @brief Position in this chunk.
|
||||
size_t pos;
|
||||
//! @brief Size of this chunk (in bytes).
|
||||
size_t size;
|
||||
|
||||
//! @brief Data.
|
||||
uint8_t data[sizeof(void*)];
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create a new instance of @c Zone allocator.
|
||||
//!
|
||||
//! @param chunkSize Default size of the first chunk.
|
||||
ASMJIT_API Zone(size_t chunkSize);
|
||||
|
||||
//! @brief Destroy @ref Zone instance.
|
||||
ASMJIT_API ~Zone();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Clear / Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Free all allocated memory except first block that remains for reuse.
|
||||
//!
|
||||
//! Note that this method will invalidate all instances using this memory
|
||||
//! allocated by this zone instance.
|
||||
ASMJIT_API void clear();
|
||||
|
||||
//! @brief Free all allocated memory at once.
|
||||
//!
|
||||
//! Note that this method will invalidate all instances using this memory
|
||||
//! allocated by this zone instance.
|
||||
ASMJIT_API void reset();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get (default) chunk size.
|
||||
ASMJIT_INLINE size_t getChunkSize() const { return _chunkSize; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Alloc]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Allocate @c size bytes of memory.
|
||||
//!
|
||||
//! Pointer allocated by this way will be valid until @c Zone object is
|
||||
//! destroyed. To create class by this way use placement @c new and @c delete
|
||||
//! operators:
|
||||
//!
|
||||
//! @code
|
||||
//! // Example of simple class allocation.
|
||||
//! using namespace asmjit
|
||||
//!
|
||||
//! // Your class.
|
||||
//! class Object
|
||||
//! {
|
||||
//! // members...
|
||||
//! };
|
||||
//!
|
||||
//! // Your function
|
||||
//! void f()
|
||||
//! {
|
||||
//! // Create zone object with chunk size of 65536 bytes.
|
||||
//! Zone zone(65536);
|
||||
//!
|
||||
//! // Create your objects using zone object allocating, for example:
|
||||
//! Object* obj = new(zone.alloc(sizeof(YourClass))) Object();
|
||||
//!
|
||||
//! // ... lifetime of your objects ...
|
||||
//!
|
||||
//! // Destroy your objects:
|
||||
//! obj->~Object();
|
||||
//!
|
||||
//! // Zone destructor will free all memory allocated through it, you can
|
||||
//! // call @c zone.reset() if you wan't to reuse current @ref Zone.
|
||||
//! }
|
||||
//! @endcode
|
||||
ASMJIT_INLINE void* alloc(size_t size) {
|
||||
Chunk* cur = _chunks;
|
||||
|
||||
if (cur == NULL || cur->getRemainingSize() < size)
|
||||
return _alloc(size);
|
||||
|
||||
uint8_t* p = cur->data + cur->pos;
|
||||
|
||||
cur->pos += size;
|
||||
ASMJIT_ASSERT(cur->pos <= cur->size);
|
||||
|
||||
return (void*)p;
|
||||
}
|
||||
|
||||
//! @brief Like @ref alloc(), but returns <code>T*</code>.
|
||||
template<typename T>
|
||||
ASMJIT_INLINE T* allocT(size_t size = sizeof(T)) {
|
||||
return static_cast<T*>(alloc(size));
|
||||
}
|
||||
|
||||
//! @internal
|
||||
ASMJIT_API void* _alloc(size_t size);
|
||||
|
||||
//! @brief Allocate @c size bytes of zeroed memory.
|
||||
ASMJIT_INLINE void* calloc(size_t size) {
|
||||
Chunk* cur = _chunks;
|
||||
|
||||
if (cur == NULL || cur->getRemainingSize() < size)
|
||||
return _calloc(size);
|
||||
|
||||
uint8_t* p = cur->data + cur->pos;
|
||||
|
||||
cur->pos += size;
|
||||
ASMJIT_ASSERT(cur->pos <= cur->size);
|
||||
|
||||
::memset(p, 0, size);
|
||||
return (void*)p;
|
||||
}
|
||||
|
||||
//! @internal
|
||||
ASMJIT_API void* _calloc(size_t size);
|
||||
|
||||
//! @brief Helper to duplicate data.
|
||||
ASMJIT_API void* dup(const void* data, size_t size);
|
||||
|
||||
//! @brief Helper to duplicate string.
|
||||
ASMJIT_API char* sdup(const char* str);
|
||||
|
||||
//! @brief Helper to duplicate formatted string, maximum length is 256 bytes.
|
||||
ASMJIT_API char* sformat(const char* str, ...);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Last allocated chunk of memory.
|
||||
Chunk* _chunks;
|
||||
//! @brief Default chunk size.
|
||||
size_t _chunkSize;
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
#endif // _ASMJIT_BASE_ZONE_H
|
||||
274
src/asmjit/build.h
Normal file
274
src/asmjit/build.h
Normal file
@@ -0,0 +1,274 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BUILD_H
|
||||
#define _ASMJIT_BUILD_H
|
||||
|
||||
// [Include]
|
||||
#if !defined(ASMJIT_CONFIG_FILE)
|
||||
#include "config.h"
|
||||
#endif // !ASMJIT_CONFIG_FILE
|
||||
|
||||
// Turn of deprecation warnings for this compiler when compiling AsmJit.
|
||||
#if defined(ASMJIT_EXPORTS) && defined(_MSC_VER)
|
||||
# if !defined(_CRT_SECURE_NO_DEPRECATE)
|
||||
# define _CRT_SECURE_NO_DEPRECATE
|
||||
# endif // !_CRT_SECURE_NO_DEPRECATE
|
||||
# if !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# endif // !_CRT_SECURE_NO_WARNINGS
|
||||
#endif // ASMJIT_EXPORTS
|
||||
|
||||
// Default includes.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_OS]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(WINDOWS) || defined(_WINDOWS) || defined(__WINDOWS__) || defined(_WIN32) || defined(_WIN64)
|
||||
# define ASMJIT_OS_WINDOWS
|
||||
#elif defined(__linux__) || defined(__unix__) || \
|
||||
defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
|
||||
defined(__DragonFly__) || defined(__BSD__) || defined(__FREEBSD__) || \
|
||||
defined(__APPLE__)
|
||||
# define ASMJIT_OS_POSIX
|
||||
#else
|
||||
# warning "AsmJit - Can't match host operating system, using ASMJIT_OS_POSIX"
|
||||
# define ASMJIT_OS_POSIX
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_HOST]
|
||||
// ============================================================================
|
||||
|
||||
// Define it only if it's not defined. On some systems -D command can be passed
|
||||
// to the compiler to bypass this autodetection.
|
||||
#if !defined(ASMJIT_HOST_X86) && !defined(ASMJIT_HOST_X64)
|
||||
# if defined(__x86_64__) || defined(__LP64) || defined(__IA64__) || defined(_M_X64) || defined(_WIN64)
|
||||
# define ASMJIT_HOST_X64
|
||||
# define ASMJIT_HOST_LE
|
||||
# else
|
||||
// _M_IX86, __INTEL__, __i386__
|
||||
# define ASMJIT_HOST_X86
|
||||
# define ASMJIT_HOST_LE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_BUILD]
|
||||
// ============================================================================
|
||||
|
||||
// Build host architecture if no architecture is selected.
|
||||
#if !defined(ASMJIT_BUILD_HOST) && \
|
||||
!defined(ASMJIT_BUILD_X86) && \
|
||||
!defined(ASMJIT_BUILD_X64)
|
||||
# define ASMJIT_BUILD_HOST
|
||||
#endif
|
||||
|
||||
// Autodetect host architecture if enabled.
|
||||
#if defined(ASMJIT_BUILD_HOST)
|
||||
# if defined(ASMJIT_HOST_X86) && !defined(ASMJIT_BUILD_X86)
|
||||
# define ASMJIT_BUILD_X86
|
||||
# endif // ASMJIT_HOST_X86 && !ASMJIT_BUILD_X86
|
||||
# if defined(ASMJIT_HOST_X64) && !defined(ASMJIT_BUILD_X64)
|
||||
# define ASMJIT_BUILD_X64
|
||||
# endif // ASMJIT_HOST_X64 && !ASMJIT_BUILD_X64
|
||||
#endif // ASMJIT_BUILD_HOST
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_API]
|
||||
// ============================================================================
|
||||
|
||||
#if !defined(ASMJIT_API)
|
||||
# if defined(ASMJIT_STATIC)
|
||||
# define ASMJIT_API
|
||||
# elif defined(ASMJIT_OS_WINDOWS)
|
||||
# if defined(__GNUC__)
|
||||
# if defined(ASMJIT_EXPORTS)
|
||||
# define ASMJIT_API __attribute__((dllexport))
|
||||
# else
|
||||
# define ASMJIT_API __attribute__((dllimport))
|
||||
# endif // ASMJIT_EXPORTS
|
||||
# else
|
||||
# if defined(ASMJIT_EXPORTS)
|
||||
# define ASMJIT_API __declspec(dllexport)
|
||||
# else
|
||||
# define ASMJIT_API __declspec(dllimport)
|
||||
# endif // ASMJIT_EXPORTS
|
||||
# endif // __GNUC__
|
||||
# else
|
||||
# if defined(__GNUC__)
|
||||
# if __GNUC__ >= 4
|
||||
# define ASMJIT_API __attribute__((visibility("default")))
|
||||
# define ASMJIT_VAR extern ASMJIT_API
|
||||
# endif // __GNUC__ >= 4
|
||||
# endif // __GNUC__
|
||||
# endif
|
||||
#endif // ASMJIT_API
|
||||
|
||||
#if !defined(ASMJIT_VAR)
|
||||
# define ASMJIT_VAR extern ASMJIT_API
|
||||
#endif // !ASMJIT_VAR
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_INLINE]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define ASMJIT_INLINE __forceinline
|
||||
#elif defined(__GNUC__) || defined(__clang__) && !defined(__MINGW32__)
|
||||
# define ASMJIT_INLINE inline __attribute__((always_inline))
|
||||
#else
|
||||
# define ASMJIT_INLINE inline
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_ENUM]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define ASMJIT_ENUM(_Name_) enum _Name_ : uint32_t
|
||||
#else
|
||||
# define ASMJIT_ENUM(_Name_) enum _Name_
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// [_ASMJIT_HOST_INDEX]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(ASMJIT_HOST_LE)
|
||||
# define _ASMJIT_HOST_INDEX(_Total_, _Index_) (_Index_)
|
||||
#else
|
||||
# define _ASMJIT_HOST_INDEX(_Total_, _Index_) ((_Total_) - 1 - (_Index_)
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_ARRAY_SIZE]
|
||||
// ============================================================================
|
||||
|
||||
#define ASMJIT_ARRAY_SIZE(_Array_) (sizeof(_Array_) / sizeof(*_Array_))
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_NO_COPY]
|
||||
// ============================================================================
|
||||
|
||||
#define ASMJIT_NO_COPY(_Type_) \
|
||||
private: \
|
||||
ASMJIT_INLINE _Type_(const _Type_& other); \
|
||||
ASMJIT_INLINE _Type_& operator=(const _Type_& other); \
|
||||
public:
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_DEBUG]
|
||||
// ============================================================================
|
||||
|
||||
// If ASMJIT_DEBUG and ASMJIT_RELEASE is not defined ASMJIT_DEBUG will be
|
||||
// detected using the compiler specific macros. This enables to set the build
|
||||
// type using IDE.
|
||||
#if !defined(ASMJIT_DEBUG) && !defined(ASMJIT_RELEASE)
|
||||
# if defined(_DEBUG)
|
||||
# define ASMJIT_DEBUG
|
||||
# endif // _DEBUG
|
||||
#endif // !ASMJIT_DEBUG && !ASMJIT_RELEASE
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_UNUSED]
|
||||
// ============================================================================
|
||||
|
||||
#if !defined(ASMJIT_UNUSED)
|
||||
# define ASMJIT_UNUSED(_Var_) ((void)_Var_)
|
||||
#endif // ASMJIT_UNUSED
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_NOP]
|
||||
// ============================================================================
|
||||
|
||||
#if !defined(ASMJIT_NOP)
|
||||
# define ASMJIT_NOP() ((void)0)
|
||||
#endif // ASMJIT_NOP
|
||||
|
||||
// ============================================================================
|
||||
// [ASMJIT_CCONV]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(ASMJIT_HOST_X86)
|
||||
# if defined(__GNUC__)
|
||||
# define ASMJIT_REGPARM_1 __attribute__((regparm(1)))
|
||||
# define ASMJIT_REGPARM_2 __attribute__((regparm(2)))
|
||||
# define ASMJIT_REGPARM_3 __attribute__((regparm(3)))
|
||||
# define ASMJIT_FASTCALL __attribute__((fastcall))
|
||||
# define ASMJIT_STDCALL __attribute__((stdcall))
|
||||
# define ASMJIT_CDECL __attribute__((cdecl))
|
||||
# else
|
||||
# define ASMJIT_FASTCALL __fastcall
|
||||
# define ASMJIT_STDCALL __stdcall
|
||||
# define ASMJIT_CDECL __cdecl
|
||||
# endif
|
||||
#else
|
||||
# define ASMJIT_FASTCALL
|
||||
# define ASMJIT_STDCALL
|
||||
# define ASMJIT_CDECL
|
||||
#endif // ASMJIT_HOST
|
||||
|
||||
// ============================================================================
|
||||
// [IntTypes]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
# include <sys/types.h>
|
||||
#endif // __MINGW32__ || __MINGW64__
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1600)
|
||||
# if !defined(ASMJIT_SUPRESS_STD_TYPES)
|
||||
# if (_MSC_VER < 1300)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
# else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
# endif // _MSC_VER
|
||||
# endif // ASMJIT_SUPRESS_STD_TYPES
|
||||
#else
|
||||
# include <stdint.h>
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define ASMJIT_INT64_C(_Num_) _Num_##i64
|
||||
# define ASMJIT_UINT64_C(_Num_) _Num_##ui64
|
||||
#else
|
||||
# define ASMJIT_INT64_C(_Num_) _Num_##LL
|
||||
# define ASMJIT_UINT64_C(_Num_) _Num_##ULL
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// [OS Support]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(ASMJIT_OS_WINDOWS) && !defined(ASMJIT_SUPRESS_WINDOWS_H)
|
||||
#include <windows.h>
|
||||
#endif // ASMJIT_OS_WINDOWS && !ASMJIT_SUPRESS_WINDOWS_H
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BUILD_H
|
||||
42
src/asmjit/config.h
Normal file
42
src/asmjit/config.h
Normal file
@@ -0,0 +1,42 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_CONFIG_H
|
||||
#define _ASMJIT_CONFIG_H
|
||||
|
||||
// This file can be used to modify built-in features of AsmJit. AsmJit is by
|
||||
// default compiled only for host processor to enable JIT compilation. Both
|
||||
// Assembler and Compiler code generators are compiled by default. However, any
|
||||
// ASMJIT_BUILD_... flag can be defined to enable building of additional
|
||||
// backends that can be used for remote code generation.
|
||||
|
||||
// ============================================================================
|
||||
// [AsmJit - Debugging]
|
||||
// ============================================================================
|
||||
|
||||
// #define ASMJIT_DEBUG // Define to enable debug-mode.
|
||||
// #define ASMJIT_RELEASE // Define to enable release-mode (no debugging).
|
||||
|
||||
// ============================================================================
|
||||
// [AsmJit - Library]
|
||||
// ============================================================================
|
||||
|
||||
// #define ASMJIT_STATIC // Define to enable static-library build.
|
||||
// #define ASMJIT_API // Define to override ASMJIT_API decorator.
|
||||
|
||||
// ============================================================================
|
||||
// [AsmJit - Features]
|
||||
// ============================================================================
|
||||
|
||||
// If none of these is defined AsmJit will select host architecture by default.
|
||||
|
||||
// #define ASMJIT_BUILD_X86 // Define to enable x86 instruction set (32-bit).
|
||||
// #define ASMJIT_BUILD_X64 // Define to enable x64 instruction set (64-bit).
|
||||
// #define ASMJIT_BUILD_HOST // Define to enable host instruction set.
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_CONFIG_H
|
||||
18
src/asmjit/contrib.h
Normal file
18
src/asmjit/contrib.h
Normal file
@@ -0,0 +1,18 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in this package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_CONTRIB_H
|
||||
#define _ASMJIT_CONTRIB_H
|
||||
|
||||
// [Dependencies - Core]
|
||||
#include "base.h"
|
||||
|
||||
// [Dependencies - Contrib]
|
||||
#include "contrib/winremoteruntime.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_CONTRIB_H
|
||||
78
src/asmjit/contrib/winremoteruntime.cpp
Normal file
78
src/asmjit/contrib/winremoteruntime.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// [AsmJit/WinRemoteRuntime]
|
||||
// Contribution for remote process handling.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base.h"
|
||||
|
||||
// [Guard - Windows]
|
||||
#if defined(ASMJIT_OS_WINDOWS)
|
||||
#include "winremoteruntime.h"
|
||||
|
||||
namespace asmjit {
|
||||
namespace contrib {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::contrib::WinRemoteRuntime - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
WinRemoteRuntime::WinRemoteRuntime(HANDLE hProcess) :
|
||||
_hProcess(hProcess),
|
||||
_memoryManager(hProcess) {
|
||||
|
||||
// We are patching another process so enable keep-virtual-memory option.
|
||||
_memoryManager.setKeepVirtualMemory(true);
|
||||
}
|
||||
|
||||
WinRemoteRuntime::~WinRemoteRuntime() {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::contrib::WinRemoteRuntime - Interface]
|
||||
// ============================================================================
|
||||
|
||||
uint32_t WinRemoteRuntime::add(void** dest, BaseAssembler* assembler) {
|
||||
// Disallow generation of no code.
|
||||
size_t codeSize = assembler->getCodeSize();
|
||||
|
||||
if (codeSize == 0) {
|
||||
*dest = NULL;
|
||||
return kErrorInvalidState;
|
||||
}
|
||||
|
||||
// Allocate temporary memory where the code will be stored and relocated.
|
||||
void* codeData = ::malloc(codeSize);
|
||||
|
||||
if (codeData == NULL) {
|
||||
*dest = NULL;
|
||||
return kErrorNoHeapMemory;
|
||||
}
|
||||
|
||||
// Allocate a pernament remote process memory.
|
||||
void* processMemPtr = _memoryManager.alloc(codeSize, kVirtualAllocPermanent);
|
||||
|
||||
if (processMemPtr == NULL) {
|
||||
::free(codeData);
|
||||
*dest = NULL;
|
||||
return kErrorNoVirtualMemory;
|
||||
}
|
||||
|
||||
// Relocate and write the code to the process memory.
|
||||
assembler->relocCode(codeData, (uintptr_t)processMemPtr);
|
||||
|
||||
::WriteProcessMemory(_hProcess, processMemPtr, codeData, codeSize, NULL);
|
||||
::free(codeData);
|
||||
|
||||
*dest = processMemPtr;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
} // contrib namespace
|
||||
} // asmjit namespace
|
||||
|
||||
// [Guard - Windows]
|
||||
#endif // ASMJIT_OS_WINDOWS
|
||||
71
src/asmjit/contrib/winremoteruntime.h
Normal file
71
src/asmjit/contrib/winremoteruntime.h
Normal file
@@ -0,0 +1,71 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_CONTRIB_WINREMOTERUNTIME_H
|
||||
#define _ASMJIT_CONTRIB_WINREMOTERUNTIME_H
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base.h"
|
||||
|
||||
// [Guard - Windows]
|
||||
#if defined(ASMJIT_OS_WINDOWS)
|
||||
|
||||
namespace asmjit {
|
||||
namespace contrib {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::contrib::WinRemoteRuntime]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief WinRemoteRuntime can be used to inject code to a remote process.
|
||||
struct WinRemoteRuntime : public BaseRuntime {
|
||||
ASMJIT_NO_COPY(WinRemoteRuntime)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
//! @brief Create a @c WinRemoteRuntime instance for a given @a hProcess.
|
||||
ASMJIT_API WinRemoteRuntime(HANDLE hProcess);
|
||||
|
||||
//! @brief Destroy the @c WinRemoteRuntime instance.
|
||||
ASMJIT_API virtual ~WinRemoteRuntime();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get the remote process handle.
|
||||
ASMJIT_INLINE HANDLE getProcess() const { return _hProcess; }
|
||||
|
||||
//! @brief Get the virtual memory manager.
|
||||
ASMJIT_INLINE VirtualMemoryManager* getMemoryManager() { return &_memoryManager; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Interface]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API virtual uint32_t add(void** dest, BaseAssembler* assembler);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Process.
|
||||
HANDLE _hProcess;
|
||||
|
||||
//! @brief Virtual memory manager.
|
||||
VirtualMemoryManager _memoryManager;
|
||||
};
|
||||
|
||||
} // contrib namespace
|
||||
} // asmjit namespace
|
||||
|
||||
// [Guard - Windows]
|
||||
#endif // ASMJIT_OS_WINDOWS
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_CONTRIB_WINREMOTERUNTIME_H
|
||||
38
src/asmjit/host.h
Normal file
38
src/asmjit/host.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_HOST_H
|
||||
#define _ASMJIT_HOST_H
|
||||
|
||||
// [Dependencies - Core]
|
||||
#include "base.h"
|
||||
|
||||
// [Host - Helpers]
|
||||
#define ASMJIT_USE_HOST(_Arch_) \
|
||||
namespace asmjit { \
|
||||
namespace host { \
|
||||
using namespace ::asmjit::_Arch_; \
|
||||
} \
|
||||
}
|
||||
|
||||
// [Host - X86]
|
||||
#if defined(ASMJIT_HOST_X86)
|
||||
#include "x86.h"
|
||||
ASMJIT_USE_HOST(x86)
|
||||
#endif // ASMJIT_HOST_X86
|
||||
|
||||
// [Host - X64]
|
||||
#if defined(ASMJIT_HOST_X64)
|
||||
#include "x86.h"
|
||||
ASMJIT_USE_HOST(x64)
|
||||
#endif // ASMJIT_HOST_X64
|
||||
|
||||
// [Host - Cleanup]
|
||||
#undef ASMJIT_USE_HOST
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_HOST_H
|
||||
21
src/asmjit/x86.h
Normal file
21
src/asmjit/x86.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_X86_H
|
||||
#define _ASMJIT_X86_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "base.h"
|
||||
|
||||
#include "x86/x86assembler.h"
|
||||
#include "x86/x86compiler.h"
|
||||
#include "x86/x86cpu.h"
|
||||
#include "x86/x86defs.h"
|
||||
#include "x86/x86func.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_X86_H
|
||||
3732
src/asmjit/x86/x86assembler.cpp
Normal file
3732
src/asmjit/x86/x86assembler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
5375
src/asmjit/x86/x86assembler.h
Normal file
5375
src/asmjit/x86/x86assembler.h
Normal file
File diff suppressed because it is too large
Load Diff
627
src/asmjit/x86/x86compiler.cpp
Normal file
627
src/asmjit/x86/x86compiler.cpp
Normal file
@@ -0,0 +1,627 @@
|
||||
// [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_BUILD_X86) || defined(ASMJIT_BUILD_X64)
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/intutil.h"
|
||||
#include "../base/string.h"
|
||||
#include "../x86/x86assembler.h"
|
||||
#include "../x86/x86compiler.h"
|
||||
#include "../x86/x86context_p.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
namespace x86x64 {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::X86X64CallNode - Prototype]
|
||||
// ============================================================================
|
||||
|
||||
Error X86X64CallNode::setPrototype(uint32_t conv, const FuncPrototype& p) {
|
||||
return _x86Decl.setPrototype(conv, p);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::X86X64CallNode - Arg / Ret]
|
||||
// ============================================================================
|
||||
|
||||
bool X86X64CallNode::_setArg(uint32_t i, const Operand& op) {
|
||||
if ((i & ~kFuncArgHi) >= _x86Decl.getArgCount())
|
||||
return false;
|
||||
|
||||
_args[i] = op;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool X86X64CallNode::_setRet(uint32_t i, const Operand& op) {
|
||||
if (i >= 2)
|
||||
return false;
|
||||
|
||||
_ret[i] = op;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::X86X64Compiler - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
X86X64Compiler::X86X64Compiler(BaseRuntime* runtime) : BaseCompiler(runtime) {}
|
||||
X86X64Compiler::~X86X64Compiler() {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::X86X64Compiler - Inst]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief Get compiler instruction item size without operands assigned.
|
||||
static ASMJIT_INLINE size_t X86X64Compiler_getInstSize(uint32_t code) {
|
||||
return (IntUtil::inInterval<uint32_t>(code, _kInstJbegin, _kInstJend)) ? sizeof(JumpNode) : sizeof(InstNode);
|
||||
}
|
||||
|
||||
static InstNode* X86X64Compiler_newInst(X86X64Compiler* self, void* p, uint32_t code, uint32_t options, Operand* opList, uint32_t opCount) {
|
||||
if (IntUtil::inInterval<uint32_t>(code, _kInstJbegin, _kInstJend)) {
|
||||
JumpNode* node = new(p) JumpNode(self, code, options, opList, opCount);
|
||||
TargetNode* jTarget = self->getTargetById(opList[0].getId());
|
||||
|
||||
node->addFlags(code == kInstJmp ? kNodeFlagIsJmp | kNodeFlagIsTaken : kNodeFlagIsJcc);
|
||||
node->_target = jTarget;
|
||||
node->_jumpNext = static_cast<JumpNode*>(jTarget->_from);
|
||||
|
||||
jTarget->_from = node;
|
||||
jTarget->addNumRefs();
|
||||
|
||||
// The 'jmp' is always taken, conditional jump can contain hint, we detect it.
|
||||
if (code == kInstJmp)
|
||||
node->addFlags(kNodeFlagIsTaken);
|
||||
else if (options & kInstOptionTaken)
|
||||
node->addFlags(kNodeFlagIsTaken);
|
||||
|
||||
node->addOptions(options);
|
||||
return node;
|
||||
}
|
||||
else {
|
||||
InstNode* node = new(p) InstNode(self, code, options, opList, opCount);
|
||||
node->addOptions(options);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::newInst(uint32_t code) {
|
||||
size_t size = X86X64Compiler_getInstSize(code);
|
||||
InstNode* inst = static_cast<InstNode*>(_zoneAllocator.alloc(size));
|
||||
|
||||
if (inst == NULL)
|
||||
goto _NoMemory;
|
||||
|
||||
return X86X64Compiler_newInst(this, inst, code, getOptionsAndClear(), NULL, 0);
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::newInst(uint32_t code, const Operand& o0) {
|
||||
size_t size = X86X64Compiler_getInstSize(code);
|
||||
InstNode* inst = static_cast<InstNode*>(_zoneAllocator.alloc(size + 1 * sizeof(Operand)));
|
||||
|
||||
if (inst == NULL)
|
||||
goto _NoMemory;
|
||||
|
||||
{
|
||||
Operand* opList = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(inst) + size);
|
||||
opList[0] = o0;
|
||||
return X86X64Compiler_newInst(this, inst, code, getOptionsAndClear(), opList, 1);
|
||||
}
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::newInst(uint32_t code, const Operand& o0, const Operand& o1) {
|
||||
size_t size = X86X64Compiler_getInstSize(code);
|
||||
InstNode* inst = static_cast<InstNode*>(_zoneAllocator.alloc(size + 2 * sizeof(Operand)));
|
||||
|
||||
if (inst == NULL)
|
||||
goto _NoMemory;
|
||||
|
||||
{
|
||||
Operand* opList = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(inst) + size);
|
||||
opList[0] = o0;
|
||||
opList[1] = o1;
|
||||
return X86X64Compiler_newInst(this, inst, code, getOptionsAndClear(), opList, 2);
|
||||
}
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::newInst(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) {
|
||||
size_t size = X86X64Compiler_getInstSize(code);
|
||||
InstNode* inst = static_cast<InstNode*>(_zoneAllocator.alloc(size + 3 * sizeof(Operand)));
|
||||
|
||||
if (inst == NULL)
|
||||
goto _NoMemory;
|
||||
|
||||
{
|
||||
Operand* opList = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(inst) + size);
|
||||
opList[0] = o0;
|
||||
opList[1] = o1;
|
||||
opList[2] = o2;
|
||||
return X86X64Compiler_newInst(this, inst, code, getOptionsAndClear(), opList, 3);
|
||||
}
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::newInst(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) {
|
||||
size_t size = X86X64Compiler_getInstSize(code);
|
||||
InstNode* inst = static_cast<InstNode*>(_zoneAllocator.alloc(size + 4 * sizeof(Operand)));
|
||||
|
||||
if (inst == NULL)
|
||||
goto _NoMemory;
|
||||
|
||||
{
|
||||
Operand* opList = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(inst) + size);
|
||||
opList[0] = o0;
|
||||
opList[1] = o1;
|
||||
opList[2] = o2;
|
||||
opList[3] = o3;
|
||||
return X86X64Compiler_newInst(this, inst, code, getOptionsAndClear(), opList, 4);
|
||||
}
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::newInst(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3, const Operand& o4) {
|
||||
size_t size = X86X64Compiler_getInstSize(code);
|
||||
InstNode* inst = static_cast<InstNode*>(_zoneAllocator.alloc(size + 5 * sizeof(Operand)));
|
||||
|
||||
if (inst == NULL)
|
||||
goto _NoMemory;
|
||||
|
||||
{
|
||||
Operand* opList = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(inst) + size);
|
||||
opList[0] = o0;
|
||||
opList[1] = o1;
|
||||
opList[2] = o2;
|
||||
opList[3] = o3;
|
||||
opList[4] = o4;
|
||||
return X86X64Compiler_newInst(this, inst, code, getOptionsAndClear(), opList, 5);
|
||||
}
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::emit(uint32_t code) {
|
||||
InstNode* node = newInst(code);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
return static_cast<InstNode*>(addNode(node));
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::emit(uint32_t code, const Operand& o0) {
|
||||
InstNode* node = newInst(code, o0);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
return static_cast<InstNode*>(addNode(node));
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::emit(uint32_t code, const Operand& o0, const Operand& o1){
|
||||
InstNode* node = newInst(code, o0, o1);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
return static_cast<InstNode*>(addNode(node));
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) {
|
||||
InstNode* node = newInst(code, o0, o1, o2);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
return static_cast<InstNode*>(addNode(node));
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3){
|
||||
InstNode* node = newInst(code, o0, o1, o2, o3);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
return static_cast<InstNode*>(addNode(node));
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3, const Operand& o4) {
|
||||
InstNode* node = newInst(code, o0, o1, o2, o3, o4);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
return static_cast<InstNode*>(addNode(node));
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::emit(uint32_t code, int o0_) {
|
||||
Imm o0(o0_);
|
||||
InstNode* node = newInst(code, o0);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
return static_cast<InstNode*>(addNode(node));
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::emit(uint32_t code, const Operand& o0, int o1_) {
|
||||
Imm o1(o1_);
|
||||
InstNode* node = newInst(code, o0, o1);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
return static_cast<InstNode*>(addNode(node));
|
||||
}
|
||||
|
||||
InstNode* X86X64Compiler::emit(uint32_t code, const Operand& o0, const Operand& o1, int o2_) {
|
||||
Imm o2(o2_);
|
||||
InstNode* node = newInst(code, o0, o1, o2);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
return static_cast<InstNode*>(addNode(node));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::X86X64Compiler - Func]
|
||||
// ============================================================================
|
||||
|
||||
X86X64FuncNode* X86X64Compiler::newFunc(uint32_t conv, const FuncPrototype& p) {
|
||||
X86X64FuncNode* func = newNode<X86X64FuncNode>();
|
||||
Error error;
|
||||
|
||||
if (func == NULL)
|
||||
goto _NoMemory;
|
||||
|
||||
// Create helper nodes.
|
||||
func->_entryNode = newTarget();
|
||||
func->_exitNode = newTarget();
|
||||
func->_end = newNode<EndNode>();
|
||||
|
||||
if (func->_entryNode == NULL || func->_exitNode == NULL || func->_end == NULL)
|
||||
goto _NoMemory;
|
||||
|
||||
// Emit push/pop sequence by default.
|
||||
func->_funcHints |= IntUtil::mask(kFuncHintPushPop);
|
||||
|
||||
// Function prototype.
|
||||
if ((error = func->_x86Decl.setPrototype(conv, p)) != kErrorOk) {
|
||||
setError(error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Function arguments stack size. Since function requires _argStackSize to be
|
||||
// set, we have to copy it from X86X64FuncDecl.
|
||||
func->_argStackSize = func->_x86Decl.getArgStackSize();
|
||||
func->_redZoneSize = static_cast<uint16_t>(func->_x86Decl.getRedZoneSize());
|
||||
func->_spillZoneSize = static_cast<uint16_t>(func->_x86Decl.getSpillZoneSize());
|
||||
|
||||
// Expected/Required stack alignment.
|
||||
func->_expectedStackAlignment = getRuntime()->getStackAlignment();
|
||||
func->_requiredStackAlignment = 0;
|
||||
|
||||
// Allocate space for function arguments.
|
||||
func->_argList = NULL;
|
||||
if (func->getArgCount() != 0) {
|
||||
func->_argList = _zoneAllocator.allocT<VarData*>(func->getArgCount() * sizeof(VarData*));
|
||||
if (func->_argList == NULL)
|
||||
goto _NoMemory;
|
||||
::memset(func->_argList, 0, func->getArgCount() * sizeof(VarData*));
|
||||
}
|
||||
|
||||
return func;
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
X86X64FuncNode* X86X64Compiler::addFunc(uint32_t conv, const FuncPrototype& p) {
|
||||
X86X64FuncNode* func = newFunc(conv, p);
|
||||
|
||||
if (func == NULL) {
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ASMJIT_ASSERT(_func == NULL);
|
||||
_func = func;
|
||||
|
||||
addNode(func);
|
||||
addNode(func->getEntryNode());
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
EndNode* X86X64Compiler::endFunc() {
|
||||
X86X64FuncNode* func = getFunc();
|
||||
ASMJIT_ASSERT(func != NULL);
|
||||
|
||||
addNode(func->getExitNode());
|
||||
addNode(func->getEnd());
|
||||
|
||||
func->addFuncFlags(kFuncFlagIsFinished);
|
||||
_func = NULL;
|
||||
|
||||
return func->getEnd();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::X86X64Compiler - Ret]
|
||||
// ============================================================================
|
||||
|
||||
RetNode* X86X64Compiler::newRet(const Operand& o0, const Operand& o1) {
|
||||
RetNode* node = newNode<RetNode>(o0, o1);
|
||||
if (node == NULL)
|
||||
goto _NoMemory;
|
||||
return node;
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RetNode* X86X64Compiler::addRet(const Operand& o0, const Operand& o1) {
|
||||
RetNode* node = newRet(o0, o1);
|
||||
if (node == NULL)
|
||||
return node;
|
||||
return static_cast<RetNode*>(addNode(node));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::X86X64Compiler - Call]
|
||||
// ============================================================================
|
||||
|
||||
X86X64CallNode* X86X64Compiler::newCall(const Operand& o0, uint32_t conv, const FuncPrototype& p) {
|
||||
X86X64CallNode* node = newNode<X86X64CallNode>(o0);
|
||||
Error error;
|
||||
uint32_t nArgs;
|
||||
|
||||
if (node == NULL)
|
||||
goto _NoMemory;
|
||||
|
||||
if ((error = node->_x86Decl.setPrototype(conv, p)) != kErrorOk) {
|
||||
setError(error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// If there are no arguments skip the allocation.
|
||||
if ((nArgs = p.getArgCount()) == 0)
|
||||
return node;
|
||||
|
||||
node->_args = static_cast<Operand*>(_zoneAllocator.alloc(nArgs * sizeof(Operand)));
|
||||
if (node->_args == NULL)
|
||||
goto _NoMemory;
|
||||
|
||||
::memset(node->_args, 0, nArgs * sizeof(Operand));
|
||||
return node;
|
||||
|
||||
_NoMemory:
|
||||
setError(kErrorNoHeapMemory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
X86X64CallNode* X86X64Compiler::addCall(const Operand& o0, uint32_t conv, const FuncPrototype& p) {
|
||||
X86X64CallNode* node = newCall(o0, conv, p);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
return static_cast<X86X64CallNode*>(addNode(node));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::X86X64Compiler - Vars]
|
||||
// ============================================================================
|
||||
|
||||
Error X86X64Compiler::setArg(uint32_t argIndex, BaseVar& var) {
|
||||
X86X64FuncNode* func = getFunc();
|
||||
|
||||
if (func == NULL)
|
||||
return kErrorInvalidArgument;
|
||||
|
||||
if (!isVarCreated(var))
|
||||
return kErrorInvalidState;
|
||||
|
||||
VarData* vd = getVd(var);
|
||||
func->setArg(argIndex, vd);
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error X86X64Compiler::_newVar(BaseVar* var, uint32_t vType, const char* name) {
|
||||
ASMJIT_ASSERT(vType < kVarTypeCount);
|
||||
|
||||
vType = _targetVarMapping[vType];
|
||||
const VarInfo& vInfo = _varInfo[vType];
|
||||
|
||||
VarData* vd = _newVd(vType, vInfo.getSize(), vInfo.getClass(), name);
|
||||
if (vd == NULL) {
|
||||
static_cast<X86Var*>(var)->reset();
|
||||
return getError();
|
||||
}
|
||||
|
||||
var->_init_packed_op_sz_w0_id(kOperandTypeVar, vd->getSize(), vInfo.getReg() << 8, vd->getId());
|
||||
var->_vreg.vType = vType;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::X86X64Compiler - Stack]
|
||||
// ============================================================================
|
||||
|
||||
Error X86X64Compiler::_newStack(BaseMem* mem, uint32_t size, uint32_t alignment, const char* name) {
|
||||
if (size == 0)
|
||||
return kErrorInvalidArgument;
|
||||
|
||||
if (alignment > 64)
|
||||
alignment = 64;
|
||||
|
||||
VarData* vd = _newVd(kVarTypeInvalid, size, kRegClassInvalid, name);
|
||||
if (vd == NULL) {
|
||||
static_cast<Mem*>(mem)->reset();
|
||||
return getError();
|
||||
}
|
||||
|
||||
vd->_isStack = true;
|
||||
vd->_alignment = static_cast<uint8_t>(alignment);
|
||||
|
||||
static_cast<Mem*>(mem)->_init(kMemTypeStackIndex, vd->getId(), 0, 0);
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::X86X64Compiler - Make]
|
||||
// ============================================================================
|
||||
|
||||
template<typename Assembler>
|
||||
static ASMJIT_INLINE void* X86X64Compiler_make(X86X64Compiler* self) {
|
||||
Assembler assembler(self->_runtime);
|
||||
BaseLogger* logger = self->_logger;
|
||||
|
||||
if (logger) {
|
||||
assembler.setLogger(logger);
|
||||
}
|
||||
|
||||
assembler._features = self->_features;
|
||||
|
||||
if (self->serialize(assembler) != kErrorOk) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (assembler.getError() != kErrorOk) {
|
||||
self->setError(assembler.getError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* result = assembler.make();
|
||||
if (logger) {
|
||||
logger->logFormat(kLoggerStyleComment,
|
||||
"*** COMPILER SUCCESS - Wrote %u bytes, code: %u, trampolines: %u.\n\n",
|
||||
static_cast<unsigned int>(assembler.getCodeSize()),
|
||||
static_cast<unsigned int>(assembler.getOffset()),
|
||||
static_cast<unsigned int>(assembler.getTrampolineSize()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void* X86X64Compiler::make() {
|
||||
#if defined(ASMJIT_BUILD_X86) && !defined(ASMJIT_BUILD_X64)
|
||||
return X86X64Compiler_make<x86::Assembler>(this);
|
||||
#elif !defined(ASMJIT_BUILD_X86) && defined(ASMJIT_BUILD_X64)
|
||||
return X86X64Compiler_make<x64::Assembler>(this);
|
||||
#else
|
||||
if (_arch == kArchX86)
|
||||
return X86X64Compiler_make<x86::Assembler>(this);
|
||||
else
|
||||
return X86X64Compiler_make<x64::Assembler>(this);
|
||||
#endif // ASMJIT_BUILD_X86 && ASMJIT_BUILD_X64
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::X86X64Compiler - Assemble]
|
||||
// ============================================================================
|
||||
|
||||
Error X86X64Compiler::serialize(BaseAssembler& assembler) {
|
||||
if (_firstNode == NULL)
|
||||
return kErrorOk;
|
||||
|
||||
X86X64Context context(this);
|
||||
Error error = kErrorOk;
|
||||
|
||||
BaseNode* node = _firstNode;
|
||||
BaseNode* start;
|
||||
|
||||
// Find function and use the context to translate/emit.
|
||||
do {
|
||||
start = node;
|
||||
|
||||
if (node->getType() == kNodeTypeFunc) {
|
||||
node = static_cast<X86X64FuncNode*>(start)->getEnd();
|
||||
error = context.compile(static_cast<X86X64FuncNode*>(start));
|
||||
|
||||
if (error != kErrorOk)
|
||||
goto _Error;
|
||||
}
|
||||
|
||||
do {
|
||||
node = node->getNext();
|
||||
} while (node != NULL && node->getType() != kNodeTypeFunc);
|
||||
|
||||
error = context.serialize(&assembler, start, node);
|
||||
if (error != kErrorOk)
|
||||
goto _Error;
|
||||
context.cleanup();
|
||||
} while (node != NULL);
|
||||
return kErrorOk;
|
||||
|
||||
_Error:
|
||||
context.cleanup();
|
||||
return error;
|
||||
}
|
||||
|
||||
} // x86x64 namespace
|
||||
} // asmjit namespace
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
|
||||
namespace asmjit {
|
||||
namespace x86 {
|
||||
|
||||
Compiler::Compiler(BaseRuntime* runtime) : X86X64Compiler(runtime) {
|
||||
_arch = kArchX86;
|
||||
_regSize = 4;
|
||||
_targetVarMapping = _varMapping;
|
||||
}
|
||||
|
||||
Compiler::~Compiler() {}
|
||||
|
||||
} // x86 namespace
|
||||
} // asmjit namespace
|
||||
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x64]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(ASMJIT_BUILD_X64)
|
||||
|
||||
namespace asmjit {
|
||||
namespace x64 {
|
||||
|
||||
Compiler::Compiler(BaseRuntime* runtime) : X86X64Compiler(runtime) {
|
||||
_arch = kArchX64;
|
||||
_regSize = 8;
|
||||
_targetVarMapping = _varMapping;
|
||||
}
|
||||
|
||||
Compiler::~Compiler() {}
|
||||
|
||||
} // x64 namespace
|
||||
} // asmjit namespace
|
||||
|
||||
#endif // ASMJIT_BUILD_X64
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
|
||||
4201
src/asmjit/x86/x86compiler.h
Normal file
4201
src/asmjit/x86/x86compiler.h
Normal file
File diff suppressed because it is too large
Load Diff
5159
src/asmjit/x86/x86context.cpp
Normal file
5159
src/asmjit/x86/x86context.cpp
Normal file
File diff suppressed because it is too large
Load Diff
498
src/asmjit/x86/x86context_p.h
Normal file
498
src/asmjit/x86/x86context_p.h
Normal file
@@ -0,0 +1,498 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_X86_X86CONTEXT_P_H
|
||||
#define _ASMJIT_X86_X86CONTEXT_P_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/compiler.h"
|
||||
#include "../base/context_p.h"
|
||||
#include "../base/intutil.h"
|
||||
#include "../x86/x86assembler.h"
|
||||
#include "../x86/x86compiler.h"
|
||||
#include "../x86/x86defs.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
namespace x86x64 {
|
||||
|
||||
//! @addtogroup asmjit_x86x64
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Context]
|
||||
// ============================================================================
|
||||
|
||||
//! @internal
|
||||
//!
|
||||
//! @brief Compiler context is used by @ref X86X64Compiler.
|
||||
//!
|
||||
//! Compiler context is used during compilation and normally developer doesn't
|
||||
//! need access to it. The context is user per function (it's reset after each
|
||||
//! function is generated).
|
||||
struct X86X64Context : public BaseContext {
|
||||
ASMJIT_NO_COPY(X86X64Context)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create a new @ref Context instance.
|
||||
X86X64Context(X86X64Compiler* compiler);
|
||||
//! @brief Destroy the @ref Context instance.
|
||||
virtual ~X86X64Context();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
virtual void reset();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get compiler as @ref X86X64Compiler.
|
||||
ASMJIT_INLINE X86X64Compiler* getCompiler() const { return static_cast<X86X64Compiler*>(_compiler); }
|
||||
//! @brief Get function as @ref X86X64FuncNode.
|
||||
ASMJIT_INLINE X86X64FuncNode* getFunc() const { return reinterpret_cast<X86X64FuncNode*>(_func); }
|
||||
|
||||
ASMJIT_INLINE bool isX64() const { return _baseRegsCount == 16; }
|
||||
|
||||
//! @brief Get clobbered registers (global).
|
||||
ASMJIT_INLINE uint32_t getClobberedRegs(uint32_t c) { return _clobberedRegs.get(c); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Helpers]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE VarInst* newVarInst(uint32_t vaCount) {
|
||||
return static_cast<VarInst*>(
|
||||
_zoneAllocator.alloc(sizeof(VarInst) + vaCount * sizeof(VarAttr)));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Emit]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
void emitLoad(VarData* vd, uint32_t regIndex, const char* reason);
|
||||
void emitSave(VarData* vd, uint32_t regIndex, const char* reason);
|
||||
void emitMove(VarData* vd, uint32_t toRegIndex, uint32_t fromRegIndex, const char* reason);
|
||||
void emitSwapGp(VarData* aVd, VarData* bVd, uint32_t aIndex, uint32_t bIndex, const char* reason);
|
||||
|
||||
void emitPushSequence(uint32_t regs);
|
||||
void emitPopSequence(uint32_t regs);
|
||||
|
||||
void emitMoveVarOnStack(uint32_t dstType, const Mem* dst, uint32_t srcType, uint32_t srcIndex);
|
||||
void emitMoveImmOnStack(uint32_t dstType, const Mem* dst, const Imm* src);
|
||||
|
||||
void emitMoveImmToReg(uint32_t dstType, uint32_t dstIndex, const Imm* src);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Register Management]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
void _checkState();
|
||||
|
||||
#if defined(ASMJIT_DEBUG)
|
||||
#define ASMJIT_CONTEXT_CHECK_STATE _checkState();
|
||||
#else
|
||||
#define ASMJIT_CONTEXT_CHECK_STATE
|
||||
#endif // ASMJIT_DEBUG
|
||||
|
||||
ASMJIT_INLINE uint32_t getRegsCount(uint32_t c) const {
|
||||
if (c == kRegClassGp || c == kRegClassXy)
|
||||
return _baseRegsCount;
|
||||
else
|
||||
return 8;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE uint32_t getRegSize() const {
|
||||
return _zsp.getSize();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Attach / Detach]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Attach.
|
||||
//!
|
||||
//! Attach a register to the 'VarData', changing 'VarData' members to show
|
||||
//! that the variable is currently alive and linking variable with the
|
||||
//! current 'VarState'.
|
||||
template<int C>
|
||||
ASMJIT_INLINE void attach(VarData* vd, uint32_t regIndex, bool modified) {
|
||||
ASMJIT_ASSERT(vd->getClass() == C);
|
||||
ASMJIT_ASSERT(regIndex != kInvalidReg);
|
||||
|
||||
// Prevent Esp allocation if C==Gp.
|
||||
ASMJIT_ASSERT(C != kRegClassGp || regIndex != kRegIndexSp);
|
||||
|
||||
uint32_t regMask = IntUtil::mask(regIndex);
|
||||
|
||||
vd->setState(kVarStateReg);
|
||||
vd->setRegIndex(regIndex);
|
||||
vd->setModified(modified);
|
||||
|
||||
_x86State.getListByClass(C)[regIndex] = vd;
|
||||
_x86State._occupied.add(C, regMask);
|
||||
_x86State._modified.add(C, static_cast<uint32_t>(modified) << regIndex);
|
||||
|
||||
ASMJIT_CONTEXT_CHECK_STATE
|
||||
}
|
||||
|
||||
//! @brief Detach.
|
||||
//!
|
||||
//! The opposite of 'Attach'. Detach resets the members in 'VarData'
|
||||
//! (regIndex, state and changed flags) and unlinks the variable with the
|
||||
//! current 'VarState'.
|
||||
template<int C>
|
||||
ASMJIT_INLINE void detach(VarData* vd, uint32_t regIndex, uint32_t vState) {
|
||||
ASMJIT_ASSERT(vd->getClass() == C);
|
||||
ASMJIT_ASSERT(vd->getRegIndex() == regIndex);
|
||||
ASMJIT_ASSERT(vState != kVarStateReg);
|
||||
|
||||
uint32_t regMask = IntUtil::mask(regIndex);
|
||||
|
||||
vd->setState(vState);
|
||||
vd->resetRegIndex();
|
||||
vd->setModified(false);
|
||||
|
||||
_x86State.getListByClass(C)[regIndex] = NULL;
|
||||
_x86State._occupied.del(C, regMask);
|
||||
_x86State._modified.del(C, regMask);
|
||||
|
||||
ASMJIT_CONTEXT_CHECK_STATE
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Rebase]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Rebase.
|
||||
//!
|
||||
//! Change the register of the 'VarData' changing also the current 'VarState'.
|
||||
//! Rebase is nearly identical to 'Detach' and 'Attach' sequence, but doesn't
|
||||
// change the 'VarData' modified flag.
|
||||
template<int C>
|
||||
ASMJIT_INLINE void rebase(VarData* vd, uint32_t newRegIndex, uint32_t oldRegIndex) {
|
||||
ASMJIT_ASSERT(vd->getClass() == C);
|
||||
|
||||
uint32_t newRegMask = IntUtil::mask(newRegIndex);
|
||||
uint32_t oldRegMask = IntUtil::mask(oldRegIndex);
|
||||
uint32_t bothRegMask = newRegMask ^ oldRegMask;
|
||||
|
||||
vd->setRegIndex(newRegIndex);
|
||||
|
||||
_x86State.getListByClass(C)[oldRegIndex] = NULL;
|
||||
_x86State.getListByClass(C)[newRegIndex] = vd;
|
||||
|
||||
_x86State._occupied.xor_(C, bothRegMask);
|
||||
_x86State._modified.xor_(C, bothRegMask & -static_cast<int32_t>(vd->isModified()));
|
||||
|
||||
ASMJIT_CONTEXT_CHECK_STATE
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Load / Save]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Load.
|
||||
//!
|
||||
//! Load variable from its memory slot to a register, emitting 'Load'
|
||||
//! instruction and changing the variable state to allocated.
|
||||
template<int C>
|
||||
ASMJIT_INLINE void load(VarData* vd, uint32_t regIndex) {
|
||||
// Can be only called if variable is not allocated.
|
||||
ASMJIT_ASSERT(vd->getClass() == C);
|
||||
ASMJIT_ASSERT(vd->getState() != kVarStateReg);
|
||||
ASMJIT_ASSERT(vd->getRegIndex() == kInvalidReg);
|
||||
|
||||
emitLoad(vd, regIndex, "Load");
|
||||
attach<C>(vd, regIndex, false);
|
||||
|
||||
ASMJIT_CONTEXT_CHECK_STATE
|
||||
}
|
||||
|
||||
//! @brief Save.
|
||||
//!
|
||||
//! Save the variable into its home location, but keep it as allocated.
|
||||
template<int C>
|
||||
ASMJIT_INLINE void save(VarData* vd) {
|
||||
ASMJIT_ASSERT(vd->getClass() == C);
|
||||
ASMJIT_ASSERT(vd->getState() == kVarStateReg);
|
||||
ASMJIT_ASSERT(vd->getRegIndex() != kInvalidReg);
|
||||
|
||||
uint32_t regIndex = vd->getRegIndex();
|
||||
uint32_t regMask = IntUtil::mask(regIndex);
|
||||
|
||||
emitSave(vd, regIndex, "Save");
|
||||
|
||||
vd->setModified(false);
|
||||
_x86State._modified.del(C, regMask);
|
||||
|
||||
ASMJIT_CONTEXT_CHECK_STATE
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Move / Swap]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Move a register.
|
||||
//!
|
||||
//! Move register from one index to another, emitting 'Move' if needed. This
|
||||
//! function does nothing if register is already at the given index.
|
||||
template<int C>
|
||||
ASMJIT_INLINE void move(VarData* vd, uint32_t regIndex) {
|
||||
ASMJIT_ASSERT(vd->getClass() == C);
|
||||
ASMJIT_ASSERT(vd->getState() == kVarStateReg);
|
||||
ASMJIT_ASSERT(vd->getRegIndex() != kInvalidReg);
|
||||
|
||||
uint32_t oldIndex = vd->getRegIndex();
|
||||
if (regIndex == oldIndex)
|
||||
return;
|
||||
|
||||
emitMove(vd, regIndex, oldIndex, "Move");
|
||||
rebase<C>(vd, regIndex, oldIndex);
|
||||
|
||||
ASMJIT_CONTEXT_CHECK_STATE
|
||||
}
|
||||
|
||||
//! @brief Swap two registers
|
||||
//!
|
||||
//! It's only possible to swap Gp registers.
|
||||
ASMJIT_INLINE void swapGp(VarData* aVd, VarData* bVd) {
|
||||
ASMJIT_ASSERT(aVd != bVd);
|
||||
|
||||
ASMJIT_ASSERT(aVd->getClass() == kRegClassGp);
|
||||
ASMJIT_ASSERT(aVd->getState() == kVarStateReg);
|
||||
ASMJIT_ASSERT(aVd->getRegIndex() != kInvalidReg);
|
||||
|
||||
ASMJIT_ASSERT(bVd->getClass() == kRegClassGp);
|
||||
ASMJIT_ASSERT(bVd->getState() == kVarStateReg);
|
||||
ASMJIT_ASSERT(bVd->getRegIndex() != kInvalidReg);
|
||||
|
||||
uint32_t aIndex = aVd->getRegIndex();
|
||||
uint32_t bIndex = bVd->getRegIndex();
|
||||
|
||||
emitSwapGp(aVd, bVd, aIndex, bIndex, "Swap");
|
||||
|
||||
aVd->setRegIndex(bIndex);
|
||||
bVd->setRegIndex(aIndex);
|
||||
|
||||
_x86State.getListByClass(kRegClassGp)[aIndex] = bVd;
|
||||
_x86State.getListByClass(kRegClassGp)[bIndex] = aVd;
|
||||
|
||||
uint32_t m = aVd->isModified() ^ bVd->isModified();
|
||||
_x86State._modified.xor_(kRegClassGp, (m << aIndex) | (m << bIndex));
|
||||
|
||||
ASMJIT_CONTEXT_CHECK_STATE
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Alloc / Spill]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Alloc
|
||||
template<int C>
|
||||
ASMJIT_INLINE void alloc(VarData* vd, uint32_t regIndex) {
|
||||
ASMJIT_ASSERT(vd->getClass() == C);
|
||||
ASMJIT_ASSERT(regIndex != kInvalidReg);
|
||||
|
||||
uint32_t oldRegIndex = vd->getRegIndex();
|
||||
uint32_t oldState = vd->getState();
|
||||
uint32_t regMask = IntUtil::mask(regIndex);
|
||||
|
||||
ASMJIT_ASSERT(_x86State.getListByClass(C)[regIndex] == NULL || regIndex == oldRegIndex);
|
||||
|
||||
if (oldState != kVarStateReg) {
|
||||
if (oldState == kVarStateMem)
|
||||
emitLoad(vd, regIndex, "Alloc");
|
||||
vd->setModified(false);
|
||||
}
|
||||
else if (oldRegIndex != regIndex) {
|
||||
emitMove(vd, regIndex, oldRegIndex, "Alloc");
|
||||
|
||||
_x86State.getListByClass(C)[oldRegIndex] = NULL;
|
||||
regMask ^= IntUtil::mask(oldRegIndex);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
vd->setState(kVarStateReg);
|
||||
vd->setRegIndex(regIndex);
|
||||
|
||||
_x86State.getListByClass(C)[regIndex] = vd;
|
||||
_x86State._occupied.xor_(C, regMask);
|
||||
_x86State._modified.xor_(C, regMask & -static_cast<int32_t>(vd->isModified()));
|
||||
|
||||
ASMJIT_CONTEXT_CHECK_STATE
|
||||
}
|
||||
|
||||
//! @brief Spill.
|
||||
//!
|
||||
//! Spill variable/register, saves the content to the memory-home if modified.
|
||||
template<int C>
|
||||
ASMJIT_INLINE void spill(VarData* vd) {
|
||||
ASMJIT_ASSERT(vd->getClass() == C);
|
||||
if (vd->getState() != kVarStateReg)
|
||||
return;
|
||||
|
||||
uint32_t regIndex = vd->getRegIndex();
|
||||
|
||||
ASMJIT_ASSERT(regIndex != kInvalidReg);
|
||||
ASMJIT_ASSERT(_x86State.getListByClass(C)[regIndex] == vd);
|
||||
|
||||
if (vd->isModified())
|
||||
emitSave(vd, regIndex, "Spill");
|
||||
detach<C>(vd, regIndex, kVarStateMem);
|
||||
|
||||
ASMJIT_CONTEXT_CHECK_STATE
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Modify]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
template<int C>
|
||||
ASMJIT_INLINE void modify(VarData* vd) {
|
||||
ASMJIT_ASSERT(vd->getClass() == C);
|
||||
|
||||
uint32_t regIndex = vd->getRegIndex();
|
||||
uint32_t regMask = IntUtil::mask(regIndex);
|
||||
|
||||
vd->setModified(true);
|
||||
_x86State._modified.add(C, regMask);
|
||||
|
||||
ASMJIT_CONTEXT_CHECK_STATE
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Unuse]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Unuse.
|
||||
//!
|
||||
//! Unuse variable, it will be detached it if it's allocated then its state
|
||||
//! will be changed to kVarStateUnused.
|
||||
template<int C>
|
||||
ASMJIT_INLINE void unuse(VarData* vd, uint32_t vState = kVarStateUnused) {
|
||||
ASMJIT_ASSERT(vd->getClass() == C);
|
||||
ASMJIT_ASSERT(vState != kVarStateReg);
|
||||
|
||||
uint32_t regIndex = vd->getRegIndex();
|
||||
if (regIndex != kInvalidReg)
|
||||
detach<C>(vd, regIndex, vState);
|
||||
else
|
||||
vd->setState(vState);
|
||||
|
||||
ASMJIT_CONTEXT_CHECK_STATE
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [State]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get state as @ref VarState.
|
||||
ASMJIT_INLINE VarState* getState() const { return const_cast<VarState*>(&_x86State); }
|
||||
|
||||
virtual void loadState(BaseVarState* src);
|
||||
virtual BaseVarState* saveState();
|
||||
|
||||
virtual void switchState(BaseVarState* src);
|
||||
virtual void intersectStates(BaseVarState* a, BaseVarState* b);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Memory]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE Mem getVarMem(VarData* vd) {
|
||||
(void)getVarCell(vd);
|
||||
|
||||
Mem mem(_memSlot);
|
||||
mem.setBase(vd->getId());
|
||||
return mem;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Prepare]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
virtual Error fetch();
|
||||
virtual Error analyze();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Translate]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
virtual Error translate();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Serialize]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
virtual Error serialize(BaseAssembler* assembler, BaseNode* start, BaseNode* stop);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief X86/X64 stack-pointer (esp or rsp).
|
||||
GpReg _zsp;
|
||||
//! @brief X86/X64 frame-pointer (ebp or rbp).
|
||||
GpReg _zbp;
|
||||
//! @brief Temporary memory operand.
|
||||
Mem _memSlot;
|
||||
|
||||
//! @brief X86/X64 specific compiler state (linked with @ref _state).
|
||||
VarState _x86State;
|
||||
//! @brief Clobbered registers (for the whole function).
|
||||
RegMask _clobberedRegs;
|
||||
|
||||
//! @brief Memory cell where is stored address used to restore manually
|
||||
//! aligned stack.
|
||||
MemCell* _stackFrameCell;
|
||||
|
||||
//! @brief Global allocable registers mask.
|
||||
uint32_t _gaRegs[kRegClassCount];
|
||||
|
||||
//! @brief X86/X64 number of Gp/Xmm registers.
|
||||
uint8_t _baseRegsCount;
|
||||
//! @brief Function arguments base pointer (register).
|
||||
uint8_t _argBaseReg;
|
||||
//! @brief Function variables base pointer (register).
|
||||
uint8_t _varBaseReg;
|
||||
//! @brief Whether to emit comments.
|
||||
uint8_t _emitComments;
|
||||
|
||||
//! @brief Function arguments base offset.
|
||||
int32_t _argBaseOffset;
|
||||
//! @brief Function variables base offset.
|
||||
int32_t _varBaseOffset;
|
||||
|
||||
//! @brief Function arguments displacement.
|
||||
int32_t _argActualDisp;
|
||||
//! @brief Function variables displacement.
|
||||
int32_t _varActualDisp;
|
||||
|
||||
//! @brief Temporary string builder used for logging.
|
||||
StringBuilderT<256> _stringBuilder;
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
} // x86x64 namespace
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_X86_X86CONTEXT_P_H
|
||||
306
src/asmjit/x86/x86cpu.cpp
Normal file
306
src/asmjit/x86/x86cpu.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
// [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_BUILD_X86) || defined(ASMJIT_BUILD_X64)
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/intutil.h"
|
||||
#include "../x86/x86cpu.h"
|
||||
|
||||
// 2009-02-05: Thanks to Mike Tajmajer for VC7.1 compiler support. It shouldn't
|
||||
// affect x64 compilation, because x64 compiler starts with VS2005 (VC8.0).
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
#include <intrin.h>
|
||||
#endif // _MSC_VER >= 1400
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
namespace x86x64 {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::hostCpuId]
|
||||
// ============================================================================
|
||||
|
||||
// This is messy, I know. Cpuid is implemented as intrinsic in VS2005, but
|
||||
// we should support other compilers as well. Main problem is that MS compilers
|
||||
// in 64-bit mode not allows to use inline assembler, so we need intrinsic and
|
||||
// we need also asm version.
|
||||
|
||||
// hostCpuId() and detectCpuInfo() for x86 and x64 platforms begins here.
|
||||
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
|
||||
void hostCpuId(uint32_t inEax, uint32_t inEcx, CpuId* result) {
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// 2009-02-05: Thanks to Mike Tajmajer for supporting VC7.1 compiler.
|
||||
// ASMJIT_HOST_X64 is here only for readibility, only VS2005 can compile 64-bit code.
|
||||
# if _MSC_VER >= 1400 || defined(ASMJIT_HOST_X64)
|
||||
// Done by intrinsics.
|
||||
__cpuidex(reinterpret_cast<int*>(result->i), inEax, inEcx);
|
||||
# else // _MSC_VER < 1400
|
||||
uint32_t cpuid_eax = inEax;
|
||||
uint32_t cpuid_ecx = inCax;
|
||||
uint32_t* cpuid_out = result->i;
|
||||
|
||||
__asm {
|
||||
mov eax, cpuid_eax
|
||||
mov ecx, cpuid_ecx
|
||||
mov edi, cpuid_out
|
||||
cpuid
|
||||
mov dword ptr[edi + 0], eax
|
||||
mov dword ptr[edi + 4], ebx
|
||||
mov dword ptr[edi + 8], ecx
|
||||
mov dword ptr[edi + 12], edx
|
||||
}
|
||||
# endif // _MSC_VER < 1400
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
// Note, patched to preserve ebx/rbx register which is used by GCC.
|
||||
# if defined(ASMJIT_HOST_X86)
|
||||
# define __myCpuId(inEax, inEcx, outEax, outEbx, outEcx, outEdx) \
|
||||
asm ("mov %%ebx, %%edi\n" \
|
||||
"cpuid\n" \
|
||||
"xchg %%edi, %%ebx\n" \
|
||||
: "=a" (outEax), "=D" (outEbx), "=c" (outEcx), "=d" (outEdx) : "a" (inEax), "c" (inEcx))
|
||||
# else
|
||||
# define __myCpuId(inEax, inEcx, outEax, outEbx, outEcx, outEdx) \
|
||||
asm ("mov %%rbx, %%rdi\n" \
|
||||
"cpuid\n" \
|
||||
"xchg %%rdi, %%rbx\n" \
|
||||
: "=a" (outEax), "=D" (outEbx), "=c" (outEcx), "=d" (outEdx) : "a" (inEax), "c" (inEcx))
|
||||
# endif
|
||||
__myCpuId(inEax, inEcx, result->eax, result->ebx, result->ecx, result->edx);
|
||||
#endif // Compiler #ifdef.
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::cpuSimplifyBrandString]
|
||||
// ============================================================================
|
||||
|
||||
static ASMJIT_INLINE void cpuSimplifyBrandString(char* s) {
|
||||
// Always clear the current character in the buffer. It ensures that there
|
||||
// is no garbage after the string NULL terminator.
|
||||
char* d = s;
|
||||
|
||||
char prev = 0;
|
||||
char curr = s[0];
|
||||
s[0] = '\0';
|
||||
|
||||
for (;;) {
|
||||
if (curr == 0)
|
||||
break;
|
||||
|
||||
if (curr == ' ') {
|
||||
if (prev == '@' || s[1] == ' ' || s[1] == '@')
|
||||
goto _Skip;
|
||||
}
|
||||
|
||||
d[0] = curr;
|
||||
d++;
|
||||
prev = curr;
|
||||
|
||||
_Skip:
|
||||
curr = *++s;
|
||||
s[0] = '\0';
|
||||
}
|
||||
|
||||
d[0] = '\0';
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::CpuVendor]
|
||||
// ============================================================================
|
||||
|
||||
struct CpuVendor {
|
||||
uint32_t id;
|
||||
char text[12];
|
||||
};
|
||||
|
||||
static const CpuVendor cpuVendorTable[] = {
|
||||
{ kCpuVendorAmd , { 'A', 'M', 'D', 'i', 's', 'b', 'e', 't', 't', 'e', 'r', '!' } },
|
||||
{ kCpuVendorAmd , { 'A', 'u', 't', 'h', 'e', 'n', 't', 'i', 'c', 'A', 'M', 'D' } },
|
||||
{ kCpuVendorVia , { 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' } },
|
||||
{ kCpuVendorNSM , { 'C', 'y', 'r', 'i', 'x', 'I', 'n', 's', 't', 'e', 'a', 'd' } },
|
||||
{ kCpuVendorIntel , { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l' } },
|
||||
{ kCpuVendorTransmeta, { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'T', 'M', 'x', '8', '6' } },
|
||||
{ kCpuVendorNSM , { 'G', 'e', 'o', 'd', 'e', ' ', 'b', 'y', ' ', 'N', 'S', 'C' } },
|
||||
{ kCpuVendorTransmeta, { 'T', 'r', 'a', 'n', 's', 'm', 'e', 't', 'a', 'C', 'P', 'U' } },
|
||||
{ kCpuVendorVia , { 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 } }
|
||||
};
|
||||
|
||||
static ASMJIT_INLINE bool cpuVendorEq(const CpuVendor& info, const char* vendorString) {
|
||||
const uint32_t* a = reinterpret_cast<const uint32_t*>(info.text);
|
||||
const uint32_t* b = reinterpret_cast<const uint32_t*>(vendorString);
|
||||
|
||||
return (a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::hostCpuDetect]
|
||||
// ============================================================================
|
||||
|
||||
void hostCpuDetect(Cpu* out) {
|
||||
CpuId regs;
|
||||
|
||||
uint32_t i;
|
||||
uint32_t maxId;
|
||||
|
||||
// Clear everything except the '_size' member.
|
||||
::memset(reinterpret_cast<uint8_t*>(out) + sizeof(uint32_t),
|
||||
0, sizeof(BaseCpu) - sizeof(uint32_t));
|
||||
|
||||
// Fill safe defaults.
|
||||
::memcpy(out->_vendorString, "Unknown", 8);
|
||||
out->_coresCount = BaseCpu::detectNumberOfCores();
|
||||
|
||||
// Get vendor string/id.
|
||||
hostCpuId(0, 0, ®s);
|
||||
|
||||
maxId = regs.eax;
|
||||
::memcpy(out->_vendorString, ®s.ebx, 4);
|
||||
::memcpy(out->_vendorString + 4, ®s.edx, 4);
|
||||
::memcpy(out->_vendorString + 8, ®s.ecx, 4);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (cpuVendorEq(cpuVendorTable[i], out->_vendorString)) {
|
||||
out->_vendorId = cpuVendorTable[i].id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get feature flags in ecx/edx and family/model in eax.
|
||||
hostCpuId(1, 0, ®s);
|
||||
|
||||
// Fill family and model fields.
|
||||
out->_family = (regs.eax >> 8) & 0x0F;
|
||||
out->_model = (regs.eax >> 4) & 0x0F;
|
||||
out->_stepping = (regs.eax ) & 0x0F;
|
||||
|
||||
// Use extended family and model fields.
|
||||
if (out->_family == 0x0F) {
|
||||
out->_family += ((regs.eax >> 20) & 0xFF);
|
||||
out->_model += ((regs.eax >> 16) & 0x0F) << 4;
|
||||
}
|
||||
|
||||
out->_processorType = ((regs.eax >> 12) & 0x03);
|
||||
out->_brandIndex = ((regs.ebx ) & 0xFF);
|
||||
out->_flushCacheLineSize = ((regs.ebx >> 8) & 0xFF) * 8;
|
||||
out->_maxLogicalProcessors = ((regs.ebx >> 16) & 0xFF);
|
||||
|
||||
if (regs.ecx & 0x00000001U) out->addFeature(kCpuFeatureSse3);
|
||||
if (regs.ecx & 0x00000002U) out->addFeature(kCpuFeaturePclmulqdq);
|
||||
if (regs.ecx & 0x00000008U) out->addFeature(kCpuFeatureMonitorMWait);
|
||||
if (regs.ecx & 0x00000200U) out->addFeature(kCpuFeatureSsse3);
|
||||
if (regs.ecx & 0x00002000U) out->addFeature(kCpuFeatureCmpXchg16B);
|
||||
if (regs.ecx & 0x00080000U) out->addFeature(kCpuFeatureSse41);
|
||||
if (regs.ecx & 0x00100000U) out->addFeature(kCpuFeatureSse42);
|
||||
if (regs.ecx & 0x00400000U) out->addFeature(kCpuFeatureMovbe);
|
||||
if (regs.ecx & 0x00800000U) out->addFeature(kCpuFeaturePopcnt);
|
||||
if (regs.ecx & 0x02000000U) out->addFeature(kCpuFeatureAesni);
|
||||
if (regs.ecx & 0x40000000U) out->addFeature(kCpuFeatureRdrand);
|
||||
|
||||
if (regs.edx & 0x00000010U) out->addFeature(kCpuFeatureRdtsc);
|
||||
if (regs.edx & 0x00000100U) out->addFeature(kCpuFeatureCmpXchg8B);
|
||||
if (regs.edx & 0x00008000U) out->addFeature(kCpuFeatureCmov);
|
||||
if (regs.edx & 0x00800000U) out->addFeature(kCpuFeatureMmx);
|
||||
if (regs.edx & 0x01000000U) out->addFeature(kCpuFeatureFxsr);
|
||||
if (regs.edx & 0x02000000U) out->addFeature(kCpuFeatureSse).addFeature(kCpuFeatureMmxExt);
|
||||
if (regs.edx & 0x04000000U) out->addFeature(kCpuFeatureSse).addFeature(kCpuFeatureSse2);
|
||||
if (regs.edx & 0x10000000U) out->addFeature(kCpuFeatureMultithreading);
|
||||
|
||||
if (out->_vendorId == kCpuVendorAmd && (regs.edx & 0x10000000U)) {
|
||||
// AMD sets Multithreading to ON if it has more cores.
|
||||
if (out->_coresCount == 1)
|
||||
out->_coresCount = 2;
|
||||
}
|
||||
|
||||
// Detect AVX.
|
||||
if (regs.ecx & 0x10000000U) {
|
||||
out->addFeature(kCpuFeatureAvx);
|
||||
|
||||
if (regs.ecx & 0x00000800U) out->addFeature(kCpuFeatureXop);
|
||||
if (regs.ecx & 0x00004000U) out->addFeature(kCpuFeatureFma3);
|
||||
if (regs.ecx & 0x00010000U) out->addFeature(kCpuFeatureFma4);
|
||||
if (regs.ecx & 0x20000000U) out->addFeature(kCpuFeatureF16C);
|
||||
}
|
||||
|
||||
// Detect new features if the processor supports CPUID-07.
|
||||
if (maxId >= 7) {
|
||||
hostCpuId(7, 0, ®s);
|
||||
|
||||
if (regs.ebx & 0x00000001) out->addFeature(kCpuFeatureFsGsBase);
|
||||
if (regs.ebx & 0x00000008) out->addFeature(kCpuFeatureBmi);
|
||||
if (regs.ebx & 0x00000010) out->addFeature(kCpuFeatureHle);
|
||||
if (regs.ebx & 0x00000100) out->addFeature(kCpuFeatureBmi2);
|
||||
if (regs.ebx & 0x00000200) out->addFeature(kCpuFeatureRepMovsbStosbExt);
|
||||
if (regs.ebx & 0x00000800) out->addFeature(kCpuFeatureRtm);
|
||||
|
||||
// AVX2 depends on AVX.
|
||||
if (out->hasFeature(kCpuFeatureAvx)) {
|
||||
if (regs.ebx & 0x00000020) out->addFeature(kCpuFeatureAvx2);
|
||||
}
|
||||
}
|
||||
|
||||
// Calling cpuid with 0x80000000 as the in argument gets the number of valid
|
||||
// extended IDs.
|
||||
hostCpuId(0x80000000, 0, ®s);
|
||||
|
||||
uint32_t maxExtId = IntUtil::iMin<uint32_t>(regs.eax, 0x80000004);
|
||||
uint32_t* brand = reinterpret_cast<uint32_t*>(out->_brandString);
|
||||
|
||||
for (i = 0x80000001; i <= maxExtId; i++) {
|
||||
hostCpuId(i, 0, ®s);
|
||||
|
||||
switch (i) {
|
||||
case 0x80000001:
|
||||
if (regs.ecx & 0x00000001U) out->addFeature(kCpuFeatureLahfSahf);
|
||||
if (regs.ecx & 0x00000020U) out->addFeature(kCpuFeatureLzcnt);
|
||||
if (regs.ecx & 0x00000040U) out->addFeature(kCpuFeatureSse4A);
|
||||
if (regs.ecx & 0x00000080U) out->addFeature(kCpuFeatureMsse);
|
||||
if (regs.ecx & 0x00000100U) out->addFeature(kCpuFeaturePrefetch);
|
||||
|
||||
if (regs.edx & 0x00100000U) out->addFeature(kCpuFeatureExecuteDisableBit);
|
||||
if (regs.edx & 0x00200000U) out->addFeature(kCpuFeatureFfxsr);
|
||||
if (regs.edx & 0x00400000U) out->addFeature(kCpuFeatureMmxExt);
|
||||
if (regs.edx & 0x08000000U) out->addFeature(kCpuFeatureRdtscp);
|
||||
if (regs.edx & 0x40000000U) out->addFeature(kCpuFeature3dNowExt).addFeature(kCpuFeatureMmxExt);
|
||||
if (regs.edx & 0x80000000U) out->addFeature(kCpuFeature3dNow);
|
||||
break;
|
||||
|
||||
case 0x80000002:
|
||||
case 0x80000003:
|
||||
case 0x80000004:
|
||||
*brand++ = regs.eax;
|
||||
*brand++ = regs.ebx;
|
||||
*brand++ = regs.ecx;
|
||||
*brand++ = regs.edx;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Additional features can be detected in the future.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Simplify the brand string (remove unnecessary spaces to make printing nicer).
|
||||
cpuSimplifyBrandString(out->_brandString);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // x86x64 namespace
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
|
||||
218
src/asmjit/x86/x86cpu.h
Normal file
218
src/asmjit/x86/x86cpu.h
Normal file
@@ -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_X86_X86CPU_H
|
||||
#define _ASMJIT_X86_X86CPU_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/cpu.h"
|
||||
#include "../base/defs.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
namespace x86x64 {
|
||||
|
||||
//! @addtogroup asmjit_x86x64
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::kCpuFeature]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief X86 CPU features.
|
||||
ASMJIT_ENUM(kCpuFeature) {
|
||||
//! @brief Cpu has multithreading.
|
||||
kCpuFeatureMultithreading = 1,
|
||||
//! @brief Cpu has execute disable bit.
|
||||
kCpuFeatureExecuteDisableBit,
|
||||
//! @brief Cpu has RDTSC.
|
||||
kCpuFeatureRdtsc,
|
||||
//! @brief Cpu has RDTSCP.
|
||||
kCpuFeatureRdtscp,
|
||||
//! @brief Cpu has CMOV.
|
||||
kCpuFeatureCmov,
|
||||
//! @brief Cpu has CMPXCHG8B.
|
||||
kCpuFeatureCmpXchg8B,
|
||||
//! @brief Cpu has CMPXCHG16B (x64).
|
||||
kCpuFeatureCmpXchg16B,
|
||||
//! @brief Cpu has CLFUSH.
|
||||
kCpuFeatureClflush,
|
||||
//! @brief Cpu has PREFETCH.
|
||||
kCpuFeaturePrefetch,
|
||||
//! @brief Cpu has LAHF/SAHF.
|
||||
kCpuFeatureLahfSahf,
|
||||
//! @brief Cpu has FXSAVE/FXRSTOR.
|
||||
kCpuFeatureFxsr,
|
||||
//! @brief Cpu has FXSAVE/FXRSTOR optimizations.
|
||||
kCpuFeatureFfxsr,
|
||||
//! @brief Cpu has MMX.
|
||||
kCpuFeatureMmx,
|
||||
//! @brief Cpu has extended MMX.
|
||||
kCpuFeatureMmxExt,
|
||||
//! @brief Cpu has 3dNow!
|
||||
kCpuFeature3dNow,
|
||||
//! @brief Cpu has enchanced 3dNow!
|
||||
kCpuFeature3dNowExt,
|
||||
//! @brief Cpu has SSE.
|
||||
kCpuFeatureSse,
|
||||
//! @brief Cpu has SSE2.
|
||||
kCpuFeatureSse2,
|
||||
//! @brief Cpu has SSE3.
|
||||
kCpuFeatureSse3,
|
||||
//! @brief Cpu has Supplemental SSE3 (SSSE3).
|
||||
kCpuFeatureSsse3,
|
||||
//! @brief Cpu has SSE4.A.
|
||||
kCpuFeatureSse4A,
|
||||
//! @brief Cpu has SSE4.1.
|
||||
kCpuFeatureSse41,
|
||||
//! @brief Cpu has SSE4.2.
|
||||
kCpuFeatureSse42,
|
||||
//! @brief Cpu has Misaligned SSE (MSSE).
|
||||
kCpuFeatureMsse,
|
||||
//! @brief Cpu has MONITOR and MWAIT.
|
||||
kCpuFeatureMonitorMWait,
|
||||
//! @brief Cpu has MOVBE.
|
||||
kCpuFeatureMovbe,
|
||||
//! @brief Cpu has POPCNT.
|
||||
kCpuFeaturePopcnt,
|
||||
//! @brief Cpu has LZCNT.
|
||||
kCpuFeatureLzcnt,
|
||||
//! @brief Cpu has AESNI.
|
||||
kCpuFeatureAesni,
|
||||
//! @brief Cpu has PCLMULQDQ.
|
||||
kCpuFeaturePclmulqdq,
|
||||
//! @brief Cpu has RDRAND.
|
||||
kCpuFeatureRdrand,
|
||||
//! @brief Cpu has AVX.
|
||||
kCpuFeatureAvx,
|
||||
//! @brief Cpu has AVX2.
|
||||
kCpuFeatureAvx2,
|
||||
//! @brief Cpu has F16C.
|
||||
kCpuFeatureF16C,
|
||||
//! @brief Cpu has FMA3.
|
||||
kCpuFeatureFma3,
|
||||
//! @brief Cpu has FMA4.
|
||||
kCpuFeatureFma4,
|
||||
//! @brief Cpu has XOP.
|
||||
kCpuFeatureXop,
|
||||
//! @brief Cpu has BMI.
|
||||
kCpuFeatureBmi,
|
||||
//! @brief Cpu has BMI2.
|
||||
kCpuFeatureBmi2,
|
||||
//! @brief Cpu has HLE.
|
||||
kCpuFeatureHle,
|
||||
//! @brief Cpu has RTM.
|
||||
kCpuFeatureRtm,
|
||||
//! @brief Cpu has FSGSBASE.
|
||||
kCpuFeatureFsGsBase,
|
||||
//! @brief Cpu has enhanced REP MOVSB/STOSB.
|
||||
kCpuFeatureRepMovsbStosbExt,
|
||||
|
||||
//! @brief Count of X86/X64 Cpu features.
|
||||
kCpuFeatureCount
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::CpuId]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief X86/X64 cpuid output.
|
||||
union CpuId {
|
||||
//! @brief EAX/EBX/ECX/EDX output.
|
||||
uint32_t i[4];
|
||||
|
||||
struct {
|
||||
//! @brief EAX output.
|
||||
uint32_t eax;
|
||||
//! @brief EBX output.
|
||||
uint32_t ebx;
|
||||
//! @brief ECX output.
|
||||
uint32_t ecx;
|
||||
//! @brief EDX output.
|
||||
uint32_t edx;
|
||||
};
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::Cpu]
|
||||
// ============================================================================
|
||||
|
||||
struct Cpu : public BaseCpu {
|
||||
ASMJIT_NO_COPY(Cpu)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE Cpu(uint32_t size = sizeof(Cpu)) : BaseCpu(size) {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get processor type.
|
||||
ASMJIT_INLINE uint32_t getProcessorType() const { return _processorType; }
|
||||
//! @brief Get brand index.
|
||||
ASMJIT_INLINE uint32_t getBrandIndex() const { return _brandIndex; }
|
||||
//! @brief Get flush cache line size.
|
||||
ASMJIT_INLINE uint32_t getFlushCacheLineSize() const { return _flushCacheLineSize; }
|
||||
//! @brief Get maximum logical processors count.
|
||||
ASMJIT_INLINE uint32_t getMaxLogicalProcessors() const { return _maxLogicalProcessors; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Statics]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get global instance of @ref X86CpuInfo.
|
||||
static ASMJIT_INLINE const Cpu* getHost()
|
||||
{ return static_cast<const Cpu*>(BaseCpu::getHost()); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Processor type.
|
||||
uint32_t _processorType;
|
||||
//! @brief Brand index.
|
||||
uint32_t _brandIndex;
|
||||
//! @brief Flush cache line size in bytes.
|
||||
uint32_t _flushCacheLineSize;
|
||||
//! @brief Maximum number of addressable IDs for logical processors.
|
||||
uint32_t _maxLogicalProcessors;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::hostCpuId / hostCpuDetect]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
|
||||
//! @brief Calls CPUID instruction with eax == @a inEax and ecx === @a inEcx
|
||||
//! and stores the result to @a result.
|
||||
//!
|
||||
//! @c cpuid() function has one input parameter that is passed to cpuid through
|
||||
//! eax register and results in four output values representing result of cpuid
|
||||
//! instruction (eax, ebx, ecx and edx registers).
|
||||
ASMJIT_API void hostCpuId(uint32_t inEax, uint32_t inEcx, CpuId* result);
|
||||
|
||||
//! @brief Detect CPU features to x86x64::Cpu structure @a out.
|
||||
//!
|
||||
//! @sa @c BaseCpu.
|
||||
ASMJIT_API void hostCpuDetect(Cpu* out);
|
||||
#endif // ASMJIT_HOST_X86 || ASMJIT_HOST_X64
|
||||
|
||||
//! @}
|
||||
|
||||
} // x86x64 namespace
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_X86_X86CPU_H
|
||||
3342
src/asmjit/x86/x86defs.cpp
Normal file
3342
src/asmjit/x86/x86defs.cpp
Normal file
File diff suppressed because it is too large
Load Diff
4209
src/asmjit/x86/x86defs.h
Normal file
4209
src/asmjit/x86/x86defs.h
Normal file
File diff suppressed because it is too large
Load Diff
539
src/asmjit/x86/x86func.cpp
Normal file
539
src/asmjit/x86/x86func.cpp
Normal file
@@ -0,0 +1,539 @@
|
||||
// [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_BUILD_X86) || defined(ASMJIT_BUILD_X64)
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/assert.h"
|
||||
#include "../base/intutil.h"
|
||||
#include "../base/string.h"
|
||||
#include "../x86/x86defs.h"
|
||||
#include "../x86/x86func.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
namespace x86x64 {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::X86X64FuncDecl - FindArgByReg]
|
||||
// ============================================================================
|
||||
|
||||
uint32_t X86X64FuncDecl::findArgByReg(uint32_t rClass, uint32_t rIndex) const {
|
||||
for (uint32_t i = 0; i < _argCount; i++) {
|
||||
const FuncInOut& arg = getArg(i);
|
||||
if (arg.getRegIndex() == rIndex && x86VarTypeToClass(arg.getVarType()) == rClass)
|
||||
return i;
|
||||
}
|
||||
|
||||
return kInvalidValue;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::X86X64FuncDecl - SetPrototype]
|
||||
// ============================================================================
|
||||
|
||||
#define R(_Index_) kRegIndex##_Index_
|
||||
static uint32_t X86X64FuncDecl_initConv(X86X64FuncDecl* self, uint32_t arch, uint32_t conv) {
|
||||
uint32_t i;
|
||||
|
||||
// Setup defaults.
|
||||
self->_argStackSize = 0;
|
||||
self->_redZoneSize = 0;
|
||||
self->_spillZoneSize = 0;
|
||||
|
||||
self->_convention = static_cast<uint8_t>(conv);
|
||||
self->_calleePopsStack = false;
|
||||
self->_direction = kFuncDirRtl;
|
||||
|
||||
self->_passed.reset();
|
||||
self->_preserved.reset();
|
||||
|
||||
for (i = 0; i < ASMJIT_ARRAY_SIZE(self->_passedOrderGp); i++) {
|
||||
self->_passedOrderGp[i] = kInvalidReg;
|
||||
}
|
||||
|
||||
for (i = 0; i < ASMJIT_ARRAY_SIZE(self->_passedOrderXmm); i++) {
|
||||
self->_passedOrderXmm[i] = kInvalidReg;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [X86 Support]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (arch == kArchX86) {
|
||||
self->_preserved.set(kRegClassGp, IntUtil::mask(R(Bx), R(Sp), R(Bp), R(Si), R(Di)));
|
||||
|
||||
switch (conv) {
|
||||
case kFuncConvCDecl:
|
||||
break;
|
||||
|
||||
case kFuncConvStdCall:
|
||||
self->_calleePopsStack = true;
|
||||
break;
|
||||
|
||||
case kFuncConvMsThisCall:
|
||||
self->_calleePopsStack = true;
|
||||
self->_passed.set(kRegClassGp, IntUtil::mask(R(Cx)));
|
||||
self->_passedOrderGp[0] = R(Cx);
|
||||
break;
|
||||
|
||||
case kFuncConvMsFastCall:
|
||||
self->_calleePopsStack = true;
|
||||
self->_passed.set(kRegClassGp, IntUtil::mask(R(Cx), R(Cx)));
|
||||
self->_passedOrderGp[0] = R(Cx);
|
||||
self->_passedOrderGp[1] = R(Dx);
|
||||
break;
|
||||
|
||||
case kFuncConvBorlandFastCall:
|
||||
self->_calleePopsStack = true;
|
||||
self->_direction = kFuncDirLtr;
|
||||
self->_passed.set(kRegClassGp, IntUtil::mask(R(Ax), R(Dx), R(Cx)));
|
||||
self->_passedOrderGp[0] = R(Ax);
|
||||
self->_passedOrderGp[1] = R(Dx);
|
||||
self->_passedOrderGp[2] = R(Cx);
|
||||
break;
|
||||
|
||||
case kFuncConvGccFastCall:
|
||||
self->_calleePopsStack = true;
|
||||
self->_passed.set(kRegClassGp, IntUtil::mask(R(Cx), R(Dx)));
|
||||
self->_passedOrderGp[0] = R(Cx);
|
||||
self->_passedOrderGp[1] = R(Dx);
|
||||
break;
|
||||
|
||||
case kFuncConvGccRegParm1:
|
||||
self->_passed.set(kRegClassGp, IntUtil::mask(R(Ax)));
|
||||
self->_passedOrderGp[0] = R(Ax);
|
||||
break;
|
||||
|
||||
case kFuncConvGccRegParm2:
|
||||
self->_passed.set(kRegClassGp, IntUtil::mask(R(Ax), R(Dx)));
|
||||
self->_passedOrderGp[0] = R(Ax);
|
||||
self->_passedOrderGp[1] = R(Dx);
|
||||
break;
|
||||
|
||||
case kFuncConvGccRegParm3:
|
||||
self->_passed.set(kRegClassGp, IntUtil::mask(R(Ax), R(Dx), R(Cx)));
|
||||
self->_passedOrderGp[0] = R(Ax);
|
||||
self->_passedOrderGp[1] = R(Dx);
|
||||
self->_passedOrderGp[2] = R(Cx);
|
||||
break;
|
||||
|
||||
default:
|
||||
ASMJIT_ASSERT(!"Reached");
|
||||
}
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [X64 Support]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if defined(ASMJIT_BUILD_X64)
|
||||
switch (conv) {
|
||||
case kFuncConvX64W:
|
||||
self->_spillZoneSize = 32;
|
||||
|
||||
self->_passed.set(kRegClassGp, IntUtil::mask(R(Cx), R(Dx), R(R8), R(R9)));
|
||||
self->_passedOrderGp[0] = R(Cx);
|
||||
self->_passedOrderGp[1] = R(Dx);
|
||||
self->_passedOrderGp[2] = R(R8);
|
||||
self->_passedOrderGp[3] = R(R9);
|
||||
|
||||
self->_passed.set(kRegClassXy, IntUtil::mask(0, 1, 2, 3));
|
||||
self->_passedOrderXmm[0] = R(Xmm0);
|
||||
self->_passedOrderXmm[1] = R(Xmm1);
|
||||
self->_passedOrderXmm[2] = R(Xmm2);
|
||||
self->_passedOrderXmm[3] = R(Xmm3);
|
||||
|
||||
self->_preserved.set(kRegClassGp, IntUtil::mask(R(Bx), R(Sp), R(Bp), R(Si), R(Di), R(R12), R(R13), R(R14), R(R15)));
|
||||
self->_preserved.set(kRegClassXy, IntUtil::mask(R(Xmm6), R(Xmm7), R(Xmm8), R(Xmm9), R(Xmm10), R(Xmm11), R(Xmm12), R(Xmm13), R(Xmm14), R(Xmm15)));
|
||||
break;
|
||||
|
||||
case kFuncConvX64U:
|
||||
self->_redZoneSize = 128;
|
||||
|
||||
self->_passed.set(kRegClassGp, IntUtil::mask(R(Di), R(Si), R(Dx), R(Cx), R(R8), R(R9)));
|
||||
self->_passedOrderGp[0] = R(Di);
|
||||
self->_passedOrderGp[1] = R(Si);
|
||||
self->_passedOrderGp[2] = R(Dx);
|
||||
self->_passedOrderGp[3] = R(Cx);
|
||||
self->_passedOrderGp[4] = R(R8);
|
||||
self->_passedOrderGp[5] = R(R9);
|
||||
|
||||
self->_passed.set(kRegClassXy, IntUtil::mask(R(Xmm0), R(Xmm1), R(Xmm2), R(Xmm3), R(Xmm4), R(Xmm5), R(Xmm6), R(Xmm7)));
|
||||
self->_passedOrderXmm[0] = R(Xmm0);
|
||||
self->_passedOrderXmm[1] = R(Xmm1);
|
||||
self->_passedOrderXmm[2] = R(Xmm2);
|
||||
self->_passedOrderXmm[3] = R(Xmm3);
|
||||
self->_passedOrderXmm[4] = R(Xmm4);
|
||||
self->_passedOrderXmm[5] = R(Xmm5);
|
||||
self->_passedOrderXmm[6] = R(Xmm6);
|
||||
self->_passedOrderXmm[7] = R(Xmm7);
|
||||
|
||||
self->_preserved.set(kRegClassGp, IntUtil::mask(R(Bx), R(Sp), R(Bp), R(R12), R(R13), R(R14), R(R15)));
|
||||
break;
|
||||
|
||||
default:
|
||||
ASMJIT_ASSERT(!"Reached");
|
||||
}
|
||||
#endif // ASMJIT_BUILD_X64
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
#undef R
|
||||
|
||||
static Error X86X64FuncDecl_initFunc(X86X64FuncDecl* self, uint32_t arch,
|
||||
uint32_t ret, const uint32_t* argList, uint32_t argCount) {
|
||||
|
||||
ASMJIT_ASSERT(argCount <= kFuncArgCount);
|
||||
|
||||
uint32_t conv = self->_convention;
|
||||
uint32_t regSize = (arch == kArchX86) ? 4 : 8;
|
||||
|
||||
int32_t i = 0;
|
||||
int32_t gpPos = 0;
|
||||
int32_t xmmPos = 0;
|
||||
int32_t stackOffset = 0;
|
||||
|
||||
const uint8_t* varMapping;
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (arch == kArchX86)
|
||||
varMapping = x86::_varMapping;
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_X64)
|
||||
if (arch == kArchX64)
|
||||
varMapping = x64::_varMapping;
|
||||
#endif // ASMJIT_BUILD_X64
|
||||
|
||||
self->_argCount = static_cast<uint8_t>(argCount);
|
||||
self->_retCount = 0;
|
||||
|
||||
for (i = 0; i < static_cast<int32_t>(argCount); i++) {
|
||||
FuncInOut& arg = self->getArg(i);
|
||||
arg._varType = static_cast<uint8_t>(argList[i]);
|
||||
arg._regIndex = kInvalidReg;
|
||||
arg._stackOffset = kFuncStackInvalid;
|
||||
}
|
||||
|
||||
for (; i < kFuncArgCount; i++) {
|
||||
self->_argList[i].reset();
|
||||
}
|
||||
|
||||
self->_retList[0].reset();
|
||||
self->_retList[1].reset();
|
||||
self->_argStackSize = 0;
|
||||
self->_used.reset();
|
||||
|
||||
if (ret != kVarTypeInvalid) {
|
||||
ret = varMapping[ret];
|
||||
switch (ret) {
|
||||
case kVarTypeInt64:
|
||||
case kVarTypeUInt64:
|
||||
// 64-bit value is returned in EDX:EAX on x86.
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (arch == kArchX86) {
|
||||
self->_retCount = 2;
|
||||
self->_retList[0]._varType = kVarTypeUInt32;
|
||||
self->_retList[0]._regIndex = kRegIndexAx;
|
||||
self->_retList[1]._varType = static_cast<uint8_t>(ret - 2);
|
||||
self->_retList[1]._regIndex = kRegIndexDx;
|
||||
}
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
// ... Fall through ...
|
||||
|
||||
case kVarTypeInt8:
|
||||
case kVarTypeUInt8:
|
||||
case kVarTypeInt16:
|
||||
case kVarTypeUInt16:
|
||||
case kVarTypeInt32:
|
||||
case kVarTypeUInt32:
|
||||
self->_retCount = 1;
|
||||
self->_retList[0]._varType = static_cast<uint8_t>(ret);
|
||||
self->_retList[0]._regIndex = kRegIndexAx;
|
||||
break;
|
||||
|
||||
case kVarTypeMm:
|
||||
self->_retCount = 1;
|
||||
self->_retList[0]._varType = static_cast<uint8_t>(ret);
|
||||
self->_retList[0]._regIndex = kRegIndexMm0;
|
||||
break;
|
||||
|
||||
case kVarTypeFp32:
|
||||
self->_retCount = 1;
|
||||
if (arch == kArchX86) {
|
||||
self->_retList[0]._varType = kVarTypeFp32;
|
||||
self->_retList[0]._regIndex = kRegIndexFp0;
|
||||
}
|
||||
else {
|
||||
self->_retList[0]._varType = kVarTypeXmmSs;
|
||||
self->_retList[0]._regIndex = kRegIndexXmm0;
|
||||
}
|
||||
break;
|
||||
|
||||
case kVarTypeFp64:
|
||||
self->_retCount = 1;
|
||||
if (arch == kArchX86) {
|
||||
self->_retList[0]._varType = kVarTypeFp64;
|
||||
self->_retList[0]._regIndex = kRegIndexFp0;
|
||||
}
|
||||
else {
|
||||
self->_retList[0]._varType = kVarTypeXmmSd;
|
||||
self->_retList[0]._regIndex = kRegIndexXmm0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case kVarTypeFpEx:
|
||||
self->_retCount = 1;
|
||||
self->_retList[0]._varType = static_cast<uint8_t>(ret);
|
||||
self->_retList[0]._regIndex = kRegIndexFp0;
|
||||
break;
|
||||
|
||||
case kVarTypeXmm:
|
||||
case kVarTypeXmmSs:
|
||||
case kVarTypeXmmSd:
|
||||
case kVarTypeXmmPs:
|
||||
case kVarTypeXmmPd:
|
||||
self->_retCount = 1;
|
||||
self->_retList[0]._varType = static_cast<uint8_t>(ret);
|
||||
self->_retList[0]._regIndex = kRegIndexXmm0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->_argCount == 0)
|
||||
return kErrorOk;
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (arch == kArchX86) {
|
||||
// Register arguments (Integer), always left-to-right.
|
||||
for (i = 0; i != static_cast<int32_t>(argCount); i++) {
|
||||
FuncInOut& arg = self->getArg(i);
|
||||
uint32_t varType = varMapping[arg.getVarType()];
|
||||
|
||||
if (x86VarIsInt(varType) && gpPos < 16 && self->_passedOrderGp[gpPos] != kInvalidReg) {
|
||||
arg._regIndex = self->_passedOrderGp[gpPos++];
|
||||
self->_used.add(kRegClassGp, IntUtil::mask(arg.getRegIndex()));
|
||||
}
|
||||
}
|
||||
|
||||
// Stack arguments.
|
||||
int32_t iStart = static_cast<int32_t>(argCount - 1);
|
||||
int32_t iEnd = -1;
|
||||
int32_t iStep = -1;
|
||||
|
||||
if (self->_direction == kFuncDirLtr) {
|
||||
iStart = 0;
|
||||
iEnd = static_cast<int32_t>(argCount);
|
||||
iStep = 1;
|
||||
}
|
||||
|
||||
for (i = iStart; i != iEnd; i += iStep) {
|
||||
FuncInOut& arg = self->getArg(i);
|
||||
uint32_t varType = varMapping[arg.getVarType()];
|
||||
|
||||
if (arg.hasRegIndex())
|
||||
continue;
|
||||
|
||||
if (x86VarIsInt(varType)) {
|
||||
stackOffset -= 4;
|
||||
arg._stackOffset = static_cast<int16_t>(stackOffset);
|
||||
}
|
||||
else if (x86VarIsFloat(varType)) {
|
||||
int32_t size = static_cast<int32_t>(_varInfo[varType].getSize());
|
||||
stackOffset -= size;
|
||||
arg._stackOffset = static_cast<int16_t>(stackOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_X64)
|
||||
if (arch == kArchX64) {
|
||||
if (conv == kFuncConvX64W) {
|
||||
int32_t argMax = argCount < 4 ? argCount : 4;
|
||||
|
||||
// Register arguments (Gp/Xmm), always left-to-right.
|
||||
for (i = 0; i != argMax; i++) {
|
||||
FuncInOut& arg = self->getArg(i);
|
||||
uint32_t varType = varMapping[arg.getVarType()];
|
||||
|
||||
if (x86VarIsInt(varType)) {
|
||||
arg._regIndex = self->_passedOrderGp[i];
|
||||
self->_used.add(kRegClassGp, IntUtil::mask(arg.getRegIndex()));
|
||||
}
|
||||
else if (x86VarIsFloat(varType)) {
|
||||
arg._regIndex = self->_passedOrderXmm[i];
|
||||
self->_used.add(kRegClassXy, IntUtil::mask(arg.getRegIndex()));
|
||||
}
|
||||
}
|
||||
|
||||
// Stack arguments (always right-to-left).
|
||||
for (i = argCount - 1; i != -1; i--) {
|
||||
FuncInOut& arg = self->getArg(i);
|
||||
uint32_t varType = varMapping[arg.getVarType()];
|
||||
|
||||
if (arg.hasRegIndex())
|
||||
continue;
|
||||
|
||||
if (x86VarIsInt(varType)) {
|
||||
stackOffset -= 8; // Always 8 bytes.
|
||||
arg._stackOffset = stackOffset;
|
||||
}
|
||||
else if (x86VarIsFloat(varType)) {
|
||||
int32_t size = static_cast<int32_t>(_varInfo[varType].getSize());
|
||||
stackOffset -= size;
|
||||
arg._stackOffset = stackOffset;
|
||||
}
|
||||
}
|
||||
|
||||
// 32 bytes shadow space (X64W calling convention specific).
|
||||
stackOffset -= 4 * 8;
|
||||
}
|
||||
else {
|
||||
// Register arguments (Gp), always left-to-right.
|
||||
for (i = 0; i != static_cast<int32_t>(argCount); i++) {
|
||||
FuncInOut& arg = self->getArg(i);
|
||||
uint32_t varType = varMapping[arg.getVarType()];
|
||||
|
||||
if (x86VarIsInt(varType) && gpPos < 32 && self->_passedOrderGp[gpPos] != kInvalidReg) {
|
||||
arg._regIndex = self->_passedOrderGp[gpPos++];
|
||||
self->_used.add(kRegClassGp, IntUtil::mask(arg.getRegIndex()));
|
||||
}
|
||||
}
|
||||
|
||||
// Register arguments (Xmm), always left-to-right.
|
||||
for (i = 0; i != static_cast<int32_t>(argCount); i++) {
|
||||
FuncInOut& arg = self->getArg(i);
|
||||
uint32_t varType = varMapping[arg.getVarType()];
|
||||
|
||||
if (x86VarIsFloat(varType)) {
|
||||
arg._regIndex = self->_passedOrderXmm[xmmPos++];
|
||||
self->_used.add(kRegClassXy, IntUtil::mask(arg.getRegIndex()));
|
||||
}
|
||||
}
|
||||
|
||||
// Stack arguments.
|
||||
for (i = argCount - 1; i != -1; i--) {
|
||||
FuncInOut& arg = self->getArg(i);
|
||||
uint32_t varType = varMapping[arg.getVarType()];
|
||||
|
||||
if (arg.hasRegIndex())
|
||||
continue;
|
||||
|
||||
if (x86VarIsInt(varType)) {
|
||||
stackOffset -= 8;
|
||||
arg._stackOffset = static_cast<int16_t>(stackOffset);
|
||||
}
|
||||
else if (x86VarIsFloat(varType)) {
|
||||
int32_t size = static_cast<int32_t>(_varInfo[varType].getSize());
|
||||
|
||||
stackOffset -= size;
|
||||
arg._stackOffset = static_cast<int16_t>(stackOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // ASMJIT_BUILD_X64
|
||||
|
||||
// Modify the stack offset, thus in result all parameters would have positive
|
||||
// non-zero stack offset.
|
||||
for (i = 0; i < static_cast<int32_t>(argCount); i++) {
|
||||
FuncInOut& arg = self->getArg(i);
|
||||
if (!arg.hasRegIndex()) {
|
||||
arg._stackOffset += static_cast<uint16_t>(static_cast<int32_t>(regSize) - stackOffset);
|
||||
}
|
||||
}
|
||||
|
||||
self->_argStackSize = static_cast<uint32_t>(-stackOffset);
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error X86X64FuncDecl::setPrototype(uint32_t conv, const FuncPrototype& p) {
|
||||
if (conv == kFuncConvNone || conv >= _kFuncConvCount)
|
||||
return kErrorInvalidArgument;
|
||||
|
||||
if (p.getArgCount() > kFuncArgCount)
|
||||
return kErrorInvalidArgument;
|
||||
|
||||
// Validate that the required convention is supported by the current asmjit
|
||||
// configuration, if only one target is compiled.
|
||||
uint32_t arch = x86GetArchFromCConv(conv);
|
||||
#if defined(ASMJIT_BUILD_X86) && !defined(ASMJIT_BUILD_X64)
|
||||
if (arch == kArchX64)
|
||||
return kErrorInvalidState;
|
||||
#endif // ASMJIT_BUILD_X86 && !ASMJIT_BUILD_X64
|
||||
|
||||
#if !defined(ASMJIT_BUILD_X86) && defined(ASMJIT_BUILD_X64)
|
||||
if (arch == kArchX86)
|
||||
return kErrorInvalidState;
|
||||
#endif // !ASMJIT_BUILD_X86 && ASMJIT_BUILD_X64
|
||||
|
||||
ASMJIT_PROPAGATE_ERROR(X86X64FuncDecl_initConv(this, arch, conv));
|
||||
ASMJIT_PROPAGATE_ERROR(X86X64FuncDecl_initFunc(this, arch, p.getRet(), p.getArgList(), p.getArgCount()));
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::X86X64FuncDecl - Reset]
|
||||
// ============================================================================
|
||||
|
||||
void X86X64FuncDecl::reset() {
|
||||
uint32_t i;
|
||||
|
||||
_convention = kFuncConvNone;
|
||||
_calleePopsStack = false;
|
||||
_direction = kFuncDirRtl;
|
||||
_reserved0 = 0;
|
||||
|
||||
_argCount = 0;
|
||||
_retCount = 0;
|
||||
|
||||
_argStackSize = 0;
|
||||
_redZoneSize = 0;
|
||||
_spillZoneSize = 0;
|
||||
|
||||
for (i = 0; i < ASMJIT_ARRAY_SIZE(_argList); i++) {
|
||||
_argList[i].reset();
|
||||
}
|
||||
|
||||
_retList[0].reset();
|
||||
_retList[1].reset();
|
||||
|
||||
_used.reset();
|
||||
_passed.reset();
|
||||
_preserved.reset();
|
||||
|
||||
for (i = 0; i < ASMJIT_ARRAY_SIZE(_passedOrderGp); i++) {
|
||||
_passedOrderGp[i] = kInvalidReg;
|
||||
}
|
||||
|
||||
for (i = 0; i < ASMJIT_ARRAY_SIZE(_passedOrderXmm); i++) {
|
||||
_passedOrderXmm[i] = kInvalidReg;
|
||||
}
|
||||
}
|
||||
|
||||
} // x86x64 namespace
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
|
||||
500
src/asmjit/x86/x86func.h
Normal file
500
src/asmjit/x86/x86func.h
Normal file
@@ -0,0 +1,500 @@
|
||||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_X86_X86FUNC_H
|
||||
#define _ASMJIT_X86_X86FUNC_H
|
||||
|
||||
// [Dependencies - AsmJit]
|
||||
#include "../base/defs.h"
|
||||
#include "../base/func.h"
|
||||
#include "../x86/x86defs.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../base/apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
namespace x86x64 {
|
||||
|
||||
//! @addtogroup asmjit_x86x64
|
||||
//! @{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::kFuncConv]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief X86 function calling conventions.
|
||||
//!
|
||||
//! Calling convention is scheme how function arguments are passed into
|
||||
//! function and how functions returns values. In assembler programming
|
||||
//! it's needed to always comply with function calling conventions, because
|
||||
//! even small inconsistency can cause undefined behavior or crash.
|
||||
//!
|
||||
//! List of calling conventions for 32-bit x86 mode:
|
||||
//! - @c kFuncConvCDecl - Calling convention for C runtime.
|
||||
//! - @c kFuncConvStdCall - Calling convention for WinAPI functions.
|
||||
//! - @c kFuncConvMsThisCall - Calling convention for C++ members under
|
||||
//! Windows (produced by MSVC and all MSVC compatible compilers).
|
||||
//! - @c kFuncConvMsFastCall - Fastest calling convention that can be used
|
||||
//! by MSVC compiler.
|
||||
//! - @c kFuncConv_BORNANDFASTCALL - Borland fastcall convention.
|
||||
//! - @c kFuncConvGccFastCall - GCC fastcall convention (2 register arguments).
|
||||
//! - @c kFuncConvGccRegParm1 - GCC regparm(1) convention.
|
||||
//! - @c kFuncConvGccRegParm2 - GCC regparm(2) convention.
|
||||
//! - @c kFuncConvGccRegParm3 - GCC regparm(3) convention.
|
||||
//!
|
||||
//! List of calling conventions for 64-bit x86 mode (x64):
|
||||
//! - @c kFuncConvX64W - Windows 64-bit calling convention (WIN64 ABI).
|
||||
//! - @c kFuncConvX64U - Unix 64-bit calling convention (AMD64 ABI).
|
||||
//!
|
||||
//! There is also @c kFuncConvHost that is defined to fit best to your
|
||||
//! compiler.
|
||||
//!
|
||||
//! These types are used together with @c asmjit::Compiler::addFunc()
|
||||
//! method.
|
||||
ASMJIT_ENUM(kFuncConv) {
|
||||
// --------------------------------------------------------------------------
|
||||
// [X64]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief X64 calling convention for Windows platform (WIN64 ABI).
|
||||
//!
|
||||
//! For first four arguments are used these registers:
|
||||
//! - 1. 32/64-bit integer or floating point argument - rcx/xmm0
|
||||
//! - 2. 32/64-bit integer or floating point argument - rdx/xmm1
|
||||
//! - 3. 32/64-bit integer or floating point argument - r8/xmm2
|
||||
//! - 4. 32/64-bit integer or floating point argument - r9/xmm3
|
||||
//!
|
||||
//! Note first four arguments here means arguments at positions from 1 to 4
|
||||
//! (included). For example if second argument is not passed in register then
|
||||
//! rdx/xmm1 register is unused.
|
||||
//!
|
||||
//! All other arguments are pushed on the stack in right-to-left direction.
|
||||
//! Stack is aligned by 16 bytes. There is 32-byte shadow space on the stack
|
||||
//! that can be used to save up to four 64-bit registers (probably designed to
|
||||
//! be used to save first four arguments passed in registers).
|
||||
//!
|
||||
//! Arguments direction:
|
||||
//! - Right to Left (except for first 4 parameters that's in registers)
|
||||
//!
|
||||
//! Stack is cleaned by:
|
||||
//! - Caller.
|
||||
//!
|
||||
//! Return value:
|
||||
//! - Integer types - RAX register.
|
||||
//! - Floating points - XMM0 register.
|
||||
//!
|
||||
//! Stack is always aligned by 16 bytes.
|
||||
//!
|
||||
//! More information about this calling convention can be found on MSDN:
|
||||
//! http://msdn.microsoft.com/en-us/library/9b372w95.aspx .
|
||||
kFuncConvX64W = 1,
|
||||
|
||||
//! @brief X64 calling convention for Unix platforms (AMD64 ABI).
|
||||
//!
|
||||
//! First six 32 or 64-bit integer arguments are passed in rdi, rsi, rdx,
|
||||
//! rcx, r8, r9 registers. First eight floating point or Xmm arguments
|
||||
//! are passed in xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 registers.
|
||||
//! This means that in registers can be transferred up to 14 arguments total.
|
||||
//!
|
||||
//! There is also RED ZONE below the stack pointer that can be used for
|
||||
//! temporary storage. The red zone is the space from [rsp-128] to [rsp-8].
|
||||
//!
|
||||
//! Arguments direction:
|
||||
//! - Right to Left (Except for arguments passed in registers).
|
||||
//!
|
||||
//! Stack is cleaned by:
|
||||
//! - Caller.
|
||||
//!
|
||||
//! Return value:
|
||||
//! - Integer types - RAX register.
|
||||
//! - Floating points - XMM0 register.
|
||||
//!
|
||||
//! Stack is always aligned by 16 bytes.
|
||||
kFuncConvX64U = 2,
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [X86]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Cdecl calling convention (used by C runtime).
|
||||
//!
|
||||
//! Compatible across MSVC and GCC.
|
||||
//!
|
||||
//! Arguments direction:
|
||||
//! - Right to Left
|
||||
//!
|
||||
//! Stack is cleaned by:
|
||||
//! - Caller.
|
||||
kFuncConvCDecl = 3,
|
||||
|
||||
//! @brief Stdcall calling convention (used by WinAPI).
|
||||
//!
|
||||
//! Compatible across MSVC and GCC.
|
||||
//!
|
||||
//! Arguments direction:
|
||||
//! - Right to Left
|
||||
//!
|
||||
//! Stack is cleaned by:
|
||||
//! - Callee.
|
||||
//!
|
||||
//! Return value:
|
||||
//! - Integer types - EAX:EDX registers.
|
||||
//! - Floating points - fp0 register.
|
||||
kFuncConvStdCall = 4,
|
||||
|
||||
//! @brief MSVC specific calling convention used by MSVC/Intel compilers
|
||||
//! for struct/class methods.
|
||||
//!
|
||||
//! This is MSVC (and Intel) only calling convention used in Windows
|
||||
//! world for C++ class methods. Implicit 'this' pointer is stored in
|
||||
//! ECX register instead of storing it on the stack.
|
||||
//!
|
||||
//! Arguments direction:
|
||||
//! - Right to Left (except this pointer in ECX)
|
||||
//!
|
||||
//! Stack is cleaned by:
|
||||
//! - Callee.
|
||||
//!
|
||||
//! Return value:
|
||||
//! - Integer types - EAX:EDX registers.
|
||||
//! - Floating points - fp0 register.
|
||||
//!
|
||||
//! C++ class methods that have variable count of arguments uses different
|
||||
//! calling convention called cdecl.
|
||||
//!
|
||||
//! @note This calling convention is always used by MSVC for class methods,
|
||||
//! it's implicit and there is no way how to override it.
|
||||
kFuncConvMsThisCall = 5,
|
||||
|
||||
//! @brief MSVC specific fastcall.
|
||||
//!
|
||||
//! Two first parameters (evaluated from left-to-right) are in ECX:EDX
|
||||
//! registers, all others on the stack in right-to-left order.
|
||||
//!
|
||||
//! Arguments direction:
|
||||
//! - Right to Left (except to first two integer arguments in ECX:EDX)
|
||||
//!
|
||||
//! Stack is cleaned by:
|
||||
//! - Callee.
|
||||
//!
|
||||
//! Return value:
|
||||
//! - Integer types - EAX:EDX registers.
|
||||
//! - Floating points - fp0 register.
|
||||
//!
|
||||
//! @note This calling convention differs to GCC one in stack cleaning
|
||||
//! mechanism.
|
||||
kFuncConvMsFastCall = 6,
|
||||
|
||||
//! @brief Borland specific fastcall with 2 parameters in registers.
|
||||
//!
|
||||
//! Two first parameters (evaluated from left-to-right) are in ECX:EDX
|
||||
//! registers, all others on the stack in left-to-right order.
|
||||
//!
|
||||
//! Arguments direction:
|
||||
//! - Left to Right (except to first two integer arguments in ECX:EDX)
|
||||
//!
|
||||
//! Stack is cleaned by:
|
||||
//! - Callee.
|
||||
//!
|
||||
//! Return value:
|
||||
//! - Integer types - EAX:EDX registers.
|
||||
//! - Floating points - fp0 register.
|
||||
//!
|
||||
//! @note Arguments on the stack are in left-to-right order that differs
|
||||
//! to other fastcall conventions used in different compilers.
|
||||
kFuncConvBorlandFastCall = 7,
|
||||
|
||||
//! @brief GCC specific fastcall convention.
|
||||
//!
|
||||
//! Two first parameters (evaluated from left-to-right) are in ECX:EDX
|
||||
//! registers, all others on the stack in right-to-left order.
|
||||
//!
|
||||
//! Arguments direction:
|
||||
//! - Right to Left (except to first two integer arguments in ECX:EDX)
|
||||
//!
|
||||
//! Stack is cleaned by:
|
||||
//! - Callee.
|
||||
//!
|
||||
//! Return value:
|
||||
//! - Integer types - EAX:EDX registers.
|
||||
//! - Floating points - fp0 register.
|
||||
//!
|
||||
//! @note This calling convention should be compatible with
|
||||
//! @c kFuncConvMsFastCall.
|
||||
kFuncConvGccFastCall = 8,
|
||||
|
||||
//! @brief GCC specific regparm(1) convention.
|
||||
//!
|
||||
//! The first parameter (evaluated from left-to-right) is in EAX register,
|
||||
//! all others on the stack in right-to-left order.
|
||||
//!
|
||||
//! Arguments direction:
|
||||
//! - Right to Left (except to first one integer argument in EAX)
|
||||
//!
|
||||
//! Stack is cleaned by:
|
||||
//! - Caller.
|
||||
//!
|
||||
//! Return value:
|
||||
//! - Integer types - EAX:EDX registers.
|
||||
//! - Floating points - fp0 register.
|
||||
kFuncConvGccRegParm1 = 9,
|
||||
|
||||
//! @brief GCC specific regparm(2) convention.
|
||||
//!
|
||||
//! Two first parameters (evaluated from left-to-right) are in EAX:EDX
|
||||
//! registers, all others on the stack in right-to-left order.
|
||||
//!
|
||||
//! Arguments direction:
|
||||
//! - Right to Left (except to first two integer arguments in EAX:EDX)
|
||||
//!
|
||||
//! Stack is cleaned by:
|
||||
//! - Caller.
|
||||
//!
|
||||
//! Return value:
|
||||
//! - Integer types - EAX:EDX registers.
|
||||
//! - Floating points - fp0 register.
|
||||
kFuncConvGccRegParm2 = 10,
|
||||
|
||||
//! @brief GCC specific fastcall with 3 parameters in registers.
|
||||
//!
|
||||
//! Three first parameters (evaluated from left-to-right) are in
|
||||
//! EAX:EDX:ECX registers, all others on the stack in right-to-left order.
|
||||
//!
|
||||
//! Arguments direction:
|
||||
//! - Right to Left (except to first three integer arguments in EAX:EDX:ECX)
|
||||
//!
|
||||
//! Stack is cleaned by:
|
||||
//! - Caller.
|
||||
//!
|
||||
//! Return value:
|
||||
//! - Integer types - EAX:EDX registers.
|
||||
//! - Floating points - fp0 register.
|
||||
kFuncConvGccRegParm3 = 11,
|
||||
|
||||
//! @internal
|
||||
//!
|
||||
//! @brief Count of function calling conventions.
|
||||
_kFuncConvCount = 12,
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Host]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @def kFuncConvHost
|
||||
//! @brief Default calling convention for current platform / operating system.
|
||||
|
||||
//! @def kFuncConvHostCDecl
|
||||
//! @brief Default C calling convention based on current compiler's settings.
|
||||
|
||||
//! @def kFuncConvHostStdCall
|
||||
//! @brief 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 @ref kFuncConvX64W or @ref kFuncConvX64U.
|
||||
|
||||
//! @def kFuncConvHostFastCall
|
||||
//! @brief 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 @ref kFuncConvX64W or @ref kFuncConvX64U.
|
||||
|
||||
#if defined(ASMJIT_HOST_X86)
|
||||
|
||||
kFuncConvHost = kFuncConvCDecl,
|
||||
kFuncConvHostCDecl = kFuncConvCDecl,
|
||||
kFuncConvHostStdCall = kFuncConvStdCall,
|
||||
|
||||
# if defined(_MSC_VER)
|
||||
kFuncConvHostFastCall = kFuncConvMsFastCall
|
||||
# elif defined(__GNUC__)
|
||||
kFuncConvHostFastCall = kFuncConvGccFastCall
|
||||
# elif defined(__BORLANDC__)
|
||||
kFuncConvHostFastCall = kFuncConvBorlandFastCall
|
||||
# else
|
||||
# error "asmjit/x86/x86func.h - asmjit::kFuncConvHostFastCall not supported."
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
# if defined(ASMJIT_OS_WINDOWS)
|
||||
kFuncConvHost = kFuncConvX64W,
|
||||
# else
|
||||
kFuncConvHost = kFuncConvX64U,
|
||||
# endif
|
||||
|
||||
kFuncConvHostCDecl = kFuncConvHost,
|
||||
kFuncConvHostStdCall = kFuncConvHost,
|
||||
kFuncConvHostFastCall = kFuncConvHost
|
||||
|
||||
#endif // ASMJIT_HOST
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::kFuncHint]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief X86 function hints.
|
||||
ASMJIT_ENUM(kFuncHint) {
|
||||
//! @brief Use push/pop sequences instead of mov sequences in function prolog
|
||||
//! and epilog.
|
||||
kFuncHintPushPop = 16,
|
||||
//! @brief Add emms instruction to the function epilog.
|
||||
kFuncHintEmms = 17,
|
||||
//! @brief Add sfence instruction to the function epilog.
|
||||
kFuncHintSFence = 18,
|
||||
//! @brief Add lfence instruction to the function epilog.
|
||||
kFuncHintLFence = 19
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::kFuncFlags]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief X86 function flags.
|
||||
ASMJIT_ENUM(kFuncFlags) {
|
||||
//! @brief Whether to emit register load/save sequence using push/pop pairs.
|
||||
kFuncFlagPushPop = 0x00010000,
|
||||
|
||||
//! @brief Whether to emit "enter" instead of three instructions in case
|
||||
//! that the function is not naked or misaligned.
|
||||
kFuncFlagEnter = 0x00020000,
|
||||
|
||||
//! @brief Whether to emit "leave" instead of two instructions in case
|
||||
//! that the function is not naked or misaligned.
|
||||
kFuncFlagLeave = 0x00040000,
|
||||
|
||||
//! @brief Whether it's required to move arguments to a new stack location,
|
||||
//! because of manual aligning.
|
||||
kFuncFlagMoveArgs = 0x00080000,
|
||||
|
||||
//! @brief Whether to emit EMMS instruction in epilog (auto-detected).
|
||||
kFuncFlagEmms = 0x01000000,
|
||||
|
||||
//! @brief Whether to emit SFence instruction in epilog (auto-detected).
|
||||
//!
|
||||
//! @note @ref kFuncFlagSFence and @ref kFuncFlagLFence
|
||||
//! combination will result in emitting mfence.
|
||||
kFuncFlagSFence = 0x02000000,
|
||||
|
||||
//! @brief Whether to emit LFence instruction in epilog (auto-detected).
|
||||
//!
|
||||
//! @note @ref kFuncFlagSFence and @ref kFuncFlagLFence
|
||||
//! combination will result in emitting mfence.
|
||||
kFuncFlagLFence = 0x04000000
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::x86GetArchFromCConv]
|
||||
// ============================================================================
|
||||
|
||||
static ASMJIT_INLINE uint32_t x86GetArchFromCConv(uint32_t conv) {
|
||||
return IntUtil::inInterval<uint32_t>(conv, kFuncConvX64W, kFuncConvX64U) ? kArchX64 : kArchX86;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::x86x64::X86X64FuncDecl]
|
||||
// ============================================================================
|
||||
|
||||
//! @brief X86 function, including calling convention, arguments and their
|
||||
//! register indices or stack positions.
|
||||
struct X86X64FuncDecl : public FuncDecl {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Create a new @ref X86X64FuncDecl instance.
|
||||
ASMJIT_INLINE X86X64FuncDecl() { reset(); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors - X86]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Get used registers (mask).
|
||||
//!
|
||||
//! @note The result depends on the function calling convention AND the
|
||||
//! function prototype. Returned mask contains only registers actually used
|
||||
//! to pass function arguments.
|
||||
ASMJIT_INLINE uint32_t getUsed(uint32_t c) const { return _used.get(c); }
|
||||
|
||||
//! @brief Get passed registers (mask).
|
||||
//!
|
||||
//! @note The result depends on the function calling convention used; the
|
||||
//! prototype of the function doesn't affect the mask returned.
|
||||
ASMJIT_INLINE uint32_t getPassed(uint32_t c) const { return _passed.get(c); }
|
||||
|
||||
//! @brief Get preserved registers (mask).
|
||||
//!
|
||||
//! @note The result depends on the function calling convention used; the
|
||||
//! prototype of the function doesn't affect the mask returned.
|
||||
ASMJIT_INLINE uint32_t getPreserved(uint32_t c) const { return _preserved.get(c); }
|
||||
|
||||
//! @brief Get ther order of passed registers (Gp).
|
||||
//!
|
||||
//! @note The result depends on the function calling convention used; the
|
||||
//! prototype of the function doesn't affect the mask returned.
|
||||
ASMJIT_INLINE const uint8_t* getPassedOrderGp() const { return _passedOrderGp; }
|
||||
|
||||
//! @brief Get ther order of passed registers (Xmm).
|
||||
//!
|
||||
//! @note The result depends on the function calling convention used; the
|
||||
//! prototype of the function doesn't affect the mask returned.
|
||||
ASMJIT_INLINE const uint8_t* getPassedOrderXmm() const { return _passedOrderXmm; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [FindArgByReg]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Find argument ID by register class and index.
|
||||
ASMJIT_API uint32_t findArgByReg(uint32_t rClass, uint32_t rIndex) const;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [SetPrototype]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Set function prototype.
|
||||
//!
|
||||
//! This will set function calling convention and setup arguments variables.
|
||||
//!
|
||||
//! @note This function will allocate variables, it can be called only once.
|
||||
ASMJIT_API Error setPrototype(uint32_t conv, const FuncPrototype& p);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API void reset();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! @brief Used registers .
|
||||
RegMask _used;
|
||||
|
||||
//! @brief Passed registers (defined by the calling convention).
|
||||
RegMask _passed;
|
||||
//! @brief Preserved registers (defined by the calling convention).
|
||||
RegMask _preserved;
|
||||
|
||||
//! @brief Order of registers defined to pass function arguments (Gp).
|
||||
uint8_t _passedOrderGp[kFuncArgCount];
|
||||
//! @brief Order of registers defined to pass function arguments (Xmm).
|
||||
uint8_t _passedOrderXmm[kFuncArgCount];
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
} // x86x64 namespace
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../base/apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_X86_X86FUNC_H
|
||||
424
tools/autoexp-patch.py
Normal file
424
tools/autoexp-patch.py
Normal file
@@ -0,0 +1,424 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
|
||||
AUTOEXP_FILES = [
|
||||
# Visual Studio 8.0 (2005).
|
||||
"C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Packages\\Debugger\\autoexp.dat",
|
||||
"C:\\Program Files (x86)\\Microsoft Visual Studio 8\\Common7\\Packages\\Debugger\\autoexp.dat",
|
||||
|
||||
# Visual Studio 9.0 (2008).
|
||||
"C:\\Program Files\\Microsoft Visual Studio 9.0\\Common7\\Packages\\Debugger\\autoexp.dat",
|
||||
"C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\Common7\\Packages\\Debugger\\autoexp.dat",
|
||||
|
||||
# Visual Studio 10.0 (2010).
|
||||
"C:\\Program Files\\Microsoft Visual Studio 10.0\\Common7\\Packages\\Debugger\\autoexp.dat",
|
||||
"C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\Common7\\Packages\\Debugger\\autoexp.dat"
|
||||
]
|
||||
|
||||
DIRECTIVE_SYMBOL = '@'
|
||||
|
||||
# =============================================================================
|
||||
# [Log]
|
||||
# =============================================================================
|
||||
|
||||
def log(str):
|
||||
print(str)
|
||||
|
||||
# =============================================================================
|
||||
# [Is...]
|
||||
# =============================================================================
|
||||
|
||||
def isDirective(c):
|
||||
return c == DIRECTIVE_SYMBOL
|
||||
|
||||
def isAlpha(c):
|
||||
c = ord(c)
|
||||
return (c >= ord('a') and c <= ord('z')) or (c >= ord('A') and c <= ord('Z'))
|
||||
|
||||
def isAlpha_(c):
|
||||
return isAlpha(c) or (c == '_')
|
||||
|
||||
def isNumber(c):
|
||||
c = ord(c)
|
||||
return (c >= ord('0')) and (c <= ord('9'))
|
||||
|
||||
def isAlnum(c):
|
||||
return isAlpha(c) or isNumber(c)
|
||||
|
||||
def isAlnum_(c):
|
||||
return isAlnum(c) or (c == '_')
|
||||
|
||||
def isSpace(c):
|
||||
return (c == ' ') or (c == '\t')
|
||||
|
||||
def isNewLine(c):
|
||||
return c == '\n'
|
||||
|
||||
# =============================================================================
|
||||
# [SyntaxError]
|
||||
# =============================================================================
|
||||
|
||||
class SyntaxError(Exception):
|
||||
def __init__(self, msg):
|
||||
self.msg = msg
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.msg)
|
||||
|
||||
# =============================================================================
|
||||
# [Context]
|
||||
# =============================================================================
|
||||
|
||||
class Context(object):
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
self.index = 0
|
||||
self.size = len(data)
|
||||
|
||||
def isNewLine(self):
|
||||
if self.index == 0:
|
||||
return True
|
||||
else:
|
||||
return self.data[self.index - 1] == '\n'
|
||||
|
||||
def isEnd(self):
|
||||
return self.index >= self.size
|
||||
|
||||
def getChar(self):
|
||||
if self.index >= self.size:
|
||||
return '\0'
|
||||
return self.data[self.index]
|
||||
|
||||
def advance(self):
|
||||
if self.index < self.size:
|
||||
self.index += 1
|
||||
|
||||
def parseUntilTrue(self, func, advance):
|
||||
while not self.isEnd():
|
||||
c = self.data[self.index]
|
||||
if func(c):
|
||||
self.index += 1
|
||||
continue
|
||||
if advance:
|
||||
self.index += 1
|
||||
return True
|
||||
return False
|
||||
|
||||
def parseUntilFalse(self, func, advance):
|
||||
while not self.isEnd():
|
||||
c = self.data[self.index]
|
||||
if not func(c):
|
||||
self.index += 1
|
||||
continue
|
||||
if advance:
|
||||
self.index += 1
|
||||
return True
|
||||
return False
|
||||
|
||||
def skipString(self):
|
||||
def func(c):
|
||||
return c == '"'
|
||||
return self.parseUntilFalse(func, True)
|
||||
|
||||
def skipSpaces(self):
|
||||
return self.parseUntilTrue(isSpace, False)
|
||||
|
||||
def skipLine(self):
|
||||
return self.parseUntilFalse(isNewLine, True)
|
||||
|
||||
def parseDirective(self, index):
|
||||
start = index
|
||||
|
||||
data = self.data
|
||||
size = self.size
|
||||
|
||||
c = data[index]
|
||||
assert isAlpha_(c)
|
||||
|
||||
while True:
|
||||
index += 1
|
||||
if index >= size:
|
||||
break
|
||||
c = data[index]
|
||||
if isAlnum_(c):
|
||||
continue
|
||||
break
|
||||
|
||||
self.index = index
|
||||
return data[start:index]
|
||||
|
||||
def parseSymbol(self, index):
|
||||
start = index
|
||||
|
||||
data = self.data
|
||||
size = self.size
|
||||
|
||||
c = data[index]
|
||||
assert isAlpha_(c)
|
||||
|
||||
while True:
|
||||
index += 1
|
||||
if index >= size:
|
||||
return data[start:index]
|
||||
c = data[index]
|
||||
if isAlnum_(c):
|
||||
continue
|
||||
if c == ':' and index + 2 < size and data[index + 1] == ':' and isAlpha_(data[index + 2]):
|
||||
index += 2
|
||||
continue
|
||||
|
||||
self.index = index
|
||||
return data[start:index]
|
||||
|
||||
def parseMacro(self, index):
|
||||
start = index
|
||||
end = None
|
||||
|
||||
data = self.data
|
||||
size = self.size
|
||||
|
||||
if index >= size:
|
||||
return ""
|
||||
|
||||
while True:
|
||||
c = data[index]
|
||||
index += 1
|
||||
|
||||
if c == '\n' or index >= size:
|
||||
if end == None:
|
||||
end = index - 1
|
||||
break
|
||||
|
||||
if c == ';':
|
||||
if end == None:
|
||||
end = index
|
||||
|
||||
while start < end and isSpace(data[end - 1]):
|
||||
end -= 1
|
||||
|
||||
self.index = index
|
||||
return data[start:end]
|
||||
|
||||
def replaceRange(self, start, end, content):
|
||||
old = self.data
|
||||
|
||||
self.data = old[0:start] + content + old[end:]
|
||||
self.size = len(self.data)
|
||||
|
||||
assert(self.index >= end)
|
||||
|
||||
self.index -= end - start
|
||||
self.index += len(content)
|
||||
|
||||
# =============================================================================
|
||||
# [AutoExpDat]
|
||||
# =============================================================================
|
||||
|
||||
class AutoExpDat(object):
|
||||
def __init__(self, data):
|
||||
self.library = None
|
||||
self.symbols = {}
|
||||
self.data = self.process(data.replace('\r', ''))
|
||||
|
||||
def process(self, data):
|
||||
ctx = Context(data)
|
||||
|
||||
while not ctx.isEnd():
|
||||
c = ctx.getChar()
|
||||
|
||||
# Skip comments.
|
||||
if c == ';':
|
||||
ctx.skipLine()
|
||||
continue
|
||||
|
||||
# Skip strings.
|
||||
if c == '"':
|
||||
ctx.advance()
|
||||
ctx.skipString()
|
||||
continue
|
||||
|
||||
# Skip numbers.
|
||||
if isNumber(c):
|
||||
ctx.parseUntilTrue(isAlnum_, True)
|
||||
continue
|
||||
|
||||
# Parse directives.
|
||||
if isDirective(c) and ctx.isNewLine():
|
||||
start = ctx.index
|
||||
|
||||
ctx.advance()
|
||||
c = ctx.getChar()
|
||||
|
||||
# Remove lines that have '@' followed by space or newline.
|
||||
if isNewLine(c) or c == '\0':
|
||||
ctx.advance()
|
||||
ctx.replaceRange(start, ctx.index, "")
|
||||
continue
|
||||
if isSpace(c):
|
||||
ctx.skipLine()
|
||||
ctx.replaceRange(start, ctx.index, "")
|
||||
continue
|
||||
|
||||
directive = ctx.parseDirective(ctx.index)
|
||||
|
||||
c = ctx.getChar()
|
||||
if not isSpace(c):
|
||||
self.error("Directive Error: @" + directive + ".")
|
||||
ctx.skipSpaces()
|
||||
|
||||
# Directive '@library'.
|
||||
if directive == "library":
|
||||
self.library = ctx.parseMacro(ctx.index)
|
||||
|
||||
# Directive '@define'.
|
||||
elif directive == "define":
|
||||
c = ctx.getChar()
|
||||
if not isAlpha_(c):
|
||||
self.error("Define Directive has to start with alpha character or underscore")
|
||||
symbol = ctx.parseSymbol(ctx.index)
|
||||
|
||||
c = ctx.getChar()
|
||||
|
||||
# No Macro.
|
||||
if isNewLine(c):
|
||||
ctx.advance()
|
||||
self.addSymbol(symbol, "")
|
||||
# Has Macro.
|
||||
else:
|
||||
ctx.skipSpaces()
|
||||
|
||||
macro = ctx.parseMacro(ctx.index)
|
||||
self.addSymbol(symbol, macro)
|
||||
|
||||
# Unknown Directive.
|
||||
else:
|
||||
self.error("Unknown Directive: @" + directive + ".")
|
||||
|
||||
ctx.replaceRange(start, ctx.index, "")
|
||||
continue
|
||||
|
||||
# Parse/Replace symbol.
|
||||
if isAlpha_(c) and ctx.index > 0 and ctx.data[ctx.index - 1] != '#':
|
||||
start = ctx.index
|
||||
symbol = ctx.parseSymbol(start)
|
||||
|
||||
if symbol in self.symbols:
|
||||
ctx.replaceRange(start, start + len(symbol), self.symbols[symbol])
|
||||
continue
|
||||
|
||||
ctx.advance()
|
||||
|
||||
return ctx.data
|
||||
|
||||
def addSymbol(self, symbol, macro):
|
||||
if symbol in self.symbols:
|
||||
self.error("Symbol '" + symbol + "' redefinition.")
|
||||
else:
|
||||
# Recurse.
|
||||
macro = self.process(macro)
|
||||
|
||||
log("-- @define " + symbol + " " + macro)
|
||||
self.symbols[symbol] = macro
|
||||
|
||||
def error(self, msg):
|
||||
raise SyntaxError(msg)
|
||||
|
||||
# =============================================================================
|
||||
# [LoadFile / SaveFile]
|
||||
# =============================================================================
|
||||
|
||||
def loadFile(file):
|
||||
h = None
|
||||
data = None
|
||||
|
||||
try:
|
||||
h = open(file, "rb")
|
||||
data = h.read()
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
if h:
|
||||
h.close()
|
||||
|
||||
return data
|
||||
|
||||
def saveFile(file, data):
|
||||
h = None
|
||||
result = False
|
||||
|
||||
try:
|
||||
h = open(file, "wb")
|
||||
h.truncate()
|
||||
h.write(data)
|
||||
result = True
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
if h:
|
||||
h.close()
|
||||
|
||||
return result
|
||||
|
||||
# =============================================================================
|
||||
# [PatchFile]
|
||||
# =============================================================================
|
||||
|
||||
def patchFile(file, mark, data):
|
||||
input = loadFile(file)
|
||||
if not input:
|
||||
return
|
||||
|
||||
beginMark = ";${" + mark + ":Begin}"
|
||||
endMark = ";${" + mark + ":End}"
|
||||
|
||||
if beginMark in input:
|
||||
# Replace.
|
||||
if not endMark in input:
|
||||
log("-- Corrupted File:\n" + " " + file)
|
||||
return
|
||||
|
||||
beginMarkIndex = input.find(beginMark)
|
||||
endMarkIndex = input.find(endMark)
|
||||
|
||||
beginMarkIndex = input.find('\n', beginMarkIndex) + 1
|
||||
endMarkIndex = input.rfind('\n', 0, endMarkIndex) + 1
|
||||
|
||||
if beginMarkIndex == -1 or \
|
||||
endMarkIndex == -1 or \
|
||||
beginMarkIndex > endMarkIndex:
|
||||
log("-- Corrupted File:\n" + " " + file)
|
||||
return
|
||||
|
||||
output = input[:beginMarkIndex] + data + input[endMarkIndex:]
|
||||
|
||||
else:
|
||||
# Add.
|
||||
output = input
|
||||
output += "\n"
|
||||
output += beginMark + "\n"
|
||||
output += data
|
||||
output += endMark + "\n"
|
||||
|
||||
if input == output:
|
||||
log("-- Unaffected:\n" + " " + file)
|
||||
else:
|
||||
log("-- Patching:\n" + " " + file)
|
||||
if not saveFile(file, output):
|
||||
log("!! Can't write:\n" + " " + file)
|
||||
|
||||
def main():
|
||||
src = loadFile("autoexp.dat")
|
||||
if src == None:
|
||||
log("!! Can't read autoexp.dat")
|
||||
return
|
||||
|
||||
src = AutoExpDat(src)
|
||||
if not src.library:
|
||||
log("!! Library not defined, use @library directive.")
|
||||
return
|
||||
|
||||
for file in AUTOEXP_FILES:
|
||||
patchFile(file, src.library, src.data)
|
||||
|
||||
main()
|
||||
922
tools/autoexp.dat
Normal file
922
tools/autoexp.dat
Normal file
@@ -0,0 +1,922 @@
|
||||
@library asmjit
|
||||
@
|
||||
@define NULL (0)
|
||||
@
|
||||
@define asmjit::kInvalidValue (0xFFFFFFFF)
|
||||
@
|
||||
@define asmjit::kOperandTypeNone (0x0)
|
||||
@define asmjit::kOperandTypeReg (0x1)
|
||||
@define asmjit::kOperandTypeVar (0x2)
|
||||
@define asmjit::kOperandTypeMem (0x3)
|
||||
@define asmjit::kOperandTypeImm (0x4)
|
||||
@define asmjit::kOperandTypeLabel (0x5)
|
||||
@
|
||||
@define asmjit::kMemTypeBaseIndex (0x0)
|
||||
@define asmjit::kMemTypeStackIndex (0x1)
|
||||
@define asmjit::kMemTypeLabel (0x2)
|
||||
@define asmjit::kMemTypeAbsolute (0x3)
|
||||
@
|
||||
@define asmjit::kVarAttrInReg (0x00000001)
|
||||
@define asmjit::kVarAttrOutReg (0x00000002)
|
||||
@define asmjit::kVarAttrInOutReg (0x00000003)
|
||||
@define asmjit::kVarAttrInMem (0x00000004)
|
||||
@define asmjit::kVarAttrOutMem (0x00000008)
|
||||
@define asmjit::kVarAttrInOutMem (0x0000000C)
|
||||
@define asmjit::kVarAttrInDecide (0x00000010)
|
||||
@define asmjit::kVarAttrOutDecide (0x00000020)
|
||||
@define asmjit::kVarAttrInOutDecide (0x00000030)
|
||||
@define asmjit::kVarAttrInConv (0x00000040)
|
||||
@define asmjit::kVarAttrOutConv (0x00000080)
|
||||
@define asmjit::kVarAttrInOutConv (0x000000C0)
|
||||
@define asmjit::kVarAttrInCall (0x00000100)
|
||||
@define asmjit::kVarAttrInArg (0x00000200)
|
||||
@define asmjit::kVarAttrInStack (0x00000400)
|
||||
@define asmjit::kVarAttrOutRet (0x00000800)
|
||||
@define asmjit::kVarAttrUnuse (0x00001000)
|
||||
@
|
||||
@define asmjit::kVarTypeInt8 (0x0)
|
||||
@define asmjit::kVarTypeUInt8 (0x1)
|
||||
@define asmjit::kVarTypeInt16 (0x2)
|
||||
@define asmjit::kVarTypeUInt16 (0x3)
|
||||
@define asmjit::kVarTypeInt32 (0x4)
|
||||
@define asmjit::kVarTypeUInt32 (0x5)
|
||||
@define asmjit::kVarTypeInt64 (0x6)
|
||||
@define asmjit::kVarTypeUInt64 (0x7)
|
||||
@define asmjit::kVarTypeFp32 (0x8)
|
||||
@define asmjit::kVarTypeFp64 (0x9)
|
||||
@define asmjit::kVarTypeFpEx (0xA)
|
||||
@define asmjit::kVarTypeInvalid (0xFF)
|
||||
@
|
||||
@define asmjit::x86x64::kVarTypeMm (0xB)
|
||||
@define asmjit::x86x64::kVarTypeXmm (0xC)
|
||||
@define asmjit::x86x64::kVarTypeXmmSs (0xD)
|
||||
@define asmjit::x86x64::kVarTypeXmmPs (0xE)
|
||||
@define asmjit::x86x64::kVarTypeXmmSd (0xF)
|
||||
@define asmjit::x86x64::kVarTypeXmmPd (0x10)
|
||||
@
|
||||
@define asmjit::kVarStateUnused (0x0)
|
||||
@define asmjit::kVarStateReg (0x1)
|
||||
@define asmjit::kVarStateMem (0x2)
|
||||
@
|
||||
@define asmjit::kNodeTypeNone (0x0)
|
||||
@define asmjit::kNodeTypeAlign (0x1)
|
||||
@define asmjit::kNodeTypeEmbed (0x2)
|
||||
@define asmjit::kNodeTypeComment (0x3)
|
||||
@define asmjit::kNodeTypeMark (0x4)
|
||||
@define asmjit::kNodeTypeHint (0x5)
|
||||
@define asmjit::kNodeTypeTarget (0x6)
|
||||
@define asmjit::kNodeTypeInst (0x7)
|
||||
@define asmjit::kNodeTypeFunc (0x8)
|
||||
@define asmjit::kNodeTypeEnd (0x9)
|
||||
@define asmjit::kNodeTypeRet (0xA)
|
||||
@define asmjit::kNodeTypeCall (0xB)
|
||||
@
|
||||
@define asmjit::kNodeFlagIsTranslated (0x0001)
|
||||
@define asmjit::kNodeFlagIsJmp (0x0002)
|
||||
@define asmjit::kNodeFlagIsJcc (0x0004)
|
||||
@define asmjit::kNodeFlagIsTaken (0x0008)
|
||||
@define asmjit::kNodeFlagIsRet (0x0010)
|
||||
@define asmjit::kNodeFlagIsSpecial (0x0020)
|
||||
@define asmjit::kNodeFlagIsFp (0x0040)
|
||||
|
||||
[Visualizer]
|
||||
|
||||
; =============================================================================
|
||||
; [asmjit::base]
|
||||
; =============================================================================
|
||||
|
||||
asmjit::PodVector<*> {
|
||||
preview(
|
||||
#(
|
||||
"[", $e._length, "]",
|
||||
"(",
|
||||
#array(
|
||||
expr: ((($T1*)($e._d + 1))[$i]),
|
||||
size: $e._d->length
|
||||
),
|
||||
")"
|
||||
)
|
||||
)
|
||||
|
||||
children(
|
||||
#(
|
||||
#([...]: [$c,!]),
|
||||
|
||||
#array(
|
||||
expr: ((($T1*)($e._d + 1))[$i]),
|
||||
size: $e._d->length
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
; =============================================================================
|
||||
; [asmjit::x86x64 - Operand]
|
||||
; =============================================================================
|
||||
|
||||
asmjit::Operand {
|
||||
preview(
|
||||
#(
|
||||
#if ($e._base.op == asmjit::kOperandTypeReg) ([(*(asmjit::BaseReg *) &$e)])
|
||||
#elif ($e._base.op == asmjit::kOperandTypeVar) ([(*(asmjit::BaseVar *) &$e)])
|
||||
#elif ($e._base.op == asmjit::kOperandTypeMem) ([(*(asmjit::BaseMem *) &$e)])
|
||||
#elif ($e._base.op == asmjit::kOperandTypeImm) ([(*(asmjit::Imm *) &$e)])
|
||||
#elif ($e._base.op == asmjit::kOperandTypeLabel) ([(*(asmjit::Label *) &$e)])
|
||||
#else ("noOperand")
|
||||
)
|
||||
)
|
||||
|
||||
children(
|
||||
#(
|
||||
#([...]: [$c,!]),
|
||||
#(base: [$e._base]),
|
||||
#(reg: [(*(asmjit::BaseReg*) &$e)]),
|
||||
#(var: [(*(asmjit::BaseVar*) &$e)]),
|
||||
#(mem: [(*(asmjit::BaseMem*) &$e)]),
|
||||
#(imm: [(*(asmjit::Imm*) &$e)]),
|
||||
#(label: [(*(asmjit::Label*) &$e)])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
asmjit::BaseReg|asmjit::x86x64::X86Reg|asmjit::x86x64::GpReg|asmjit::x86x64::FpReg|asmjit::x86x64::MmReg|asmjit::x86x64::XmmReg|asmjit::x86x64::SegReg {
|
||||
preview(
|
||||
#(
|
||||
#if ($e._reg.code == 0x0100) ("al")
|
||||
#elif ($e._reg.code == 0x0101) ("cl")
|
||||
#elif ($e._reg.code == 0x0102) ("dl")
|
||||
#elif ($e._reg.code == 0x0103) ("bl")
|
||||
#elif ($e._reg.code == 0x0104) ("spl")
|
||||
#elif ($e._reg.code == 0x0105) ("bpl")
|
||||
#elif ($e._reg.code == 0x0106) ("sil")
|
||||
#elif ($e._reg.code == 0x0107) ("dil")
|
||||
#elif ($e._reg.code == 0x0108) ("r8b")
|
||||
#elif ($e._reg.code == 0x0109) ("r9b")
|
||||
#elif ($e._reg.code == 0x010A) ("r10b")
|
||||
#elif ($e._reg.code == 0x010B) ("r11b")
|
||||
#elif ($e._reg.code == 0x010C) ("r12b")
|
||||
#elif ($e._reg.code == 0x010D) ("r13b")
|
||||
#elif ($e._reg.code == 0x010E) ("r14b")
|
||||
#elif ($e._reg.code == 0x010F) ("r15b")
|
||||
|
||||
#elif ($e._reg.code == 0x0200) ("ah")
|
||||
#elif ($e._reg.code == 0x0201) ("ch")
|
||||
#elif ($e._reg.code == 0x0202) ("dh")
|
||||
#elif ($e._reg.code == 0x0203) ("bh")
|
||||
|
||||
#elif ($e._reg.code == 0x1000) ("ax")
|
||||
#elif ($e._reg.code == 0x1001) ("cx")
|
||||
#elif ($e._reg.code == 0x1002) ("dx")
|
||||
#elif ($e._reg.code == 0x1003) ("bx")
|
||||
#elif ($e._reg.code == 0x1004) ("sp")
|
||||
#elif ($e._reg.code == 0x1005) ("bp")
|
||||
#elif ($e._reg.code == 0x1006) ("si")
|
||||
#elif ($e._reg.code == 0x1007) ("di")
|
||||
#elif ($e._reg.code == 0x1008) ("r8w")
|
||||
#elif ($e._reg.code == 0x1009) ("r9w")
|
||||
#elif ($e._reg.code == 0x100A) ("r10w")
|
||||
#elif ($e._reg.code == 0x100B) ("r11w")
|
||||
#elif ($e._reg.code == 0x100C) ("r12w")
|
||||
#elif ($e._reg.code == 0x100D) ("r13w")
|
||||
#elif ($e._reg.code == 0x100E) ("r14w")
|
||||
#elif ($e._reg.code == 0x100F) ("r15w")
|
||||
|
||||
#elif ($e._reg.code == 0x2000) ("eax")
|
||||
#elif ($e._reg.code == 0x2001) ("ecx")
|
||||
#elif ($e._reg.code == 0x2002) ("edx")
|
||||
#elif ($e._reg.code == 0x2003) ("ebx")
|
||||
#elif ($e._reg.code == 0x2004) ("esp")
|
||||
#elif ($e._reg.code == 0x2005) ("ebp")
|
||||
#elif ($e._reg.code == 0x2006) ("esi")
|
||||
#elif ($e._reg.code == 0x2007) ("edi")
|
||||
#elif ($e._reg.code == 0x2008) ("r8d")
|
||||
#elif ($e._reg.code == 0x2009) ("r9d")
|
||||
#elif ($e._reg.code == 0x200A) ("r10d")
|
||||
#elif ($e._reg.code == 0x200B) ("r11d")
|
||||
#elif ($e._reg.code == 0x200C) ("r12d")
|
||||
#elif ($e._reg.code == 0x200D) ("r13d")
|
||||
#elif ($e._reg.code == 0x200E) ("r14d")
|
||||
#elif ($e._reg.code == 0x200F) ("r15d")
|
||||
|
||||
#elif ($e._reg.code == 0x3000) ("rax")
|
||||
#elif ($e._reg.code == 0x3001) ("rcx")
|
||||
#elif ($e._reg.code == 0x3002) ("rdx")
|
||||
#elif ($e._reg.code == 0x3003) ("rbx")
|
||||
#elif ($e._reg.code == 0x3004) ("rsp")
|
||||
#elif ($e._reg.code == 0x3005) ("rbp")
|
||||
#elif ($e._reg.code == 0x3006) ("rsi")
|
||||
#elif ($e._reg.code == 0x3007) ("rdi")
|
||||
#elif ($e._reg.code == 0x3008) ("r8")
|
||||
#elif ($e._reg.code == 0x3009) ("r9")
|
||||
#elif ($e._reg.code == 0x300A) ("r10")
|
||||
#elif ($e._reg.code == 0x300B) ("r11")
|
||||
#elif ($e._reg.code == 0x300C) ("r12")
|
||||
#elif ($e._reg.code == 0x300D) ("r13")
|
||||
#elif ($e._reg.code == 0x300E) ("r14")
|
||||
#elif ($e._reg.code == 0x300F) ("r15")
|
||||
|
||||
#elif ($e._reg.code == 0x5000) ("fp0")
|
||||
#elif ($e._reg.code == 0x5001) ("fp1")
|
||||
#elif ($e._reg.code == 0x5002) ("fp2")
|
||||
#elif ($e._reg.code == 0x5003) ("fp3")
|
||||
#elif ($e._reg.code == 0x5004) ("fp4")
|
||||
#elif ($e._reg.code == 0x5005) ("fp5")
|
||||
#elif ($e._reg.code == 0x5006) ("fp6")
|
||||
#elif ($e._reg.code == 0x5007) ("fp7")
|
||||
|
||||
#elif ($e._reg.code == 0x6000) ("mm0")
|
||||
#elif ($e._reg.code == 0x6001) ("mm1")
|
||||
#elif ($e._reg.code == 0x6002) ("mm2")
|
||||
#elif ($e._reg.code == 0x6003) ("mm3")
|
||||
#elif ($e._reg.code == 0x6004) ("mm4")
|
||||
#elif ($e._reg.code == 0x6005) ("mm5")
|
||||
#elif ($e._reg.code == 0x6006) ("mm6")
|
||||
#elif ($e._reg.code == 0x6007) ("mm7")
|
||||
|
||||
#elif ($e._reg.code == 0x7000) ("xmm0")
|
||||
#elif ($e._reg.code == 0x7001) ("xmm1")
|
||||
#elif ($e._reg.code == 0x7002) ("xmm2")
|
||||
#elif ($e._reg.code == 0x7003) ("xmm3")
|
||||
#elif ($e._reg.code == 0x7004) ("xmm4")
|
||||
#elif ($e._reg.code == 0x7005) ("xmm5")
|
||||
#elif ($e._reg.code == 0x7006) ("xmm6")
|
||||
#elif ($e._reg.code == 0x7007) ("xmm7")
|
||||
#elif ($e._reg.code == 0x7008) ("xmm8")
|
||||
#elif ($e._reg.code == 0x7009) ("xmm9")
|
||||
#elif ($e._reg.code == 0x700A) ("xmm10")
|
||||
#elif ($e._reg.code == 0x700B) ("xmm11")
|
||||
#elif ($e._reg.code == 0x700C) ("xmm12")
|
||||
#elif ($e._reg.code == 0x700D) ("xmm13")
|
||||
#elif ($e._reg.code == 0x700E) ("xmm14")
|
||||
#elif ($e._reg.code == 0x700F) ("xmm15")
|
||||
|
||||
#elif ($e._reg.code == 0x8000) ("ymm0")
|
||||
#elif ($e._reg.code == 0x8001) ("ymm1")
|
||||
#elif ($e._reg.code == 0x8002) ("ymm2")
|
||||
#elif ($e._reg.code == 0x8003) ("ymm3")
|
||||
#elif ($e._reg.code == 0x8004) ("ymm4")
|
||||
#elif ($e._reg.code == 0x8005) ("ymm5")
|
||||
#elif ($e._reg.code == 0x8006) ("ymm6")
|
||||
#elif ($e._reg.code == 0x8007) ("ymm7")
|
||||
#elif ($e._reg.code == 0x8008) ("ymm8")
|
||||
#elif ($e._reg.code == 0x8009) ("ymm9")
|
||||
#elif ($e._reg.code == 0x800A) ("ymm10")
|
||||
#elif ($e._reg.code == 0x800B) ("ymm11")
|
||||
#elif ($e._reg.code == 0x800C) ("ymm12")
|
||||
#elif ($e._reg.code == 0x800D) ("ymm13")
|
||||
#elif ($e._reg.code == 0x800E) ("ymm14")
|
||||
#elif ($e._reg.code == 0x800F) ("ymm15")
|
||||
|
||||
#elif ($e._reg.code == 0xD000) ("es")
|
||||
#elif ($e._reg.code == 0xD001) ("cs")
|
||||
#elif ($e._reg.code == 0xD002) ("ss")
|
||||
#elif ($e._reg.code == 0xD003) ("ds")
|
||||
#elif ($e._reg.code == 0xD004) ("fs")
|
||||
#elif ($e._reg.code == 0xD005) ("gs")
|
||||
|
||||
#else ("noReg")
|
||||
)
|
||||
)
|
||||
|
||||
children(
|
||||
#(
|
||||
#([...]: [$c,!]),
|
||||
#(op: [$e._reg.op, x]),
|
||||
#(size: [$e._reg.size, u]),
|
||||
#(code: [$e._reg.code, x])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
asmjit::BaseVar|asmjit::x86x64::X86Var|asmjit::x86x64::GpVar|asmjit::x86x64::FpVar|asmjit::x86x64::MmVar|asmjit::x86x64::XmmVar {
|
||||
preview(
|
||||
#(
|
||||
#if ($e._var.varType == asmjit::kVarTypeInt8) ("gpbLo")
|
||||
#elif ($e._var.varType == asmjit::kVarTypeUInt8) ("gpbLo")
|
||||
#elif ($e._var.varType == asmjit::kVarTypeInt16) ("gpw")
|
||||
#elif ($e._var.varType == asmjit::kVarTypeUInt16) ("gpw")
|
||||
#elif ($e._var.varType == asmjit::kVarTypeInt32) ("gpd")
|
||||
#elif ($e._var.varType == asmjit::kVarTypeUInt32) ("gpd")
|
||||
#elif ($e._var.varType == asmjit::kVarTypeInt64) ("gpq")
|
||||
#elif ($e._var.varType == asmjit::kVarTypeUInt64) ("gpq")
|
||||
#elif ($e._var.varType == asmjit::kVarTypeFp32) ("fp32")
|
||||
#elif ($e._var.varType == asmjit::kVarTypeFp64) ("fp64")
|
||||
#elif ($e._var.varType == asmjit::kVarTypeFpEx) ("fpEx")
|
||||
#elif ($e._var.varType == asmjit::x86x64::kVarTypeMm) ("mm")
|
||||
#elif ($e._var.varType == asmjit::x86x64::kVarTypeXmm) ("xmm")
|
||||
#elif ($e._var.varType == asmjit::x86x64::kVarTypeXmmSs) ("xmmSs")
|
||||
#elif ($e._var.varType == asmjit::x86x64::kVarTypeXmmSd) ("xmmSd")
|
||||
#elif ($e._var.varType == asmjit::x86x64::kVarTypeXmmPs) ("xmmPs")
|
||||
#elif ($e._var.varType == asmjit::x86x64::kVarTypeXmmPd) ("xmmPd")
|
||||
#elif ($e._var.varType == asmjit::x86x64::kVarTypeYmm) ("ymm")
|
||||
#elif ($e._var.varType == asmjit::x86x64::kVarTypeYmmPs) ("ymmPs")
|
||||
#elif ($e._var.varType == asmjit::x86x64::kVarTypeYmmPd) ("ymmPd")
|
||||
#else ("noVar"),
|
||||
"(",
|
||||
"id=",
|
||||
#if ($e._var.id != asmjit::kInvalidValue) (
|
||||
[$e._var.id, x]
|
||||
)
|
||||
#else (
|
||||
"INVALID"
|
||||
),
|
||||
")"
|
||||
)
|
||||
)
|
||||
|
||||
children(
|
||||
#(
|
||||
#([...]: [$c,!]),
|
||||
#(op: [$e._var.op, x]),
|
||||
#(size: [$e._var.size, u]),
|
||||
#(id: [$e._var.id, x]),
|
||||
#(code: [$e._var.code, x]),
|
||||
#(varType: [$e._var.varType, x])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
asmjit::BaseMem|asmjit::x86x64::Mem {
|
||||
preview(
|
||||
#(
|
||||
#if ($e._mem.size == 1) ("byte ptr")
|
||||
#elif ($e._mem.size == 2) ("word ptr")
|
||||
#elif ($e._mem.size == 4) ("dword ptr")
|
||||
#elif ($e._mem.size == 8) ("qword ptr")
|
||||
#elif ($e._mem.size == 10) ("tword ptr")
|
||||
#elif ($e._mem.size == 16) ("dqword ptr")
|
||||
#elif ($e._mem.size == 32) ("qqword ptr")
|
||||
#else ("ptr"),
|
||||
|
||||
#if ($e._mem.segment == 0) (" es:")
|
||||
#elif ($e._mem.segment == 1) (" cs:")
|
||||
#elif ($e._mem.segment == 2) (" ss:")
|
||||
#elif ($e._mem.segment == 3) (" ds:")
|
||||
#elif ($e._mem.segment == 4) (" fs:")
|
||||
#elif ($e._mem.segment == 5) (" gs:")
|
||||
#else (""),
|
||||
|
||||
"[",
|
||||
|
||||
#if ($e._mem.id == asmjit::kInvalidValue) (
|
||||
#(
|
||||
#if ($e._mem.type == asmjit::kMemTypeBaseIndex) (
|
||||
#if ((sizeof(uintptr_t) == 4) && ($e._mem.sizePrefix == 1)) (
|
||||
#if (($e._mem.base & 0xFF) == 0x0) ("ax")
|
||||
#elif (($e._mem.base & 0xFF) == 0x1) ("cx")
|
||||
#elif (($e._mem.base & 0xFF) == 0x2) ("dx")
|
||||
#elif (($e._mem.base & 0xFF) == 0x3) ("bx")
|
||||
#elif (($e._mem.base & 0xFF) == 0x4) ("sp")
|
||||
#elif (($e._mem.base & 0xFF) == 0x5) ("bp")
|
||||
#elif (($e._mem.base & 0xFF) == 0x6) ("si")
|
||||
#elif (($e._mem.base & 0xFF) == 0x7) ("di")
|
||||
#elif (($e._mem.base & 0xFF) == 0x8) ("r8w")
|
||||
#elif (($e._mem.base & 0xFF) == 0x9) ("r9w")
|
||||
#elif (($e._mem.base & 0xFF) == 0xA) ("r10w")
|
||||
#elif (($e._mem.base & 0xFF) == 0xB) ("r11w")
|
||||
#elif (($e._mem.base & 0xFF) == 0xC) ("r12w")
|
||||
#elif (($e._mem.base & 0xFF) == 0xD) ("r13w")
|
||||
#elif (($e._mem.base & 0xFF) == 0xE) ("r14w")
|
||||
#elif (($e._mem.base & 0xFF) == 0xF) ("r15w")
|
||||
#else ("INVALID")
|
||||
)
|
||||
#elif ((sizeof(uintptr_t) == 4) || ($e._mem.sizePrefix == 1)) (
|
||||
#if (($e._mem.base & 0xFF) == 0x0) ("eax")
|
||||
#elif (($e._mem.base & 0xFF) == 0x1) ("ecx")
|
||||
#elif (($e._mem.base & 0xFF) == 0x2) ("edx")
|
||||
#elif (($e._mem.base & 0xFF) == 0x3) ("ebx")
|
||||
#elif (($e._mem.base & 0xFF) == 0x4) ("esp")
|
||||
#elif (($e._mem.base & 0xFF) == 0x5) ("ebp")
|
||||
#elif (($e._mem.base & 0xFF) == 0x6) ("esi")
|
||||
#elif (($e._mem.base & 0xFF) == 0x7) ("edi")
|
||||
#elif (($e._mem.base & 0xFF) == 0x8) ("r8d")
|
||||
#elif (($e._mem.base & 0xFF) == 0x9) ("r9d")
|
||||
#elif (($e._mem.base & 0xFF) == 0xA) ("r10d")
|
||||
#elif (($e._mem.base & 0xFF) == 0xB) ("r11d")
|
||||
#elif (($e._mem.base & 0xFF) == 0xC) ("r12d")
|
||||
#elif (($e._mem.base & 0xFF) == 0xD) ("r13d")
|
||||
#elif (($e._mem.base & 0xFF) == 0xE) ("r14d")
|
||||
#elif (($e._mem.base & 0xFF) == 0xF) ("r15d")
|
||||
#else ("INVALID")
|
||||
)
|
||||
#else (
|
||||
#if (($e._mem.base & 0xFF) == 0x0) ("rax")
|
||||
#elif (($e._mem.base & 0xFF) == 0x1) ("rcx")
|
||||
#elif (($e._mem.base & 0xFF) == 0x2) ("rdx")
|
||||
#elif (($e._mem.base & 0xFF) == 0x3) ("rbx")
|
||||
#elif (($e._mem.base & 0xFF) == 0x4) ("rsp")
|
||||
#elif (($e._mem.base & 0xFF) == 0x5) ("rbp")
|
||||
#elif (($e._mem.base & 0xFF) == 0x6) ("rsi")
|
||||
#elif (($e._mem.base & 0xFF) == 0x7) ("rdi")
|
||||
#elif (($e._mem.base & 0xFF) == 0x8) ("r8")
|
||||
#elif (($e._mem.base & 0xFF) == 0x9) ("r9")
|
||||
#elif (($e._mem.base & 0xFF) == 0xA) ("r10")
|
||||
#elif (($e._mem.base & 0xFF) == 0xB) ("r11")
|
||||
#elif (($e._mem.base & 0xFF) == 0xC) ("r12")
|
||||
#elif (($e._mem.base & 0xFF) == 0xD) ("r13")
|
||||
#elif (($e._mem.base & 0xFF) == 0xE) ("r14")
|
||||
#elif (($e._mem.base & 0xFF) == 0xF) ("r15")
|
||||
#else ("INVALID")
|
||||
)
|
||||
)
|
||||
#elif ($e._mem.type == asmjit::kMemTypeLabel) (
|
||||
#(
|
||||
"L.",
|
||||
#if ($e._mem.base != asmjit::kInvalidValue) (
|
||||
[$e._mem.base & 0x3FFFFFFF, x]
|
||||
)
|
||||
#else (
|
||||
"INVALID"
|
||||
)
|
||||
)
|
||||
)
|
||||
#else (
|
||||
[$e._mem.target]
|
||||
)
|
||||
)
|
||||
)
|
||||
#else (
|
||||
#("{id=", [$e._mem.id, x], "}")
|
||||
),
|
||||
|
||||
#if ($e._mem.index != asmjit::kInvalidValue) (
|
||||
#(
|
||||
" + ",
|
||||
|
||||
#if ((sizeof(uintptr_t) == 4) && ($e._mem.sizePrefix == 1)) (
|
||||
#if (($e._mem.index & 0xFF) == 0x0) ("ax")
|
||||
#elif (($e._mem.index & 0xFF) == 0x1) ("cx")
|
||||
#elif (($e._mem.index & 0xFF) == 0x2) ("dx")
|
||||
#elif (($e._mem.index & 0xFF) == 0x3) ("bx")
|
||||
#elif (($e._mem.index & 0xFF) == 0x4) ("sp")
|
||||
#elif (($e._mem.index & 0xFF) == 0x5) ("bp")
|
||||
#elif (($e._mem.index & 0xFF) == 0x6) ("si")
|
||||
#elif (($e._mem.index & 0xFF) == 0x7) ("di")
|
||||
#elif (($e._mem.index & 0xFF) == 0x8) ("r8w")
|
||||
#elif (($e._mem.index & 0xFF) == 0x9) ("r9w")
|
||||
#elif (($e._mem.index & 0xFF) == 0xA) ("r10w")
|
||||
#elif (($e._mem.index & 0xFF) == 0xB) ("r11w")
|
||||
#elif (($e._mem.index & 0xFF) == 0xC) ("r12w")
|
||||
#elif (($e._mem.index & 0xFF) == 0xD) ("r13w")
|
||||
#elif (($e._mem.index & 0xFF) == 0xE) ("r14w")
|
||||
#elif (($e._mem.index & 0xFF) == 0xF) ("r15w")
|
||||
#else ("INVALID")
|
||||
)
|
||||
#elif ((sizeof(uintptr_t) == 4) || ($e._mem.sizePrefix == 1)) (
|
||||
#if (($e._mem.index & 0xFF) == 0x0) ("eax")
|
||||
#elif (($e._mem.index & 0xFF) == 0x1) ("ecx")
|
||||
#elif (($e._mem.index & 0xFF) == 0x2) ("edx")
|
||||
#elif (($e._mem.index & 0xFF) == 0x3) ("ebx")
|
||||
#elif (($e._mem.index & 0xFF) == 0x4) ("esp")
|
||||
#elif (($e._mem.index & 0xFF) == 0x5) ("ebp")
|
||||
#elif (($e._mem.index & 0xFF) == 0x6) ("esi")
|
||||
#elif (($e._mem.index & 0xFF) == 0x7) ("edi")
|
||||
#elif (($e._mem.index & 0xFF) == 0x8) ("r8d")
|
||||
#elif (($e._mem.index & 0xFF) == 0x9) ("r9d")
|
||||
#elif (($e._mem.index & 0xFF) == 0xA) ("r10d")
|
||||
#elif (($e._mem.index & 0xFF) == 0xB) ("r11d")
|
||||
#elif (($e._mem.index & 0xFF) == 0xC) ("r12d")
|
||||
#elif (($e._mem.index & 0xFF) == 0xD) ("r13d")
|
||||
#elif (($e._mem.index & 0xFF) == 0xE) ("r14d")
|
||||
#elif (($e._mem.index & 0xFF) == 0xF) ("r15d")
|
||||
#else ("INVALID")
|
||||
)
|
||||
#else (
|
||||
#if (($e._mem.index & 0xFF) == 0x0) ("rax")
|
||||
#elif (($e._mem.index & 0xFF) == 0x1) ("rcx")
|
||||
#elif (($e._mem.index & 0xFF) == 0x2) ("rdx")
|
||||
#elif (($e._mem.index & 0xFF) == 0x3) ("rbx")
|
||||
#elif (($e._mem.index & 0xFF) == 0x4) ("rsp")
|
||||
#elif (($e._mem.index & 0xFF) == 0x5) ("rbp")
|
||||
#elif (($e._mem.index & 0xFF) == 0x6) ("rsi")
|
||||
#elif (($e._mem.index & 0xFF) == 0x7) ("rdi")
|
||||
#elif (($e._mem.index & 0xFF) == 0x8) ("r8")
|
||||
#elif (($e._mem.index & 0xFF) == 0x9) ("r9")
|
||||
#elif (($e._mem.index & 0xFF) == 0xA) ("r10")
|
||||
#elif (($e._mem.index & 0xFF) == 0xB) ("r11")
|
||||
#elif (($e._mem.index & 0xFF) == 0xC) ("r12")
|
||||
#elif (($e._mem.index & 0xFF) == 0xD) ("r13")
|
||||
#elif (($e._mem.index & 0xFF) == 0xE) ("r14")
|
||||
#elif (($e._mem.index & 0xFF) == 0xF) ("r15")
|
||||
#else ("INVALID")
|
||||
),
|
||||
|
||||
#if ($e._mem.shift == 1) (" * 2")
|
||||
#elif ($e._mem.shift == 2) (" * 4")
|
||||
#elif ($e._mem.shift == 3) (" * 8")
|
||||
#else ("")
|
||||
)
|
||||
),
|
||||
|
||||
#if (($e._mem.type != asmjit::kMemTypeAbsolute) && ($e._mem.displacement != 0)) (
|
||||
#if ($e._mem.displacement < 0) (
|
||||
#(" - ", [-$e._mem.displacement, i])
|
||||
)
|
||||
#else (
|
||||
#(" + ", [$e._mem.displacement, i])
|
||||
)
|
||||
),
|
||||
|
||||
"]"
|
||||
)
|
||||
)
|
||||
|
||||
children(
|
||||
#(
|
||||
#([...]: [$c,!]),
|
||||
|
||||
#(op: [$e._mem.op, x]),
|
||||
#(size: [$e._mem.size, u]),
|
||||
|
||||
#(type: [$e._mem.type, u]),
|
||||
#(segment: [$e._mem.segment, u]),
|
||||
|
||||
#(sizePrefix: [$e._mem.sizePrefix, u]),
|
||||
#(shift: [$e._mem.shift, u]),
|
||||
|
||||
#(id: [$e._mem.id, x]),
|
||||
#(base: [$e._mem.base, u]),
|
||||
#(index: [$e._mem.index, u]),
|
||||
|
||||
#(target: [$e._mem.target]),
|
||||
#(displacement: [$e._mem.displacement, i])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
asmjit::Imm {
|
||||
preview(
|
||||
#(
|
||||
"i=", [(int64_t)$e._imm.value, i],
|
||||
" ",
|
||||
"u=", [(uint64_t)$e._imm.value, u],
|
||||
" ",
|
||||
"x=", [(uint64_t)$e._imm.value, x]
|
||||
)
|
||||
)
|
||||
|
||||
children(
|
||||
#(
|
||||
#([...]: [$c,!]),
|
||||
|
||||
#(op: [$e._imm.op, x]),
|
||||
#(size: [$e._imm.size, u]),
|
||||
|
||||
#(value_s: [(int64_t)$e._imm.value, i]),
|
||||
#(value_u: [(uint64_t)$e._imm.value, u]),
|
||||
#(value_x: [(uint64_t)$e._imm.value, x])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
asmjit::Label {
|
||||
preview(
|
||||
#(
|
||||
"L_",
|
||||
#if ($e._label.id != asmjit::kInvalidValue) (
|
||||
[$e._label.id, x]
|
||||
)
|
||||
#else (
|
||||
"INVALID"
|
||||
),
|
||||
""
|
||||
)
|
||||
)
|
||||
|
||||
children(
|
||||
#(
|
||||
#([...]: [$c,!]),
|
||||
|
||||
#(op: [$e._label.op, x]),
|
||||
#(size: [$e._label.size, u]),
|
||||
|
||||
#(id: [$e._label.id, x])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
; =============================================================================
|
||||
; [asmjit::x86x64 - RegMask]
|
||||
; =============================================================================
|
||||
|
||||
asmjit::x86x64::RegMask {
|
||||
preview(
|
||||
#(
|
||||
#if (($e._gp | $e._fp | $e._mm | $e._xy) != 0) (
|
||||
#(
|
||||
#if ($e._gp != 0) (
|
||||
#(
|
||||
"gp=", [$e._gp, x],
|
||||
#if ($e._gp & 0x0001) ("|rax"),
|
||||
#if ($e._gp & 0x0002) ("|rcx"),
|
||||
#if ($e._gp & 0x0004) ("|rdx"),
|
||||
#if ($e._gp & 0x0008) ("|rbx"),
|
||||
#if ($e._gp & 0x0010) ("|rsp"),
|
||||
#if ($e._gp & 0x0020) ("|rbp"),
|
||||
#if ($e._gp & 0x0040) ("|rsi"),
|
||||
#if ($e._gp & 0x0080) ("|rdi"),
|
||||
#if ($e._gp & 0x0100) ("|r8"),
|
||||
#if ($e._gp & 0x0200) ("|r9"),
|
||||
#if ($e._gp & 0x0400) ("|r10"),
|
||||
#if ($e._gp & 0x0800) ("|r11"),
|
||||
#if ($e._gp & 0x1000) ("|r12"),
|
||||
#if ($e._gp & 0x2000) ("|r13"),
|
||||
#if ($e._gp & 0x4000) ("|r14"),
|
||||
#if ($e._gp & 0x8000) ("|r15"),
|
||||
#if (($e._fp | $e._mm | $e._xy) != 0) (" ")
|
||||
)
|
||||
),
|
||||
|
||||
#if ($e._fp != 0) (
|
||||
#(
|
||||
"fp=", [$e._fp, x],
|
||||
#if ($e._fp & 0x0001) ("|fp0"),
|
||||
#if ($e._fp & 0x0002) ("|fp1"),
|
||||
#if ($e._fp & 0x0004) ("|fp2"),
|
||||
#if ($e._fp & 0x0008) ("|fp3"),
|
||||
#if ($e._fp & 0x0010) ("|fp4"),
|
||||
#if ($e._fp & 0x0020) ("|fp5"),
|
||||
#if ($e._fp & 0x0040) ("|fp6"),
|
||||
#if ($e._fp & 0x0080) ("|fp7"),
|
||||
#if (($e._mm | $e._xy) != 0) (" ")
|
||||
)
|
||||
),
|
||||
|
||||
#if ($e._mm != 0) (
|
||||
#(
|
||||
"mm=", [$e._mm, x],
|
||||
#if ($e._mm & 0x0001) ("|mm0"),
|
||||
#if ($e._mm & 0x0002) ("|mm1"),
|
||||
#if ($e._mm & 0x0004) ("|mm2"),
|
||||
#if ($e._mm & 0x0008) ("|mm3"),
|
||||
#if ($e._mm & 0x0010) ("|mm4"),
|
||||
#if ($e._mm & 0x0020) ("|mm5"),
|
||||
#if ($e._mm & 0x0040) ("|mm6"),
|
||||
#if ($e._mm & 0x0080) ("|mm7"),
|
||||
#if ($e._xy != 0) (" ")
|
||||
)
|
||||
),
|
||||
|
||||
#if ($e._xy != 0) (
|
||||
#(
|
||||
"xy=", [$e._xy, x],
|
||||
#if ($e._xy & 0x0001) ("|xy0"),
|
||||
#if ($e._xy & 0x0002) ("|xy1"),
|
||||
#if ($e._xy & 0x0004) ("|xy2"),
|
||||
#if ($e._xy & 0x0008) ("|xy3"),
|
||||
#if ($e._xy & 0x0010) ("|xy4"),
|
||||
#if ($e._xy & 0x0020) ("|xy5"),
|
||||
#if ($e._xy & 0x0040) ("|xy6"),
|
||||
#if ($e._xy & 0x0080) ("|xy7"),
|
||||
#if ($e._xy & 0x0100) ("|xy8"),
|
||||
#if ($e._xy & 0x0200) ("|xy9"),
|
||||
#if ($e._xy & 0x0400) ("|xy10"),
|
||||
#if ($e._xy & 0x0800) ("|xy11"),
|
||||
#if ($e._xy & 0x1000) ("|xy12"),
|
||||
#if ($e._xy & 0x2000) ("|xy13"),
|
||||
#if ($e._xy & 0x4000) ("|xy14"),
|
||||
#if ($e._xy & 0x8000) ("|xy15")
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
#else (
|
||||
"empty"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
children(
|
||||
#(
|
||||
#([...]: [$c,!]),
|
||||
|
||||
#(gp: [$e._gp, x]),
|
||||
#(fp: [$e._fp, x]),
|
||||
#(mm: [$e._mm, x]),
|
||||
#(xy: [$e._xy, x])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
; =============================================================================
|
||||
; [asmjit::x86x64 - Var]
|
||||
; =============================================================================
|
||||
|
||||
asmjit::BaseVarAttr|asmjit::x86x64::VarAttr {
|
||||
preview(
|
||||
#(
|
||||
"VarAttr(",
|
||||
#if ($e._vd != NULL) (
|
||||
#(
|
||||
"id=",
|
||||
[$e._vd->_id, x],
|
||||
" ",
|
||||
|
||||
#if (($e._vd->_contextId) != asmjit::kInvalidValue) (
|
||||
#("cid=", [($e._vd->_contextId), u], " ")
|
||||
),
|
||||
|
||||
#if (($e._vd->_name) != NULL) (
|
||||
#("name=", [($e._vd->_name), s], " ")
|
||||
),
|
||||
|
||||
"state=",
|
||||
#if ($e._vd->_state == asmjit::kVarStateUnused) ("unused")
|
||||
#elif ($e._vd->_state == asmjit::kVarStateReg) (#("reg|", [$e._vd->_regIndex, u]))
|
||||
#elif ($e._vd->_state == asmjit::kVarStateMem) ("mem")
|
||||
#else ("INVALID"),
|
||||
" ",
|
||||
|
||||
#if (($e._flags & (asmjit::kVarAttrInReg | asmjit::kVarAttrInMem | asmjit::kVarAttrInDecide | asmjit::kVarAttrInConv | asmjit::kVarAttrInCall | asmjit::kVarAttrInArg | asmjit::kVarAttrInStack)) != 0) (
|
||||
#(
|
||||
"in[",
|
||||
#if (($e._flags & asmjit::kVarAttrInReg) != 0) ("reg "),
|
||||
#if (($e._flags & asmjit::kVarAttrInMem) != 0) ("mem "),
|
||||
#if (($e._flags & asmjit::kVarAttrInDecide) != 0) ("decide "),
|
||||
#if (($e._flags & asmjit::kVarAttrInConv) != 0) ("conv "),
|
||||
#if (($e._flags & asmjit::kVarAttrInCall) != 0) ("call "),
|
||||
#if (($e._flags & asmjit::kVarAttrInArg) != 0) ("arg "),
|
||||
#if (($e._flags & asmjit::kVarAttrInStack) != 0) ("stack "),
|
||||
"] "
|
||||
)
|
||||
),
|
||||
#if (($e._flags & (asmjit::kVarAttrOutReg | asmjit::kVarAttrOutMem | asmjit::kVarAttrOutDecide | asmjit::kVarAttrOutConv | asmjit::kVarAttrOutRet)) != 0) (
|
||||
#(
|
||||
"out[",
|
||||
#if (($e._flags & asmjit::kVarAttrOutReg) != 0) ("reg "),
|
||||
#if (($e._flags & asmjit::kVarAttrOutMem) != 0) ("mem "),
|
||||
#if (($e._flags & asmjit::kVarAttrOutDecide) != 0) ("decide "),
|
||||
#if (($e._flags & asmjit::kVarAttrOutConv) != 0) ("conv "),
|
||||
#if (($e._flags & asmjit::kVarAttrOutRet) != 0) ("ret "),
|
||||
"] "
|
||||
)
|
||||
),
|
||||
#if (($e._flags & asmjit::kVarAttrUnuse) == asmjit::kVarAttrUnuse) ("unuse ")
|
||||
)
|
||||
)
|
||||
#else (
|
||||
"INVALID "
|
||||
),
|
||||
")"
|
||||
)
|
||||
)
|
||||
|
||||
children(
|
||||
#(
|
||||
#([...]: [$c,!]),
|
||||
|
||||
#(vd: [(asmjit::x86x64::VarData*)$e._vd]),
|
||||
#(flags: [$e._flags, x]),
|
||||
#(varCount: [$e._varCount, u]),
|
||||
#(argCount: [$e._argCount, u]),
|
||||
#(inRegIndex: [$e._inRegIndex, u]),
|
||||
#(outRegIndex: [$e._outRegIndex, u]),
|
||||
#(inRegs: [$e._inRegs, x]),
|
||||
#(allocableRegs: [$e._allocableRegs, x])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
asmjit::BaseVarInst|asmjit::x86x64::VarInst {
|
||||
children(
|
||||
#(
|
||||
#([...]: [$c,!]),
|
||||
|
||||
#(inRegs: [$e._inRegs]),
|
||||
#(outRegs: [$e._outRegs]),
|
||||
#(clobberedRegs: [$e._clobberedRegs]),
|
||||
#(start: [$e._start]),
|
||||
#(count: [$e._count]),
|
||||
|
||||
#(vaCount: [$e._vaCount, u]),
|
||||
#array(
|
||||
expr: $e._list[$i],
|
||||
size: $e._vaCount
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
; =============================================================================
|
||||
; [asmjit::X86 - Compiler - BaseNode]
|
||||
; =============================================================================
|
||||
|
||||
asmjit::BaseNode|asmjit::AlignNode|asmjit::EmbedNode|asmjit::CommentNode|asmjit::MarkNode|asmjit::HintNode|asmjit::TargetNode|asmjit::InstNode|asmjit::JumpNode::asmjit::FuncNode|asmjit::EndNode|asmjit::RetNode|asmjit::x86x64::X86X64FuncNode|asmjit::x86x64::X86X64CallNode {
|
||||
preview(
|
||||
#(
|
||||
#if ($e._type == asmjit::kNodeTypeAlign) ("AlignNode")
|
||||
#elif ($e._type == asmjit::kNodeTypeEmbed) ("EmbedNode")
|
||||
#elif ($e._type == asmjit::kNodeTypeComment) ("CommentNode")
|
||||
#elif ($e._type == asmjit::kNodeTypeMark) ("MarkNode")
|
||||
#elif ($e._type == asmjit::kNodeTypeHint) ("HintNode")
|
||||
#elif ($e._type == asmjit::kNodeTypeTarget) ("TargetNode")
|
||||
#elif ($e._type == asmjit::kNodeTypeInst) ("InstNode")
|
||||
#elif ($e._type == asmjit::kNodeTypeFunc) ("FuncNode")
|
||||
#elif ($e._type == asmjit::kNodeTypeEnd) ("EndNode")
|
||||
#elif ($e._type == asmjit::kNodeTypeRet) ("RetNode")
|
||||
#elif ($e._type == asmjit::kNodeTypeCall) ("CallNode")
|
||||
#else ("BaseNode"),
|
||||
|
||||
"(",
|
||||
#if (($e._liveness) != NULL) ("analyzed "),
|
||||
#if (($e._flags & asmjit::kNodeFlagIsTranslated) != 0) ("translated "),
|
||||
#if (($e._flags & asmjit::kNodeFlagIsJmp) != 0) ("jmp "),
|
||||
#if (($e._flags & asmjit::kNodeFlagIsJcc) != 0) ("jcc "),
|
||||
#if (($e._flags & asmjit::kNodeFlagIsTaken) != 0) ("taken "),
|
||||
#if (($e._flags & asmjit::kNodeFlagIsRet) != 0) ("ret "),
|
||||
")"
|
||||
)
|
||||
)
|
||||
|
||||
children(
|
||||
#(
|
||||
#([...]: [$c,!]),
|
||||
|
||||
#(prev: [$e._prev]),
|
||||
#(next: [$e._next]),
|
||||
|
||||
#(type: [$e._type]),
|
||||
#(flags: [$e._flags]),
|
||||
#(flowId: [$e._flowId]),
|
||||
#(comment: [$e._comment]),
|
||||
|
||||
#(varInst: [( (asmjit::x86x64::VarInst*)($e._varInst) )]),
|
||||
#(liveness: [( (asmjit::VarBits*)($e._liveness) )]),
|
||||
#(state: [( (asmjit::x86x64::VarState*)($e._state) )]),
|
||||
|
||||
#if ($e._type == asmjit::kNodeTypeAlign) (
|
||||
#(
|
||||
#(size : [( ((asmjit::AlignNode*)&$e)->_size )])
|
||||
)
|
||||
)
|
||||
#elif (($e._type == asmjit::kNodeTypeEmbed) && (($e._packedData.embed.size) <= (sizeof(uintptr_t)))) (
|
||||
#(
|
||||
#(size : [( ((asmjit::EmbedNode*)&$e)->_size )]),
|
||||
#(data : [( ((asmjit::EmbedNode*)&$e)->_data.buf )])
|
||||
)
|
||||
)
|
||||
#elif (($e._type == asmjit::kNodeTypeEmbed) && (($e._packedData.embed.size) > (sizeof(uintptr_t)))) (
|
||||
#(
|
||||
#(size : [( ((asmjit::EmbedNode*)&$e)->_size )]),
|
||||
#(data : [( ((asmjit::EmbedNode*)&$e)->_data.ptr )])
|
||||
)
|
||||
)
|
||||
#elif ($e._type == asmjit::kNodeTypeHint) (
|
||||
#(
|
||||
#(var : [( (asmjit::x86x64::VarData*) (((asmjit::HintNode*)&$e)->_var) )]),
|
||||
#(hint : [( ((asmjit::HintNode*)&$e)->_hint )]),
|
||||
#(value : [( ((asmjit::HintNode*)&$e)->_value )])
|
||||
)
|
||||
)
|
||||
#elif ($e._type == asmjit::kNodeTypeTarget) (
|
||||
#(
|
||||
#(label : [( ((asmjit::TargetNode*)&$e)->_label )]),
|
||||
#(from : [( ((asmjit::TargetNode*)&$e)->_from )]),
|
||||
#(numRefs: [( ((asmjit::TargetNode*)&$e)->_numRefs )])
|
||||
)
|
||||
)
|
||||
#elif ($e._type == asmjit::kNodeTypeInst) (
|
||||
#(
|
||||
#(opCount: [( ((asmjit::x86x64::X86X64InstNode*)&$e)->_opCount )]),
|
||||
#array(
|
||||
expr: ( ((asmjit::x86x64::X86X64InstNode*)&$e)->_opList[$i] ),
|
||||
size: ( ((asmjit::x86x64::X86X64InstNode*)&$e)->_opCount )
|
||||
)
|
||||
)
|
||||
)
|
||||
#elif ($e._type == asmjit::kNodeTypeFunc) (
|
||||
#(
|
||||
#(entryTarget : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_entryTarget )]),
|
||||
#(exitTarget : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_exitTarget )]),
|
||||
#(decl : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_x86Decl )]),
|
||||
#(end : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_end )]),
|
||||
#(argList : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_argList )]),
|
||||
#(funcHints : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_funcHints )]),
|
||||
#(funcFlags : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_funcFlags )]),
|
||||
|
||||
#(expectedStackAlignment: [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_expectedStackAlignment )]),
|
||||
#(requiredStackAlignment: [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_requiredStackAlignment )]),
|
||||
|
||||
#(redZoneSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_redZoneSize )]),
|
||||
#(spillZoneSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_spillZoneSize )]),
|
||||
#(argStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_argStackSize )]),
|
||||
#(memStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_memStackSize )]),
|
||||
#(callStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_callStackSize )]),
|
||||
|
||||
; X86.
|
||||
#(saveRestoreRegs : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_saveRestoreRegs )]),
|
||||
|
||||
#(alignStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_alignStackSize )]),
|
||||
#(alignedMemStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_alignedMemStackSize )]),
|
||||
#(pushPopStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_pushPopStackSize )]),
|
||||
#(moveStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_moveStackSize )]),
|
||||
#(extraStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_extraStackSize )]),
|
||||
|
||||
#(stackFrameRegIndex : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_stackFrameRegIndex )]),
|
||||
#(stackFrameRegPreserved: [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_isStackFrameRegPreserved )]),
|
||||
#(stackFrameCopyGpIndex : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_stackFrameCopyGpIndex )])
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
9
tools/configure-mac-xcode.sh
Normal file
9
tools/configure-mac-xcode.sh
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
ASMJIT_CURRENT_DIR=`pwd`
|
||||
ASMJIT_BUILD_DIR="build_xcode"
|
||||
|
||||
mkdir ../${ASMJIT_BUILD_DIR}
|
||||
cd ../${ASMJIT_BUILD_DIR}
|
||||
cmake .. -G"Xcode" -DASMJIT_BUILD_SAMPLES=1
|
||||
cd ${ASMJIT_CURRENT_DIR}
|
||||
9
tools/configure-unix-makefiles-dbg.sh
Normal file
9
tools/configure-unix-makefiles-dbg.sh
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
ASMJIT_CURRENT_DIR=`pwd`
|
||||
ASMJIT_BUILD_DIR="build_makefiles_dbg"
|
||||
|
||||
mkdir ../${ASMJIT_BUILD_DIR}
|
||||
cd ../${ASMJIT_BUILD_DIR}
|
||||
cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_SAMPLES=1
|
||||
cd ${ASMJIT_CURRENT_DIR}
|
||||
9
tools/configure-unix-makefiles-rel.sh
Normal file
9
tools/configure-unix-makefiles-rel.sh
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
ASMJIT_CURRENT_DIR=`pwd`
|
||||
ASMJIT_BUILD_DIR="build_makefiles_rel"
|
||||
|
||||
mkdir ../${ASMJIT_BUILD_DIR}
|
||||
cd ../${ASMJIT_BUILD_DIR}
|
||||
cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_SAMPLES=1
|
||||
cd ${ASMJIT_CURRENT_DIR}
|
||||
9
tools/configure-win-mingw-dbg.bat
Normal file
9
tools/configure-win-mingw-dbg.bat
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
|
||||
set ASMJIT_CURRENT_DIR=%CD%
|
||||
set ASMJIT_BUILD_DIR="build_mingw_dbg"
|
||||
|
||||
mkdir ..\%ASMJIT_BUILD_DIR%
|
||||
cd ..\%ASMJIT_BUILD_DIR%
|
||||
cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_SAMPLES=1
|
||||
cd %ASMJIT_CURRENT_DIR%
|
||||
9
tools/configure-win-mingw-rel.bat
Normal file
9
tools/configure-win-mingw-rel.bat
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
|
||||
set ASMJIT_CURRENT_DIR=%CD%
|
||||
set ASMJIT_BUILD_DIR="build_mingw_rel"
|
||||
|
||||
mkdir ..\%ASMJIT_BUILD_DIR%
|
||||
cd ..\%ASMJIT_BUILD_DIR%
|
||||
cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_SAMPLES=1
|
||||
cd %ASMJIT_CURRENT_DIR%
|
||||
9
tools/configure-win-vs2005-x64.bat
Normal file
9
tools/configure-win-vs2005-x64.bat
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
|
||||
set ASMJIT_CURRENT_DIR=%CD%
|
||||
set ASMJIT_BUILD_DIR="build_vs2005_x64"
|
||||
|
||||
mkdir ..\%ASMJIT_BUILD_DIR%
|
||||
cd ..\%ASMJIT_BUILD_DIR%
|
||||
cmake .. -G"Visual Studio 8 2005 Win64" -DASMJIT_BUILD_SAMPLES=1
|
||||
cd %ASMJIT_CURRENT_DIR%
|
||||
9
tools/configure-win-vs2005-x86.bat
Normal file
9
tools/configure-win-vs2005-x86.bat
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
|
||||
set ASMJIT_CURRENT_DIR=%CD%
|
||||
set ASMJIT_BUILD_DIR="build_vs2005_x86"
|
||||
|
||||
mkdir ..\%ASMJIT_BUILD_DIR%
|
||||
cd ..\%ASMJIT_BUILD_DIR%
|
||||
cmake .. -G"Visual Studio 8 2005" -DASMJIT_BUILD_SAMPLES=1
|
||||
cd %ASMJIT_CURRENT_DIR%
|
||||
9
tools/configure-win-vs2008-x64.bat
Normal file
9
tools/configure-win-vs2008-x64.bat
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
|
||||
set ASMJIT_CURRENT_DIR=%CD%
|
||||
set ASMJIT_BUILD_DIR="build_vs2008_x64"
|
||||
|
||||
mkdir ..\%ASMJIT_BUILD_DIR%
|
||||
cd ..\%ASMJIT_BUILD_DIR%
|
||||
cmake .. -G"Visual Studio 9 2008 Win64" -DASMJIT_BUILD_SAMPLES=1
|
||||
cd %ASMJIT_CURRENT_DIR%
|
||||
9
tools/configure-win-vs2008-x86.bat
Normal file
9
tools/configure-win-vs2008-x86.bat
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
|
||||
set ASMJIT_CURRENT_DIR=%CD%
|
||||
set ASMJIT_BUILD_DIR="build_vs2008_x86"
|
||||
|
||||
mkdir ..\%ASMJIT_BUILD_DIR%
|
||||
cd ..\%ASMJIT_BUILD_DIR%
|
||||
cmake .. -G"Visual Studio 9 2008" -DASMJIT_BUILD_SAMPLES=1
|
||||
cd %ASMJIT_CURRENT_DIR%
|
||||
9
tools/configure-win-vs2010-x64.bat
Normal file
9
tools/configure-win-vs2010-x64.bat
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
|
||||
set ASMJIT_CURRENT_DIR=%CD%
|
||||
set ASMJIT_BUILD_DIR="build_vs2010_x64"
|
||||
|
||||
mkdir ..\%ASMJIT_BUILD_DIR%
|
||||
cd ..\%ASMJIT_BUILD_DIR%
|
||||
cmake .. -G"Visual Studio 10 Win64" -DASMJIT_BUILD_SAMPLES=1
|
||||
cd %ASMJIT_CURRENT_DIR%
|
||||
9
tools/configure-win-vs2010-x86.bat
Normal file
9
tools/configure-win-vs2010-x86.bat
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
|
||||
set ASMJIT_CURRENT_DIR=%CD%
|
||||
set ASMJIT_BUILD_DIR="build_vs2010_x86"
|
||||
|
||||
mkdir ..\%ASMJIT_BUILD_DIR%
|
||||
cd ..\%ASMJIT_BUILD_DIR%
|
||||
cmake .. -G"Visual Studio 10" -DASMJIT_BUILD_SAMPLES=1
|
||||
cd %ASMJIT_CURRENT_DIR%
|
||||
9
tools/configure-win-vs2013-x64.bat
Normal file
9
tools/configure-win-vs2013-x64.bat
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
|
||||
set ASMJIT_CURRENT_DIR=%CD%
|
||||
set ASMJIT_BUILD_DIR="build_vs2013_x64"
|
||||
|
||||
mkdir ..\%ASMJIT_BUILD_DIR%
|
||||
cd ..\%ASMJIT_BUILD_DIR%
|
||||
cmake .. -G"Visual Studio 12 Win64" -DASMJIT_BUILD_SAMPLES=1
|
||||
cd %ASMJIT_CURRENT_DIR%
|
||||
9
tools/configure-win-vs2013-x86.bat
Normal file
9
tools/configure-win-vs2013-x86.bat
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
|
||||
set ASMJIT_CURRENT_DIR=%CD%
|
||||
set ASMJIT_BUILD_DIR="build_vs2013_x86"
|
||||
|
||||
mkdir ..\%ASMJIT_BUILD_DIR%
|
||||
cd ..\%ASMJIT_BUILD_DIR%
|
||||
cmake .. -G"Visual Studio 12" -DASMJIT_BUILD_SAMPLES=1
|
||||
cd %ASMJIT_CURRENT_DIR%
|
||||
1634
tools/doxygen.conf
Normal file
1634
tools/doxygen.conf
Normal file
File diff suppressed because it is too large
Load Diff
405
tools/doxygen.css
Normal file
405
tools/doxygen.css
Normal file
@@ -0,0 +1,405 @@
|
||||
body, table, div, p, dl {
|
||||
font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* @group Heading Levels */
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 150%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
caption {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.qindex, div.navtab{
|
||||
background-color: #e8eef2;
|
||||
border: 1px solid #84b0c7;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
div.qindex, div.navpath {
|
||||
width: 100%;
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
div.navtab {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
/* @group Link Styling */
|
||||
|
||||
a {
|
||||
color: #153788;
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.contents a:visited {
|
||||
color: #1b77c5;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.qindex {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a.qindexHL {
|
||||
font-weight: bold;
|
||||
background-color: #6666cc;
|
||||
color: #ffffff;
|
||||
border: 1px double #9295C2;
|
||||
}
|
||||
|
||||
.contents a.qindexHL:visited {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
a.el {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a.elRef {
|
||||
}
|
||||
|
||||
a.code {
|
||||
}
|
||||
|
||||
a.codeRef {
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
dl.el {
|
||||
margin-left: -1cm;
|
||||
}
|
||||
|
||||
.fragment {
|
||||
font-family: monospace, fixed;
|
||||
font-size: 105%;
|
||||
}
|
||||
|
||||
pre.fragment {
|
||||
border: 1px dotted #CCCCFF;
|
||||
padding: 4px 6px;
|
||||
margin: 4px 8px 4px 2px;
|
||||
}
|
||||
|
||||
div.ah {
|
||||
background-color: black;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
margin-bottom: 3px;
|
||||
margin-top: 3px
|
||||
}
|
||||
|
||||
div.groupHeader {
|
||||
margin-left: 16px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.groupText {
|
||||
margin-left: 16px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
body {
|
||||
background: white;
|
||||
color: black;
|
||||
margin-right: 20px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
td.indexkey {
|
||||
background-color: #e8eef2;
|
||||
font-weight: bold;
|
||||
border: 1px solid #CCCCCC;
|
||||
margin: 2px 0px 2px 0;
|
||||
padding: 2px 10px;
|
||||
}
|
||||
|
||||
td.indexvalue {
|
||||
background-color: #e8eef2;
|
||||
border: 1px solid #CCCCCC;
|
||||
padding: 2px 10px;
|
||||
margin: 2px 0px;
|
||||
}
|
||||
|
||||
tr.memlist {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
p.formulaDsp {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
img.formulaDsp {
|
||||
|
||||
}
|
||||
|
||||
img.formulaInl {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* @group Code Colorization */
|
||||
|
||||
span.keyword {
|
||||
color: #008000
|
||||
}
|
||||
|
||||
span.keywordtype {
|
||||
color: #604020
|
||||
}
|
||||
|
||||
span.keywordflow {
|
||||
color: #e08000
|
||||
}
|
||||
|
||||
span.comment {
|
||||
color: #800000
|
||||
}
|
||||
|
||||
span.preprocessor {
|
||||
color: #806020
|
||||
}
|
||||
|
||||
span.stringliteral {
|
||||
color: #002080
|
||||
}
|
||||
|
||||
span.charliteral {
|
||||
color: #008080
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
td.tiny {
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
.dirtab {
|
||||
padding: 4px;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #84b0c7;
|
||||
}
|
||||
|
||||
th.dirtab {
|
||||
background: #e8eef2;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 0;
|
||||
border: none;
|
||||
border-top: 1px solid #666;
|
||||
}
|
||||
|
||||
/* @group Member Descriptions */
|
||||
|
||||
.mdescLeft, .mdescRight,
|
||||
.memItemLeft, .memItemRight,
|
||||
.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
|
||||
background-color: #FFFFFF;
|
||||
border: none;
|
||||
margin: 4px;
|
||||
padding: 1px 0 0 8px;
|
||||
}
|
||||
|
||||
.mdescLeft, .mdescRight {
|
||||
padding: 0px 8px 4px 8px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.memItemLeft, .memItemRight {
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
border-top: 1px solid #CCCCFF;
|
||||
}
|
||||
|
||||
.mdescLeft, .mdescRight {
|
||||
}
|
||||
|
||||
.memTemplParams {
|
||||
color: #606060;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Member Details */
|
||||
|
||||
/* Styles for detailed member documentation */
|
||||
|
||||
.memtemplate {
|
||||
margin-left: 3px;
|
||||
font-weight: normal;
|
||||
font-size: 80%;
|
||||
color: #606060;
|
||||
}
|
||||
|
||||
.memnav {
|
||||
background-color: #e8eef2;
|
||||
border: 1px solid #84b0c7;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
margin-right: 15px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.memitem {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.memname {
|
||||
white-space: nowrap;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.memproto, .memdoc {
|
||||
}
|
||||
|
||||
.memproto {
|
||||
padding: 0;
|
||||
background-color: #EEEEFF;
|
||||
border: 1px solid #CCCCFF;
|
||||
}
|
||||
|
||||
.memdoc {
|
||||
padding: 2px 5px;
|
||||
border-left: 1px solid #CCCCFF;
|
||||
border-right: 1px solid #CCCCFF;
|
||||
border-bottom: 1px solid #CCCCFF;
|
||||
}
|
||||
|
||||
.paramkey {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.paramtype {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.paramname {
|
||||
color: #606060;
|
||||
font-weight: normal;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.paramname em {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Directory (tree) */
|
||||
|
||||
/* for the tree view */
|
||||
|
||||
.ftvtree {
|
||||
font-family: sans-serif;
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
/* these are for tree view when used as main index */
|
||||
|
||||
.directory {
|
||||
font-size: 9pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.directory h3 {
|
||||
margin: 0px;
|
||||
margin-top: 1em;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
/*
|
||||
The following two styles can be used to replace the root node title
|
||||
with an image of your choice. Simply uncomment the next two styles,
|
||||
specify the name of your image and be sure to set 'height' to the
|
||||
proper pixel height of your image.
|
||||
*/
|
||||
|
||||
/*
|
||||
.directory h3.swap {
|
||||
height: 61px;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url("yourimage.gif");
|
||||
}
|
||||
.directory h3.swap span {
|
||||
display: none;
|
||||
}
|
||||
*/
|
||||
|
||||
.directory > h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.directory p {
|
||||
margin: 0px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.directory div {
|
||||
display: none;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.directory img {
|
||||
vertical-align: -30%;
|
||||
}
|
||||
|
||||
/* these are for tree view when not used as main index */
|
||||
|
||||
.directory-alt {
|
||||
font-size: 100%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.directory-alt h3 {
|
||||
margin: 0px;
|
||||
margin-top: 1em;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
.directory-alt > h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.directory-alt p {
|
||||
margin: 0px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.directory-alt div {
|
||||
display: none;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.directory-alt img {
|
||||
vertical-align: -30%;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
address {
|
||||
font-style: normal;
|
||||
color: #333;
|
||||
}
|
||||
253
tools/src-gendefs.js
Normal file
253
tools/src-gendefs.js
Normal file
@@ -0,0 +1,253 @@
|
||||
// [GenDefs]
|
||||
//
|
||||
// The purpose of this script is to fetch all instructions' names into a single
|
||||
// string. It prevents relocation that has to be done by linked to make all
|
||||
// pointers the binary application/library uses valid. This approach decreases
|
||||
// the final size of AsmJit binary.
|
||||
|
||||
var fs = require("fs");
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// [Configuration]
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
var injectStartMarker = "// ${kInstData:Begin}\n"
|
||||
var injectEndMarker = "// ${kInstData:End}\n"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// [Utilities]
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
var uppercaseFirst = function(s) {
|
||||
if (!s)
|
||||
return s;
|
||||
return s[0].toUpperCase() + s.substr(1);
|
||||
};
|
||||
|
||||
var inject = function(s, start, end, code) {
|
||||
var iStart = s.indexOf(start);
|
||||
var iEnd = s.indexOf(end);
|
||||
|
||||
if (iStart === -1)
|
||||
throw new Error("Couldn't locate start mark.");
|
||||
|
||||
if (iEnd === -1)
|
||||
throw new Error("Couldn't locate end mark.");
|
||||
|
||||
return s.substr(0, iStart + start.length) + code + s.substr(iEnd);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// [Database]
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// FullIndex - Index of the name of the instruction in one big string (no
|
||||
// prefix/suffix concept).
|
||||
// PrefixIndex - Index to a prefix string.
|
||||
// SuffixIndex - Index to a suffix string.
|
||||
|
||||
var Database = (function() {
|
||||
function bestSuffix(s, suffixes) {
|
||||
var best = -1;
|
||||
|
||||
for (var i = 0; i < suffixes.length; i++) {
|
||||
var suffix = suffixes[i];
|
||||
var si = s.lastIndexOf(suffix);
|
||||
|
||||
if (si === -1 || si + suffix.length != s.length)
|
||||
continue;
|
||||
|
||||
if (best !== -1 && suffix.length < suffixes[best].length)
|
||||
continue;
|
||||
|
||||
best = i;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
var IndexedString = function() {
|
||||
this.array = [];
|
||||
this.index = 0;
|
||||
this.map = {};
|
||||
};
|
||||
|
||||
IndexedString.prototype.add = function(s) {
|
||||
var index = this.map[s];
|
||||
if (typeof index === "number")
|
||||
return index;
|
||||
|
||||
index = this.index;
|
||||
this.array.push(s);
|
||||
this.index += s.length + 1;
|
||||
this.map[s] = index;
|
||||
return index;
|
||||
};
|
||||
|
||||
IndexedString.prototype.get = function(s) {
|
||||
return this.map[s];
|
||||
};
|
||||
|
||||
IndexedString.prototype.format = function(indent) {
|
||||
var s = "";
|
||||
var array = this.array;
|
||||
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
s += indent + "\"" + array[i] + "\\0\"";
|
||||
if (i === array.length - 1)
|
||||
s += ";";
|
||||
s += "\n";
|
||||
}
|
||||
|
||||
return s;
|
||||
};
|
||||
|
||||
IndexedString.prototype.getSize = function() {
|
||||
return this.index;
|
||||
};
|
||||
|
||||
var Database = function(suffixes) {
|
||||
this.map = {};
|
||||
this.suffixes = suffixes;
|
||||
|
||||
this.fullString = new IndexedString();
|
||||
this.prefixString = new IndexedString();
|
||||
this.suffixString = new IndexedString();
|
||||
};
|
||||
|
||||
Database.prototype.add = function(name, id) {
|
||||
this.map[name] = {
|
||||
id: id,
|
||||
fullIndex: 0,
|
||||
prefixIndex: 0,
|
||||
suffixIndex: 0,
|
||||
hasV: 0
|
||||
};
|
||||
};
|
||||
|
||||
Database.prototype.index = function() {
|
||||
var map = this.map;
|
||||
var suffixes = this.suffixes;
|
||||
|
||||
for (var i = 0; i < suffixes.length; i++) {
|
||||
this.suffixString.add(suffixes[i]);
|
||||
}
|
||||
|
||||
for (var name in map) {
|
||||
var inst = map[name];
|
||||
var si = bestSuffix(name, suffixes);
|
||||
|
||||
inst.fullIndex = this.fullString.add(name);
|
||||
|
||||
if (name.indexOf("v") === 0) {
|
||||
inst.hasV = 1;
|
||||
name = name.substr(1);
|
||||
}
|
||||
|
||||
if (si !== -1) {
|
||||
var suffix = suffixes[si];
|
||||
var prefix = name.substr(0, name.length - suffix.length);
|
||||
|
||||
inst.prefixIndex = this.prefixString.add(prefix);
|
||||
inst.suffixIndex = this.suffixString.add(suffix);
|
||||
}
|
||||
else {
|
||||
inst.prefixIndex = this.prefixString.add(name);
|
||||
inst.suffixIndex = this.suffixString.add("");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return Database;
|
||||
})();
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// [Generate]
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
var generate = function(fileName, arch, suffixes) {
|
||||
var oldData = fs.readFileSync(fileName, "utf8").replace(/\r\n/g, "\n");
|
||||
|
||||
var data = oldData;
|
||||
var code = "";
|
||||
|
||||
var Arch = uppercaseFirst(arch);
|
||||
|
||||
// Create database.
|
||||
var db = new Database(suffixes);
|
||||
var re = new RegExp("INST\\(([A-Za-z0-9_]+)\\s*,\\s*\\\"([A-Za-z0-9_ ]*)\\\"", "g");
|
||||
|
||||
while (m = re.exec(data)) {
|
||||
var id = m[1];
|
||||
var name = m[2];
|
||||
|
||||
db.add(name, id);
|
||||
}
|
||||
db.index();
|
||||
|
||||
console.log("Full size: " + db.fullString.getSize());
|
||||
console.log("Prefix size: " + db.prefixString.getSize());
|
||||
console.log("Suffix size: " + db.suffixString.getSize());
|
||||
|
||||
// Generate InstName[] string.
|
||||
code += "const char _instName[] =\n";
|
||||
for (var k in db.map) {
|
||||
var inst = db.map[k];
|
||||
code += " \"" + k + "\\0\"\n";
|
||||
}
|
||||
code = code.substr(code, code.length - 1) + ";\n\n";
|
||||
|
||||
// Generate NameIndex.
|
||||
code += "enum kInstData_NameIndex {\n";
|
||||
for (var k in db.map) {
|
||||
var inst = db.map[k];
|
||||
code += " " + inst.id + "_NameIndex = " + inst.fullIndex + ",\n";
|
||||
}
|
||||
code = code.substr(code, code.length - 2) + "\n};\n";
|
||||
|
||||
// Inject.
|
||||
data = inject(data, injectStartMarker, injectEndMarker, code);
|
||||
|
||||
// Save only if modified.
|
||||
if (data !== oldData)
|
||||
fs.writeFileSync(fileName, data, "utf8");
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// [Main]
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
var main = function(files) {
|
||||
files.forEach(function(file) {
|
||||
generate(file.name, file.arch, file.suffixes);
|
||||
});
|
||||
};
|
||||
|
||||
main([
|
||||
{
|
||||
name: "../src/asmjit/x86/x86defs.cpp",
|
||||
arch: "x86",
|
||||
suffixes: [
|
||||
"a", "ae",
|
||||
"b", "bd", "be", "bq", "bw",
|
||||
"c",
|
||||
"d", "dq", "dqa", "dqu", "dw",
|
||||
"e",
|
||||
"f128",
|
||||
"g", "ge",
|
||||
"hpd", "hps",
|
||||
"i", "i128", "ip",
|
||||
"l", "last", "ld", "le", "lpd", "lps", "lw",
|
||||
"na", "nae", "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no", "np", "ns", "nz",
|
||||
"o",
|
||||
"p", "pd", "pe", "ph", "pi", "po", "pp", "ps",
|
||||
"q",
|
||||
"r",
|
||||
"s", "sb", "sd", "si", "sq", "ss", "sw",
|
||||
"usb", "usw",
|
||||
"vpd", "vps",
|
||||
"w", "wb", "wd", "wq",
|
||||
"z"
|
||||
]
|
||||
}
|
||||
]);
|
||||
177
tools/src-sanity.js
Normal file
177
tools/src-sanity.js
Normal file
@@ -0,0 +1,177 @@
|
||||
var assert = require("assert");
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
|
||||
/**
|
||||
* List all files that can be processed by sanitizer in the given directory.
|
||||
*/
|
||||
var filesToSanitize = (function() {
|
||||
var listPrivate = function(array, dir, displayDir, accept) {
|
||||
var files = fs.readdirSync(dir);
|
||||
var subarray = [];
|
||||
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var baseName = files[i];
|
||||
var fullName = path.normalize(path.join(dir, baseName));
|
||||
|
||||
var stat = fs.lstatSync(fullName);
|
||||
if (stat.isSymbolicLink())
|
||||
continue;
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
listPrivate(subarray, path.join(dir, baseName), displayDir + baseName, accept);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stat.isFile()) {
|
||||
if (accept(baseName))
|
||||
array.push({ name: fullName, display: displayDir + baseName });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return array.concat(subarray);
|
||||
};
|
||||
|
||||
return function(dir, accept) {
|
||||
return listPrivate([], dir, "", accept);
|
||||
};
|
||||
})();
|
||||
|
||||
var isCppHeaderExt = function(ext) {
|
||||
return ext === ".h" ||
|
||||
ext === ".hh" ||
|
||||
ext === ".hpp" ||
|
||||
ext === ".hxx" ;
|
||||
};
|
||||
|
||||
var isCppSourceExt = function(ext) {
|
||||
return ext === ".c" ||
|
||||
ext === ".cc" ||
|
||||
ext === ".cpp" ||
|
||||
ext === ".cxx" ;
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter that returns true if the given file name should be processed.
|
||||
*/
|
||||
var filesToAccept = function(name) {
|
||||
var ext = path.extname(name).toLowerCase();
|
||||
|
||||
return isCppHeaderExt(ext) ||
|
||||
isCppSourceExt(ext) ||
|
||||
ext === ".cmake" ||
|
||||
ext === ".m" ||
|
||||
ext === ".md" ||
|
||||
ext === ".mm" ;
|
||||
};
|
||||
|
||||
var sanitySpaces = function(data) {
|
||||
// Remove carriage return.
|
||||
data = data.replace(/\r\n/g, "\n");
|
||||
// Remove spaces before the end of the line.
|
||||
data = data.replace(/[ \t]+\n/g, "\n");
|
||||
// Convert tabs to spaces.
|
||||
data = data.replace(/\t/g, " ");
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
var sanityHeaderGuards = function(data) {
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
var sanityIncludeOrder = function(data, directive) {
|
||||
var i = 0;
|
||||
var nl = true;
|
||||
|
||||
var startPosition = -1;
|
||||
var endPosition = -1;
|
||||
var list = null;
|
||||
var replacement;
|
||||
|
||||
while (i < data.length) {
|
||||
if (nl && data.indexOf(directive, i) === i) {
|
||||
var iLocal = i
|
||||
|
||||
if (startPosition === -1) {
|
||||
startPosition = i;
|
||||
list = [];
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (++i >= data.length) {
|
||||
list.push(data.substring(iLocal, i));
|
||||
break;
|
||||
}
|
||||
if (data[i] === '\n') {
|
||||
list.push(data.substring(iLocal, i));
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (startPosition !== -1) {
|
||||
assert(nl === true);
|
||||
endPosition = i;
|
||||
|
||||
if (list.length > 1) {
|
||||
list.sort();
|
||||
replacement = list.join("\n");
|
||||
assert(replacement.length == endPosition - startPosition - 1);
|
||||
|
||||
data = data.substring(0, startPosition) +
|
||||
replacement +
|
||||
"\n" +
|
||||
data.substring(endPosition);
|
||||
}
|
||||
|
||||
startPosition = -1;
|
||||
endPosition = -1;
|
||||
list = null;
|
||||
|
||||
nl = false;
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
nl = data[i] === '\n';
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
var sanity = function(data, name) {
|
||||
var ext = path.extname(name).toLowerCase();
|
||||
|
||||
// Sanity spaces.
|
||||
data = sanitySpaces(data);
|
||||
|
||||
// Fix C/C++ header guards.
|
||||
if (isCppHeaderExt(ext)) {
|
||||
data = sanityHeaderGuards(data);
|
||||
}
|
||||
|
||||
// Sort #include files.
|
||||
if (isCppHeaderExt(ext) || isCppSourceExt(ext)) {
|
||||
data = sanityIncludeOrder(data, "#include");
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
var main = function(dir) {
|
||||
filesToSanitize(dir, filesToAccept).forEach(function(file) {
|
||||
var oldData = fs.readFileSync(file.name, "utf8");
|
||||
var newData = sanity(oldData, file.display);
|
||||
|
||||
if (oldData !== newData) {
|
||||
console.log("Sanitizing: " + file.display);
|
||||
fs.writeFileSync(file.name, newData, "utf8");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
main(path.join(__dirname, "../src"));
|
||||
Reference in New Issue
Block a user