Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
tsoc
openmm
Commits
a83607d6
Commit
a83607d6
authored
Sep 16, 2014
by
peastman
Browse files
Preliminary implementation of JIT compilation for CompiledExpressions
parent
4c19a401
Changes
65
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
7312 additions
and
0 deletions
+7312
-0
libraries/asmjit/base/cputicks.h
libraries/asmjit/base/cputicks.h
+40
-0
libraries/asmjit/base/error.cpp
libraries/asmjit/base/error.cpp
+81
-0
libraries/asmjit/base/error.h
libraries/asmjit/base/error.h
+218
-0
libraries/asmjit/base/globals.cpp
libraries/asmjit/base/globals.cpp
+30
-0
libraries/asmjit/base/globals.h
libraries/asmjit/base/globals.h
+177
-0
libraries/asmjit/base/intutil.cpp
libraries/asmjit/base/intutil.cpp
+210
-0
libraries/asmjit/base/intutil.h
libraries/asmjit/base/intutil.h
+713
-0
libraries/asmjit/base/lock.h
libraries/asmjit/base/lock.h
+131
-0
libraries/asmjit/base/logger.cpp
libraries/asmjit/base/logger.cpp
+167
-0
libraries/asmjit/base/logger.h
libraries/asmjit/base/logger.h
+246
-0
libraries/asmjit/base/operand.cpp
libraries/asmjit/base/operand.cpp
+38
-0
libraries/asmjit/base/operand.h
libraries/asmjit/base/operand.h
+1090
-0
libraries/asmjit/base/runtime.cpp
libraries/asmjit/base/runtime.cpp
+191
-0
libraries/asmjit/base/runtime.h
libraries/asmjit/base/runtime.h
+262
-0
libraries/asmjit/base/string.cpp
libraries/asmjit/base/string.cpp
+374
-0
libraries/asmjit/base/string.h
libraries/asmjit/base/string.h
+372
-0
libraries/asmjit/base/vectypes.h
libraries/asmjit/base/vectypes.h
+1251
-0
libraries/asmjit/base/vmem.cpp
libraries/asmjit/base/vmem.cpp
+1286
-0
libraries/asmjit/base/vmem.h
libraries/asmjit/base/vmem.h
+240
-0
libraries/asmjit/base/zone.cpp
libraries/asmjit/base/zone.cpp
+195
-0
No files found.
libraries/asmjit/base/cputicks.h
0 → 100644
View file @
a83607d6
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CPUTICKS_H
#define _ASMJIT_BASE_CPUTICKS_H
// [Dependencies - AsmJit]
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::CpuTicks]
// ============================================================================
//! CPU ticks utilities.
struct
CpuTicks
{
//! Get the current CPU ticks for benchmarking (1ms resolution).
static
ASMJIT_API
uint32_t
now
();
};
//! \}
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CPUTICKS_H
libraries/asmjit/base/error.cpp
0 → 100644
View file @
a83607d6
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/error.h"
#include "../base/intutil.h"
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
// ============================================================================
// [asmjit::ErrorHandler - Construction / Destruction]
// ============================================================================
ErrorHandler
::
ErrorHandler
()
{}
ErrorHandler
::~
ErrorHandler
()
{}
// ============================================================================
// [asmjit::ErrorHandler - Interface]
// ============================================================================
ErrorHandler
*
ErrorHandler
::
addRef
()
const
{
return
const_cast
<
ErrorHandler
*>
(
this
);
}
void
ErrorHandler
::
release
()
{}
// ============================================================================
// [asmjit::ErrorUtil - AsString]
// ============================================================================
#if !defined(ASMJIT_DISABLE_NAMES)
static
const
char
errorMessages
[]
=
{
"Ok
\0
"
"No heap memory
\0
"
"No virtual memory
\0
"
"Invalid argument
\0
"
"Invalid state
\0
"
"No code generated
\0
"
"Code too large
\0
"
"Label already bound
\0
"
"Unknown instruction
\0
"
"Illegal instruction
\0
"
"Illegal addressing
\0
"
"Illegal displacement
\0
"
"Overlapped arguments
\0
"
"Unknown error
\0
"
};
static
const
char
*
findPackedString
(
const
char
*
p
,
uint32_t
id
,
uint32_t
maxId
)
{
uint32_t
i
=
0
;
if
(
id
>
maxId
)
id
=
maxId
;
while
(
i
<
id
)
{
while
(
p
[
0
])
p
++
;
p
++
;
}
return
p
;
}
const
char
*
ErrorUtil
::
asString
(
Error
e
)
{
return
findPackedString
(
errorMessages
,
e
,
kErrorCount
);
}
#endif // ASMJIT_DISABLE_NAMES
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
libraries/asmjit/base/error.h
0 → 100644
View file @
a83607d6
// [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 "../apibegin.h"
// [Dependencies - AsmJit]
#include "../base/globals.h"
namespace
asmjit
{
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kError]
// ============================================================================
//! AsmJit error codes.
ASMJIT_ENUM
(
kError
)
{
//! No error (success).
//!
//! This is default state and state you want.
kErrorOk
=
0
,
//! Heap memory allocation failed.
kErrorNoHeapMemory
=
1
,
//! Virtual memory allocation failed.
kErrorNoVirtualMemory
=
2
,
//! Invalid argument.
kErrorInvalidArgument
=
3
,
//! Invalid state.
kErrorInvalidState
=
4
,
//! No code generated.
//!
//! Returned by runtime if the code-generator contains no code.
kErrorNoCodeGenerated
=
5
,
//! Code generated is too large to fit in memory reserved.
//!
//! Returned by `StaticRuntime` in case that the code generated is too large
//! to fit in the memory already reserved for it.
kErrorCodeTooLarge
=
6
,
//! Label is already bound.
kErrorLabelAlreadyBound
=
7
,
//! Unknown instruction (an instruction ID is out of bounds or instruction
//! name is invalid).
kErrorUnknownInst
=
8
,
//! Illegal instruction.
//!
//! This status code can also be returned in X64 mode if AH, BH, CH or DH
//! registers have been used together with a REX prefix. The instruction
//! is not encodable in such case.
//!
//! Example of raising `kErrorIllegalInst` error.
//!
//! ~~~
//! // Invalid address size.
//! a.mov(dword_ptr(eax), al);
//!
//! // Undecodable instruction - AH used with R10, however R10 can only be
//! // encoded by using REX prefix, which conflicts with AH.
//! a.mov(byte_ptr(r10), ah);
//! ~~~
//!
//! \note In debug mode assertion is raised instead of returning an error.
kErrorIllegalInst
=
9
,
//! Illegal (unencodable) addressing used.
kErrorIllegalAddresing
=
10
,
//! Illegal (unencodable) displacement used.
//!
//! X86/X64
//! -------
//!
//! Short form of jump instruction has been used, but the displacement is out
//! of bounds.
kErrorIllegalDisplacement
=
11
,
//! A variable has been assigned more than once to a function argument (Compiler).
kErrorOverlappedArgs
=
12
,
//! Count of AsmJit error codes.
kErrorCount
=
13
};
// ============================================================================
// [asmjit::Error]
// ============================================================================
//! AsmJit error type (unsigned integer).
typedef
uint32_t
Error
;
// ============================================================================
// [asmjit::ErrorHandler]
// ============================================================================
//! Error handler.
//!
//! Error handler can be used to override the default behavior of `CodeGen`
//! error handling and propagation. See `handleError` on how to override it.
//!
//! Please note that `addRef` and `release` functions are used, but there is
//! no reference counting implemented by default, reimplement to change the
//! default behavior.
struct
ASMJIT_VCLASS
ErrorHandler
{
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `ErrorHandler` instance.
ASMJIT_API
ErrorHandler
();
//! Destroy the `ErrorHandler` instance.
ASMJIT_API
virtual
~
ErrorHandler
();
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
//! Reference this error handler.
//!
//! \note This member function is provided for convenience. The default
//! implementation does nothing. If you are working in environment where
//! multiple `ErrorHandler` instances are used by a different code generators
//! you may provide your own functionality for reference counting. In that
//! case `addRef()` and `release()` functions should be overridden.
ASMJIT_API
virtual
ErrorHandler
*
addRef
()
const
;
//! Release this error handler.
//!
//! \note This member function is provided for convenience. See `addRef()`
//! for more detailed information related to reference counting.
ASMJIT_API
virtual
void
release
();
//! Error handler (pure).
//!
//! Error handler is called when an error happened. An error can happen in
//! many places, but error handler is mostly used by `Assembler` and
//! `Compiler` classes to report anything that may cause incorrect code
//! generation. There are multiple ways how the error handler can be used
//! and each has it's pros/cons.
//!
//! AsmJit library doesn't use exceptions and can be compiled with or without
//! exception handling support. Even if the AsmJit library is compiled without
//! exceptions it is exception-safe and handleError() can report an incoming
//! error by throwing an exception of any type. It's guaranteed that the
//! exception won't be catched by AsmJit and will be propagated to the code
//! calling AsmJit `Assembler` or `Compiler` methods. Alternative to
//! throwing an exception is using `setjmp()` and `longjmp()` pair available
//! in the standard C library.
//!
//! If the exception or setjmp() / longjmp() mechanism is used, the state of
//! the `BaseAssember` or `Compiler` is unchanged and if it's possible the
//! execution (instruction serialization) can continue. However if the error
//! happened during any phase that translates or modifies the stored code
//! (for example relocation done by `Assembler` or analysis/translation
//! done by `Compiler`) the execution can't continue and the error will
//! be also stored in `Assembler` or `Compiler`.
//!
//! Finally, if no exceptions nor setjmp() / longjmp() mechanisms were used,
//! you can still implement a compatible handling by returning from your
//! error handler. Returning `true` means that error was reported and AsmJit
//! should continue execution, but `false` sets the rror immediately to the
//! `Assembler` or `Compiler` and execution shouldn't continue (this
//! is the default behavior in case no error handler is used).
virtual
bool
handleError
(
Error
code
,
const
char
*
message
)
=
0
;
};
// ============================================================================
// [asmjit::ErrorUtil]
// ============================================================================
//! Error utilities.
struct
ErrorUtil
{
#if !defined(ASMJIT_DISABLE_NAMES)
//! Get printable version of AsmJit `kError` code.
static
ASMJIT_API
const
char
*
asString
(
Error
code
);
#endif // ASMJIT_DISABLE_NAMES
};
//! \}
// ============================================================================
// [ASMJIT_PROPAGATE_ERROR]
// ============================================================================
//! \internal
//!
//! Used by AsmJit to return the `_Exp_` result if it's an error.
#define ASMJIT_PROPAGATE_ERROR(_Exp_) \
do { \
::asmjit::Error errval_ = (_Exp_); \
if (errval_ != ::asmjit::kErrorOk) \
return errval_; \
} while (0)
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_ERROR_H
libraries/asmjit/base/globals.cpp
0 → 100644
View file @
a83607d6
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
// ============================================================================
// [asmjit::Assert]
// ============================================================================
void
assertionFailed
(
const
char
*
exp
,
const
char
*
file
,
int
line
)
{
::
fprintf
(
stderr
,
"Assertion failed: %s
\n
, file %s, line %d
\n
"
,
exp
,
file
,
line
);
::
abort
();
}
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
libraries/asmjit/base/globals.h
0 → 100644
View file @
a83607d6
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_GLOBALS_H
#define _ASMJIT_BASE_GLOBALS_H
// [Dependencies - AsmJit]
#include "../build.h"
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::Ptr / SignedPtr]
// ============================================================================
//! 64-bit unsigned pointer, compatible with JIT and non-JIT generators.
//!
//! This is the preferred pointer type to use with AsmJit library. It has a
//! capability to hold any pointer for any architecture making it an ideal
//! candidate for cross-platform code generation.
typedef
uint64_t
Ptr
;
//! 64-bit signed pointer, like \ref Ptr, but made signed.
typedef
int64_t
SignedPtr
;
// ============================================================================
// [asmjit::kGlobals]
// ============================================================================
//! Invalid index
//!
//! Invalid index is the last possible index that is never used in practice. In
//! AsmJit it is used exclusively with strings to indicate the the length of the
//! string is not known and has to be determined.
static
const
size_t
kInvalidIndex
=
~
static_cast
<
size_t
>
(
0
);
//! Invalid base address.
static
const
Ptr
kNoBaseAddress
=
static_cast
<
Ptr
>
(
static_cast
<
SignedPtr
>
(
-
1
));
//! Global constants.
ASMJIT_ENUM
(
kGlobals
)
{
//! Invalid value or operand id.
kInvalidValue
=
0xFFFFFFFF
,
//! Invalid register index.
kInvalidReg
=
0xFF
,
//! Invalid variable type.
kInvalidVar
=
0xFF
,
//! Host memory allocator overhead.
//!
//! The overhead is decremented from all zone allocators so the operating
//! system doesn't have allocate extra virtual page to keep tract of the
//! requested memory block.
//!
//! The number is actually a guess.
kMemAllocOverhead
=
sizeof
(
intptr_t
)
*
4
,
//! Memory grow threshold.
//!
//! After the grow threshold is reached the capacity won't be doubled
//! anymore.
kMemAllocGrowMax
=
8192
*
1024
};
// ============================================================================
// [asmjit::kArch]
// ============================================================================
//! Architecture.
ASMJIT_ENUM
(
kArch
)
{
//! No/Unknown architecture.
kArchNone
=
0
,
//! X86 architecture.
kArchX86
=
1
,
//! X64 architecture, also called AMD64.
kArchX64
=
2
,
//! Arm architecture.
kArchArm
=
4
,
#if defined(ASMJIT_HOST_X86)
kArchHost
=
kArchX86
,
#endif // ASMJIT_HOST_X86
#if defined(ASMJIT_HOST_X64)
kArchHost
=
kArchX64
,
#endif // ASMJIT_HOST_X64
#if defined(ASMJIT_HOST_ARM)
kArchHost
=
kArchArm
,
#endif // ASMJIT_HOST_ARM
//! Whether the host is 64-bit.
kArchHost64Bit
=
sizeof
(
intptr_t
)
>=
8
};
//! \}
// ============================================================================
// [asmjit::Init / NoInit]
// ============================================================================
#if !defined(ASMJIT_DOCGEN)
struct
_Init
{};
static
const
_Init
Init
=
{};
struct
_NoInit
{};
static
const
_NoInit
NoInit
=
{};
#endif // !ASMJIT_DOCGEN
// ============================================================================
// [asmjit::Assert]
// ============================================================================
//! \addtogroup asmjit_base_general
//! \{
//! Called in debug build on assertion failure.
//!
//! \param exp Expression that failed.
//! \param file Source file name where it happened.
//! \param line Line in the source file.
//!
//! If you have problems with assertions put a breakpoint at assertionFailed()
//! function (asmjit/base/globals.cpp) and check the call stack to locate the
//! failing code.
ASMJIT_API
void
assertionFailed
(
const
char
*
exp
,
const
char
*
file
,
int
line
);
#if defined(ASMJIT_DEBUG)
#define ASMJIT_ASSERT(_Exp_) \
do { \
if (!(_Exp_)) ::asmjit::assertionFailed(#_Exp_, __FILE__, __LINE__); \
} while (0)
#else
#define ASMJIT_ASSERT(_Exp_) ASMJIT_NOP()
#endif // DEBUG
//! \}
}
// asmjit namespace
// ============================================================================
// [asmjit_cast<>]
// ============================================================================
//! \addtogroup asmjit_base_util
//! \{
//! Cast used to cast pointer to function. It's like reinterpret_cast<>,
//! but uses internally C style cast to work with MinGW.
//!
//! If you are using single compiler and `reinterpret_cast<>` works for you,
//! there is no reason to use `asmjit_cast<>`. If you are writing
//! cross-platform software with various compiler support, consider using
//! `asmjit_cast<>` instead of `reinterpret_cast<>`.
template
<
typename
T
,
typename
Z
>
static
ASMJIT_INLINE
T
asmjit_cast
(
Z
*
p
)
{
return
(
T
)
p
;
}
//! \}
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_GLOBALS_H
libraries/asmjit/base/intutil.cpp
0 → 100644
View file @
a83607d6
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/intutil.h"
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
#if defined(ASMJIT_TEST)
UNIT
(
base_intutil
)
{
uint32_t
i
;
INFO
(
"IntTraits<>."
);
EXPECT
(
IntTraits
<
signed
char
>::
kIsSigned
,
"IntTraits<signed char> should report signed."
);
EXPECT
(
IntTraits
<
unsigned
char
>::
kIsUnsigned
,
"IntTraits<unsigned char> should report unsigned."
);
EXPECT
(
IntTraits
<
signed
short
>::
kIsSigned
,
"IntTraits<signed short> should report signed."
);
EXPECT
(
IntTraits
<
unsigned
short
>::
kIsUnsigned
,
"IntTraits<unsigned short> should report unsigned."
);
EXPECT
(
IntTraits
<
int
>::
kIsSigned
,
"IntTraits<int> should report signed."
);
EXPECT
(
IntTraits
<
unsigned
int
>::
kIsUnsigned
,
"IntTraits<unsigned int> should report unsigned."
);
EXPECT
(
IntTraits
<
long
>::
kIsSigned
,
"IntTraits<long> should report signed."
);
EXPECT
(
IntTraits
<
unsigned
long
>::
kIsUnsigned
,
"IntTraits<unsigned long> should report unsigned."
);
EXPECT
(
IntTraits
<
intptr_t
>::
kIsSigned
,
"IntTraits<intptr_t> should report signed."
);
EXPECT
(
IntTraits
<
uintptr_t
>::
kIsUnsigned
,
"IntTraits<uintptr_t> should report unsigned."
);
EXPECT
(
IntTraits
<
intptr_t
>::
kIsIntPtr
,
"IntTraits<intptr_t> should report intptr_t type."
);
EXPECT
(
IntTraits
<
uintptr_t
>::
kIsIntPtr
,
"IntTraits<uintptr_t> should report intptr_t type."
);
INFO
(
"IntUtil::iMin()/iMax()."
);
EXPECT
(
IntUtil
::
iMin
<
int
>
(
0
,
-
1
)
==
-
1
,
"IntUtil::iMin<int> should return a minimum value."
);
EXPECT
(
IntUtil
::
iMin
<
int
>
(
-
1
,
-
2
)
==
-
2
,
"IntUtil::iMin<int> should return a minimum value."
);
EXPECT
(
IntUtil
::
iMin
<
int
>
(
1
,
2
)
==
1
,
"IntUtil::iMin<int> should return a minimum value."
);
EXPECT
(
IntUtil
::
iMax
<
int
>
(
0
,
-
1
)
==
0
,
"IntUtil::iMax<int> should return a maximum value."
);
EXPECT
(
IntUtil
::
iMax
<
int
>
(
-
1
,
-
2
)
==
-
1
,
"IntUtil::iMax<int> should return a maximum value."
);
EXPECT
(
IntUtil
::
iMax
<
int
>
(
1
,
2
)
==
2
,
"IntUtil::iMax<int> should return a maximum value."
);
INFO
(
"IntUtil::inInterval()."
);
EXPECT
(
IntUtil
::
inInterval
<
int
>
(
11
,
10
,
20
)
==
true
,
"IntUtil::inInterval<int> should return true if inside."
);
EXPECT
(
IntUtil
::
inInterval
<
int
>
(
101
,
10
,
20
)
==
false
,
"IntUtil::inInterval<int> should return false if outside."
);
INFO
(
"IntUtil::isInt8()."
);
EXPECT
(
IntUtil
::
isInt8
(
-
128
)
==
true
,
"IntUtil::isInt8<> should return true if inside."
);
EXPECT
(
IntUtil
::
isInt8
(
127
)
==
true
,
"IntUtil::isInt8<> should return true if inside."
);
EXPECT
(
IntUtil
::
isInt8
(
-
129
)
==
false
,
"IntUtil::isInt8<> should return false if outside."
);
EXPECT
(
IntUtil
::
isInt8
(
128
)
==
false
,
"IntUtil::isInt8<> should return false if outside."
);
INFO
(
"IntUtil::isUInt8()."
);
EXPECT
(
IntUtil
::
isUInt8
(
255
)
==
true
,
"IntUtil::isUInt8<> should return true if inside."
);
EXPECT
(
IntUtil
::
isUInt8
(
256
)
==
false
,
"IntUtil::isUInt8<> should return false if outside."
);
EXPECT
(
IntUtil
::
isUInt8
(
-
1
)
==
false
,
"IntUtil::isUInt8<> should return false if negative."
);
INFO
(
"IntUtil::isInt16()."
);
EXPECT
(
IntUtil
::
isInt16
(
-
32768
)
==
true
,
"IntUtil::isInt16<> should return true if inside."
);
EXPECT
(
IntUtil
::
isInt16
(
32767
)
==
true
,
"IntUtil::isInt16<> should return true if inside."
);
EXPECT
(
IntUtil
::
isInt16
(
-
32769
)
==
false
,
"IntUtil::isInt16<> should return false if outside."
);
EXPECT
(
IntUtil
::
isInt16
(
32768
)
==
false
,
"IntUtil::isInt16<> should return false if outside."
);
INFO
(
"IntUtil::isUInt16()."
);
EXPECT
(
IntUtil
::
isUInt16
(
65535
)
==
true
,
"IntUtil::isUInt16<> should return true if inside."
);
EXPECT
(
IntUtil
::
isUInt16
(
65536
)
==
false
,
"IntUtil::isUInt16<> should return false if outside."
);
EXPECT
(
IntUtil
::
isUInt16
(
-
1
)
==
false
,
"IntUtil::isUInt16<> should return false if negative."
);
INFO
(
"IntUtil::isInt32()."
);
EXPECT
(
IntUtil
::
isInt32
(
2147483647
)
==
true
,
"IntUtil::isInt32<int> should return true if inside."
);
EXPECT
(
IntUtil
::
isInt32
(
-
2147483647
-
1
)
==
true
,
"IntUtil::isInt32<int> should return true if inside."
);
EXPECT
(
IntUtil
::
isInt32
(
ASMJIT_UINT64_C
(
2147483648
))
==
false
,
"IntUtil::isInt32<int> should return false if outside."
);
EXPECT
(
IntUtil
::
isInt32
(
ASMJIT_UINT64_C
(
0xFFFFFFFF
))
==
false
,
"IntUtil::isInt32<int> should return false if outside."
);
EXPECT
(
IntUtil
::
isInt32
(
ASMJIT_UINT64_C
(
0xFFFFFFFF
)
+
1
)
==
false
,
"IntUtil::isInt32<int> should return false if outside."
);
INFO
(
"IntUtil::isUInt32()."
);
EXPECT
(
IntUtil
::
isUInt32
(
ASMJIT_UINT64_C
(
0xFFFFFFFF
))
==
true
,
"IntUtil::isUInt32<int> should return true if inside."
);
EXPECT
(
IntUtil
::
isUInt32
(
ASMJIT_UINT64_C
(
0xFFFFFFFF
)
+
1
)
==
false
,
"IntUtil::isUInt32<int> should return false if outside."
);
EXPECT
(
IntUtil
::
isUInt32
(
-
1
)
==
false
,
"IntUtil::isUInt32<int> should return false if negative."
);
INFO
(
"IntUtil::isPower2()."
);
for
(
i
=
0
;
i
<
64
;
i
++
)
{
EXPECT
(
IntUtil
::
isPowerOf2
(
static_cast
<
uint64_t
>
(
1
)
<<
i
)
==
true
,
"IntUtil::isPower2() didn't report power of 2."
);
EXPECT
(
IntUtil
::
isPowerOf2
((
static_cast
<
uint64_t
>
(
1
)
<<
i
)
^
0x001101
)
==
false
,
"IntUtil::isPower2() didn't report not power of 2."
);
}
INFO
(
"IntUtil::mask()."
);
for
(
i
=
0
;
i
<
32
;
i
++
)
{
EXPECT
(
IntUtil
::
mask
(
i
)
==
(
1
<<
i
),
"IntUtil::mask(%u) should return %X."
,
i
,
(
1
<<
i
));
}
INFO
(
"IntUtil::bits()."
);
for
(
i
=
0
;
i
<
32
;
i
++
)
{
uint32_t
expectedBits
=
0
;
for
(
uint32_t
b
=
0
;
b
<
i
;
b
++
)
expectedBits
|=
static_cast
<
uint32_t
>
(
1
)
<<
b
;
EXPECT
(
IntUtil
::
bits
(
i
)
==
expectedBits
,
"IntUtil::bits(%u) should return %X."
,
i
,
expectedBits
);
}
INFO
(
"IntUtil::hasBit()."
);
for
(
i
=
0
;
i
<
32
;
i
++
)
{
EXPECT
(
IntUtil
::
hasBit
((
1
<<
i
),
i
)
==
true
,
"IntUtil::hasBit(%X, %u) should return true."
,
(
1
<<
i
),
i
);
}
INFO
(
"IntUtil::bitCount()."
);
for
(
i
=
0
;
i
<
32
;
i
++
)
{
EXPECT
(
IntUtil
::
bitCount
((
1
<<
i
))
==
1
,
"IntUtil::bitCount(%X) should return true."
,
(
1
<<
i
));
}
EXPECT
(
IntUtil
::
bitCount
(
0x000000F0
)
==
4
,
""
);
EXPECT
(
IntUtil
::
bitCount
(
0x10101010
)
==
4
,
""
);
EXPECT
(
IntUtil
::
bitCount
(
0xFF000000
)
==
8
,
""
);
EXPECT
(
IntUtil
::
bitCount
(
0xFFFFFFF7
)
==
31
,
""
);
EXPECT
(
IntUtil
::
bitCount
(
0x7FFFFFFF
)
==
31
,
""
);
INFO
(
"IntUtil::findFirstBit()."
);
for
(
i
=
0
;
i
<
32
;
i
++
)
{
EXPECT
(
IntUtil
::
findFirstBit
((
1
<<
i
))
==
i
,
"IntUtil::findFirstBit(%X) should return %u."
,
(
1
<<
i
),
i
);
}
INFO
(
"IntUtil::isAligned()."
);
EXPECT
(
IntUtil
::
isAligned
<
size_t
>
(
0xFFFF
,
4
)
==
false
,
""
);
EXPECT
(
IntUtil
::
isAligned
<
size_t
>
(
0xFFF4
,
4
)
==
true
,
""
);
EXPECT
(
IntUtil
::
isAligned
<
size_t
>
(
0xFFF8
,
8
)
==
true
,
""
);
EXPECT
(
IntUtil
::
isAligned
<
size_t
>
(
0xFFF0
,
16
)
==
true
,
""
);
INFO
(
"IntUtil::alignTo()."
);
EXPECT
(
IntUtil
::
alignTo
<
size_t
>
(
0xFFFF
,
4
)
==
0x10000
,
""
);
EXPECT
(
IntUtil
::
alignTo
<
size_t
>
(
0xFFF4
,
4
)
==
0x0FFF4
,
""
);
EXPECT
(
IntUtil
::
alignTo
<
size_t
>
(
0xFFF8
,
8
)
==
0x0FFF8
,
""
);
EXPECT
(
IntUtil
::
alignTo
<
size_t
>
(
0xFFF0
,
16
)
==
0x0FFF0
,
""
);
EXPECT
(
IntUtil
::
alignTo
<
size_t
>
(
0xFFF0
,
32
)
==
0x10000
,
""
);
INFO
(
"IntUtil::alignToPowerOf2()."
);
EXPECT
(
IntUtil
::
alignToPowerOf2
<
size_t
>
(
0xFFFF
)
==
0x10000
,
""
);
EXPECT
(
IntUtil
::
alignToPowerOf2
<
size_t
>
(
0xF123
)
==
0x10000
,
""
);
EXPECT
(
IntUtil
::
alignToPowerOf2
<
size_t
>
(
0x0F00
)
==
0x01000
,
""
);
EXPECT
(
IntUtil
::
alignToPowerOf2
<
size_t
>
(
0x0100
)
==
0x00100
,
""
);
EXPECT
(
IntUtil
::
alignToPowerOf2
<
size_t
>
(
0x1001
)
==
0x02000
,
""
);
INFO
(
"IntUtil::deltaTo()."
);
EXPECT
(
IntUtil
::
deltaTo
<
size_t
>
(
0xFFFF
,
4
)
==
1
,
""
);
EXPECT
(
IntUtil
::
deltaTo
<
size_t
>
(
0xFFF4
,
4
)
==
0
,
""
);
EXPECT
(
IntUtil
::
deltaTo
<
size_t
>
(
0xFFF8
,
8
)
==
0
,
""
);
EXPECT
(
IntUtil
::
deltaTo
<
size_t
>
(
0xFFF0
,
16
)
==
0
,
""
);
EXPECT
(
IntUtil
::
deltaTo
<
size_t
>
(
0xFFF0
,
32
)
==
16
,
""
);
}
#endif // ASMJIT_TEST
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
libraries/asmjit/base/intutil.h
0 → 100644
View file @
a83607d6
// [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/globals.h"
#if defined(_MSC_VER)
#pragma intrinsic(_BitScanForward)
#endif // ASMJIT_OS_WINDOWS
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::IntTraits]
// ============================================================================
//! \internal
template
<
typename
T
>
struct
IntTraits
{
enum
{
kIsSigned
=
static_cast
<
T
>
(
~
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]
// ============================================================================
//! Integer utilities.
struct
IntUtil
{
// --------------------------------------------------------------------------
// [Float <-> Int]
// --------------------------------------------------------------------------
//! \internal
union
Float
{
int32_t
i
;
float
f
;
};
//! \internal
union
Double
{
int64_t
i
;
double
d
;
};
//! Bit-cast `float` to 32-bit integer.
static
ASMJIT_INLINE
int32_t
floatAsInt
(
float
f
)
{
Float
m
;
m
.
f
=
f
;
return
m
.
i
;
}
//! Bit-cast 32-bit integer to `float`.
static
ASMJIT_INLINE
float
intAsFloat
(
int32_t
i
)
{
Float
m
;
m
.
i
=
i
;
return
m
.
f
;
}
//! Bit-cast `double` to 64-bit integer.
static
ASMJIT_INLINE
int64_t
doubleAsInt
(
double
d
)
{
Double
m
;
m
.
d
=
d
;
return
m
.
i
;
}
//! Bit-cast 64-bit integer to `double`.
static
ASMJIT_INLINE
double
intAsDouble
(
int64_t
i
)
{
Double
m
;
m
.
i
=
i
;
return
m
.
d
;
}
// --------------------------------------------------------------------------
// [AsmJit - Pack / Unpack]
// --------------------------------------------------------------------------
//! Pack two 8-bit integer and one 16-bit integer into a 32-bit integer as it
//! is an array of `{u0,u1,w2}`.
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
}
//! Pack four 8-bit integer into a 32-bit integer as it is an array of `{u0,u1,u2,u3}`.
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
}
//! Pack two 32-bit integer into a 64-bit integer as it is an array of `{u0,u1}`.
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.
//! Get minimum value of `a` and `b`.
template
<
typename
T
>
static
ASMJIT_INLINE
T
iMin
(
const
T
&
a
,
const
T
&
b
)
{
return
a
<
b
?
a
:
b
;
}
//! Get maximum value of `a` and `b`.
template
<
typename
T
>
static
ASMJIT_INLINE
T
iMax
(
const
T
&
a
,
const
T
&
b
)
{
return
a
>
b
?
a
:
b
;
}
// --------------------------------------------------------------------------
// [AsmJit - MaxUInt]
// --------------------------------------------------------------------------
//! Get maximum unsigned value of `T`.
template
<
typename
T
>
static
ASMJIT_INLINE
T
maxUInt
()
{
return
~
T
(
0
);
}
// --------------------------------------------------------------------------
// [AsmJit - InInterval]
// --------------------------------------------------------------------------
//! Get whether `x` is greater or equal than `start` and less or equal than `end`.
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]
// --------------------------------------------------------------------------
//! Get whether the given integer `x` can be casted to 8-bit signed 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
);
}
//! Get whether the given integer `x` can be casted to 8-bit unsigned 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
);
}
//! Get whether the given integer `x` can be casted to 16-bit signed 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
));
}
//! Get whether the given integer `x` can be casted to 16-bit unsigned 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
);
}
//! Get whether the given integer `x` can be casted to 32-bit signed integer.
template
<
typename
T
>
static
ASMJIT_INLINE
bool
isInt32
(
T
x
)
{
if
(
IntTraits
<
T
>::
kIsSigned
)
return
sizeof
(
T
)
<=
sizeof
(
int32_t
)
?
true
:
x
>=
T
(
-
2147483647
)
-
1
&&
x
<=
T
(
2147483647
);
else
return
x
>=
T
(
0
)
&&
(
sizeof
(
T
)
<=
sizeof
(
int32_t
)
?
true
:
x
<=
T
(
2147483647
));
}
//! Get whether the given integer `x` can be casted to 32-bit unsigned 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]
// --------------------------------------------------------------------------
//! Get whether the `n` value is a power of two (only one bit is set).
template
<
typename
T
>
static
ASMJIT_INLINE
bool
isPowerOf2
(
T
n
)
{
return
n
!=
0
&&
(
n
&
(
n
-
1
))
==
0
;
}
// --------------------------------------------------------------------------
// [AsmJit - Mask]
// --------------------------------------------------------------------------
//! Generate a bit-mask that has `x` bit set.
static
ASMJIT_INLINE
uint32_t
mask
(
uint32_t
x
)
{
ASMJIT_ASSERT
(
x
<
32
);
return
(
1U
<<
x
);
}
//! Generate a bit-mask that has `x0` and `x1` bits set.
static
ASMJIT_INLINE
uint32_t
mask
(
uint32_t
x0
,
uint32_t
x1
)
{
return
mask
(
x0
)
|
mask
(
x1
);
}
//! Generate a bit-mask that has `x0`, `x1` and `x2` bits set.
static
ASMJIT_INLINE
uint32_t
mask
(
uint32_t
x0
,
uint32_t
x1
,
uint32_t
x2
)
{
return
mask
(
x0
)
|
mask
(
x1
)
|
mask
(
x2
);
}
//! Generate a bit-mask that has `x0`, `x1`, `x2` and `x3` bits set.
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
);
}
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3` and `x4` bits set.
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
)
;
}
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4` and `x5` bits set.
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
)
;
}
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5` and `x6` bits set.
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
)
;
}
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6` and `x7` bits set.
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
)
;
}
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7` and `x8` bits set.
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
)
;
}
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7`, `x8` and `x9` bits set.
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]
// --------------------------------------------------------------------------
//! Generate a bit-mask that has `x` most significant bits set.
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]
// --------------------------------------------------------------------------
//! Get whether `x` has bit `n` set.
static
ASMJIT_INLINE
bool
hasBit
(
uint32_t
x
,
uint32_t
n
)
{
return
static_cast
<
bool
>
((
x
>>
n
)
&
0x1
);
}
// --------------------------------------------------------------------------
// [AsmJit - BitCount]
// --------------------------------------------------------------------------
//! Get count of bits in `x`.
//!
//! Taken 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]
// --------------------------------------------------------------------------
//! \internal
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
;
}
//! Find a first bit in `mask`.
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
;
}
//! Align `base` to `alignment`.
template
<
typename
T
>
static
ASMJIT_INLINE
T
alignTo
(
T
base
,
T
alignment
)
{
return
(
base
+
(
alignment
-
1
))
&
~
(
alignment
-
1
);
}
template
<
typename
T
>
static
ASMJIT_INLINE
T
alignToPowerOf2
(
T
base
)
{
// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.
base
-=
1
;
#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
;
}
//! Get delta required to align `base` to `alignment`.
template
<
typename
T
>
static
ASMJIT_INLINE
T
deltaTo
(
T
base
,
T
alignment
)
{
return
alignTo
(
base
,
alignment
)
-
base
;
}
};
// ============================================================================
// [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 "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_INTUTIL_H
libraries/asmjit/base/lock.h
0 → 100644
View file @
a83607d6
// [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 - Posix]
#if defined(ASMJIT_OS_POSIX)
# include <pthread.h>
#endif // ASMJIT_OS_POSIX
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::Lock]
// ============================================================================
//! Lock - used in thread-safe code for locking.
struct
Lock
{
ASMJIT_NO_COPY
(
Lock
)
// --------------------------------------------------------------------------
// [Windows]
// --------------------------------------------------------------------------
#if defined(ASMJIT_OS_WINDOWS)
typedef
CRITICAL_SECTION
Handle
;
//! Create a new `Lock` instance.
ASMJIT_INLINE
Lock
()
{
InitializeCriticalSection
(
&
_handle
);
}
//! Destroy the `Lock` instance.
ASMJIT_INLINE
~
Lock
()
{
DeleteCriticalSection
(
&
_handle
);
}
//! Lock.
ASMJIT_INLINE
void
lock
()
{
EnterCriticalSection
(
&
_handle
);
}
//! Unlock.
ASMJIT_INLINE
void
unlock
()
{
LeaveCriticalSection
(
&
_handle
);
}
#endif // ASMJIT_OS_WINDOWS
// --------------------------------------------------------------------------
// [Posix]
// --------------------------------------------------------------------------
#if defined(ASMJIT_OS_POSIX)
typedef
pthread_mutex_t
Handle
;
//! Create a new `Lock` instance.
ASMJIT_INLINE
Lock
()
{
pthread_mutex_init
(
&
_handle
,
NULL
);
}
//! Destroy the `Lock` instance.
ASMJIT_INLINE
~
Lock
()
{
pthread_mutex_destroy
(
&
_handle
);
}
//! Lock.
ASMJIT_INLINE
void
lock
()
{
pthread_mutex_lock
(
&
_handle
);
}
//! Unlock.
ASMJIT_INLINE
void
unlock
()
{
pthread_mutex_unlock
(
&
_handle
);
}
#endif // ASMJIT_OS_POSIX
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get handle.
ASMJIT_INLINE
Handle
&
getHandle
()
{
return
_handle
;
}
//! \overload
ASMJIT_INLINE
const
Handle
&
getHandle
()
const
{
return
_handle
;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Handle.
Handle
_handle
;
};
// ============================================================================
// [asmjit::AutoLock]
// ============================================================================
//! Scoped lock.
struct
AutoLock
{
ASMJIT_NO_COPY
(
AutoLock
)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Autolock `target`, scoped.
ASMJIT_INLINE
AutoLock
(
Lock
&
target
)
:
_target
(
target
)
{
_target
.
lock
();
}
//! Autounlock `target`.
ASMJIT_INLINE
~
AutoLock
()
{
_target
.
unlock
();
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Pointer to target (lock).
Lock
&
_target
;
};
//! \}
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_LOCK_H
libraries/asmjit/base/logger.cpp
0 → 100644
View file @
a83607d6
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Guard]
#include "../build.h"
#if !defined(ASMJIT_DISABLE_LOGGER)
// [Dependencies - AsmJit]
#include "../base/intutil.h"
#include "../base/logger.h"
#include "../base/string.h"
// [Dependencies - C]
#include <stdarg.h>
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
// ============================================================================
// [asmjit::Logger - Construction / Destruction]
// ============================================================================
Logger
::
Logger
()
{
_options
=
0
;
::
memset
(
_indentation
,
0
,
ASMJIT_ARRAY_SIZE
(
_indentation
));
}
Logger
::~
Logger
()
{}
// ============================================================================
// [asmjit::Logger - Logging]
// ============================================================================
void
Logger
::
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
Logger
::
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
::
iMin
<
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::Logger - LogBinary]
// ============================================================================
void
Logger
::
setOption
(
uint32_t
id
,
bool
value
)
{
if
(
id
>=
kLoggerOptionCount
)
return
;
uint32_t
mask
=
1
<<
id
;
if
(
value
)
_options
|=
mask
;
else
_options
&=
~
mask
;
}
// ============================================================================
// [asmjit::Logger - Indentation]
// ============================================================================
void
Logger
::
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]
// ============================================================================
//! 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 "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_LOGGER
libraries/asmjit/base/logger.h
0 → 100644
View file @
a83607d6
// [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
#include "../build.h"
#if !defined(ASMJIT_DISABLE_LOGGER)
// [Dependencies - AsmJit]
#include "../base/string.h"
// [Dependencies - C]
#include <stdarg.h>
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::kLoggerOption]
// ============================================================================
//! Logger options.
ASMJIT_ENUM
(
kLoggerOption
)
{
//! Whether to output instructions also in binary form.
kLoggerOptionBinaryForm
=
0
,
//! Whether to output immediates as hexadecimal numbers.
kLoggerOptionHexImmediate
=
1
,
//! Whether to output displacements as hexadecimal numbers.
kLoggerOptionHexDisplacement
=
2
,
//! Count of logger options.
kLoggerOptionCount
=
3
};
// ============================================================================
// [asmjit::kLoggerStyle]
// ============================================================================
//! Logger style.
ASMJIT_ENUM
(
kLoggerStyle
)
{
kLoggerStyleDefault
=
0
,
kLoggerStyleDirective
=
1
,
kLoggerStyleLabel
=
2
,
kLoggerStyleData
=
3
,
kLoggerStyleComment
=
4
,
kLoggerStyleCount
=
5
};
// ============================================================================
// [asmjit::Logger]
// ============================================================================
//! Abstract logging class.
//!
//! This class can be inherited and reimplemented to fit into your logging
//! subsystem. When reimplementing use `Logger::log()` method to log into
//! a custom stream.
//!
//! This class also contain `_enabled` member that can be used to enable
//! or disable logging.
struct
ASMJIT_VCLASS
Logger
{
ASMJIT_NO_COPY
(
Logger
)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a `Logger` instance.
ASMJIT_API
Logger
();
//! Destroy the `Logger` instance.
ASMJIT_API
virtual
~
Logger
();
// --------------------------------------------------------------------------
// [Logging]
// --------------------------------------------------------------------------
//! Log output.
virtual
void
logString
(
uint32_t
style
,
const
char
*
buf
,
size_t
len
=
kInvalidIndex
)
=
0
;
//! Log formatter message (like sprintf) sending output to `logString()` method.
ASMJIT_API
void
logFormat
(
uint32_t
style
,
const
char
*
fmt
,
...);
//! Log binary data.
ASMJIT_API
void
logBinary
(
uint32_t
style
,
const
void
*
data
,
size_t
size
);
// --------------------------------------------------------------------------
// [Options]
// --------------------------------------------------------------------------
//! Get all logger options as a single integer.
ASMJIT_INLINE
uint32_t
getOptions
()
const
{
return
_options
;
}
//! Get the given logger option.
ASMJIT_INLINE
bool
getOption
(
uint32_t
id
)
const
{
ASMJIT_ASSERT
(
id
<
kLoggerOptionCount
);
return
static_cast
<
bool
>
((
_options
>>
id
)
&
0x1
);
}
//! Set the given logger option.
ASMJIT_API
void
setOption
(
uint32_t
id
,
bool
value
);
// --------------------------------------------------------------------------
// [Indentation]
// --------------------------------------------------------------------------
//! Get indentation.
ASMJIT_INLINE
const
char
*
getIndentation
()
const
{
return
_indentation
;
}
//! Set indentation.
ASMJIT_API
void
setIndentation
(
const
char
*
indentation
);
//! Reset indentation.
ASMJIT_INLINE
void
resetIndentation
()
{
setIndentation
(
NULL
);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Options, see `kLoggerOption`.
uint32_t
_options
;
//! Indentation.
char
_indentation
[
12
];
};
// ============================================================================
// [asmjit::FileLogger]
// ============================================================================
//! Logger that can log to standard C `FILE*` stream.
struct
ASMJIT_VCLASS
FileLogger
:
public
Logger
{
ASMJIT_NO_COPY
(
FileLogger
)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `FileLogger` that logs to a `FILE` stream.
ASMJIT_API
FileLogger
(
FILE
*
stream
=
NULL
);
//! Destroy the `FileLogger`.
ASMJIT_API
virtual
~
FileLogger
();
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get `FILE*` stream.
//!
//! \note Return value can be `NULL`.
ASMJIT_INLINE
FILE
*
getStream
()
const
{
return
_stream
;
}
//! Set `FILE*` stream, can be set to `NULL` to disable logging, although
//! the `CodeGen` will still call `logString` even if there is no stream.
ASMJIT_API
void
setStream
(
FILE
*
stream
);
// --------------------------------------------------------------------------
// [Logging]
// --------------------------------------------------------------------------
ASMJIT_API
virtual
void
logString
(
uint32_t
style
,
const
char
*
buf
,
size_t
len
=
kInvalidIndex
);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! C file stream.
FILE
*
_stream
;
};
// ============================================================================
// [asmjit::StringLogger]
// ============================================================================
//! String logger.
struct
ASMJIT_VCLASS
StringLogger
:
public
Logger
{
ASMJIT_NO_COPY
(
StringLogger
)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create new `StringLogger`.
ASMJIT_API
StringLogger
();
//! Destroy the `StringLogger`.
ASMJIT_API
virtual
~
StringLogger
();
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get <code>char*</code> pointer which represents the resulting
//! string.
//!
//! The pointer is owned by `StringLogger`, it can't be modified or freed.
ASMJIT_INLINE
const
char
*
getString
()
const
{
return
_stringBuilder
.
getData
();
}
//! 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]
// --------------------------------------------------------------------------
//! Output.
StringBuilder
_stringBuilder
;
};
//! \}
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_LOGGER
#endif // _ASMJIT_BASE_LOGGER_H
libraries/asmjit/base/operand.cpp
0 → 100644
View file @
a83607d6
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
// ============================================================================
// [asmjit::Operand]
// ============================================================================
// Prevent static initialization.
struct
Operand
{
uint8_t
op
;
uint8_t
size
;
uint8_t
reserved_2_1
;
uint8_t
reserved_3_1
;
uint32_t
id
;
uint64_t
reserved_8_8
;
};
ASMJIT_VAR
const
Operand
noOperand
;
const
Operand
noOperand
=
{
0
,
0
,
0
,
0
,
kInvalidValue
,
0
};
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
libraries/asmjit/base/operand.h
0 → 100644
View file @
a83607d6
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_OPERAND_H
#define _ASMJIT_BASE_OPERAND_H
// [Dependencies - AsmJit]
#include "../base/intutil.h"
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
// ============================================================================
// [Forward Declarations]
// ============================================================================
struct
Assembler
;
struct
Compiler
;
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kOperandType]
// ============================================================================
//! Operand types that can be encoded in `Operand`.
ASMJIT_ENUM
(
kOperandType
)
{
//! Invalid operand, used only internally (not initialized Operand).
kOperandTypeNone
=
0
,
//! Operand is a register.
kOperandTypeReg
=
1
,
//! Operand is a variable.
kOperandTypeVar
=
2
,
//! Operand is a memory.
kOperandTypeMem
=
3
,
//! Operand is an immediate value.
kOperandTypeImm
=
4
,
//! Operand is a label.
kOperandTypeLabel
=
5
};
// ============================================================================
// [asmjit::kOperandId]
// ============================================================================
//! Operand id masks used to determine the operand type.
ASMJIT_ENUM
(
kOperandId
)
{
//! Operand id refers to `Var`.
kOperandIdVar
=
0x80000000U
,
//! Operand id to real index mask.
kOperandIdNum
=
0x7FFFFFFFU
};
// ============================================================================
// [asmjit::kRegClass]
// ============================================================================
//! Register class.
ASMJIT_ENUM
(
kRegClass
)
{
//! Gp register class, compatible with all architectures.
kRegClassGp
=
0
};
// ============================================================================
// [asmjit::kSize]
// ============================================================================
//! Common size of registers and pointers.
ASMJIT_ENUM
(
kSize
)
{
//! 1 byte size (BYTE).
kSizeByte
=
1
,
//! 2 bytes size (WORD).
kSizeWord
=
2
,
//! 4 bytes size (DWORD).
kSizeDWord
=
4
,
//! 8 bytes size (QWORD).
kSizeQWord
=
8
,
//! 10 bytes size (TWORD).
kSizeTWord
=
10
,
//! 16 bytes size (OWORD / DQWORD).
kSizeOWord
=
16
,
//! 32 bytes size (YWORD / QQWORD).
kSizeYWord
=
32
};
// ============================================================================
// [asmjit::kMemType]
// ============================================================================
//! Type of memory operand.
ASMJIT_ENUM
(
kMemType
)
{
//! Memory operand is a combination of base register and optional index register
//! and displacement.
//!
//! The `Assembler` interprets `kMemTypeBaseIndex` and `kMemTypeStackIndex`
//! types the same way, but `Compiler` interprets `kMemTypeBaseIndex` as
//! `[base + index]` and `kMemTypeStackIndex` as `[stack(base) + index]`.
kMemTypeBaseIndex
=
0
,
//! Memory operand is a combination of variable's memory location,
//! optional index register and displacement.
//!
//! The `Assembler` interprets `kMemTypeBaseIndex` and `kMemTypeStackIndex`
//! types in the same way, but `Compiler` interprets `kMemTypeBaseIndex` as
//! `[base + index]` and `kMemTypeStackIndex` as `[stack(base) + index]`.
kMemTypeStackIndex
=
1
,
//! Memory operand refers to the memory location specified by a label.
kMemTypeLabel
=
2
,
//! Memory operand is an absolute memory location.
//!
//! Supported mostly by x86, truncated to a 32-bit value when running in
//! 64-bit mode (x64).
kMemTypeAbsolute
=
3
};
// ============================================================================
// [asmjit::Operand]
// ============================================================================
//! Operand can contain register, memory location, immediate, or label.
struct
Operand
{
// --------------------------------------------------------------------------
// [Structs]
// --------------------------------------------------------------------------
//! \internal
//!
//! Base operand data.
struct
BaseOp
{
//! Type of operand, see `kOperandType`.
uint8_t
op
;
//! Size of operand (register, address, immediate, or variable).
uint8_t
size
;
//! \internal
uint8_t
reserved_2_1
;
//! \internal
uint8_t
reserved_3_1
;
//! Operand id, identifier used by `Assembler` and `Compiler`.
//!
//! \note Uninitialized operand has always set id to `kInvalidValue`.
uint32_t
id
;
//! \internal
uint32_t
reserved_8_4
;
//! \internal
uint32_t
reserved_12_4
;
};
//! \internal
//!
//! Register or Variable operand data.
struct
VRegOp
{
//! Type of operand, `kOperandTypeReg`.
uint8_t
op
;
//! Size of register or variable.
uint8_t
size
;
union
{
//! Register code = (type << 8) | index.
uint16_t
code
;
//! Register type and index access.
struct
{
#if defined(ASMJIT_HOST_LE)
//! Register index.
uint8_t
index
;
//! Register type.
uint8_t
type
;
#else
//! Register type.
uint8_t
type
;
//! Register index.
uint8_t
index
;
#endif // ASMJIT_HOST
};
};
//! Variable id, used by `Compiler` to identify variables.
uint32_t
id
;
union
{
struct
{
//! Variable type.
uint32_t
vType
;
//! \internal
uint32_t
reserved_12_4
;
};
//! \internal
//!
//! This is not needed or used, it's just to force compiler to always
//! align this struct to 8-bytes (so the struct is compatible to others
//! when it comes to alignment). It should fix VS linker warning as well.
uint64_t
reserved8_8
;
};
};
//! \internal
//!
//! Memory or Variable operand data.
struct
VMemOp
{
//! Type of operand, `kOperandTypeMem`.
uint8_t
op
;
//! Size of the pointer in bytes.
uint8_t
size
;
//! Type of the memory operand, see `kMemType`.
uint8_t
type
;
//! X86/X64 layout:
//! - segment [3 bits], see `kX86Seg`.
//! - shift [2 bits], index register shift (0 to 3).
uint8_t
flags
;
//! Base register, variable or label id.
uint32_t
base
;
//! Index register or variable.
uint32_t
index
;
//! 32-bit displacement or absolute address.
int32_t
displacement
;
};
//! \internal
//!
//! Immediate operand data.
struct
ImmOp
{
//! Type of operand, `kOperandTypeImm`.
uint8_t
op
;
//! Size of immediate (or 0 to autodetect).
uint8_t
size
;
//! \internal
uint8_t
reserved_2_1
;
//! \internal
uint8_t
reserved_3_1
;
//! Operand id, always set to `kInvalidValue` (immediates don't have IDs).
uint32_t
id
;
union
{
//! 8x8-bit signed immediate values.
int8_t
_i8
[
8
];
//! 8x8-bit unsigned immediate values.
uint8_t
_u8
[
8
];
//! 4x16-bit signed immediate values.
int16_t
_i16
[
4
];
//! 4x16-bit unsigned immediate values.
uint16_t
_u16
[
4
];
//! 2x32-bit signed immediate values.
int32_t
_i32
[
2
];
//! 2x32-bit unsigned immediate values.
uint32_t
_u32
[
2
];
//! 1x64-bit signed immediate value.
int64_t
_i64
[
1
];
//! 1x64-bit unsigned immediate value.
uint64_t
_u64
[
1
];
//! 2x SP-FP values.
float
_f32
[
2
];
//! 1x DP-FP value.
double
_f64
[
1
];
}
value
;
};
//! \internal
//!
//! Label operand data.
struct
LabelOp
{
//! Type of operand, `kOperandTypeLabel`.
uint8_t
op
;
//! Always zero, labels don't have size.
uint8_t
size
;
//! \internal
uint8_t
reserved_2_1
;
//! \internal
uint8_t
reserved_3_1
;
//! Operand id (`kInvalidValue` if the label is not initialized by code
//! generator).
uint32_t
id
;
//! \internal
uint32_t
reserved_8_4
;
//! \internal
uint32_t
reserved_12_4
;
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create an uninitialized operand.
ASMJIT_INLINE
Operand
()
{
_init_packed_op_sz_b0_b1_id
(
kOperandTypeNone
,
0
,
0
,
0
,
kInvalidValue
);
_init_packed_d2_d3
(
0
,
0
);
}
//! Create a reference to `other` operand.
ASMJIT_INLINE
Operand
(
const
Operand
&
other
)
{
_init
(
other
);
}
explicit
ASMJIT_INLINE
Operand
(
const
_NoInit
&
)
{}
// --------------------------------------------------------------------------
// [Operand]
// --------------------------------------------------------------------------
//! Clone `Operand`.
ASMJIT_INLINE
Operand
clone
()
const
{
return
Operand
(
*
this
);
}
// --------------------------------------------------------------------------
// [Init & Copy]
// --------------------------------------------------------------------------
//! \internal
//!
//! Initialize operand to `other` (used by constructors).
ASMJIT_INLINE
void
_init
(
const
Operand
&
other
)
{
::
memcpy
(
this
,
&
other
,
sizeof
(
Operand
));
}
ASMJIT_INLINE
void
_init_packed_op_sz_b0_b1_id
(
uint32_t
op
,
uint32_t
sz
,
uint32_t
r0
,
uint32_t
r1
,
uint32_t
id
)
{
// This hack is not for performance, but to decrease the size of the binary
// generated when constructing AsmJit operands (mostly for third parties).
// Some compilers are not able to join four BYTE writes to a single DWORD
// write. Because the 'a', 'b', 'c' and 'd' variables are usually compile
// time constants the compiler can do a really nice job if they are joined
// by using bitwise operations.
_packed
[
0
].
setPacked_2x32
(
IntUtil
::
pack32_4x8
(
op
,
sz
,
r0
,
r1
),
id
);
}
ASMJIT_INLINE
void
_init_packed_op_sz_w0_id
(
uint32_t
op
,
uint32_t
sz
,
uint32_t
w0
,
uint32_t
id
)
{
_packed
[
0
].
setPacked_2x32
(
IntUtil
::
pack32_2x8_1x16
(
op
,
sz
,
w0
),
id
);
}
ASMJIT_INLINE
void
_init_packed_d0_d1
(
uint32_t
u0
,
uint32_t
u1
)
{
_packed
[
0
].
setPacked_2x32
(
u0
,
u1
);
}
ASMJIT_INLINE
void
_init_packed_d2_d3
(
uint32_t
u2
,
uint32_t
u3
)
{
_packed
[
1
].
setPacked_2x32
(
u2
,
u3
);
}
//! \internal
//!
//! Initialize operand to `other` (used by assign operators).
ASMJIT_INLINE
void
_copy
(
const
Operand
&
other
)
{
::
memcpy
(
this
,
&
other
,
sizeof
(
Operand
));
}
// --------------------------------------------------------------------------
// [Data]
// --------------------------------------------------------------------------
template
<
typename
T
>
ASMJIT_INLINE
T
&
getData
()
{
return
reinterpret_cast
<
T
&>
(
_base
);
}
template
<
typename
T
>
ASMJIT_INLINE
const
T
&
getData
()
const
{
return
reinterpret_cast
<
const
T
&>
(
_base
);
}
// --------------------------------------------------------------------------
// [Type]
// --------------------------------------------------------------------------
//! Get type of the operand, see `kOperandType`.
ASMJIT_INLINE
uint32_t
getOp
()
const
{
return
_base
.
op
;
}
//! Get whether the operand is none - `kOperandTypeNone`.
ASMJIT_INLINE
bool
isNone
()
const
{
return
(
_base
.
op
==
kOperandTypeNone
);
}
//! Get whether the operand is a register - `kOperandTypeReg`.
ASMJIT_INLINE
bool
isReg
()
const
{
return
(
_base
.
op
==
kOperandTypeReg
);
}
//! Get whether the operand is a variable - `kOperandTypeVar`.
ASMJIT_INLINE
bool
isVar
()
const
{
return
(
_base
.
op
==
kOperandTypeVar
);
}
//! Get whether the operand is a memory address - `kOperandTypeMem`.
ASMJIT_INLINE
bool
isMem
()
const
{
return
(
_base
.
op
==
kOperandTypeMem
);
}
//! Get whether the operand is an immediate value - `kOperandTypeImm`.
ASMJIT_INLINE
bool
isImm
()
const
{
return
(
_base
.
op
==
kOperandTypeImm
);
}
//! Get whether the operand is a label - `kOperandTypeLabel`.
ASMJIT_INLINE
bool
isLabel
()
const
{
return
(
_base
.
op
==
kOperandTypeLabel
);
}
// --------------------------------------------------------------------------
// [Type - Combined]
// --------------------------------------------------------------------------
//! Get register type.
ASMJIT_INLINE
uint32_t
getRegType
()
const
{
return
_vreg
.
type
;
}
//! Get register index.
ASMJIT_INLINE
uint32_t
getRegIndex
()
const
{
return
_vreg
.
index
;
}
//! Get whether the operand is register of `type`.
ASMJIT_INLINE
bool
isRegType
(
uint32_t
type
)
const
{
return
(
_packed
[
0
].
u32
[
0
]
&
IntUtil
::
pack32_2x8_1x16
(
0xFF
,
0
,
0xFF00
))
==
IntUtil
::
pack32_2x8_1x16
(
kOperandTypeReg
,
0
,
(
type
<<
8
));
}
//! Get whether the operand is register and of `type` and `index`.
ASMJIT_INLINE
bool
isRegCode
(
uint32_t
type
,
uint32_t
index
)
const
{
return
(
_packed
[
0
].
u32
[
0
]
&
IntUtil
::
pack32_2x8_1x16
(
0xFF
,
0
,
0xFFFF
))
==
IntUtil
::
pack32_2x8_1x16
(
kOperandTypeReg
,
0
,
(
type
<<
8
)
+
index
);
}
//! Get whether the operand is a register or memory.
ASMJIT_INLINE
bool
isRegOrMem
()
const
{
ASMJIT_ASSERT
(
kOperandTypeReg
==
1
);
ASMJIT_ASSERT
(
kOperandTypeMem
==
3
);
return
(
static_cast
<
uint32_t
>
(
_base
.
op
)
|
0x2U
)
==
0x3U
;
}
//! Get whether the operand is variable or memory.
ASMJIT_INLINE
bool
isVarOrMem
()
const
{
ASMJIT_ASSERT
(
kOperandTypeVar
==
2
);
ASMJIT_ASSERT
(
kOperandTypeMem
==
3
);
return
(
static_cast
<
uint32_t
>
(
_base
.
op
)
-
2U
)
<=
1
;
}
// --------------------------------------------------------------------------
// [Size]
// --------------------------------------------------------------------------
//! Get size of the operand in bytes.
ASMJIT_INLINE
uint32_t
getSize
()
const
{
return
_base
.
size
;
}
// --------------------------------------------------------------------------
// [Id]
// --------------------------------------------------------------------------
//! Get operand id.
//!
//! Operand id's are used internally by `Assembler` and `Compiler`.
//!
//! There is no way to change or remove operand id. Unneeded operands can be
//! simply reassigned by `operator=`.
ASMJIT_INLINE
uint32_t
getId
()
const
{
return
_base
.
id
;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
union
{
//! Base data.
BaseOp
_base
;
//! Register or variable data.
VRegOp
_vreg
;
//! Memory data.
VMemOp
_vmem
;
//! Immediate data.
ImmOp
_imm
;
//! Label data.
LabelOp
_label
;
//! Packed operand as two 64-bit integers.
UInt64
_packed
[
2
];
};
};
// ============================================================================
// [asmjit::OperandUtil]
// ============================================================================
//! Operand utilities.
struct
OperandUtil
{
//! Make variable id.
static
ASMJIT_INLINE
uint32_t
makeVarId
(
uint32_t
id
)
{
return
id
|
kOperandIdVar
;
}
//! Make label id.
static
ASMJIT_INLINE
uint32_t
makeLabelId
(
uint32_t
id
)
{
return
id
;
}
//! Strip variable id bit so it becomes a pure index to `VarData[]` array.
static
ASMJIT_INLINE
uint32_t
stripVarId
(
uint32_t
id
)
{
return
id
&
0x7FFFFFFFU
;
}
//! Get whether the id refers to `Var`.
//!
//! \note The function will never return `true` if the id is `kInvalidValue`.
//! The trick is to compare a given id to -1 (kInvalidValue) so we check both
//! using only one comparison.
static
ASMJIT_INLINE
bool
isVarId
(
uint32_t
id
)
{
return
static_cast
<
int32_t
>
(
id
)
<
-
1
;
}
//! Get whether the id refers to `Label`.
//!
//! \note The function will never return `true` if the id is `kInvalidValue`.
static
ASMJIT_INLINE
bool
isLabelId
(
uint32_t
id
)
{
return
static_cast
<
int32_t
>
(
id
)
>=
0
;
}
};
// ============================================================================
// [asmjit::Reg]
// ============================================================================
//! Base class for all register operands.
struct
Reg
:
public
Operand
{
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a dummy base register.
ASMJIT_INLINE
Reg
()
:
Operand
(
NoInit
)
{
_init_packed_op_sz_w0_id
(
kOperandTypeReg
,
0
,
(
kInvalidReg
<<
8
)
+
kInvalidReg
,
kInvalidValue
);
_init_packed_d2_d3
(
kInvalidVar
,
0
);
}
//! Create a new base register.
ASMJIT_INLINE
Reg
(
uint32_t
type
,
uint32_t
index
,
uint32_t
size
)
:
Operand
(
NoInit
)
{
_init_packed_op_sz_w0_id
(
kOperandTypeReg
,
size
,
(
type
<<
8
)
+
index
,
kInvalidValue
);
_init_packed_d2_d3
(
kInvalidVar
,
0
);
}
//! Create a new reference to `other`.
ASMJIT_INLINE
Reg
(
const
Reg
&
other
)
:
Operand
(
other
)
{}
//! Create a new reference to `other` and change the index to `index`.
ASMJIT_INLINE
Reg
(
const
Reg
&
other
,
uint32_t
index
)
:
Operand
(
other
)
{
_vreg
.
index
=
static_cast
<
uint8_t
>
(
index
);
}
explicit
ASMJIT_INLINE
Reg
(
const
_NoInit
&
)
:
Operand
(
NoInit
)
{}
// --------------------------------------------------------------------------
// [Reg Specific]
// --------------------------------------------------------------------------
//! Clone `Reg` operand.
ASMJIT_INLINE
Reg
clone
()
const
{
return
Reg
(
*
this
);
}
//! Get whether register code is equal to `type`.
ASMJIT_INLINE
bool
isRegType
(
uint32_t
type
)
const
{
return
_vreg
.
type
==
type
;
}
//! Get whether register code is equal to `type`.
ASMJIT_INLINE
bool
isRegCode
(
uint32_t
code
)
const
{
return
_vreg
.
code
==
code
;
}
//! Get whether register code is equal to `type`.
ASMJIT_INLINE
bool
isRegCode
(
uint32_t
type
,
uint32_t
index
)
const
{
return
_vreg
.
code
==
(
type
<<
8
)
+
index
;
}
//! Get register code that equals to '(type << 8) + index'.
ASMJIT_INLINE
uint32_t
getRegCode
()
const
{
return
_vreg
.
code
;
}
//! Get register type.
ASMJIT_INLINE
uint32_t
getRegType
()
const
{
return
_vreg
.
type
;
}
//! Get register index.
ASMJIT_INLINE
uint32_t
getRegIndex
()
const
{
return
_vreg
.
index
;
}
#define ASMJIT_REG_OP(_Type_) \
ASMJIT_INLINE _Type_ clone() const { \
return _Type_(*this); \
} \
\
/*! Set register `size`. */
\
ASMJIT_INLINE _Type_& setSize(uint32_t size) { \
_vreg.size = static_cast<uint8_t>(size); \
return *this; \
} \
\
/*! Set register `code`. */
\
ASMJIT_INLINE _Type_& setCode(uint32_t code) { \
_vreg.code = static_cast<uint16_t>(code); \
return *this; \
} \
\
/*! Set register `type` and `index`. */
\
ASMJIT_INLINE _Type_& setCode(uint32_t type, uint32_t index) { \
_vreg.type = static_cast<uint8_t>(type); \
_vreg.index = static_cast<uint8_t>(index); \
return *this; \
} \
\
/*! Set register `type`. */
\
ASMJIT_INLINE _Type_& setType(uint32_t type) { \
_vreg.type = static_cast<uint8_t>(type); \
return *this; \
} \
\
/*! Set register `index`. */
\
ASMJIT_INLINE _Type_& setIndex(uint32_t index) { \
_vreg.index = static_cast<uint8_t>(index); \
return *this; \
} \
\
ASMJIT_INLINE _Type_& operator=(const _Type_& other) { _copy(other); return *this; } \
\
ASMJIT_INLINE bool operator==(const _Type_& other) const { return _packed[0].u32[0] == other._packed[0].u32[0]; } \
ASMJIT_INLINE bool operator!=(const _Type_& other) const { return !operator==(other); }
};
// ============================================================================
// [asmjit::BaseMem]
// ============================================================================
//! Base class for all memory operands.
struct
BaseMem
:
public
Operand
{
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE
BaseMem
()
:
Operand
(
NoInit
)
{
reset
();
}
ASMJIT_INLINE
BaseMem
(
const
BaseMem
&
other
)
:
Operand
(
other
)
{}
explicit
ASMJIT_INLINE
BaseMem
(
const
_NoInit
&
)
:
Operand
(
NoInit
)
{}
// --------------------------------------------------------------------------
// [BaseMem Specific]
// --------------------------------------------------------------------------
//! Clone `BaseMem` operand.
ASMJIT_INLINE
BaseMem
clone
()
const
{
return
BaseMem
(
*
this
);
}
//! Reset `BaseMem` operand.
ASMJIT_INLINE
void
reset
()
{
_init_packed_op_sz_b0_b1_id
(
kOperandTypeMem
,
0
,
kMemTypeBaseIndex
,
0
,
kInvalidValue
);
_init_packed_d2_d3
(
kInvalidValue
,
0
);
}
//! Get the type of the memory operand, see `kMemType`.
ASMJIT_INLINE
uint32_t
getMemType
()
const
{
return
_vmem
.
type
;
}
//! Get whether the type of the memory operand is either `kMemTypeBaseIndex`
//! or `kMemTypeStackIndex`.
ASMJIT_INLINE
bool
isBaseIndexType
()
const
{
return
_vmem
.
type
<=
kMemTypeStackIndex
;
}
//! Get whether the memory operand has base register.
ASMJIT_INLINE
bool
hasBase
()
const
{
return
_vmem
.
base
!=
kInvalidValue
;
}
//! Get memory operand base id, or `kInvalidValue`.
ASMJIT_INLINE
uint32_t
getBase
()
const
{
return
_vmem
.
base
;
}
//! Set memory operand size.
ASMJIT_INLINE
BaseMem
&
setSize
(
uint32_t
size
)
{
_vmem
.
size
=
static_cast
<
uint8_t
>
(
size
);
return
*
this
;
}
//! Get memory operand relative displacement.
ASMJIT_INLINE
int32_t
getDisplacement
()
const
{
return
_vmem
.
displacement
;
}
//! Set memory operand relative displacement.
ASMJIT_INLINE
BaseMem
&
setDisplacement
(
int32_t
disp
)
{
_vmem
.
displacement
=
disp
;
return
*
this
;
}
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
ASMJIT_INLINE
BaseMem
&
operator
=
(
const
BaseMem
&
other
)
{
_copy
(
other
);
return
*
this
;
}
ASMJIT_INLINE
bool
operator
==
(
const
BaseMem
&
other
)
const
{
return
(
_packed
[
0
]
==
other
.
_packed
[
0
])
&
(
_packed
[
1
]
==
other
.
_packed
[
1
]);
}
ASMJIT_INLINE
bool
operator
!=
(
const
BaseMem
&
other
)
const
{
return
!
(
*
this
==
other
);
}
};
// ============================================================================
// [asmjit::Imm]
// ============================================================================
//! Immediate operand.
//!
//! Immediate operand is usually part of instruction itself. It's inlined after
//! or before the instruction opcode. Immediates can be only signed or unsigned
//! integers.
//!
//! To create immediate operand use `imm()` or `imm_u()` non-members or `Imm`
//! constructors.
struct
Imm
:
public
Operand
{
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new immediate value (initial value is 0).
Imm
()
:
Operand
(
NoInit
)
{
_init_packed_op_sz_b0_b1_id
(
kOperandTypeImm
,
0
,
0
,
0
,
kInvalidValue
);
_imm
.
value
.
_i64
[
0
]
=
0
;
}
//! Create a new signed immediate value, assigning the value to `val`.
explicit
Imm
(
int64_t
val
)
:
Operand
(
NoInit
)
{
_init_packed_op_sz_b0_b1_id
(
kOperandTypeImm
,
0
,
0
,
0
,
kInvalidValue
);
_imm
.
value
.
_i64
[
0
]
=
val
;
}
//! Create a new immediate value from `other`.
ASMJIT_INLINE
Imm
(
const
Imm
&
other
)
:
Operand
(
other
)
{}
explicit
ASMJIT_INLINE
Imm
(
const
_NoInit
&
)
:
Operand
(
NoInit
)
{}
// --------------------------------------------------------------------------
// [Immediate Specific]
// --------------------------------------------------------------------------
//! Clone `Imm` operand.
ASMJIT_INLINE
Imm
clone
()
const
{
return
Imm
(
*
this
);
}
//! Get whether the immediate can be casted to 8-bit signed integer.
ASMJIT_INLINE
bool
isInt8
()
const
{
return
IntUtil
::
isInt8
(
_imm
.
value
.
_i64
[
0
]);
}
//! Get whether the immediate can be casted to 8-bit unsigned integer.
ASMJIT_INLINE
bool
isUInt8
()
const
{
return
IntUtil
::
isUInt8
(
_imm
.
value
.
_i64
[
0
]);
}
//! Get whether the immediate can be casted to 16-bit signed integer.
ASMJIT_INLINE
bool
isInt16
()
const
{
return
IntUtil
::
isInt16
(
_imm
.
value
.
_i64
[
0
]);
}
//! Get whether the immediate can be casted to 16-bit unsigned integer.
ASMJIT_INLINE
bool
isUInt16
()
const
{
return
IntUtil
::
isUInt16
(
_imm
.
value
.
_i64
[
0
]);
}
//! Get whether the immediate can be casted to 32-bit signed integer.
ASMJIT_INLINE
bool
isInt32
()
const
{
return
IntUtil
::
isInt32
(
_imm
.
value
.
_i64
[
0
]);
}
//! Get whether the immediate can be casted to 32-bit unsigned integer.
ASMJIT_INLINE
bool
isUInt32
()
const
{
return
IntUtil
::
isUInt32
(
_imm
.
value
.
_i64
[
0
]);
}
//! Get immediate value as 8-bit signed integer.
ASMJIT_INLINE
int8_t
getInt8
()
const
{
return
_imm
.
value
.
_i8
[
_ASMJIT_HOST_INDEX
(
8
,
0
)];
}
//! Get immediate value as 8-bit unsigned integer.
ASMJIT_INLINE
uint8_t
getUInt8
()
const
{
return
_imm
.
value
.
_u8
[
_ASMJIT_HOST_INDEX
(
8
,
0
)];
}
//! Get immediate value as 16-bit signed integer.
ASMJIT_INLINE
int16_t
getInt16
()
const
{
return
_imm
.
value
.
_i16
[
_ASMJIT_HOST_INDEX
(
4
,
0
)];
}
//! Get immediate value as 16-bit unsigned integer.
ASMJIT_INLINE
uint16_t
getUInt16
()
const
{
return
_imm
.
value
.
_u16
[
_ASMJIT_HOST_INDEX
(
4
,
0
)];
}
//! Get immediate value as 32-bit signed integer.
ASMJIT_INLINE
int32_t
getInt32
()
const
{
return
_imm
.
value
.
_i32
[
_ASMJIT_HOST_INDEX
(
2
,
0
)];
}
//! Get immediate value as 32-bit unsigned integer.
ASMJIT_INLINE
uint32_t
getUInt32
()
const
{
return
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
0
)];
}
//! Get immediate value as 64-bit signed integer.
ASMJIT_INLINE
int64_t
getInt64
()
const
{
return
_imm
.
value
.
_i64
[
0
];
}
//! Get immediate value as 64-bit unsigned integer.
ASMJIT_INLINE
uint64_t
getUInt64
()
const
{
return
_imm
.
value
.
_u64
[
0
];
}
//! Get immediate value as `intptr_t`.
ASMJIT_INLINE
intptr_t
getIntPtr
()
const
{
if
(
sizeof
(
intptr_t
)
==
sizeof
(
int64_t
))
return
static_cast
<
intptr_t
>
(
getInt64
());
else
return
static_cast
<
intptr_t
>
(
getInt32
());
}
//! Get immediate value as `uintptr_t`.
ASMJIT_INLINE
uintptr_t
getUIntPtr
()
const
{
if
(
sizeof
(
uintptr_t
)
==
sizeof
(
uint64_t
))
return
static_cast
<
uintptr_t
>
(
getUInt64
());
else
return
static_cast
<
uintptr_t
>
(
getUInt32
());
}
//! Get low 32-bit signed integer.
ASMJIT_INLINE
int32_t
getInt32Lo
()
const
{
return
_imm
.
value
.
_i32
[
_ASMJIT_HOST_INDEX
(
2
,
0
)];
}
//! Get low 32-bit signed integer.
ASMJIT_INLINE
uint32_t
getUInt32Lo
()
const
{
return
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
0
)];
}
//! Get high 32-bit signed integer.
ASMJIT_INLINE
int32_t
getInt32Hi
()
const
{
return
_imm
.
value
.
_i32
[
_ASMJIT_HOST_INDEX
(
2
,
1
)];
}
//! Get high 32-bit signed integer.
ASMJIT_INLINE
uint32_t
getUInt32Hi
()
const
{
return
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
1
)];
}
//! Set immediate value to 8-bit signed integer `val`.
ASMJIT_INLINE
Imm
&
setInt8
(
int8_t
val
)
{
if
(
kArchHost64Bit
)
{
_imm
.
value
.
_i64
[
0
]
=
static_cast
<
int64_t
>
(
val
);
}
else
{
int32_t
val32
=
static_cast
<
int32_t
>
(
val
);
_imm
.
value
.
_i32
[
_ASMJIT_HOST_INDEX
(
2
,
0
)]
=
val32
;
_imm
.
value
.
_i32
[
_ASMJIT_HOST_INDEX
(
2
,
1
)]
=
val32
>>
31
;
}
return
*
this
;
}
//! Set immediate value to 8-bit unsigned integer `val`.
ASMJIT_INLINE
Imm
&
setUInt8
(
uint8_t
val
)
{
if
(
kArchHost64Bit
)
{
_imm
.
value
.
_u64
[
0
]
=
static_cast
<
uint64_t
>
(
val
);
}
else
{
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
0
)]
=
static_cast
<
uint32_t
>
(
val
);
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
1
)]
=
0
;
}
return
*
this
;
}
//! Set immediate value to 16-bit signed integer `val`.
ASMJIT_INLINE
Imm
&
setInt16
(
int16_t
val
)
{
if
(
kArchHost64Bit
)
{
_imm
.
value
.
_i64
[
0
]
=
static_cast
<
int64_t
>
(
val
);
}
else
{
int32_t
val32
=
static_cast
<
int32_t
>
(
val
);
_imm
.
value
.
_i32
[
_ASMJIT_HOST_INDEX
(
2
,
0
)]
=
val32
;
_imm
.
value
.
_i32
[
_ASMJIT_HOST_INDEX
(
2
,
1
)]
=
val32
>>
31
;
}
return
*
this
;
}
//! Set immediate value to 16-bit unsigned integer `val`.
ASMJIT_INLINE
Imm
&
setUInt16
(
uint16_t
val
)
{
if
(
kArchHost64Bit
)
{
_imm
.
value
.
_u64
[
0
]
=
static_cast
<
uint64_t
>
(
val
);
}
else
{
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
0
)]
=
static_cast
<
uint32_t
>
(
val
);
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
1
)]
=
0
;
}
return
*
this
;
}
//! Set immediate value to 32-bit signed integer `val`.
ASMJIT_INLINE
Imm
&
setInt32
(
int32_t
val
)
{
if
(
kArchHost64Bit
)
{
_imm
.
value
.
_i64
[
0
]
=
static_cast
<
int64_t
>
(
val
);
}
else
{
_imm
.
value
.
_i32
[
_ASMJIT_HOST_INDEX
(
2
,
0
)]
=
val
;
_imm
.
value
.
_i32
[
_ASMJIT_HOST_INDEX
(
2
,
1
)]
=
val
>>
31
;
}
return
*
this
;
}
//! Set immediate value to 32-bit unsigned integer `val`.
ASMJIT_INLINE
Imm
&
setUInt32
(
uint32_t
val
)
{
if
(
kArchHost64Bit
)
{
_imm
.
value
.
_u64
[
0
]
=
static_cast
<
uint64_t
>
(
val
);
}
else
{
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
0
)]
=
val
;
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
1
)]
=
0
;
}
return
*
this
;
}
//! Set immediate value to 64-bit signed integer `val`.
ASMJIT_INLINE
Imm
&
setInt64
(
int64_t
val
)
{
_imm
.
value
.
_i64
[
0
]
=
val
;
return
*
this
;
}
//! Set immediate value to 64-bit unsigned integer `val`.
ASMJIT_INLINE
Imm
&
setUInt64
(
uint64_t
val
)
{
_imm
.
value
.
_u64
[
0
]
=
val
;
return
*
this
;
}
//! Set immediate value to intptr_t `val`.
ASMJIT_INLINE
Imm
&
setIntPtr
(
intptr_t
val
)
{
_imm
.
value
.
_i64
[
0
]
=
static_cast
<
int64_t
>
(
val
);
return
*
this
;
}
//! Set immediate value to uintptr_t `val`.
ASMJIT_INLINE
Imm
&
setUIntPtr
(
uintptr_t
val
)
{
_imm
.
value
.
_u64
[
0
]
=
static_cast
<
uint64_t
>
(
val
);
return
*
this
;
}
//! Set immediate value as unsigned type to `val`.
ASMJIT_INLINE
Imm
&
setPtr
(
void
*
p
)
{
return
setIntPtr
((
intptr_t
)
p
);
}
// --------------------------------------------------------------------------
// [Float]
// --------------------------------------------------------------------------
ASMJIT_INLINE
Imm
&
setFloat
(
float
f
)
{
_imm
.
value
.
_f32
[
_ASMJIT_HOST_INDEX
(
2
,
0
)]
=
f
;
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
1
)]
=
0
;
return
*
this
;
}
ASMJIT_INLINE
Imm
&
setDouble
(
double
d
)
{
_imm
.
value
.
_f64
[
0
]
=
d
;
return
*
this
;
}
// --------------------------------------------------------------------------
// [Truncate]
// --------------------------------------------------------------------------
ASMJIT_INLINE
Imm
&
truncateTo8Bits
()
{
if
(
kArchHost64Bit
)
{
_imm
.
value
.
_u64
[
0
]
&=
static_cast
<
uint64_t
>
(
0x000000FFU
);
}
else
{
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
0
)]
&=
0x000000FFU
;
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
1
)]
=
0
;
}
return
*
this
;
}
ASMJIT_INLINE
Imm
&
truncateTo16Bits
()
{
if
(
kArchHost64Bit
)
{
_imm
.
value
.
_u64
[
0
]
&=
static_cast
<
uint64_t
>
(
0x0000FFFFU
);
}
else
{
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
0
)]
&=
0x0000FFFFU
;
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
1
)]
=
0
;
}
return
*
this
;
}
ASMJIT_INLINE
Imm
&
truncateTo32Bits
()
{
_imm
.
value
.
_u32
[
_ASMJIT_HOST_INDEX
(
2
,
1
)]
=
0
;
return
*
this
;
}
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
//! Assign `other` to the immediate operand.
ASMJIT_INLINE
Imm
&
operator
=
(
const
Imm
&
other
)
{
_copy
(
other
);
return
*
this
;
}
};
// ============================================================================
// [asmjit::Label]
// ============================================================================
//! Label (jump target or data location).
//!
//! Label represents a location in code typically used as jump targets, but may
//! be also reference data or static variables. Label has to be explicitly
//! created by a code-generator by calling `CodeGen::newLabel()` where `CodeGen`
//! is your code generator, which derives from `Assembler` or `Compiler`.
//!
//! Example of using labels:
//!
//! ~~~
//! // Create Assembler/Compiler.
//! host::Assembler a;
//!
//! // Create Label instance.
//! Label L_1(a);
//!
//! // ... your code ...
//!
//! // Using label.
//! a.jump(L_1);
//!
//! // ... your code ...
//!
//! // Bind label to the current position, see `CodeGen::bind()`.
//! a.bind(L_1);
//! ~~~
struct
Label
:
public
Operand
{
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create new, unassociated label.
ASMJIT_INLINE
Label
()
:
Operand
(
NoInit
)
{
reset
();
}
explicit
ASMJIT_INLINE
Label
(
uint32_t
id
)
:
Operand
(
NoInit
)
{
_init_packed_op_sz_b0_b1_id
(
kOperandTypeLabel
,
0
,
0
,
0
,
id
);
_init_packed_d2_d3
(
0
,
0
);
}
//! Create new initialized label.
explicit
ASMJIT_INLINE
Label
(
Assembler
&
a
);
//! Create new initialized label.
explicit
ASMJIT_INLINE
Label
(
Compiler
&
c
);
//! Create reference to another label.
ASMJIT_INLINE
Label
(
const
Label
&
other
)
:
Operand
(
other
)
{}
explicit
ASMJIT_INLINE
Label
(
const
_NoInit
&
)
:
Operand
(
NoInit
)
{}
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
ASMJIT_INLINE
void
reset
()
{
_init_packed_op_sz_b0_b1_id
(
kOperandTypeLabel
,
0
,
0
,
0
,
kInvalidValue
);
_init_packed_d2_d3
(
0
,
0
);
}
// --------------------------------------------------------------------------
// [Label Specific]
// --------------------------------------------------------------------------
//! Get whether the label has been initialized by `Assembler` or `Compiler`.
ASMJIT_INLINE
bool
isInitialized
()
const
{
return
_label
.
id
!=
kInvalidValue
;
}
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
ASMJIT_INLINE
Label
&
operator
=
(
const
Label
&
other
)
{
_copy
(
other
);
return
*
this
;
}
ASMJIT_INLINE
bool
operator
==
(
const
Label
&
other
)
const
{
return
_base
.
id
==
other
.
_base
.
id
;
}
ASMJIT_INLINE
bool
operator
!=
(
const
Label
&
other
)
const
{
return
_base
.
id
!=
other
.
_base
.
id
;
}
};
// ============================================================================
// [asmjit::Operand - Globals]
// ============================================================================
//! No operand, can be used to reset an operand by assignment or to refer to an
//! operand that doesn't exist.
ASMJIT_VAR
const
Operand
noOperand
;
//! Create signed immediate value operand.
static
ASMJIT_INLINE
Imm
imm
(
int64_t
val
)
{
return
Imm
(
val
);
}
//! Create unsigned immediate value operand.
static
ASMJIT_INLINE
Imm
imm_u
(
uint64_t
val
)
{
return
Imm
(
static_cast
<
int64_t
>
(
val
));
}
//! Create void* pointer immediate value operand.
static
ASMJIT_INLINE
Imm
imm_ptr
(
void
*
p
)
{
return
Imm
(
static_cast
<
int64_t
>
((
intptr_t
)
p
));
}
//! \}
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_OPERAND_H
libraries/asmjit/base/runtime.cpp
0 → 100644
View file @
a83607d6
// [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/cpuinfo.h"
#include "../base/error.h"
#include "../base/runtime.h"
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
// ============================================================================
// [asmjit::Runtime - Construction / Destruction]
// ============================================================================
Runtime
::
Runtime
()
{
_sizeLimit
=
0
;
_runtimeType
=
kRuntimeTypeNone
;
_allocType
=
kVMemAllocFreeable
;
::
memset
(
_reserved
,
0
,
sizeof
(
_reserved
));
_baseAddress
=
kNoBaseAddress
;
}
Runtime
::~
Runtime
()
{}
// ============================================================================
// [asmjit::HostRuntime - Construction / Destruction]
// ============================================================================
HostRuntime
::
HostRuntime
()
{
_runtimeType
=
kRuntimeTypeJit
;
}
HostRuntime
::~
HostRuntime
()
{}
// ============================================================================
// [asmjit::HostRuntime - Interface]
// ============================================================================
const
CpuInfo
*
HostRuntime
::
getCpuInfo
()
{
return
CpuInfo
::
getHost
();
}
uint32_t
HostRuntime
::
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
;
}
void
HostRuntime
::
flush
(
void
*
p
,
size_t
size
)
{
// Only useful on non-x86 architectures.
#if !defined(ASMJIT_HOST_X86) && !defined(ASMJIT_HOST_X64)
// Windows has built-in support in kernel32.dll.
#if defined(ASMJIT_OS_WINDOWS)
::
FlushInstructionCache
(
_memMgr
.
getProcessHandle
(),
p
,
size
);
#endif // ASMJIT_OS_WINDOWS
#endif // !ASMJIT_HOST_X86 && !ASMJIT_HOST_X64
}
// ============================================================================
// [asmjit::StaticRuntime - Construction / Destruction]
// ============================================================================
StaticRuntime
::
StaticRuntime
(
void
*
baseAddress
,
size_t
sizeLimit
)
{
_sizeLimit
=
sizeLimit
;
_baseAddress
=
static_cast
<
Ptr
>
((
uintptr_t
)
baseAddress
);
}
StaticRuntime
::~
StaticRuntime
()
{}
// ============================================================================
// [asmjit::StaticRuntime - Interface]
// ============================================================================
Error
StaticRuntime
::
add
(
void
**
dst
,
Assembler
*
assembler
)
{
size_t
codeSize
=
assembler
->
getCodeSize
();
size_t
sizeLimit
=
_sizeLimit
;
if
(
codeSize
==
0
)
{
*
dst
=
NULL
;
return
kErrorNoCodeGenerated
;
}
if
(
sizeLimit
!=
0
&&
sizeLimit
<
codeSize
)
{
*
dst
=
NULL
;
return
kErrorCodeTooLarge
;
}
Ptr
baseAddress
=
_baseAddress
;
uint8_t
*
p
=
static_cast
<
uint8_t
*>
((
void
*
)
static_cast
<
uintptr_t
>
(
baseAddress
));
// Since the base address is known the `relocSize` returned should be equal
// to `codeSize`. It's better to fail if they don't match instead of passsing
// silently.
size_t
relocSize
=
assembler
->
relocCode
(
p
,
baseAddress
);
if
(
relocSize
==
0
||
codeSize
!=
relocSize
)
{
*
dst
=
NULL
;
return
kErrorInvalidState
;
}
_baseAddress
+=
codeSize
;
if
(
sizeLimit
)
sizeLimit
-=
codeSize
;
flush
(
p
,
codeSize
);
*
dst
=
p
;
return
kErrorOk
;
}
Error
StaticRuntime
::
release
(
void
*
p
)
{
// There is nothing to release as `StaticRuntime` doesn't manage any memory.
ASMJIT_UNUSED
(
p
);
return
kErrorOk
;
}
// ============================================================================
// [asmjit::JitRuntime - Construction / Destruction]
// ============================================================================
JitRuntime
::
JitRuntime
()
{}
JitRuntime
::~
JitRuntime
()
{}
// ============================================================================
// [asmjit::JitRuntime - Interface]
// ============================================================================
Error
JitRuntime
::
add
(
void
**
dst
,
Assembler
*
assembler
)
{
size_t
codeSize
=
assembler
->
getCodeSize
();
if
(
codeSize
==
0
)
{
*
dst
=
NULL
;
return
kErrorNoCodeGenerated
;
}
void
*
p
=
_memMgr
.
alloc
(
codeSize
,
getAllocType
());
if
(
p
==
NULL
)
{
*
dst
=
NULL
;
return
kErrorNoVirtualMemory
;
}
// Relocate the code and release the unused memory back to `VMemMgr`.
size_t
relocSize
=
assembler
->
relocCode
(
p
);
if
(
relocSize
<
codeSize
)
{
_memMgr
.
shrink
(
p
,
relocSize
);
}
flush
(
p
,
relocSize
);
*
dst
=
p
;
return
kErrorOk
;
}
Error
JitRuntime
::
release
(
void
*
p
)
{
return
_memMgr
.
release
(
p
);
}
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
libraries/asmjit/base/runtime.h
0 → 100644
View file @
a83607d6
// [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"
#include "../base/vmem.h"
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
// ============================================================================
// [Forward Declarations]
// ============================================================================
struct
Assembler
;
struct
CpuInfo
;
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kRuntimeType]
// ============================================================================
ASMJIT_ENUM
(
kRuntimeType
)
{
kRuntimeTypeNone
=
0
,
kRuntimeTypeJit
=
1
,
kRuntimeTypeRemote
=
2
};
// ============================================================================
// [asmjit::Runtime]
// ============================================================================
//! Base runtime.
struct
ASMJIT_VCLASS
Runtime
{
ASMJIT_NO_COPY
(
Runtime
)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a `Runtime` instance.
ASMJIT_API
Runtime
();
//! Destroy the `Runtime` instance.
ASMJIT_API
virtual
~
Runtime
();
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get runtime type.
ASMJIT_INLINE
uint32_t
getRuntimeType
()
const
{
return
_runtimeType
;
}
//! Get whether the runtime has a base address.
//!
//! \sa \ref getBaseAddress()
ASMJIT_INLINE
bool
hasBaseAddress
()
const
{
return
_baseAddress
==
kNoBaseAddress
;
}
//! Get the base address.
ASMJIT_INLINE
Ptr
getBaseAddress
()
const
{
return
_baseAddress
;
}
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
//! Get CPU information.
virtual
const
CpuInfo
*
getCpuInfo
()
=
0
;
//! Get stack alignment of target runtime.
virtual
uint32_t
getStackAlignment
()
=
0
;
//! Allocate a memory needed for a code generated by `assembler` and
//! relocate it to the target location.
//!
//! The beginning of the memory allocated for the function is returned in
//! `dst`. Returns Status code as \ref kError, on failure `dst` is set to
//! `NULL`.
virtual
Error
add
(
void
**
dst
,
Assembler
*
assembler
)
=
0
;
//! Release memory allocated by `add`.
virtual
Error
release
(
void
*
p
)
=
0
;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Maximum size of the code that can be added to the runtime (0=unlimited).
size_t
_sizeLimit
;
//! Base address (-1 means no base address).
Ptr
_baseAddress
;
//! Type of the runtime.
uint8_t
_runtimeType
;
//! Type of the allocation.
uint8_t
_allocType
;
//! \internal
uint8_t
_reserved
[
sizeof
(
intptr_t
)
-
2
];
};
// ============================================================================
// [asmjit::HostRuntime]
// ============================================================================
//! Base runtime for JIT code generation.
struct
ASMJIT_VCLASS
HostRuntime
:
public
Runtime
{
ASMJIT_NO_COPY
(
HostRuntime
)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a `HostRuntime` instance.
ASMJIT_API
HostRuntime
();
//! Destroy the `HostRuntime` instance.
ASMJIT_API
virtual
~
HostRuntime
();
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
ASMJIT_API
virtual
const
CpuInfo
*
getCpuInfo
();
ASMJIT_API
virtual
uint32_t
getStackAlignment
();
//! Flush an instruction cache.
//!
//! This member function is called after the code has been copied to the
//! destination buffer. It is only useful for JIT code generation as it
//! causes a flush of the processor cache.
//!
//! Flushing is basically a NOP under X86/X64, but is needed by architectures
//! that do not have a transparent instruction cache.
//!
//! This function can also be overridden to improve compatibility with tools
//! such as Valgrind, however, it's not an official part of AsmJit.
ASMJIT_API
virtual
void
flush
(
void
*
p
,
size_t
size
);
};
// ============================================================================
// [asmjit::StaticRuntime]
// ============================================================================
//! JIT static runtime.
//!
//! JIT static runtime can be used to generate code to a memory location that
//! is known.
struct
ASMJIT_VCLASS
StaticRuntime
:
public
HostRuntime
{
ASMJIT_NO_COPY
(
StaticRuntime
)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a `StaticRuntime` instance.
//!
//! The `address` specifies a fixed target address, which will be used as a
//! base address for relocation, and `sizeLimit` specified the maximum size
//! of a code that can be copied to it. If there is no limit `sizeLimit`
//! should be zero.
ASMJIT_API
StaticRuntime
(
void
*
baseAddress
,
size_t
sizeLimit
=
0
);
//! Destroy the `StaticRuntime` instance.
ASMJIT_API
virtual
~
StaticRuntime
();
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the base address.
ASMJIT_INLINE
Ptr
getBaseAddress
()
const
{
return
_baseAddress
;
}
//! Get the maximum size of the code that can be relocated to the target
//! address or zero if unlimited.
ASMJIT_INLINE
size_t
getSizeLimit
()
const
{
return
_sizeLimit
;
}
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
ASMJIT_API
virtual
Error
add
(
void
**
dst
,
Assembler
*
assembler
);
ASMJIT_API
virtual
Error
release
(
void
*
p
);
};
// ============================================================================
// [asmjit::JitRuntime]
// ============================================================================
//! JIT runtime.
struct
ASMJIT_VCLASS
JitRuntime
:
public
HostRuntime
{
ASMJIT_NO_COPY
(
JitRuntime
)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a `JitRuntime` instance.
ASMJIT_API
JitRuntime
();
//! Destroy the `JitRuntime` instance.
ASMJIT_API
virtual
~
JitRuntime
();
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the type of allocation.
ASMJIT_INLINE
uint32_t
getAllocType
()
const
{
return
_allocType
;
}
//! Set the type of allocation.
ASMJIT_INLINE
void
setAllocType
(
uint32_t
allocType
)
{
_allocType
=
allocType
;
}
//! Get the virtual memory manager.
ASMJIT_INLINE
VMemMgr
*
getMemMgr
()
const
{
return
const_cast
<
VMemMgr
*>
(
&
_memMgr
);
}
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
ASMJIT_API
virtual
Error
add
(
void
**
dst
,
Assembler
*
assembler
);
ASMJIT_API
virtual
Error
release
(
void
*
p
);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Virtual memory manager.
VMemMgr
_memMgr
;
};
//! \}
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_RUNTIME_H
libraries/asmjit/base/string.cpp
0 → 100644
View file @
a83607d6
// [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/string.h"
// [Api-Begin]
#include "../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
)
ASMJIT_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
*>
(
ASMJIT_ALLOC
(
to
+
sizeof
(
intptr_t
)));
if
(
newData
==
NULL
)
{
clear
();
return
NULL
;
}
if
(
_canFree
)
ASMJIT_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
*>
(
ASMJIT_ALLOC
(
to
+
sizeof
(
intptr_t
)));
if
(
newData
==
NULL
)
return
NULL
;
::
memcpy
(
newData
,
_data
,
_length
);
if
(
_canFree
)
ASMJIT_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
*>
(
ASMJIT_ALLOC
(
to
+
sizeof
(
intptr_t
)));
if
(
newData
==
NULL
)
return
false
;
::
memcpy
(
newData
,
_data
,
_length
+
1
);
if
(
_canFree
)
ASMJIT_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 "../apiend.h"
libraries/asmjit/base/string.h
0 → 100644
View file @
a83607d6
// [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/globals.h"
// [Dependencies - C]
#include <stdarg.h>
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::kStringOp]
// ============================================================================
//! \internal
//!
//! String operation.
ASMJIT_ENUM
(
kStringOp
)
{
//! Replace the current string by a given content.
kStringOpSet
=
0
,
//! Append a given content to the current string.
kStringOpAppend
=
1
};
// ============================================================================
// [asmjit::kStringFormat]
// ============================================================================
//! \internal
//!
//! String format flags.
ASMJIT_ENUM
(
kStringFormat
)
{
kStringFormatShowSign
=
0x00000001
,
kStringFormatShowSpace
=
0x00000002
,
kStringFormatAlternate
=
0x00000004
,
kStringFormatSigned
=
0x80000000
};
// ============================================================================
// [asmjit::StringUtil]
// ============================================================================
//! 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]
// ============================================================================
//! 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
_NoInit
&
)
{}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get string builder capacity.
ASMJIT_INLINE
size_t
getCapacity
()
const
{
return
_capacity
;
}
//! Get length.
ASMJIT_INLINE
size_t
getLength
()
const
{
return
_length
;
}
//! Get null-terminated string data.
ASMJIT_INLINE
char
*
getData
()
{
return
_data
;
}
//! Get null-terminated string data (const).
ASMJIT_INLINE
const
char
*
getData
()
const
{
return
_data
;
}
// --------------------------------------------------------------------------
// [Prepare / Reserve]
// --------------------------------------------------------------------------
//! Prepare to set/append.
ASMJIT_API
char
*
prepare
(
uint32_t
op
,
size_t
len
);
//! Reserve `to` bytes in string builder.
ASMJIT_API
bool
reserve
(
size_t
to
);
// --------------------------------------------------------------------------
// [Clear]
// --------------------------------------------------------------------------
//! 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]
// --------------------------------------------------------------------------
//! Replace the current content by `str` of `len`.
ASMJIT_INLINE
bool
setString
(
const
char
*
str
,
size_t
len
=
kInvalidIndex
)
{
return
_opString
(
kStringOpSet
,
str
,
len
);
}
//! Replace the current content by formatted string `fmt`.
ASMJIT_INLINE
bool
setVFormat
(
const
char
*
fmt
,
va_list
ap
)
{
return
_opVFormat
(
kStringOpSet
,
fmt
,
ap
);
}
//! Replace the current content by formatted string `fmt`.
ASMJIT_API
bool
setFormat
(
const
char
*
fmt
,
...);
//! Replace the current content by `c` character.
ASMJIT_INLINE
bool
setChar
(
char
c
)
{
return
_opChar
(
kStringOpSet
,
c
);
}
//! Replace the current content by `c` of `len`.
ASMJIT_INLINE
bool
setChars
(
char
c
,
size_t
len
)
{
return
_opChars
(
kStringOpSet
,
c
,
len
);
}
//! Replace the current content by formatted integer `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
);
}
//! Replace the current content by formatted integer `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
);
}
//! Replace the current content by the given `data` converted to a HEX string.
ASMJIT_INLINE
bool
setHex
(
const
void
*
data
,
size_t
len
)
{
return
_opHex
(
kStringOpSet
,
data
,
len
);
}
// --------------------------------------------------------------------------
// [Append]
// --------------------------------------------------------------------------
//! Append `str` of `len`.
ASMJIT_INLINE
bool
appendString
(
const
char
*
str
,
size_t
len
=
kInvalidIndex
)
{
return
_opString
(
kStringOpAppend
,
str
,
len
);
}
//! Append a formatted string `fmt` to the current content.
ASMJIT_INLINE
bool
appendVFormat
(
const
char
*
fmt
,
va_list
ap
)
{
return
_opVFormat
(
kStringOpAppend
,
fmt
,
ap
);
}
//! Append a formatted string `fmt` to the current content.
ASMJIT_API
bool
appendFormat
(
const
char
*
fmt
,
...);
//! Append `c` character.
ASMJIT_INLINE
bool
appendChar
(
char
c
)
{
return
_opChar
(
kStringOpAppend
,
c
);
}
//! Append `c` of `len`.
ASMJIT_INLINE
bool
appendChars
(
char
c
,
size_t
len
)
{
return
_opChars
(
kStringOpAppend
,
c
,
len
);
}
//! Append `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
);
}
//! Append `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
);
}
//! Append the given `data` converted to a HEX string.
ASMJIT_INLINE
bool
appendHex
(
const
void
*
data
,
size_t
len
)
{
return
_opHex
(
kStringOpAppend
,
data
,
len
);
}
// --------------------------------------------------------------------------
// [_Append]
// --------------------------------------------------------------------------
//! Append `str` of `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
;
}
}
//! Append `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'
;
}
//! Append `c` of `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]
// --------------------------------------------------------------------------
//! Check for equality with other `str` of `len`.
ASMJIT_API
bool
eq
(
const
char
*
str
,
size_t
len
=
kInvalidIndex
)
const
;
//! Check for equality with `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]
// --------------------------------------------------------------------------
//! String data.
char
*
_data
;
//! Length.
size_t
_length
;
//! Capacity.
size_t
_capacity
;
//! Whether the string can be freed.
size_t
_canFree
;
};
// ============================================================================
// [asmjit::StringBuilderT]
// ============================================================================
//! \internal
template
<
size_t
N
>
struct
StringBuilderT
:
public
StringBuilder
{
ASMJIT_NO_COPY
(
StringBuilderT
<
N
>
)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE
StringBuilderT
()
:
StringBuilder
(
NoInit
)
{
_data
=
_embeddedData
;
_data
[
0
]
=
0
;
_length
=
0
;
_capacity
=
N
;
_canFree
=
false
;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! 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 "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_STRING_H
libraries/asmjit/base/vectypes.h
0 → 100644
View file @
a83607d6
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_VECTYPES_H
#define _ASMJIT_BASE_VECTYPES_H
// [Dependencies - AsmJit]
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::Vec64]
// ============================================================================
//! 64-bit vector register data.
union
Vec64
{
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Set all eight 8-bit signed integers.
static
ASMJIT_INLINE
Vec64
fromSb
(
int8_t
x0
,
int8_t
x1
,
int8_t
x2
,
int8_t
x3
,
int8_t
x4
,
int8_t
x5
,
int8_t
x6
,
int8_t
x7
)
{
Vec64
self
;
self
.
setSb
(
x0
,
x1
,
x2
,
x3
,
x4
,
x5
,
x6
,
x7
);
return
self
;
}
//! Set all eight 8-bit signed integers.
static
ASMJIT_INLINE
Vec64
fromSb
(
int8_t
x0
)
{
Vec64
self
;
self
.
setSb
(
x0
);
return
self
;
}
//! Set all eight 8-bit unsigned integers.
static
ASMJIT_INLINE
Vec64
fromUb
(
uint8_t
x0
,
uint8_t
x1
,
uint8_t
x2
,
uint8_t
x3
,
uint8_t
x4
,
uint8_t
x5
,
uint8_t
x6
,
uint8_t
x7
)
{
Vec64
self
;
self
.
setUb
(
x0
,
x1
,
x2
,
x3
,
x4
,
x5
,
x6
,
x7
);
return
self
;
}
//! Set all eight 8-bit unsigned integers.
static
ASMJIT_INLINE
Vec64
fromUb
(
uint8_t
x0
)
{
Vec64
self
;
self
.
setUb
(
x0
);
return
self
;
}
//! Set all four 16-bit signed integers.
static
ASMJIT_INLINE
Vec64
fromSw
(
int16_t
x0
,
int16_t
x1
,
int16_t
x2
,
int16_t
x3
)
{
Vec64
self
;
self
.
setSw
(
x0
,
x1
,
x2
,
x3
);
return
self
;
}
//! Set all four 16-bit signed integers.
static
ASMJIT_INLINE
Vec64
fromSw
(
int16_t
x0
)
{
Vec64
self
;
self
.
setSw
(
x0
);
return
self
;
}
//! Set all four 16-bit unsigned integers.
static
ASMJIT_INLINE
Vec64
fromUw
(
uint16_t
x0
,
uint16_t
x1
,
uint16_t
x2
,
uint16_t
x3
)
{
Vec64
self
;
self
.
setUw
(
x0
,
x1
,
x2
,
x3
);
return
self
;
}
//! Set all four 16-bit unsigned integers.
static
ASMJIT_INLINE
Vec64
fromUw
(
uint16_t
x0
)
{
Vec64
self
;
self
.
setUw
(
x0
);
return
self
;
}
//! Set all two 32-bit signed integers.
static
ASMJIT_INLINE
Vec64
fromSd
(
int32_t
x0
,
int32_t
x1
)
{
Vec64
self
;
self
.
setSd
(
x0
,
x1
);
return
self
;
}
//! Set all two 32-bit signed integers.
static
ASMJIT_INLINE
Vec64
fromSd
(
int32_t
x0
)
{
Vec64
self
;
self
.
setSd
(
x0
);
return
self
;
}
//! Set all two 32-bit unsigned integers.
static
ASMJIT_INLINE
Vec64
fromUd
(
uint32_t
x0
,
uint32_t
x1
)
{
Vec64
self
;
self
.
setUd
(
x0
,
x1
);
return
self
;
}
//! Set all two 32-bit unsigned integers.
static
ASMJIT_INLINE
Vec64
fromUd
(
uint32_t
x0
)
{
Vec64
self
;
self
.
setUd
(
x0
);
return
self
;
}
//! Set 64-bit signed integer.
static
ASMJIT_INLINE
Vec64
fromSq
(
int64_t
x0
)
{
Vec64
self
;
self
.
setSq
(
x0
);
return
self
;
}
//! Set 64-bit unsigned integer.
static
ASMJIT_INLINE
Vec64
fromUq
(
uint64_t
x0
)
{
Vec64
self
;
self
.
setUq
(
x0
);
return
self
;
}
//! Set all two SP-FP values.
static
ASMJIT_INLINE
Vec64
fromSf
(
float
x0
,
float
x1
)
{
Vec64
self
;
self
.
setSf
(
x0
,
x1
);
return
self
;
}
//! Set all two SP-FP values.
static
ASMJIT_INLINE
Vec64
fromSf
(
float
x0
)
{
Vec64
self
;
self
.
setSf
(
x0
);
return
self
;
}
//! Set all two SP-FP values.
static
ASMJIT_INLINE
Vec64
fromDf
(
double
x0
)
{
Vec64
self
;
self
.
setDf
(
x0
);
return
self
;
}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Set all eight 8-bit signed integers.
ASMJIT_INLINE
void
setSb
(
int8_t
x0
,
int8_t
x1
,
int8_t
x2
,
int8_t
x3
,
int8_t
x4
,
int8_t
x5
,
int8_t
x6
,
int8_t
x7
)
{
sb
[
0
]
=
x0
;
sb
[
1
]
=
x1
;
sb
[
2
]
=
x2
;
sb
[
3
]
=
x3
;
sb
[
4
]
=
x4
;
sb
[
5
]
=
x5
;
sb
[
6
]
=
x6
;
sb
[
7
]
=
x7
;
}
//! Set all eight 8-bit signed integers.
ASMJIT_INLINE
void
setSb
(
int8_t
x0
)
{
setUb
(
static_cast
<
uint8_t
>
(
x0
));
}
//! Set all eight 8-bit unsigned integers.
ASMJIT_INLINE
void
setUb
(
uint8_t
x0
,
uint8_t
x1
,
uint8_t
x2
,
uint8_t
x3
,
uint8_t
x4
,
uint8_t
x5
,
uint8_t
x6
,
uint8_t
x7
)
{
ub
[
0
]
=
x0
;
ub
[
1
]
=
x1
;
ub
[
2
]
=
x2
;
ub
[
3
]
=
x3
;
ub
[
4
]
=
x4
;
ub
[
5
]
=
x5
;
ub
[
6
]
=
x6
;
ub
[
7
]
=
x7
;
}
//! Set all eight 8-bit unsigned integers.
ASMJIT_INLINE
void
setUb
(
uint8_t
x0
)
{
if
(
kArchHost64Bit
)
{
uint64_t
t
=
static_cast
<
uint64_t
>
(
x0
)
*
ASMJIT_UINT64_C
(
0x0101010101010101
);
uq
[
0
]
=
t
;
}
else
{
uint32_t
t
=
static_cast
<
uint32_t
>
(
x0
)
*
static_cast
<
uint32_t
>
(
0x01010101U
);
ud
[
0
]
=
t
;
ud
[
1
]
=
t
;
}
}
//! Set all four 16-bit signed integers.
ASMJIT_INLINE
void
setSw
(
int16_t
x0
,
int16_t
x1
,
int16_t
x2
,
int16_t
x3
)
{
sw
[
0
]
=
x0
;
sw
[
1
]
=
x1
;
sw
[
2
]
=
x2
;
sw
[
3
]
=
x3
;
}
//! Set all four 16-bit signed integers.
ASMJIT_INLINE
void
setSw
(
int16_t
x0
)
{
setUw
(
static_cast
<
uint16_t
>
(
x0
));
}
//! Set all four 16-bit unsigned integers.
ASMJIT_INLINE
void
setUw
(
uint16_t
x0
,
uint16_t
x1
,
uint16_t
x2
,
uint16_t
x3
)
{
uw
[
0
]
=
x0
;
uw
[
1
]
=
x1
;
uw
[
2
]
=
x2
;
uw
[
3
]
=
x3
;
}
//! Set all four 16-bit unsigned integers.
ASMJIT_INLINE
void
setUw
(
uint16_t
x0
)
{
if
(
kArchHost64Bit
)
{
uint64_t
t
=
static_cast
<
uint64_t
>
(
x0
)
*
ASMJIT_UINT64_C
(
0x0001000100010001
);
uq
[
0
]
=
t
;
}
else
{
uint32_t
t
=
static_cast
<
uint32_t
>
(
x0
)
*
static_cast
<
uint32_t
>
(
0x00010001U
);
ud
[
0
]
=
t
;
ud
[
1
]
=
t
;
}
}
//! Set all two 32-bit signed integers.
ASMJIT_INLINE
void
setSd
(
int32_t
x0
,
int32_t
x1
)
{
sd
[
0
]
=
x0
;
sd
[
1
]
=
x1
;
}
//! Set all two 32-bit signed integers.
ASMJIT_INLINE
void
setSd
(
int32_t
x0
)
{
sd
[
0
]
=
x0
;
sd
[
1
]
=
x0
;
}
//! Set all two 32-bit unsigned integers.
ASMJIT_INLINE
void
setUd
(
uint32_t
x0
,
uint32_t
x1
)
{
ud
[
0
]
=
x0
;
ud
[
1
]
=
x1
;
}
//! Set all two 32-bit unsigned integers.
ASMJIT_INLINE
void
setUd
(
uint32_t
x0
)
{
ud
[
0
]
=
x0
;
ud
[
1
]
=
x0
;
}
//! Set 64-bit signed integer.
ASMJIT_INLINE
void
setSq
(
int64_t
x0
)
{
sq
[
0
]
=
x0
;
}
//! Set 64-bit unsigned integer.
ASMJIT_INLINE
void
setUq
(
uint64_t
x0
)
{
uq
[
0
]
=
x0
;
}
//! Set all two SP-FP values.
ASMJIT_INLINE
void
setSf
(
float
x0
,
float
x1
)
{
sf
[
0
]
=
x0
;
sf
[
1
]
=
x1
;
}
//! Set all two SP-FP values.
ASMJIT_INLINE
void
setSf
(
float
x0
)
{
sf
[
0
]
=
x0
;
sf
[
1
]
=
x0
;
}
//! Set all two SP-FP values.
ASMJIT_INLINE
void
setDf
(
double
x0
)
{
df
[
0
]
=
x0
;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Array of eight 8-bit signed integers.
int8_t
sb
[
8
];
//! Array of eight 8-bit unsigned integers.
uint8_t
ub
[
8
];
//! Array of four 16-bit signed integers.
int16_t
sw
[
4
];
//! Array of four 16-bit unsigned integers.
uint16_t
uw
[
4
];
//! Array of two 32-bit signed integers.
int32_t
sd
[
2
];
//! Array of two 32-bit unsigned integers.
uint32_t
ud
[
2
];
//! Array of one 64-bit signed integer.
int64_t
sq
[
1
];
//! Array of one 64-bit unsigned integer.
uint64_t
uq
[
1
];
//! Array of two SP-FP values.
float
sf
[
2
];
//! Array of one DP-FP value.
double
df
[
1
];
};
// ============================================================================
// [asmjit::Vec128]
// ============================================================================
//! 128-bit vector register data.
union
Vec128
{
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Set all sixteen 8-bit signed integers.
static
ASMJIT_INLINE
Vec128
fromSb
(
int8_t
x0
,
int8_t
x1
,
int8_t
x2
,
int8_t
x3
,
int8_t
x4
,
int8_t
x5
,
int8_t
x6
,
int8_t
x7
,
int8_t
x8
,
int8_t
x9
,
int8_t
x10
,
int8_t
x11
,
int8_t
x12
,
int8_t
x13
,
int8_t
x14
,
int8_t
x15
)
{
Vec128
self
;
self
.
setSb
(
x0
,
x1
,
x2
,
x3
,
x4
,
x5
,
x6
,
x7
,
x8
,
x9
,
x10
,
x11
,
x12
,
x13
,
x14
,
x15
);
return
self
;
}
//! Set all sixteen 8-bit signed integers.
static
ASMJIT_INLINE
Vec128
fromSb
(
int8_t
x0
)
{
Vec128
self
;
self
.
setSb
(
x0
);
return
self
;
}
//! Set all sixteen 8-bit unsigned integers.
static
ASMJIT_INLINE
Vec128
fromUb
(
uint8_t
x0
,
uint8_t
x1
,
uint8_t
x2
,
uint8_t
x3
,
uint8_t
x4
,
uint8_t
x5
,
uint8_t
x6
,
uint8_t
x7
,
uint8_t
x8
,
uint8_t
x9
,
uint8_t
x10
,
uint8_t
x11
,
uint8_t
x12
,
uint8_t
x13
,
uint8_t
x14
,
uint8_t
x15
)
{
Vec128
self
;
self
.
setUb
(
x0
,
x1
,
x2
,
x3
,
x4
,
x5
,
x6
,
x7
,
x8
,
x9
,
x10
,
x11
,
x12
,
x13
,
x14
,
x15
);
return
self
;
}
//! Set all sixteen 8-bit unsigned integers.
static
ASMJIT_INLINE
Vec128
fromUb
(
uint8_t
x0
)
{
Vec128
self
;
self
.
setUb
(
x0
);
return
self
;
}
//! Set all eight 16-bit signed integers.
static
ASMJIT_INLINE
Vec128
fromSw
(
int16_t
x0
,
int16_t
x1
,
int16_t
x2
,
int16_t
x3
,
int16_t
x4
,
int16_t
x5
,
int16_t
x6
,
int16_t
x7
)
{
Vec128
self
;
self
.
setSw
(
x0
,
x1
,
x2
,
x3
,
x4
,
x5
,
x6
,
x7
);
return
self
;
}
//! Set all eight 16-bit signed integers.
static
ASMJIT_INLINE
Vec128
fromSw
(
int16_t
x0
)
{
Vec128
self
;
self
.
setSw
(
x0
);
return
self
;
}
//! Set all eight 16-bit unsigned integers.
static
ASMJIT_INLINE
Vec128
fromUw
(
uint16_t
x0
,
uint16_t
x1
,
uint16_t
x2
,
uint16_t
x3
,
uint16_t
x4
,
uint16_t
x5
,
uint16_t
x6
,
uint16_t
x7
)
{
Vec128
self
;
self
.
setUw
(
x0
,
x1
,
x2
,
x3
,
x4
,
x5
,
x6
,
x7
);
return
self
;
}
//! Set all eight 16-bit unsigned integers.
static
ASMJIT_INLINE
Vec128
fromUw
(
uint16_t
x0
)
{
Vec128
self
;
self
.
setUw
(
x0
);
return
self
;
}
//! Set all four 32-bit signed integers.
static
ASMJIT_INLINE
Vec128
fromSd
(
int32_t
x0
,
int32_t
x1
,
int32_t
x2
,
int32_t
x3
)
{
Vec128
self
;
self
.
setSd
(
x0
,
x1
,
x2
,
x3
);
return
self
;
}
//! Set all four 32-bit signed integers.
static
ASMJIT_INLINE
Vec128
fromSd
(
int32_t
x0
)
{
Vec128
self
;
self
.
setSd
(
x0
);
return
self
;
}
//! Set all four 32-bit unsigned integers.
static
ASMJIT_INLINE
Vec128
fromUd
(
uint32_t
x0
,
uint32_t
x1
,
uint32_t
x2
,
uint32_t
x3
)
{
Vec128
self
;
self
.
setUd
(
x0
,
x1
,
x2
,
x3
);
return
self
;
}
//! Set all four 32-bit unsigned integers.
static
ASMJIT_INLINE
Vec128
fromUd
(
uint32_t
x0
)
{
Vec128
self
;
self
.
setUd
(
x0
);
return
self
;
}
//! Set all two 64-bit signed integers.
static
ASMJIT_INLINE
Vec128
fromSq
(
int64_t
x0
,
int64_t
x1
)
{
Vec128
self
;
self
.
setSq
(
x0
,
x1
);
return
self
;
}
//! Set all two 64-bit signed integers.
static
ASMJIT_INLINE
Vec128
fromSq
(
int64_t
x0
)
{
Vec128
self
;
self
.
setSq
(
x0
);
return
self
;
}
//! Set all two 64-bit unsigned integers.
static
ASMJIT_INLINE
Vec128
fromUq
(
uint64_t
x0
,
uint64_t
x1
)
{
Vec128
self
;
self
.
setUq
(
x0
,
x1
);
return
self
;
}
//! Set all two 64-bit unsigned integers.
static
ASMJIT_INLINE
Vec128
fromUq
(
uint64_t
x0
)
{
Vec128
self
;
self
.
setUq
(
x0
);
return
self
;
}
//! Set all four SP-FP floats.
static
ASMJIT_INLINE
Vec128
fromSf
(
float
x0
,
float
x1
,
float
x2
,
float
x3
)
{
Vec128
self
;
self
.
setSf
(
x0
,
x1
,
x2
,
x3
);
return
self
;
}
//! Set all four SP-FP floats.
static
ASMJIT_INLINE
Vec128
fromSf
(
float
x0
)
{
Vec128
self
;
self
.
setSf
(
x0
);
return
self
;
}
//! Set all two DP-FP floats.
static
ASMJIT_INLINE
Vec128
fromDf
(
double
x0
,
double
x1
)
{
Vec128
self
;
self
.
setDf
(
x0
,
x1
);
return
self
;
}
//! Set all two DP-FP floats.
static
ASMJIT_INLINE
Vec128
fromDf
(
double
x0
)
{
Vec128
self
;
self
.
setDf
(
x0
);
return
self
;
}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Set all sixteen 8-bit signed integers.
ASMJIT_INLINE
void
setSb
(
int8_t
x0
,
int8_t
x1
,
int8_t
x2
,
int8_t
x3
,
int8_t
x4
,
int8_t
x5
,
int8_t
x6
,
int8_t
x7
,
int8_t
x8
,
int8_t
x9
,
int8_t
x10
,
int8_t
x11
,
int8_t
x12
,
int8_t
x13
,
int8_t
x14
,
int8_t
x15
)
{
sb
[
0
]
=
x0
;
sb
[
1
]
=
x1
;
sb
[
2
]
=
x2
;
sb
[
3
]
=
x3
;
sb
[
4
]
=
x4
;
sb
[
5
]
=
x5
;
sb
[
6
]
=
x6
;
sb
[
7
]
=
x7
;
sb
[
8
]
=
x8
;
sb
[
9
]
=
x9
;
sb
[
10
]
=
x10
;
sb
[
11
]
=
x11
;
sb
[
12
]
=
x12
;
sb
[
13
]
=
x13
;
sb
[
14
]
=
x14
;
sb
[
15
]
=
x15
;
}
//! Set all sixteen 8-bit signed integers.
ASMJIT_INLINE
void
setSb
(
int8_t
x0
)
{
setUb
(
static_cast
<
uint8_t
>
(
x0
));
}
//! Set all sixteen 8-bit unsigned integers.
ASMJIT_INLINE
void
setUb
(
uint8_t
x0
,
uint8_t
x1
,
uint8_t
x2
,
uint8_t
x3
,
uint8_t
x4
,
uint8_t
x5
,
uint8_t
x6
,
uint8_t
x7
,
uint8_t
x8
,
uint8_t
x9
,
uint8_t
x10
,
uint8_t
x11
,
uint8_t
x12
,
uint8_t
x13
,
uint8_t
x14
,
uint8_t
x15
)
{
ub
[
0
]
=
x0
;
ub
[
1
]
=
x1
;
ub
[
2
]
=
x2
;
ub
[
3
]
=
x3
;
ub
[
4
]
=
x4
;
ub
[
5
]
=
x5
;
ub
[
6
]
=
x6
;
ub
[
7
]
=
x7
;
ub
[
8
]
=
x8
;
ub
[
9
]
=
x9
;
ub
[
10
]
=
x10
;
ub
[
11
]
=
x11
;
ub
[
12
]
=
x12
;
ub
[
13
]
=
x13
;
ub
[
14
]
=
x14
;
ub
[
15
]
=
x15
;
}
//! Set all sixteen 8-bit unsigned integers.
ASMJIT_INLINE
void
setUb
(
uint8_t
x0
)
{
if
(
kArchHost64Bit
)
{
uint64_t
t
=
static_cast
<
uint64_t
>
(
x0
)
*
ASMJIT_UINT64_C
(
0x0101010101010101
);
uq
[
0
]
=
t
;
uq
[
1
]
=
t
;
}
else
{
uint32_t
t
=
static_cast
<
uint32_t
>
(
x0
)
*
static_cast
<
uint32_t
>
(
0x01010101U
);
ud
[
0
]
=
t
;
ud
[
1
]
=
t
;
ud
[
2
]
=
t
;
ud
[
3
]
=
t
;
}
}
//! Set all eight 16-bit signed integers.
ASMJIT_INLINE
void
setSw
(
int16_t
x0
,
int16_t
x1
,
int16_t
x2
,
int16_t
x3
,
int16_t
x4
,
int16_t
x5
,
int16_t
x6
,
int16_t
x7
)
{
sw
[
0
]
=
x0
;
sw
[
1
]
=
x1
;
sw
[
2
]
=
x2
;
sw
[
3
]
=
x3
;
sw
[
4
]
=
x4
;
sw
[
5
]
=
x5
;
sw
[
6
]
=
x6
;
sw
[
7
]
=
x7
;
}
//! Set all eight 16-bit signed integers.
ASMJIT_INLINE
void
setSw
(
int16_t
x0
)
{
setUw
(
static_cast
<
uint16_t
>
(
x0
));
}
//! Set all eight 16-bit unsigned integers.
ASMJIT_INLINE
void
setUw
(
uint16_t
x0
,
uint16_t
x1
,
uint16_t
x2
,
uint16_t
x3
,
uint16_t
x4
,
uint16_t
x5
,
uint16_t
x6
,
uint16_t
x7
)
{
uw
[
0
]
=
x0
;
uw
[
1
]
=
x1
;
uw
[
2
]
=
x2
;
uw
[
3
]
=
x3
;
uw
[
4
]
=
x4
;
uw
[
5
]
=
x5
;
uw
[
6
]
=
x6
;
uw
[
7
]
=
x7
;
}
//! Set all eight 16-bit unsigned integers.
ASMJIT_INLINE
void
setUw
(
uint16_t
x0
)
{
if
(
kArchHost64Bit
)
{
uint64_t
t
=
static_cast
<
uint64_t
>
(
x0
)
*
ASMJIT_UINT64_C
(
0x0001000100010001
);
uq
[
0
]
=
t
;
uq
[
1
]
=
t
;
}
else
{
uint32_t
t
=
static_cast
<
uint32_t
>
(
x0
)
*
static_cast
<
uint32_t
>
(
0x00010001U
);
ud
[
0
]
=
t
;
ud
[
1
]
=
t
;
ud
[
2
]
=
t
;
ud
[
3
]
=
t
;
}
}
//! Set all four 32-bit signed integers.
ASMJIT_INLINE
void
setSd
(
int32_t
x0
,
int32_t
x1
,
int32_t
x2
,
int32_t
x3
)
{
sd
[
0
]
=
x0
;
sd
[
1
]
=
x1
;
sd
[
2
]
=
x2
;
sd
[
3
]
=
x3
;
}
//! Set all four 32-bit signed integers.
ASMJIT_INLINE
void
setSd
(
int32_t
x0
)
{
setUd
(
static_cast
<
uint32_t
>
(
x0
));
}
//! Set all four 32-bit unsigned integers.
ASMJIT_INLINE
void
setUd
(
uint32_t
x0
,
uint32_t
x1
,
uint32_t
x2
,
uint32_t
x3
)
{
ud
[
0
]
=
x0
;
ud
[
1
]
=
x1
;
ud
[
2
]
=
x2
;
ud
[
3
]
=
x3
;
}
//! Set all four 32-bit unsigned integers.
ASMJIT_INLINE
void
setUd
(
uint32_t
x0
)
{
if
(
kArchHost64Bit
)
{
uint64_t
t
=
(
static_cast
<
uint64_t
>
(
x0
)
<<
32
)
+
x0
;
uq
[
0
]
=
t
;
uq
[
1
]
=
t
;
}
else
{
ud
[
0
]
=
x0
;
ud
[
1
]
=
x0
;
ud
[
2
]
=
x0
;
ud
[
3
]
=
x0
;
}
}
//! Set all two 64-bit signed integers.
ASMJIT_INLINE
void
setSq
(
int64_t
x0
,
int64_t
x1
)
{
sq
[
0
]
=
x0
;
sq
[
1
]
=
x1
;
}
//! Set all two 64-bit signed integers.
ASMJIT_INLINE
void
setSq
(
int64_t
x0
)
{
sq
[
0
]
=
x0
;
sq
[
1
]
=
x0
;
}
//! Set all two 64-bit unsigned integers.
ASMJIT_INLINE
void
setUq
(
uint64_t
x0
,
uint64_t
x1
)
{
uq
[
0
]
=
x0
;
uq
[
1
]
=
x1
;
}
//! Set all two 64-bit unsigned integers.
ASMJIT_INLINE
void
setUq
(
uint64_t
x0
)
{
uq
[
0
]
=
x0
;
uq
[
1
]
=
x0
;
}
//! Set all four SP-FP floats.
ASMJIT_INLINE
void
setSf
(
float
x0
,
float
x1
,
float
x2
,
float
x3
)
{
sf
[
0
]
=
x0
;
sf
[
1
]
=
x1
;
sf
[
2
]
=
x2
;
sf
[
3
]
=
x3
;
}
//! Set all four SP-FP floats.
ASMJIT_INLINE
void
setSf
(
float
x0
)
{
sf
[
0
]
=
x0
;
sf
[
1
]
=
x0
;
sf
[
2
]
=
x0
;
sf
[
3
]
=
x0
;
}
//! Set all two DP-FP floats.
ASMJIT_INLINE
void
setDf
(
double
x0
,
double
x1
)
{
df
[
0
]
=
x0
;
df
[
1
]
=
x1
;
}
//! Set all two DP-FP floats.
ASMJIT_INLINE
void
setDf
(
double
x0
)
{
df
[
0
]
=
x0
;
df
[
1
]
=
x0
;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Array of sixteen 8-bit signed integers.
int8_t
sb
[
16
];
//! Array of sixteen 8-bit unsigned integers.
uint8_t
ub
[
16
];
//! Array of eight 16-bit signed integers.
int16_t
sw
[
8
];
//! Array of eight 16-bit unsigned integers.
uint16_t
uw
[
8
];
//! Array of four 32-bit signed integers.
int32_t
sd
[
4
];
//! Array of four 32-bit unsigned integers.
uint32_t
ud
[
4
];
//! Array of two 64-bit signed integers.
int64_t
sq
[
2
];
//! Array of two 64-bit unsigned integers.
uint64_t
uq
[
2
];
//! Array of four 32-bit single precision floating points.
float
sf
[
4
];
//! Array of two 64-bit double precision floating points.
double
df
[
2
];
};
// ============================================================================
// [asmjit::Vec256]
// ============================================================================
//! 256-bit vector register data.
union
Vec256
{
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Set all thirty two 8-bit signed integers.
static
ASMJIT_INLINE
Vec256
fromSb
(
int8_t
x0
,
int8_t
x1
,
int8_t
x2
,
int8_t
x3
,
int8_t
x4
,
int8_t
x5
,
int8_t
x6
,
int8_t
x7
,
int8_t
x8
,
int8_t
x9
,
int8_t
x10
,
int8_t
x11
,
int8_t
x12
,
int8_t
x13
,
int8_t
x14
,
int8_t
x15
,
int8_t
x16
,
int8_t
x17
,
int8_t
x18
,
int8_t
x19
,
int8_t
x20
,
int8_t
x21
,
int8_t
x22
,
int8_t
x23
,
int8_t
x24
,
int8_t
x25
,
int8_t
x26
,
int8_t
x27
,
int8_t
x28
,
int8_t
x29
,
int8_t
x30
,
int8_t
x31
)
{
Vec256
self
;
self
.
setSb
(
x0
,
x1
,
x2
,
x3
,
x4
,
x5
,
x6
,
x7
,
x8
,
x9
,
x10
,
x11
,
x12
,
x13
,
x14
,
x15
,
x16
,
x17
,
x18
,
x19
,
x20
,
x21
,
x22
,
x23
,
x24
,
x25
,
x26
,
x27
,
x28
,
x29
,
x30
,
x31
);
return
self
;
}
//! Set all thirty two 8-bit signed integers.
static
ASMJIT_INLINE
Vec256
fromSb
(
int8_t
x0
)
{
Vec256
self
;
self
.
setSb
(
x0
);
return
self
;
}
//! Set all thirty two 8-bit unsigned integers.
static
ASMJIT_INLINE
Vec256
fromUb
(
uint8_t
x0
,
uint8_t
x1
,
uint8_t
x2
,
uint8_t
x3
,
uint8_t
x4
,
uint8_t
x5
,
uint8_t
x6
,
uint8_t
x7
,
uint8_t
x8
,
uint8_t
x9
,
uint8_t
x10
,
uint8_t
x11
,
uint8_t
x12
,
uint8_t
x13
,
uint8_t
x14
,
uint8_t
x15
,
uint8_t
x16
,
uint8_t
x17
,
uint8_t
x18
,
uint8_t
x19
,
uint8_t
x20
,
uint8_t
x21
,
uint8_t
x22
,
uint8_t
x23
,
uint8_t
x24
,
uint8_t
x25
,
uint8_t
x26
,
uint8_t
x27
,
uint8_t
x28
,
uint8_t
x29
,
uint8_t
x30
,
uint8_t
x31
)
{
Vec256
self
;
self
.
setUb
(
x0
,
x1
,
x2
,
x3
,
x4
,
x5
,
x6
,
x7
,
x8
,
x9
,
x10
,
x11
,
x12
,
x13
,
x14
,
x15
,
x16
,
x17
,
x18
,
x19
,
x20
,
x21
,
x22
,
x23
,
x24
,
x25
,
x26
,
x27
,
x28
,
x29
,
x30
,
x31
);
return
self
;
}
//! Set all thirty two 8-bit unsigned integers.
static
ASMJIT_INLINE
Vec256
fromUb
(
uint8_t
x0
)
{
Vec256
self
;
self
.
setUb
(
x0
);
return
self
;
}
//! Set all sixteen 16-bit signed integers.
static
ASMJIT_INLINE
Vec256
fromSw
(
int16_t
x0
,
int16_t
x1
,
int16_t
x2
,
int16_t
x3
,
int16_t
x4
,
int16_t
x5
,
int16_t
x6
,
int16_t
x7
,
int16_t
x8
,
int16_t
x9
,
int16_t
x10
,
int16_t
x11
,
int16_t
x12
,
int16_t
x13
,
int16_t
x14
,
int16_t
x15
)
{
Vec256
self
;
self
.
setSw
(
x0
,
x1
,
x2
,
x3
,
x4
,
x5
,
x6
,
x7
,
x8
,
x9
,
x10
,
x11
,
x12
,
x13
,
x14
,
x15
);
return
self
;
}
//! Set all sixteen 16-bit signed integers.
static
ASMJIT_INLINE
Vec256
fromSw
(
int16_t
x0
)
{
Vec256
self
;
self
.
setSw
(
x0
);
return
self
;
}
//! Set all sixteen 16-bit unsigned integers.
static
ASMJIT_INLINE
Vec256
fromUw
(
uint16_t
x0
,
uint16_t
x1
,
uint16_t
x2
,
uint16_t
x3
,
uint16_t
x4
,
uint16_t
x5
,
uint16_t
x6
,
uint16_t
x7
,
uint16_t
x8
,
uint16_t
x9
,
uint16_t
x10
,
uint16_t
x11
,
uint16_t
x12
,
uint16_t
x13
,
uint16_t
x14
,
uint16_t
x15
)
{
Vec256
self
;
self
.
setUw
(
x0
,
x1
,
x2
,
x3
,
x4
,
x5
,
x6
,
x7
,
x8
,
x9
,
x10
,
x11
,
x12
,
x13
,
x14
,
x15
);
return
self
;
}
//! Set all sixteen 16-bit unsigned integers.
static
ASMJIT_INLINE
Vec256
fromUw
(
uint16_t
x0
)
{
Vec256
self
;
self
.
setUw
(
x0
);
return
self
;
}
//! Set all eight 32-bit signed integers.
static
ASMJIT_INLINE
Vec256
fromSd
(
int32_t
x0
,
int32_t
x1
,
int32_t
x2
,
int32_t
x3
,
int32_t
x4
,
int32_t
x5
,
int32_t
x6
,
int32_t
x7
)
{
Vec256
self
;
self
.
setSd
(
x0
,
x1
,
x2
,
x3
,
x4
,
x5
,
x6
,
x7
);
return
self
;
}
//! Set all eight 32-bit signed integers.
static
ASMJIT_INLINE
Vec256
fromSd
(
int32_t
x0
)
{
Vec256
self
;
self
.
setSd
(
x0
);
return
self
;
}
//! Set all eight 32-bit unsigned integers.
static
ASMJIT_INLINE
Vec256
fromUd
(
uint32_t
x0
,
uint32_t
x1
,
uint32_t
x2
,
uint32_t
x3
,
uint32_t
x4
,
uint32_t
x5
,
uint32_t
x6
,
uint32_t
x7
)
{
Vec256
self
;
self
.
setUd
(
x0
,
x1
,
x2
,
x3
,
x4
,
x5
,
x6
,
x7
);
return
self
;
}
//! Set all eight 32-bit unsigned integers.
static
ASMJIT_INLINE
Vec256
fromUd
(
uint32_t
x0
)
{
Vec256
self
;
self
.
setUd
(
x0
);
return
self
;
}
//! Set all four 64-bit signed integers.
static
ASMJIT_INLINE
Vec256
fromSq
(
int64_t
x0
,
int64_t
x1
,
int64_t
x2
,
int64_t
x3
)
{
Vec256
self
;
self
.
setSq
(
x0
,
x1
,
x2
,
x3
);
return
self
;
}
//! Set all four 64-bit signed integers.
static
ASMJIT_INLINE
Vec256
fromSq
(
int64_t
x0
)
{
Vec256
self
;
self
.
setSq
(
x0
);
return
self
;
}
//! Set all four 64-bit unsigned integers.
static
ASMJIT_INLINE
Vec256
fromUq
(
uint64_t
x0
,
uint64_t
x1
,
uint64_t
x2
,
uint64_t
x3
)
{
Vec256
self
;
self
.
setUq
(
x0
,
x1
,
x2
,
x3
);
return
self
;
}
//! Set all four 64-bit unsigned integers.
static
ASMJIT_INLINE
Vec256
fromUq
(
uint64_t
x0
)
{
Vec256
self
;
self
.
setUq
(
x0
);
return
self
;
}
//! Set all eight SP-FP floats.
static
ASMJIT_INLINE
Vec256
fromSf
(
float
x0
,
float
x1
,
float
x2
,
float
x3
,
float
x4
,
float
x5
,
float
x6
,
float
x7
)
{
Vec256
self
;
self
.
setSf
(
x0
,
x1
,
x2
,
x3
,
x4
,
x5
,
x6
,
x7
);
return
self
;
}
//! Set all eight SP-FP floats.
static
ASMJIT_INLINE
Vec256
fromSf
(
float
x0
)
{
Vec256
self
;
self
.
setSf
(
x0
);
return
self
;
}
//! Set all four DP-FP floats.
static
ASMJIT_INLINE
Vec256
fromDf
(
double
x0
,
double
x1
,
double
x2
,
double
x3
)
{
Vec256
self
;
self
.
setDf
(
x0
,
x1
,
x2
,
x3
);
return
self
;
}
//! Set all four DP-FP floats.
static
ASMJIT_INLINE
Vec256
fromDf
(
double
x0
)
{
Vec256
self
;
self
.
setDf
(
x0
);
return
self
;
}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Set all thirty two 8-bit signed integers.
ASMJIT_INLINE
void
setSb
(
int8_t
x0
,
int8_t
x1
,
int8_t
x2
,
int8_t
x3
,
int8_t
x4
,
int8_t
x5
,
int8_t
x6
,
int8_t
x7
,
int8_t
x8
,
int8_t
x9
,
int8_t
x10
,
int8_t
x11
,
int8_t
x12
,
int8_t
x13
,
int8_t
x14
,
int8_t
x15
,
int8_t
x16
,
int8_t
x17
,
int8_t
x18
,
int8_t
x19
,
int8_t
x20
,
int8_t
x21
,
int8_t
x22
,
int8_t
x23
,
int8_t
x24
,
int8_t
x25
,
int8_t
x26
,
int8_t
x27
,
int8_t
x28
,
int8_t
x29
,
int8_t
x30
,
int8_t
x31
)
{
sb
[
0
]
=
x0
;
sb
[
1
]
=
x1
;
sb
[
2
]
=
x2
;
sb
[
3
]
=
x3
;
sb
[
4
]
=
x4
;
sb
[
5
]
=
x5
;
sb
[
6
]
=
x6
;
sb
[
7
]
=
x7
;
sb
[
8
]
=
x8
;
sb
[
9
]
=
x9
;
sb
[
10
]
=
x10
;
sb
[
11
]
=
x11
;
sb
[
12
]
=
x12
;
sb
[
13
]
=
x13
;
sb
[
14
]
=
x14
;
sb
[
15
]
=
x15
;
sb
[
16
]
=
x16
;
sb
[
17
]
=
x17
;
sb
[
18
]
=
x18
;
sb
[
19
]
=
x19
;
sb
[
20
]
=
x20
;
sb
[
21
]
=
x21
;
sb
[
22
]
=
x22
;
sb
[
23
]
=
x23
;
sb
[
24
]
=
x24
;
sb
[
25
]
=
x25
;
sb
[
26
]
=
x26
;
sb
[
27
]
=
x27
;
sb
[
28
]
=
x28
;
sb
[
29
]
=
x29
;
sb
[
30
]
=
x30
;
sb
[
31
]
=
x31
;
}
//! Set all thirty two 8-bit signed integers.
ASMJIT_INLINE
void
setSb
(
int8_t
x0
)
{
setUb
(
static_cast
<
uint8_t
>
(
x0
));
}
//! Set all thirty two 8-bit unsigned integers.
ASMJIT_INLINE
void
setUb
(
uint8_t
x0
,
uint8_t
x1
,
uint8_t
x2
,
uint8_t
x3
,
uint8_t
x4
,
uint8_t
x5
,
uint8_t
x6
,
uint8_t
x7
,
uint8_t
x8
,
uint8_t
x9
,
uint8_t
x10
,
uint8_t
x11
,
uint8_t
x12
,
uint8_t
x13
,
uint8_t
x14
,
uint8_t
x15
,
uint8_t
x16
,
uint8_t
x17
,
uint8_t
x18
,
uint8_t
x19
,
uint8_t
x20
,
uint8_t
x21
,
uint8_t
x22
,
uint8_t
x23
,
uint8_t
x24
,
uint8_t
x25
,
uint8_t
x26
,
uint8_t
x27
,
uint8_t
x28
,
uint8_t
x29
,
uint8_t
x30
,
uint8_t
x31
)
{
ub
[
0
]
=
x0
;
ub
[
1
]
=
x1
;
ub
[
2
]
=
x2
;
ub
[
3
]
=
x3
;
ub
[
4
]
=
x4
;
ub
[
5
]
=
x5
;
ub
[
6
]
=
x6
;
ub
[
7
]
=
x7
;
ub
[
8
]
=
x8
;
ub
[
9
]
=
x9
;
ub
[
10
]
=
x10
;
ub
[
11
]
=
x11
;
ub
[
12
]
=
x12
;
ub
[
13
]
=
x13
;
ub
[
14
]
=
x14
;
ub
[
15
]
=
x15
;
ub
[
16
]
=
x16
;
ub
[
17
]
=
x17
;
ub
[
18
]
=
x18
;
ub
[
19
]
=
x19
;
ub
[
20
]
=
x20
;
ub
[
21
]
=
x21
;
ub
[
22
]
=
x22
;
ub
[
23
]
=
x23
;
ub
[
24
]
=
x24
;
ub
[
25
]
=
x25
;
ub
[
26
]
=
x26
;
ub
[
27
]
=
x27
;
ub
[
28
]
=
x28
;
ub
[
29
]
=
x29
;
ub
[
30
]
=
x30
;
ub
[
31
]
=
x31
;
}
//! Set all thirty two 8-bit unsigned integers.
ASMJIT_INLINE
void
setUb
(
uint8_t
x0
)
{
if
(
kArchHost64Bit
)
{
uint64_t
t
=
static_cast
<
uint64_t
>
(
x0
)
*
ASMJIT_UINT64_C
(
0x0101010101010101
);
uq
[
0
]
=
t
;
uq
[
1
]
=
t
;
uq
[
2
]
=
t
;
uq
[
3
]
=
t
;
}
else
{
uint32_t
t
=
static_cast
<
uint32_t
>
(
x0
)
*
static_cast
<
uint32_t
>
(
0x01010101U
);
ud
[
0
]
=
t
;
ud
[
1
]
=
t
;
ud
[
2
]
=
t
;
ud
[
3
]
=
t
;
ud
[
4
]
=
t
;
ud
[
5
]
=
t
;
ud
[
6
]
=
t
;
ud
[
7
]
=
t
;
}
}
//! Set all sixteen 16-bit signed integers.
ASMJIT_INLINE
void
setSw
(
int16_t
x0
,
int16_t
x1
,
int16_t
x2
,
int16_t
x3
,
int16_t
x4
,
int16_t
x5
,
int16_t
x6
,
int16_t
x7
,
int16_t
x8
,
int16_t
x9
,
int16_t
x10
,
int16_t
x11
,
int16_t
x12
,
int16_t
x13
,
int16_t
x14
,
int16_t
x15
)
{
sw
[
0
]
=
x0
;
sw
[
1
]
=
x1
;
sw
[
2
]
=
x2
;
sw
[
3
]
=
x3
;
sw
[
4
]
=
x4
;
sw
[
5
]
=
x5
;
sw
[
6
]
=
x6
;
sw
[
7
]
=
x7
;
sw
[
8
]
=
x8
;
sw
[
9
]
=
x9
;
sw
[
10
]
=
x10
;
sw
[
11
]
=
x11
;
sw
[
12
]
=
x12
;
sw
[
13
]
=
x13
;
sw
[
14
]
=
x14
;
sw
[
15
]
=
x15
;
}
//! Set all sixteen 16-bit signed integers.
ASMJIT_INLINE
void
setSw
(
int16_t
x0
)
{
setUw
(
static_cast
<
uint16_t
>
(
x0
));
}
//! Set all sixteen 16-bit unsigned integers.
ASMJIT_INLINE
void
setUw
(
uint16_t
x0
,
uint16_t
x1
,
uint16_t
x2
,
uint16_t
x3
,
uint16_t
x4
,
uint16_t
x5
,
uint16_t
x6
,
uint16_t
x7
,
uint16_t
x8
,
uint16_t
x9
,
uint16_t
x10
,
uint16_t
x11
,
uint16_t
x12
,
uint16_t
x13
,
uint16_t
x14
,
uint16_t
x15
)
{
uw
[
0
]
=
x0
;
uw
[
1
]
=
x1
;
uw
[
2
]
=
x2
;
uw
[
3
]
=
x3
;
uw
[
4
]
=
x4
;
uw
[
5
]
=
x5
;
uw
[
6
]
=
x6
;
uw
[
7
]
=
x7
;
uw
[
8
]
=
x8
;
uw
[
9
]
=
x9
;
uw
[
10
]
=
x10
;
uw
[
11
]
=
x11
;
uw
[
12
]
=
x12
;
uw
[
13
]
=
x13
;
uw
[
14
]
=
x14
;
uw
[
15
]
=
x15
;
}
//! Set all eight 16-bit unsigned integers.
ASMJIT_INLINE
void
setUw
(
uint16_t
x0
)
{
if
(
kArchHost64Bit
)
{
uint64_t
t
=
static_cast
<
uint64_t
>
(
x0
)
*
ASMJIT_UINT64_C
(
0x0001000100010001
);
uq
[
0
]
=
t
;
uq
[
1
]
=
t
;
uq
[
2
]
=
t
;
uq
[
3
]
=
t
;
}
else
{
uint32_t
t
=
static_cast
<
uint32_t
>
(
x0
)
*
static_cast
<
uint32_t
>
(
0x00010001U
);
ud
[
0
]
=
t
;
ud
[
1
]
=
t
;
ud
[
2
]
=
t
;
ud
[
3
]
=
t
;
ud
[
4
]
=
t
;
ud
[
5
]
=
t
;
ud
[
6
]
=
t
;
ud
[
7
]
=
t
;
}
}
//! Set all eight 32-bit signed integers.
ASMJIT_INLINE
void
setSd
(
int32_t
x0
,
int32_t
x1
,
int32_t
x2
,
int32_t
x3
,
int32_t
x4
,
int32_t
x5
,
int32_t
x6
,
int32_t
x7
)
{
sd
[
0
]
=
x0
;
sd
[
1
]
=
x1
;
sd
[
2
]
=
x2
;
sd
[
3
]
=
x3
;
sd
[
4
]
=
x4
;
sd
[
5
]
=
x5
;
sd
[
6
]
=
x6
;
sd
[
7
]
=
x7
;
}
//! Set all eight 32-bit signed integers.
ASMJIT_INLINE
void
setSd
(
int32_t
x0
)
{
setUd
(
static_cast
<
uint32_t
>
(
x0
));
}
//! Set all eight 32-bit unsigned integers.
ASMJIT_INLINE
void
setUd
(
uint32_t
x0
,
uint32_t
x1
,
uint32_t
x2
,
uint32_t
x3
,
uint32_t
x4
,
uint32_t
x5
,
uint32_t
x6
,
uint32_t
x7
)
{
ud
[
0
]
=
x0
;
ud
[
1
]
=
x1
;
ud
[
2
]
=
x2
;
ud
[
3
]
=
x3
;
ud
[
4
]
=
x4
;
ud
[
5
]
=
x5
;
ud
[
6
]
=
x6
;
ud
[
7
]
=
x7
;
}
//! Set all eight 32-bit unsigned integers.
ASMJIT_INLINE
void
setUd
(
uint32_t
x0
)
{
if
(
kArchHost64Bit
)
{
uint64_t
t
=
(
static_cast
<
uint64_t
>
(
x0
)
<<
32
)
+
x0
;
uq
[
0
]
=
t
;
uq
[
1
]
=
t
;
uq
[
2
]
=
t
;
uq
[
3
]
=
t
;
}
else
{
ud
[
0
]
=
x0
;
ud
[
1
]
=
x0
;
ud
[
2
]
=
x0
;
ud
[
3
]
=
x0
;
ud
[
4
]
=
x0
;
ud
[
5
]
=
x0
;
ud
[
6
]
=
x0
;
ud
[
7
]
=
x0
;
}
}
//! Set all four 64-bit signed integers.
ASMJIT_INLINE
void
setSq
(
int64_t
x0
,
int64_t
x1
,
int64_t
x2
,
int64_t
x3
)
{
sq
[
0
]
=
x0
;
sq
[
1
]
=
x1
;
sq
[
2
]
=
x2
;
sq
[
3
]
=
x3
;
}
//! Set all four 64-bit signed integers.
ASMJIT_INLINE
void
setSq
(
int64_t
x0
)
{
sq
[
0
]
=
x0
;
sq
[
1
]
=
x0
;
sq
[
2
]
=
x0
;
sq
[
3
]
=
x0
;
}
//! Set all four 64-bit unsigned integers.
ASMJIT_INLINE
void
setUq
(
uint64_t
x0
,
uint64_t
x1
,
uint64_t
x2
,
uint64_t
x3
)
{
uq
[
0
]
=
x0
;
uq
[
1
]
=
x1
;
uq
[
2
]
=
x2
;
uq
[
3
]
=
x3
;
}
//! Set all four 64-bit unsigned integers.
ASMJIT_INLINE
void
setUq
(
uint64_t
x0
)
{
uq
[
0
]
=
x0
;
uq
[
1
]
=
x0
;
uq
[
2
]
=
x0
;
uq
[
3
]
=
x0
;
}
//! Set all eight SP-FP floats.
ASMJIT_INLINE
void
setSf
(
float
x0
,
float
x1
,
float
x2
,
float
x3
,
float
x4
,
float
x5
,
float
x6
,
float
x7
)
{
sf
[
0
]
=
x0
;
sf
[
1
]
=
x1
;
sf
[
2
]
=
x2
;
sf
[
3
]
=
x3
;
sf
[
4
]
=
x4
;
sf
[
5
]
=
x5
;
sf
[
6
]
=
x6
;
sf
[
7
]
=
x7
;
}
//! Set all eight SP-FP floats.
ASMJIT_INLINE
void
setSf
(
float
x0
)
{
sf
[
0
]
=
x0
;
sf
[
1
]
=
x0
;
sf
[
2
]
=
x0
;
sf
[
3
]
=
x0
;
sf
[
4
]
=
x0
;
sf
[
5
]
=
x0
;
sf
[
6
]
=
x0
;
sf
[
7
]
=
x0
;
}
//! Set all four DP-FP floats.
ASMJIT_INLINE
void
setDf
(
double
x0
,
double
x1
,
double
x2
,
double
x3
)
{
df
[
0
]
=
x0
;
df
[
1
]
=
x1
;
df
[
2
]
=
x2
;
df
[
3
]
=
x3
;
}
//! Set all four DP-FP floats.
ASMJIT_INLINE
void
setDf
(
double
x0
)
{
df
[
0
]
=
x0
;
df
[
1
]
=
x0
;
df
[
2
]
=
x0
;
df
[
3
]
=
x0
;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Array of thirty two 8-bit signed integers.
int8_t
sb
[
32
];
//! Array of thirty two 8-bit unsigned integers.
uint8_t
ub
[
32
];
//! Array of sixteen 16-bit signed integers.
int16_t
sw
[
16
];
//! Array of sixteen 16-bit unsigned integers.
uint16_t
uw
[
16
];
//! Array of eight 32-bit signed integers.
int32_t
sd
[
8
];
//! Array of eight 32-bit unsigned integers.
uint32_t
ud
[
8
];
//! Array of four 64-bit signed integers.
int64_t
sq
[
4
];
//! Array of four 64-bit unsigned integers.
uint64_t
uq
[
4
];
//! Array of eight 32-bit single precision floating points.
float
sf
[
8
];
//! Array of four 64-bit double precision floating points.
double
df
[
4
];
};
//! \}
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_VECTYPES_H
libraries/asmjit/base/vmem.cpp
0 → 100644
View file @
a83607d6
// [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/globals.h"
#include "../base/intutil.h"
#include "../base/lock.h"
#include "../base/vmem.h"
// [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 "../apibegin.h"
// This file contains implementation of virtual memory management for AsmJit
// library. The initial concept is to keep this implementation simple but
// efficient. There are several goals I decided to write implementation myself.
//
// Goals:
//
// - Granularity of allocated blocks is different than granularity for a typical
// C malloc. It is at least 64-bytes so Assembler/Compiler can guarantee the
// alignment required. Alignment requirements can grow in the future, but at
// the moment 64 bytes is safe (we may jump to 128 bytes if necessary or make
// it configurable).
//
// - Keep memory manager information outside of the allocated virtual memory
// pages, because these pages allow executing of machine code and there should
// not be data required to keep track of these blocks. Another reason is that
// some environments (i.e. iOS) allow to generate and run JIT code, but this
// code has to be set to [Executable, but not Writable].
//
// - Keep implementation simple and easy to follow.
//
// Implementation is based on bit arrays and binary trees. Bit arrays contain
// information related to allocated and unused blocks of memory. The size of
// a block is described by `MemNode::density`. Count of blocks is stored in
// `MemNode::blocks`. For example if density is 64 and count of blocks is 20,
// memory node contains 64*20 bytes of memory and smallest possible allocation
// (and also alignment) is 64 bytes. So density is also related to memory
// alignment. Binary trees (RB) are used to enable fast lookup into all addresses
// allocated by memory manager instance. This is used mainly by `VMemPrivate::release()`.
//
// Bit array looks like this (empty = unused, X = used) - Size of block 64:
//
// -------------------------------------------------------------------------
// | |X|X| | | | | |X|X|X|X|X|X| | | | | | | | | | | | |X| | | | |X|X|X| | |
// -------------------------------------------------------------------------
// (Maximum continuous block)
//
// These bits show that there are 12 allocated blocks (X) of 64 bytes, so total
// size allocated is 768 bytes. Maximum count of continuous memory is 12 * 64.
namespace
asmjit
{
// ============================================================================
// [asmjit::VMemUtil - Windows]
// ============================================================================
// Windows specific implementation using `VirtualAllocEx` and `VirtualFree`.
#if defined(ASMJIT_OS_WINDOWS)
struct
VMemLocal
{
// AsmJit allows to pass a `NULL` handle to `VMemUtil`. This function is just
// a convenient way to convert such handle to the current process one.
ASMJIT_INLINE
HANDLE
getSafeProcessHandle
(
HANDLE
hParam
)
const
{
return
hParam
!=
NULL
?
hParam
:
hProcess
;
}
size_t
pageSize
;
size_t
pageGranularity
;
HANDLE
hProcess
;
};
static
VMemLocal
vMemLocal
;
static
const
VMemLocal
&
vMemGet
()
{
VMemLocal
&
vMem
=
vMemLocal
;
if
(
!
vMem
.
hProcess
)
{
SYSTEM_INFO
info
;
::
GetSystemInfo
(
&
info
);
vMem
.
pageSize
=
IntUtil
::
alignToPowerOf2
<
uint32_t
>
(
info
.
dwPageSize
);
vMem
.
pageGranularity
=
info
.
dwAllocationGranularity
;
vMem
.
hProcess
=
::
GetCurrentProcess
();
}
return
vMem
;
};
size_t
VMemUtil
::
getPageSize
()
{
const
VMemLocal
&
vMem
=
vMemGet
();
return
vMem
.
pageSize
;
}
size_t
VMemUtil
::
getPageGranularity
()
{
const
VMemLocal
&
vMem
=
vMemGet
();
return
vMem
.
pageGranularity
;
}
void
*
VMemUtil
::
alloc
(
size_t
length
,
size_t
*
allocated
,
uint32_t
flags
)
{
return
allocProcessMemory
(
static_cast
<
HANDLE
>
(
0
),
length
,
allocated
,
flags
);
}
void
*
VMemUtil
::
allocProcessMemory
(
HANDLE
hProcess
,
size_t
length
,
size_t
*
allocated
,
uint32_t
flags
)
{
if
(
length
==
0
)
return
NULL
;
const
VMemLocal
&
vMem
=
vMemGet
();
hProcess
=
vMem
.
getSafeProcessHandle
(
hProcess
);
// VirtualAlloc rounds allocated size to a page size automatically.
size_t
mSize
=
IntUtil
::
alignTo
(
length
,
vMem
.
pageSize
);
// Windows XP SP2 / Vista allow Data Excution Prevention (DEP).
DWORD
protectFlags
=
0
;
if
(
flags
&
kVMemFlagExecutable
)
protectFlags
|=
(
flags
&
kVMemFlagWritable
)
?
PAGE_EXECUTE_READWRITE
:
PAGE_EXECUTE_READ
;
else
protectFlags
|=
(
flags
&
kVMemFlagWritable
)
?
PAGE_READWRITE
:
PAGE_READONLY
;
LPVOID
mBase
=
::
VirtualAllocEx
(
hProcess
,
NULL
,
mSize
,
MEM_COMMIT
|
MEM_RESERVE
,
protectFlags
);
if
(
mBase
==
NULL
)
return
NULL
;
ASMJIT_ASSERT
(
IntUtil
::
isAligned
<
size_t
>
(
reinterpret_cast
<
size_t
>
(
mBase
),
vMem
.
pageSize
));
if
(
allocated
!=
NULL
)
*
allocated
=
mSize
;
return
mBase
;
}
Error
VMemUtil
::
release
(
void
*
addr
,
size_t
length
)
{
return
releaseProcessMemory
(
static_cast
<
HANDLE
>
(
0
),
addr
,
length
);
}
Error
VMemUtil
::
releaseProcessMemory
(
HANDLE
hProcess
,
void
*
addr
,
size_t
/* length */
)
{
hProcess
=
vMemGet
().
getSafeProcessHandle
(
hProcess
);
if
(
!::
VirtualFreeEx
(
hProcess
,
addr
,
0
,
MEM_RELEASE
))
return
kErrorInvalidState
;
return
kErrorOk
;
}
#endif // ASMJIT_OS_WINDOWS
// ============================================================================
// [asmjit::VMemUtil - Posix]
// ============================================================================
// Posix specific implementation using `mmap` and `munmap`.
#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
{
size_t
pageSize
;
size_t
pageGranularity
;
};
static
VMemLocal
vMemLocal
;
static
const
VMemLocal
&
vMemGet
()
{
VMemLocal
&
vMem
=
vMemLocal
;
if
(
!
vMem
.
pageSize
)
{
size_t
pageSize
=
::
getpagesize
();
vMem
.
pageSize
=
pageSize
;
vMem
.
pageGranularity
=
IntUtil
::
iMax
<
size_t
>
(
pageSize
,
65536
);
}
return
vMem
;
};
size_t
VMemUtil
::
getPageSize
()
{
const
VMemLocal
&
vMem
=
vMemGet
();
return
vMem
.
pageSize
;
}
size_t
VMemUtil
::
getPageGranularity
()
{
const
VMemLocal
&
vMem
=
vMemGet
();
return
vMem
.
pageGranularity
;
}
void
*
VMemUtil
::
alloc
(
size_t
length
,
size_t
*
allocated
,
uint32_t
flags
)
{
const
VMemLocal
&
vMem
=
vMemGet
();
size_t
msize
=
IntUtil
::
alignTo
<
size_t
>
(
length
,
vMem
.
pageSize
);
int
protection
=
PROT_READ
;
if
(
flags
&
kVMemFlagWritable
)
protection
|=
PROT_WRITE
;
if
(
flags
&
kVMemFlagExecutable
)
protection
|=
PROT_EXEC
;
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
;
}
Error
VMemUtil
::
release
(
void
*
addr
,
size_t
length
)
{
if
(
::
munmap
(
addr
,
length
)
!=
0
)
return
kErrorInvalidState
;
return
kErrorOk
;
}
#endif // ASMJIT_OS_POSIX
// ============================================================================
// [asmjit::VMemMgr - BitOps]
// ============================================================================
#define M_DIV(x, y) ((x) / (y))
#define M_MOD(x, y) ((x) % (y))
//! \internal
enum
{
kBitsPerEntity
=
(
sizeof
(
size_t
)
*
8
)
};
//! \internal
//!
//! Set `len` bits in `buf` starting at `index` bit index.
static
void
_SetBits
(
size_t
*
buf
,
size_t
index
,
size_t
len
)
{
if
(
len
==
0
)
return
;
size_t
i
=
index
/
kBitsPerEntity
;
// size_t[]
size_t
j
=
index
%
kBitsPerEntity
;
// size_t[][] bit index
// How many bytes process in the first group.
size_t
c
=
kBitsPerEntity
-
j
;
if
(
c
>
len
)
c
=
len
;
// Offset.
buf
+=
i
;
*
buf
++
|=
((
~
(
size_t
)
0
)
>>
(
kBitsPerEntity
-
c
))
<<
j
;
len
-=
c
;
while
(
len
>=
kBitsPerEntity
)
{
*
buf
++
=
~
(
size_t
)
0
;
len
-=
kBitsPerEntity
;
}
if
(
len
)
*
buf
|=
((
~
(
size_t
)
0
)
>>
(
kBitsPerEntity
-
len
));
}
// ============================================================================
// [asmjit::VMemMgr::TypeDefs]
// ============================================================================
typedef
VMemMgr
::
RbNode
RbNode
;
typedef
VMemMgr
::
MemNode
MemNode
;
typedef
VMemMgr
::
PermanentNode
PermanentNode
;
// ============================================================================
// [asmjit::VMemMgr::RbNode]
// ============================================================================
//! \internal
//!
//! Base red-black tree node.
struct
VMemMgr
::
RbNode
{
// Implementation is based on article by Julienne Walker (Public Domain),
// including C code and original comments. Thanks for the excellent article.
// Left[0] and right[1] nodes.
RbNode
*
node
[
2
];
// Virtual memory address.
uint8_t
*
mem
;
// Whether the node is RED.
uint32_t
red
;
};
//! \internal
//!
//! Get whether the node is red (NULL or node with red flag).
static
ASMJIT_INLINE
bool
rbIsRed
(
RbNode
*
node
)
{
return
node
!=
NULL
&&
node
->
red
;
}
//! \internal
//!
//! Check whether the RB tree is valid.
static
int
rbAssert
(
RbNode
*
root
)
{
if
(
root
==
NULL
)
return
1
;
RbNode
*
ln
=
root
->
node
[
0
];
RbNode
*
rn
=
root
->
node
[
1
];
// Red violation.
ASMJIT_ASSERT
(
!
(
rbIsRed
(
root
)
&&
(
rbIsRed
(
ln
)
||
rbIsRed
(
rn
)))
);
int
lh
=
rbAssert
(
ln
);
int
rh
=
rbAssert
(
rn
);
// Invalid btree.
ASMJIT_ASSERT
(
ln
==
NULL
||
ln
->
mem
<
root
->
mem
);
ASMJIT_ASSERT
(
rn
==
NULL
||
rn
->
mem
>
root
->
mem
);
// Black violation.
ASMJIT_ASSERT
(
!
(
lh
!=
0
&&
rh
!=
0
&&
lh
!=
rh
)
);
// Only count black links.
if
(
lh
!=
0
&&
rh
!=
0
)
return
rbIsRed
(
root
)
?
lh
:
lh
+
1
;
else
return
0
;
}
//! \internal
//!
//! Single rotation.
static
ASMJIT_INLINE
RbNode
*
rbRotateSingle
(
RbNode
*
root
,
int
dir
)
{
RbNode
*
save
=
root
->
node
[
!
dir
];
root
->
node
[
!
dir
]
=
save
->
node
[
dir
];
save
->
node
[
dir
]
=
root
;
root
->
red
=
1
;
save
->
red
=
0
;
return
save
;
}
//! \internal
//!
//! Double rotation.
static
ASMJIT_INLINE
RbNode
*
rbRotateDouble
(
RbNode
*
root
,
int
dir
)
{
root
->
node
[
!
dir
]
=
rbRotateSingle
(
root
->
node
[
!
dir
],
!
dir
);
return
rbRotateSingle
(
root
,
dir
);
}
// ============================================================================
// [asmjit::VMemMgr::MemNode]
// ============================================================================
struct
VMemMgr
::
MemNode
:
public
RbNode
{
// --------------------------------------------------------------------------
// [Helpers]
// --------------------------------------------------------------------------
// Get available space.
ASMJIT_INLINE
size_t
getAvailable
()
const
{
return
size
-
used
;
}
ASMJIT_INLINE
void
fillData
(
MemNode
*
other
)
{
mem
=
other
->
mem
;
size
=
other
->
size
;
used
=
other
->
used
;
blocks
=
other
->
blocks
;
density
=
other
->
density
;
largestBlock
=
other
->
largestBlock
;
baUsed
=
other
->
baUsed
;
baCont
=
other
->
baCont
;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
MemNode
*
prev
;
// Prev node in list.
MemNode
*
next
;
// Next node in list.
size_t
size
;
// How many bytes contain this node.
size_t
used
;
// How many bytes are used in this node.
size_t
blocks
;
// How many blocks are here.
size_t
density
;
// Minimum count of allocated bytes in this node (also alignment).
size_t
largestBlock
;
// Contains largest block that can be allocated.
size_t
*
baUsed
;
// Contains bits about used blocks (0 = unused, 1 = used).
size_t
*
baCont
;
// Contains bits about continuous blocks (0 = stop , 1 = continue).
};
// ============================================================================
// [asmjit::VMemMgr::PermanentNode]
// ============================================================================
//! \internal
//!
//! Permanent node.
struct
VMemMgr
::
PermanentNode
{
// --------------------------------------------------------------------------
// [Helpers]
// --------------------------------------------------------------------------
//! Get available space.
ASMJIT_INLINE
size_t
getAvailable
()
const
{
return
size
-
used
;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
PermanentNode
*
prev
;
// Pointer to prev chunk or NULL.
uint8_t
*
mem
;
// Base pointer (virtual memory address).
size_t
size
;
// Count of bytes allocated.
size_t
used
;
// Count of bytes used.
};
// ============================================================================
// [asmjit::VMemMgr - Private]
// ============================================================================
//! \internal
//!
//! Helper to avoid `#ifdef`s in the code.
ASMJIT_INLINE
uint8_t
*
vMemMgrAllocVMem
(
VMemMgr
*
self
,
size_t
size
,
size_t
*
vSize
)
{
uint32_t
flags
=
kVMemFlagWritable
|
kVMemFlagExecutable
;
#if !defined(ASMJIT_OS_WINDOWS)
return
static_cast
<
uint8_t
*>
(
VMemUtil
::
alloc
(
size
,
vSize
,
flags
));
#else
return
static_cast
<
uint8_t
*>
(
VMemUtil
::
allocProcessMemory
(
self
->
_hProcess
,
size
,
vSize
,
flags
));
#endif
}
//! \internal
//!
//! Helper to avoid `#ifdef`s in the code.
ASMJIT_INLINE
Error
vMemMgrReleaseVMem
(
VMemMgr
*
self
,
void
*
p
,
size_t
vSize
)
{
#if !defined(ASMJIT_OS_WINDOWS)
return
VMemUtil
::
release
(
p
,
vSize
);
#else
return
VMemUtil
::
releaseProcessMemory
(
self
->
_hProcess
,
p
,
vSize
);
#endif
}
//! \internal
//!
//! Check whether the Red-Black tree is valid.
static
bool
vMemMgrCheckTree
(
VMemMgr
*
self
)
{
return
rbAssert
(
self
->
_root
)
>
0
;
}
//! \internal
//!
//! Alloc virtual memory including a heap memory needed for `MemNode` data.
//!
//! Returns set-up `MemNode*` or NULL if allocation failed.
static
MemNode
*
vMemMgrCreateNode
(
VMemMgr
*
self
,
size_t
size
,
size_t
density
)
{
size_t
vSize
;
uint8_t
*
vmem
=
vMemMgrAllocVMem
(
self
,
size
,
&
vSize
);
// Out of memory.
if
(
vmem
==
NULL
)
return
NULL
;
size_t
blocks
=
(
vSize
/
density
);
size_t
bsize
=
(((
blocks
+
7
)
>>
3
)
+
sizeof
(
size_t
)
-
1
)
&
~
(
size_t
)(
sizeof
(
size_t
)
-
1
);
MemNode
*
node
=
static_cast
<
MemNode
*>
(
ASMJIT_ALLOC
(
sizeof
(
MemNode
)));
uint8_t
*
data
=
static_cast
<
uint8_t
*>
(
ASMJIT_ALLOC
(
bsize
*
2
));
// Out of memory.
if
(
node
==
NULL
||
data
==
NULL
)
{
vMemMgrReleaseVMem
(
self
,
vmem
,
vSize
);
if
(
node
)
ASMJIT_FREE
(
node
);
if
(
data
)
ASMJIT_FREE
(
data
);
return
NULL
;
}
// Initialize RbNode data.
node
->
node
[
0
]
=
NULL
;
node
->
node
[
1
]
=
NULL
;
node
->
mem
=
vmem
;
node
->
red
=
1
;
// Initialize MemNode data.
node
->
prev
=
NULL
;
node
->
next
=
NULL
;
node
->
size
=
vSize
;
node
->
used
=
0
;
node
->
blocks
=
blocks
;
node
->
density
=
density
;
node
->
largestBlock
=
vSize
;
::
memset
(
data
,
0
,
bsize
*
2
);
node
->
baUsed
=
reinterpret_cast
<
size_t
*>
(
data
);
node
->
baCont
=
reinterpret_cast
<
size_t
*>
(
data
+
bsize
);
return
node
;
}
static
void
vMemMgrInsertNode
(
VMemMgr
*
self
,
MemNode
*
node
)
{
if
(
self
->
_root
==
NULL
)
{
// Empty tree case.
self
->
_root
=
node
;
}
else
{
// False tree root.
RbNode
head
=
{
0
};
// Grandparent & parent.
RbNode
*
g
=
NULL
;
RbNode
*
t
=
&
head
;
// Iterator & parent.
RbNode
*
p
=
NULL
;
RbNode
*
q
=
t
->
node
[
1
]
=
self
->
_root
;
int
dir
=
0
,
last
;
// Search down the tree.
for
(;;)
{
if
(
q
==
NULL
)
{
// Insert new node at the bottom.
q
=
node
;
p
->
node
[
dir
]
=
node
;
}
else
if
(
rbIsRed
(
q
->
node
[
0
])
&&
rbIsRed
(
q
->
node
[
1
]))
{
// Color flip.
q
->
red
=
1
;
q
->
node
[
0
]
->
red
=
0
;
q
->
node
[
1
]
->
red
=
0
;
}
// Fix red violation.
if
(
rbIsRed
(
q
)
&&
rbIsRed
(
p
))
{
int
dir2
=
t
->
node
[
1
]
==
g
;
t
->
node
[
dir2
]
=
q
==
p
->
node
[
last
]
?
rbRotateSingle
(
g
,
!
last
)
:
rbRotateDouble
(
g
,
!
last
);
}
// Stop if found.
if
(
q
==
node
)
break
;
last
=
dir
;
dir
=
q
->
mem
<
node
->
mem
;
// Update helpers.
if
(
g
!=
NULL
)
t
=
g
;
g
=
p
;
p
=
q
;
q
=
q
->
node
[
dir
];
}
// Update root.
self
->
_root
=
static_cast
<
MemNode
*>
(
head
.
node
[
1
]);
}
// Make root black.
self
->
_root
->
red
=
0
;
// Link with others.
node
->
prev
=
self
->
_last
;
if
(
self
->
_first
==
NULL
)
{
self
->
_first
=
node
;
self
->
_last
=
node
;
self
->
_optimal
=
node
;
}
else
{
node
->
prev
=
self
->
_last
;
self
->
_last
->
next
=
node
;
self
->
_last
=
node
;
}
}
//! \internal
//!
//! Remove node from Red-Black tree.
//!
//! Returns node that should be freed, but it doesn't have to be necessarily
//! the `node` passed.
static
MemNode
*
vMemMgrRemoveNode
(
VMemMgr
*
self
,
MemNode
*
node
)
{
// False tree root.
RbNode
head
=
{
0
};
// Helpers.
RbNode
*
q
=
&
head
;
RbNode
*
p
=
NULL
;
RbNode
*
g
=
NULL
;
// Found item.
RbNode
*
f
=
NULL
;
int
dir
=
1
;
// Set up.
q
->
node
[
1
]
=
self
->
_root
;
// Search and push a red down.
while
(
q
->
node
[
dir
]
!=
NULL
)
{
int
last
=
dir
;
// Update helpers.
g
=
p
;
p
=
q
;
q
=
q
->
node
[
dir
];
dir
=
q
->
mem
<
node
->
mem
;
// Save found node.
if
(
q
==
node
)
f
=
q
;
// Push the red node down.
if
(
!
rbIsRed
(
q
)
&&
!
rbIsRed
(
q
->
node
[
dir
]))
{
if
(
rbIsRed
(
q
->
node
[
!
dir
]))
{
p
=
p
->
node
[
last
]
=
rbRotateSingle
(
q
,
dir
);
}
else
if
(
!
rbIsRed
(
q
->
node
[
!
dir
]))
{
RbNode
*
s
=
p
->
node
[
!
last
];
if
(
s
!=
NULL
)
{
if
(
!
rbIsRed
(
s
->
node
[
!
last
])
&&
!
rbIsRed
(
s
->
node
[
last
]))
{
// Color flip.
p
->
red
=
0
;
s
->
red
=
1
;
q
->
red
=
1
;
}
else
{
int
dir2
=
g
->
node
[
1
]
==
p
;
if
(
rbIsRed
(
s
->
node
[
last
]))
g
->
node
[
dir2
]
=
rbRotateDouble
(
p
,
last
);
else
if
(
rbIsRed
(
s
->
node
[
!
last
]))
g
->
node
[
dir2
]
=
rbRotateSingle
(
p
,
last
);
// Ensure correct coloring.
q
->
red
=
g
->
node
[
dir2
]
->
red
=
1
;
g
->
node
[
dir2
]
->
node
[
0
]
->
red
=
0
;
g
->
node
[
dir2
]
->
node
[
1
]
->
red
=
0
;
}
}
}
}
}
// Replace and remove.
ASMJIT_ASSERT
(
f
!=
NULL
);
ASMJIT_ASSERT
(
f
!=
&
head
);
ASMJIT_ASSERT
(
q
!=
&
head
);
if
(
f
!=
q
)
{
ASMJIT_ASSERT
(
f
!=
&
head
);
static_cast
<
MemNode
*>
(
f
)
->
fillData
(
static_cast
<
MemNode
*>
(
q
));
}
p
->
node
[
p
->
node
[
1
]
==
q
]
=
q
->
node
[
q
->
node
[
0
]
==
NULL
];
// Update root and make it black.
self
->
_root
=
static_cast
<
MemNode
*>
(
head
.
node
[
1
]);
if
(
self
->
_root
!=
NULL
)
self
->
_root
->
red
=
0
;
// Unlink.
MemNode
*
next
=
static_cast
<
MemNode
*>
(
q
)
->
next
;
MemNode
*
prev
=
static_cast
<
MemNode
*>
(
q
)
->
prev
;
if
(
prev
)
prev
->
next
=
next
;
else
self
->
_first
=
next
;
if
(
next
)
next
->
prev
=
prev
;
else
self
->
_last
=
prev
;
if
(
self
->
_optimal
==
q
)
self
->
_optimal
=
prev
?
prev
:
next
;
return
static_cast
<
MemNode
*>
(
q
);
}
static
MemNode
*
vMemMgrFindNodeByPtr
(
VMemMgr
*
self
,
uint8_t
*
mem
)
{
MemNode
*
node
=
self
->
_root
;
while
(
node
!=
NULL
)
{
uint8_t
*
nodeMem
=
node
->
mem
;
// Go left.
if
(
mem
<
nodeMem
)
{
node
=
static_cast
<
MemNode
*>
(
node
->
node
[
0
]);
continue
;
}
// Go right.
uint8_t
*
nodeEnd
=
nodeMem
+
node
->
size
;
if
(
mem
>=
nodeEnd
)
{
node
=
static_cast
<
MemNode
*>
(
node
->
node
[
1
]);
continue
;
}
// Match.
break
;
}
return
node
;
}
static
void
*
vMemMgrAllocPermanent
(
VMemMgr
*
self
,
size_t
vSize
)
{
static
const
size_t
permanentAlignment
=
32
;
static
const
size_t
permanentNodeSize
=
32768
;
vSize
=
IntUtil
::
alignTo
<
size_t
>
(
vSize
,
permanentAlignment
);
AutoLock
locked
(
self
->
_lock
);
PermanentNode
*
node
=
self
->
_permanent
;
// Try to find space in allocated chunks.
while
(
node
&&
vSize
>
node
->
getAvailable
())
node
=
node
->
prev
;
// Or allocate new node.
if
(
node
==
NULL
)
{
size_t
nodeSize
=
permanentNodeSize
;
if
(
nodeSize
<
vSize
)
nodeSize
=
vSize
;
node
=
static_cast
<
PermanentNode
*>
(
ASMJIT_ALLOC
(
sizeof
(
PermanentNode
)));
// Out of memory.
if
(
node
==
NULL
)
return
NULL
;
node
->
mem
=
vMemMgrAllocVMem
(
self
,
nodeSize
,
&
node
->
size
);
// Out of memory.
if
(
node
->
mem
==
NULL
)
{
ASMJIT_FREE
(
node
);
return
NULL
;
}
node
->
used
=
0
;
node
->
prev
=
self
->
_permanent
;
self
->
_permanent
=
node
;
}
// Finally, copy function code to our space we reserved for.
uint8_t
*
result
=
node
->
mem
+
node
->
used
;
// Update Statistics.
node
->
used
+=
vSize
;
self
->
_usedBytes
+=
vSize
;
// Code can be null to only reserve space for code.
return
static_cast
<
void
*>
(
result
);
}
static
void
*
vMemMgrAllocFreeable
(
VMemMgr
*
self
,
size_t
vSize
)
{
// Current index.
size_t
i
;
// How many we need to be freed.
size_t
need
;
size_t
minVSize
;
// Align to 32 bytes by default.
vSize
=
IntUtil
::
alignTo
<
size_t
>
(
vSize
,
32
);
if
(
vSize
==
0
)
return
NULL
;
AutoLock
locked
(
self
->
_lock
);
MemNode
*
node
=
self
->
_optimal
;
minVSize
=
self
->
_blockSize
;
// Try to find memory block in existing nodes.
while
(
node
)
{
// Skip this node?
if
((
node
->
getAvailable
()
<
vSize
)
||
(
node
->
largestBlock
<
vSize
&&
node
->
largestBlock
!=
0
))
{
MemNode
*
next
=
node
->
next
;
if
(
node
->
getAvailable
()
<
minVSize
&&
node
==
self
->
_optimal
&&
next
)
self
->
_optimal
=
next
;
node
=
next
;
continue
;
}
size_t
*
up
=
node
->
baUsed
;
// Current ubits address.
size_t
ubits
;
// Current ubits[0] value.
size_t
bit
;
// Current bit mask.
size_t
blocks
=
node
->
blocks
;
// Count of blocks in node.
size_t
cont
=
0
;
// How many bits are currently freed in find loop.
size_t
maxCont
=
0
;
// Largest continuous block (bits count).
size_t
j
;
need
=
M_DIV
((
vSize
+
node
->
density
-
1
),
node
->
density
);
i
=
0
;
// Try to find node that is large enough.
while
(
i
<
blocks
)
{
ubits
=
*
up
++
;
// Fast skip used blocks.
if
(
ubits
==
~
(
size_t
)
0
)
{
if
(
cont
>
maxCont
)
maxCont
=
cont
;
cont
=
0
;
i
+=
kBitsPerEntity
;
continue
;
}
size_t
max
=
kBitsPerEntity
;
if
(
i
+
max
>
blocks
)
max
=
blocks
-
i
;
for
(
j
=
0
,
bit
=
1
;
j
<
max
;
bit
<<=
1
)
{
j
++
;
if
((
ubits
&
bit
)
==
0
)
{
if
(
++
cont
==
need
)
{
i
+=
j
;
i
-=
cont
;
goto
_Found
;
}
continue
;
}
if
(
cont
>
maxCont
)
maxCont
=
cont
;
cont
=
0
;
}
i
+=
kBitsPerEntity
;
}
// Because we traversed the entire node, we can set largest node size that
// will be used to cache next traversing.
node
->
largestBlock
=
maxCont
*
node
->
density
;
node
=
node
->
next
;
}
// If we are here, we failed to find existing memory block and we must
// allocate a new one.
{
size_t
blockSize
=
self
->
_blockSize
;
if
(
blockSize
<
vSize
)
blockSize
=
vSize
;
node
=
vMemMgrCreateNode
(
self
,
blockSize
,
self
->
_blockDensity
);
if
(
node
==
NULL
)
return
NULL
;
// Update binary tree.
vMemMgrInsertNode
(
self
,
node
);
ASMJIT_ASSERT
(
vMemMgrCheckTree
(
self
));
// Alloc first node at start.
i
=
0
;
need
=
(
vSize
+
node
->
density
-
1
)
/
node
->
density
;
// Update statistics.
self
->
_allocatedBytes
+=
node
->
size
;
}
_Found:
// Update bits.
_SetBits
(
node
->
baUsed
,
i
,
need
);
_SetBits
(
node
->
baCont
,
i
,
need
-
1
);
// Update statistics.
{
size_t
u
=
need
*
node
->
density
;
node
->
used
+=
u
;
node
->
largestBlock
=
0
;
self
->
_usedBytes
+=
u
;
}
// And return pointer to allocated memory.
uint8_t
*
result
=
node
->
mem
+
i
*
node
->
density
;
ASMJIT_ASSERT
(
result
>=
node
->
mem
&&
result
<=
node
->
mem
+
node
->
size
-
vSize
);
return
result
;
}
//! \internal
//!
//! Reset the whole `VMemMgr` instance, freeing all heap memory allocated an
//! virtual memory allocated unless `keepVirtualMemory` is true (and this is
//! only used when writing data to a remote process).
static
void
vMemMgrReset
(
VMemMgr
*
self
,
bool
keepVirtualMemory
)
{
MemNode
*
node
=
self
->
_first
;
while
(
node
!=
NULL
)
{
MemNode
*
next
=
node
->
next
;
if
(
!
keepVirtualMemory
)
vMemMgrReleaseVMem
(
self
,
node
->
mem
,
node
->
size
);
ASMJIT_FREE
(
node
->
baUsed
);
ASMJIT_FREE
(
node
);
node
=
next
;
}
self
->
_allocatedBytes
=
0
;
self
->
_usedBytes
=
0
;
self
->
_root
=
NULL
;
self
->
_first
=
NULL
;
self
->
_last
=
NULL
;
self
->
_optimal
=
NULL
;
}
// ============================================================================
// [asmjit::VMemMgr - Construction / Destruction]
// ============================================================================
#if !defined(ASMJIT_OS_WINDOWS)
VMemMgr
::
VMemMgr
()
#else
VMemMgr
::
VMemMgr
(
HANDLE
hProcess
)
:
_hProcess
(
vMemGet
().
getSafeProcessHandle
(
hProcess
))
#endif // ASMJIT_OS_WINDOWS
{
_blockSize
=
VMemUtil
::
getPageGranularity
();
_blockDensity
=
64
;
_allocatedBytes
=
0
;
_usedBytes
=
0
;
_root
=
NULL
;
_first
=
NULL
;
_last
=
NULL
;
_optimal
=
NULL
;
_permanent
=
NULL
;
_keepVirtualMemory
=
false
;
}
VMemMgr
::~
VMemMgr
()
{
// Freeable memory cleanup - Also frees the virtual memory if configured to.
vMemMgrReset
(
this
,
_keepVirtualMemory
);
// Permanent memory cleanup - Never frees the virtual memory.
PermanentNode
*
node
=
_permanent
;
while
(
node
)
{
PermanentNode
*
prev
=
node
->
prev
;
ASMJIT_FREE
(
node
);
node
=
prev
;
}
}
// ============================================================================
// [asmjit::VMemMgr - Reset]
// ============================================================================
void
VMemMgr
::
reset
()
{
vMemMgrReset
(
this
,
false
);
}
// ============================================================================
// [asmjit::VMemMgr - Alloc / Release]
// ============================================================================
void
*
VMemMgr
::
alloc
(
size_t
size
,
uint32_t
type
)
{
if
(
type
==
kVMemAllocPermanent
)
return
vMemMgrAllocPermanent
(
this
,
size
);
else
return
vMemMgrAllocFreeable
(
this
,
size
);
}
Error
VMemMgr
::
release
(
void
*
p
)
{
if
(
p
==
NULL
)
return
kErrorOk
;
AutoLock
locked
(
_lock
);
MemNode
*
node
=
vMemMgrFindNodeByPtr
(
this
,
static_cast
<
uint8_t
*>
(
p
));
if
(
node
==
NULL
)
return
kErrorInvalidArgument
;
size_t
offset
=
(
size_t
)((
uint8_t
*
)
p
-
(
uint8_t
*
)
node
->
mem
);
size_t
bitpos
=
M_DIV
(
offset
,
node
->
density
);
size_t
i
=
(
bitpos
/
kBitsPerEntity
);
size_t
*
up
=
node
->
baUsed
+
i
;
// Current ubits address.
size_t
*
cp
=
node
->
baCont
+
i
;
// Current cbits address.
size_t
ubits
=
*
up
;
// Current ubits[0] value.
size_t
cbits
=
*
cp
;
// Current cbits[0] value.
size_t
bit
=
(
size_t
)
1
<<
(
bitpos
%
kBitsPerEntity
);
size_t
cont
=
0
;
bool
stop
;
for
(;;)
{
stop
=
(
cbits
&
bit
)
==
0
;
ubits
&=
~
bit
;
cbits
&=
~
bit
;
bit
<<=
1
;
cont
++
;
if
(
stop
||
bit
==
0
)
{
*
up
=
ubits
;
*
cp
=
cbits
;
if
(
stop
)
break
;
ubits
=
*++
up
;
cbits
=
*++
cp
;
bit
=
1
;
}
}
// If the freed block is fully allocated node then it's needed to
// update 'optimal' pointer in memory manager.
if
(
node
->
used
==
node
->
size
)
{
MemNode
*
cur
=
_optimal
;
do
{
cur
=
cur
->
prev
;
if
(
cur
==
node
)
{
_optimal
=
node
;
break
;
}
}
while
(
cur
);
}
// Statistics.
cont
*=
node
->
density
;
if
(
node
->
largestBlock
<
cont
)
node
->
largestBlock
=
cont
;
node
->
used
-=
cont
;
_usedBytes
-=
cont
;
// If page is empty, we can free it.
if
(
node
->
used
==
0
)
{
// Free memory associated with node (this memory is not accessed
// anymore so it's safe).
vMemMgrReleaseVMem
(
this
,
node
->
mem
,
node
->
size
);
ASMJIT_FREE
(
node
->
baUsed
);
node
->
baUsed
=
NULL
;
node
->
baCont
=
NULL
;
// Statistics.
_allocatedBytes
-=
node
->
size
;
// Remove node. This function can return different node than
// passed into, but data is copied into previous node if needed.
ASMJIT_FREE
(
vMemMgrRemoveNode
(
this
,
node
));
ASMJIT_ASSERT
(
vMemMgrCheckTree
(
this
));
}
return
kErrorOk
;
}
Error
VMemMgr
::
shrink
(
void
*
p
,
size_t
used
)
{
if
(
p
==
NULL
)
return
kErrorOk
;
if
(
used
==
0
)
return
release
(
p
);
AutoLock
locked
(
_lock
);
MemNode
*
node
=
vMemMgrFindNodeByPtr
(
this
,
(
uint8_t
*
)
p
);
if
(
node
==
NULL
)
return
kErrorInvalidArgument
;
size_t
offset
=
(
size_t
)((
uint8_t
*
)
p
-
(
uint8_t
*
)
node
->
mem
);
size_t
bitpos
=
M_DIV
(
offset
,
node
->
density
);
size_t
i
=
(
bitpos
/
kBitsPerEntity
);
size_t
*
up
=
node
->
baUsed
+
i
;
// Current ubits address.
size_t
*
cp
=
node
->
baCont
+
i
;
// Current cbits address.
size_t
ubits
=
*
up
;
// Current ubits[0] value.
size_t
cbits
=
*
cp
;
// Current cbits[0] value.
size_t
bit
=
(
size_t
)
1
<<
(
bitpos
%
kBitsPerEntity
);
size_t
cont
=
0
;
size_t
usedBlocks
=
(
used
+
node
->
density
-
1
)
/
node
->
density
;
bool
stop
;
// Find the first block we can mark as free.
for
(;;)
{
stop
=
(
cbits
&
bit
)
==
0
;
if
(
stop
)
return
kErrorOk
;
if
(
++
cont
==
usedBlocks
)
break
;
bit
<<=
1
;
if
(
bit
==
0
)
{
ubits
=
*++
up
;
cbits
=
*++
cp
;
bit
=
1
;
}
}
// Free the tail blocks.
cont
=
~
(
size_t
)
0
;
goto
_EnterFreeLoop
;
for
(;;)
{
stop
=
(
cbits
&
bit
)
==
0
;
ubits
&=
~
bit
;
_EnterFreeLoop:
cbits
&=
~
bit
;
bit
<<=
1
;
cont
++
;
if
(
stop
||
bit
==
0
)
{
*
up
=
ubits
;
*
cp
=
cbits
;
if
(
stop
)
break
;
ubits
=
*++
up
;
cbits
=
*++
cp
;
bit
=
1
;
}
}
// Statistics.
cont
*=
node
->
density
;
if
(
node
->
largestBlock
<
cont
)
node
->
largestBlock
=
cont
;
node
->
used
-=
cont
;
_usedBytes
-=
cont
;
return
kErrorOk
;
}
// ============================================================================
// [asmjit::VMem - Test]
// ============================================================================
#if defined(ASMJIT_TEST)
static
void
VMemTest_fill
(
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
VMemTest_verify
(
void
*
a
,
void
*
b
)
{
int
ai
=
*
(
int
*
)
a
;
int
bi
=
*
(
int
*
)
b
;
EXPECT
(
ai
==
bi
,
"The length of 'a' (%d) and 'b' (%d) should be same"
,
ai
,
bi
);
EXPECT
(
::
memcmp
(
a
,
b
,
ai
)
==
0
,
"Pattern (%p) doesn't match"
,
a
);
}
static
void
VMemTest_stats
(
VMemMgr
&
memmgr
)
{
INFO
(
"Used : %u"
,
static_cast
<
unsigned
int
>
(
memmgr
.
getUsedBytes
()));
INFO
(
"Allocated: %u"
,
static_cast
<
unsigned
int
>
(
memmgr
.
getAllocatedBytes
()));
}
static
void
VMemTest_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
;
}
}
UNIT
(
base_vmem
)
{
VMemMgr
memmgr
;
// Should be predictible.
srand
(
100
);
int
i
;
int
kCount
=
200000
;
INFO
(
"Memory alloc/free test - %d allocations."
,
static_cast
<
int
>
(
kCount
));
void
**
a
=
(
void
**
)
ASMJIT_ALLOC
(
sizeof
(
void
*
)
*
kCount
);
void
**
b
=
(
void
**
)
ASMJIT_ALLOC
(
sizeof
(
void
*
)
*
kCount
);
EXPECT
(
a
!=
NULL
&&
b
!=
NULL
,
"Couldn't allocate %u bytes on heap."
,
kCount
*
2
);
INFO
(
"Allocating virtual memory..."
);
for
(
i
=
0
;
i
<
kCount
;
i
++
)
{
int
r
=
(
rand
()
%
1000
)
+
4
;
a
[
i
]
=
memmgr
.
alloc
(
r
);
EXPECT
(
a
[
i
]
!=
NULL
,
"Couldn't allocate %d bytes of virtual memory"
,
r
);
::
memset
(
a
[
i
],
0
,
r
);
}
VMemTest_stats
(
memmgr
);
INFO
(
"Freeing virtual memory..."
);
for
(
i
=
0
;
i
<
kCount
;
i
++
)
{
EXPECT
(
memmgr
.
release
(
a
[
i
])
==
kErrorOk
,
"Failed to free %p."
,
b
[
i
]);
}
VMemTest_stats
(
memmgr
);
INFO
(
"Verified alloc/free test - %d allocations."
,
static_cast
<
int
>
(
kCount
));
for
(
i
=
0
;
i
<
kCount
;
i
++
)
{
int
r
=
(
rand
()
%
1000
)
+
4
;
a
[
i
]
=
memmgr
.
alloc
(
r
);
EXPECT
(
a
[
i
]
!=
NULL
,
"Couldn't allocate %d bytes of virtual memory."
,
r
);
b
[
i
]
=
ASMJIT_ALLOC
(
r
);
EXPECT
(
b
[
i
]
!=
NULL
,
"Couldn't allocate %d bytes on heap."
,
r
);
VMemTest_fill
(
a
[
i
],
b
[
i
],
r
);
}
VMemTest_stats
(
memmgr
);
INFO
(
"Shuffling..."
);
VMemTest_shuffle
(
a
,
b
,
kCount
);
INFO
(
"Verify and free..."
);
for
(
i
=
0
;
i
<
kCount
/
2
;
i
++
)
{
VMemTest_verify
(
a
[
i
],
b
[
i
]);
EXPECT
(
memmgr
.
release
(
a
[
i
])
==
kErrorOk
,
"Failed to free %p."
,
a
[
i
]);
ASMJIT_FREE
(
b
[
i
]);
}
VMemTest_stats
(
memmgr
);
INFO
(
"Alloc again."
);
for
(
i
=
0
;
i
<
kCount
/
2
;
i
++
)
{
int
r
=
(
rand
()
%
1000
)
+
4
;
a
[
i
]
=
memmgr
.
alloc
(
r
);
EXPECT
(
a
[
i
]
!=
NULL
,
"Couldn't allocate %d bytes of virtual memory."
,
r
);
b
[
i
]
=
ASMJIT_ALLOC
(
r
);
EXPECT
(
b
[
i
]
!=
NULL
,
"Couldn't allocate %d bytes on heap."
);
VMemTest_fill
(
a
[
i
],
b
[
i
],
r
);
}
VMemTest_stats
(
memmgr
);
INFO
(
"Verify and free..."
);
for
(
i
=
0
;
i
<
kCount
;
i
++
)
{
VMemTest_verify
(
a
[
i
],
b
[
i
]);
EXPECT
(
memmgr
.
release
(
a
[
i
])
==
kErrorOk
,
"Failed to free %p."
,
a
[
i
]);
ASMJIT_FREE
(
b
[
i
]);
}
VMemTest_stats
(
memmgr
);
ASMJIT_FREE
(
a
);
ASMJIT_FREE
(
b
);
}
#endif // ASMJIT_TEST
}
// asmjit namespace
libraries/asmjit/base/vmem.h
0 → 100644
View file @
a83607d6
// [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
// [Dependencies]
#include "../base/error.h"
#include "../base/lock.h"
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::kVMemAlloc]
// ============================================================================
//! Type of virtual memory allocation, see `VMemMgr::alloc()`.
ASMJIT_ENUM
(
kVMemAlloc
)
{
//! Normal memory allocation, has to be freed by `VMemMgr::release()`.
kVMemAllocFreeable
=
0
,
//! Allocate permanent memory, can't be freed.
kVMemAllocPermanent
=
1
};
// ============================================================================
// [asmjit::kVMemFlags]
// ============================================================================
//! Type of virtual memory allocation, see `VMemMgr::alloc()`.
ASMJIT_ENUM
(
kVMemFlags
)
{
//! Memory is writable.
kVMemFlagWritable
=
0x00000001
,
//! Memory is executable.
kVMemFlagExecutable
=
0x00000002
};
// ============================================================================
// [asmjit::VMemUtil]
// ============================================================================
//! Virtual memory utilities.
//!
//! Defines functions that provide facility to allocate and free memory that is
//! executable in a platform independent manner. If both the processor and host
//! operating system support data-execution-prevention then the only way how to
//! run machine code is to allocate it to a memory that has marked as executable.
//! VMemUtil is just unified interface to platform dependent APIs.
//!
//! `VirtualAlloc()` function is used on Windows operating system and `mmap()`
//! on POSIX. `VirtualAlloc()` and `mmap()` documentation provide a detailed
//! overview on how to use a platform specific APIs.
struct
VMemUtil
{
//! Get a size/alignment of a single virtual memory page.
static
ASMJIT_API
size_t
getPageSize
();
//! Get a recommended granularity for a single `alloc` call.
static
ASMJIT_API
size_t
getPageGranularity
();
//! 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
,
uint32_t
flags
);
#if defined(ASMJIT_OS_WINDOWS)
//! Allocate virtual memory of `hProcess`.
//!
//! \note This function is Windows specific.
static
ASMJIT_API
void
*
allocProcessMemory
(
HANDLE
hProcess
,
size_t
length
,
size_t
*
allocated
,
uint32_t
flags
);
#endif // ASMJIT_OS_WINDOWS
//! Free memory allocated by `alloc()`.
static
ASMJIT_API
Error
release
(
void
*
addr
,
size_t
length
);
#if defined(ASMJIT_OS_WINDOWS)
//! Release virtual memory of `hProcess`.
//!
//! \note This function is Windows specific.
static
ASMJIT_API
Error
releaseProcessMemory
(
HANDLE
hProcess
,
void
*
addr
,
size_t
length
);
#endif // ASMJIT_OS_WINDOWS
};
// ============================================================================
// [asmjit::VMemMgr]
// ============================================================================
//! Reference implementation of memory manager that uses `VMemUtil` to allocate
//! chunks of virtual memory and bit arrays to manage it.
struct
VMemMgr
{
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
#if !defined(ASMJIT_OS_WINDOWS)
//! Create a `VMemMgr` instance.
ASMJIT_API
VMemMgr
();
#else
//! Create a `VMemMgr` instance.
//!
//! \note When running on Windows it's possible to specify a `hProcess` to
//! be used for memory allocation. This allows to allocate memory of remote
//! process.
ASMJIT_API
VMemMgr
(
HANDLE
hProcess
=
static_cast
<
HANDLE
>
(
0
));
#endif // ASMJIT_OS_WINDOWS
//! Destroy the `VMemMgr` instance and free all blocks.
ASMJIT_API
~
VMemMgr
();
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
//! Free all allocated memory.
ASMJIT_API
void
reset
();
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
#if defined(ASMJIT_OS_WINDOWS)
//! Get the handle of the process memory manager is bound to.
ASMJIT_INLINE
HANDLE
getProcessHandle
()
const
{
return
_hProcess
;
}
#endif // ASMJIT_OS_WINDOWS
//! Get how many bytes are currently allocated.
ASMJIT_INLINE
size_t
getAllocatedBytes
()
const
{
return
_allocatedBytes
;
}
//! Get how many bytes are currently used.
ASMJIT_INLINE
size_t
getUsedBytes
()
const
{
return
_usedBytes
;
}
//! Get whether to keep allocated memory after the `VMemMgr` is destroyed.
//!
//! \sa \ref setKeepVirtualMemory.
ASMJIT_INLINE
bool
getKeepVirtualMemory
()
const
{
return
_keepVirtualMemory
;
}
//! 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
//! VMemMgr destructor. After destruction all internal
//! structures are freed, only the process virtual memory remains.
//!
//! \note Memory allocated with kVMemAllocPermanent is always kept.
//!
//! \sa \ref getKeepVirtualMemory.
ASMJIT_INLINE
void
setKeepVirtualMemory
(
bool
keepVirtualMemory
)
{
_keepVirtualMemory
=
keepVirtualMemory
;
}
// --------------------------------------------------------------------------
// [Alloc / Release]
// --------------------------------------------------------------------------
//! Allocate 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.
ASMJIT_API
void
*
alloc
(
size_t
size
,
uint32_t
type
=
kVMemAllocFreeable
);
//! Free previously allocated memory at a given `address`.
ASMJIT_API
Error
release
(
void
*
p
);
//! Free extra memory allocated with `p`.
ASMJIT_API
Error
shrink
(
void
*
p
,
size_t
used
);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
#if defined(ASMJIT_OS_WINDOWS)
//! Process passed to `VirtualAllocEx` and `VirtualFree`.
HANDLE
_hProcess
;
#endif // ASMJIT_OS_WINDOWS
//! Lock to enable thread-safe functionality.
Lock
_lock
;
//! Default block size.
size_t
_blockSize
;
//! Default block density.
size_t
_blockDensity
;
// Whether to keep virtual memory after destroy.
bool
_keepVirtualMemory
;
//! How many bytes are currently allocated.
size_t
_allocatedBytes
;
//! How many bytes are currently used.
size_t
_usedBytes
;
//! \internal
//! \{
struct
RbNode
;
struct
MemNode
;
struct
PermanentNode
;
// Memory nodes root.
MemNode
*
_root
;
// Memory nodes list.
MemNode
*
_first
;
MemNode
*
_last
;
MemNode
*
_optimal
;
// Permanent memory.
PermanentNode
*
_permanent
;
//! \}
};
//! \}
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_VMEM_H
libraries/asmjit/base/zone.cpp
0 → 100644
View file @
a83607d6
// [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/zone.h"
// [Dependencies - C]
#include <stdarg.h>
// [Api-Begin]
#include "../apibegin.h"
namespace
asmjit
{
//! Zero size block used by `Zone` that doesn't have any memory allocated.
static
const
Zone
::
Block
Zone_zeroBlock
=
{
NULL
,
NULL
,
NULL
,
NULL
,
{
0
}
};
// ============================================================================
// [asmjit::Zone - Construction / Destruction]
// ============================================================================
Zone
::
Zone
(
size_t
blockSize
)
{
_block
=
const_cast
<
Zone
::
Block
*>
(
&
Zone_zeroBlock
);
_blockSize
=
blockSize
;
}
Zone
::~
Zone
()
{
reset
(
true
);
}
// ============================================================================
// [asmjit::Zone - Reset]
// ============================================================================
void
Zone
::
reset
(
bool
releaseMemory
)
{
Block
*
cur
=
_block
;
// Can't be altered.
if
(
cur
==
&
Zone_zeroBlock
)
return
;
if
(
releaseMemory
)
{
// Since cur can be in the middle of the double-linked list, we have to
// traverse to both directions `prev` and `next` separately.
Block
*
next
=
cur
->
next
;
do
{
Block
*
prev
=
cur
->
prev
;
ASMJIT_FREE
(
cur
);
cur
=
prev
;
}
while
(
cur
!=
NULL
);
cur
=
next
;
while
(
cur
!=
NULL
)
{
next
=
cur
->
next
;
ASMJIT_FREE
(
cur
);
cur
=
next
;
}
_block
=
const_cast
<
Zone
::
Block
*>
(
&
Zone_zeroBlock
);
}
else
{
while
(
cur
->
prev
!=
NULL
)
cur
=
cur
->
prev
;
cur
->
pos
=
cur
->
data
;
_block
=
cur
;
}
}
// ============================================================================
// [asmjit::Zone - Alloc]
// ============================================================================
void
*
Zone
::
_alloc
(
size_t
size
)
{
Block
*
curBlock
=
_block
;
size_t
blockSize
=
IntUtil
::
iMax
<
size_t
>
(
_blockSize
,
size
);
// The `_alloc()` method can only be called if there is not enough space
// in the current block, see `alloc()` implementation for more details.
ASMJIT_ASSERT
(
curBlock
==
&
Zone_zeroBlock
||
curBlock
->
getRemainingSize
()
<
size
);
// If the `Zone` has been reset the current block doesn't have to be the
// last one. Check if there is a block that can be used instead of allocating
// a new one. If there is a `next` block it's completely unused, we don't have
// to check for remaining bytes.
Block
*
next
=
curBlock
->
next
;
if
(
next
!=
NULL
&&
next
->
getBlockSize
()
>=
size
)
{
next
->
pos
=
next
->
data
+
size
;
_block
=
next
;
return
static_cast
<
void
*>
(
next
->
data
);
}
// Prevent arithmetic overflow.
if
(
blockSize
>
~
static_cast
<
size_t
>
(
0
)
-
sizeof
(
Block
))
return
NULL
;
Block
*
newBlock
=
static_cast
<
Block
*>
(
ASMJIT_ALLOC
(
sizeof
(
Block
)
-
sizeof
(
void
*
)
+
blockSize
));
if
(
newBlock
==
NULL
)
return
NULL
;
newBlock
->
pos
=
newBlock
->
data
+
size
;
newBlock
->
end
=
newBlock
->
data
+
blockSize
;
newBlock
->
prev
=
NULL
;
newBlock
->
next
=
NULL
;
if
(
curBlock
!=
&
Zone_zeroBlock
)
{
newBlock
->
prev
=
curBlock
;
curBlock
->
next
=
newBlock
;
// Does only happen if there is a next block, but the requested memory
// can't fit into it. In this case a new buffer is allocated and inserted
// between the current block and the next one.
if
(
next
!=
NULL
)
{
newBlock
->
next
=
next
;
next
->
prev
=
newBlock
;
}
}
_block
=
newBlock
;
return
static_cast
<
void
*>
(
newBlock
->
data
);
}
void
*
Zone
::
allocZeroed
(
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
[
512
];
size_t
len
;
va_list
ap
;
va_start
(
ap
,
fmt
);
len
=
vsnprintf
(
buf
,
ASMJIT_ARRAY_SIZE
(
buf
)
-
1
,
fmt
,
ap
);
buf
[
len
++
]
=
0
;
va_end
(
ap
);
return
static_cast
<
char
*>
(
dup
(
buf
,
len
));
}
}
// asmjit namespace
// [Api-End]
#include "../apiend.h"
Prev
1
2
3
4
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment