Added minimalist unit testing (and removed some apps that did some tests).

This commit is contained in:
kobalicek
2014-06-04 22:12:52 +02:00
parent 02a9d6abbd
commit db322d5dc1
33 changed files with 1076 additions and 729 deletions

View File

@@ -14,6 +14,12 @@ CMake_Minimum_Required(VERSION 2.8.12)
# Whether to build static library (default FALSE). # Whether to build static library (default FALSE).
# Set(ASMJIT_STATIC FALSE) # Set(ASMJIT_STATIC FALSE)
# Whether to build contribution together with AsmJit (default FALSE)
# Set(ASMJIT_BUILD_CONTRIB)
# Whether to build tests (default FALSE).
# Set(ASMJIT_BUILD_TEST FALSE)
# Whether to build samples (default FALSE). # Whether to build samples (default FALSE).
# Set(ASMJIT_BUILD_SAMPLES FALSE) # Set(ASMJIT_BUILD_SAMPLES FALSE)
@@ -73,9 +79,13 @@ Set(ASMJIT_CFLAGS)
Set(ASMJIT_CFLAGS_DBG) Set(ASMJIT_CFLAGS_DBG)
Set(ASMJIT_CFLAGS_REL) Set(ASMJIT_CFLAGS_REL)
Set(ASMJIT_DEFINE "-D")
# MSVC. # MSVC.
If(MSVC) If(MSVC)
Message("-- Using MSVC") Message("-- Using MSVC")
Set(ASMJIT_DEFINE "/D")
Set(ASMJIT_LFLAGS "/OPT:REF /OPT:ICF") Set(ASMJIT_LFLAGS "/OPT:REF /OPT:ICF")
Set(ASMJIT_CFLAGS /GF) Set(ASMJIT_CFLAGS /GF)
Set(ASMJIT_CFLAGS_DBG /DASMJIT_DEBUG /GS /GR-) Set(ASMJIT_CFLAGS_DBG /DASMJIT_DEBUG /GS /GR-)
@@ -86,10 +96,6 @@ If(MSVC)
List(APPEND ASMJIT_CFLAGS /D_UNICODE) List(APPEND ASMJIT_CFLAGS /D_UNICODE)
EndIf() EndIf()
If(ASMJIT_STATIC)
List(APPEND ASMJIT_CFLAGS /DASMJIT_STATIC)
EndIf()
# Enable multi-process compilation. # Enable multi-process compilation.
If(NOT MSVC60 AND NOT MSVC70 AND NOT MSVC71) If(NOT MSVC60 AND NOT MSVC70 AND NOT MSVC71)
List(APPEND ASMJIT_CFLAGS /MP) List(APPEND ASMJIT_CFLAGS /MP)
@@ -99,6 +105,7 @@ EndIf()
# GCC. # GCC.
If(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) If(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
Message("-- Using GCC") Message("-- Using GCC")
Set(ASMJIT_CFLAGS Set(ASMJIT_CFLAGS
-fno-exceptions) -fno-exceptions)
Set(ASMJIT_CFLAGS_DBG -DASMJIT_DEBUG -O0 Set(ASMJIT_CFLAGS_DBG -DASMJIT_DEBUG -O0
@@ -113,10 +120,11 @@ If(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
If(WIN32) If(WIN32)
List(APPEND ASMJIT_CFLAGS -D_UNICODE) List(APPEND ASMJIT_CFLAGS -D_UNICODE)
EndIf() EndIf()
If(ASMJIT_STATIC)
List(APPEND ASMJIT_CFLAGS -DASMJIT_STATIC)
EndIf() EndIf()
# Static library.
If(ASMJIT_STATIC)
List(APPEND ASMJIT_CFLAGS "${ASMJIT_DEFINE}ASMJIT_STATIC")
EndIf() EndIf()
# Dependencies - Base. # Dependencies - Base.
@@ -171,8 +179,7 @@ Macro(AsmJit_AddLibrary in_name in_src in_deps in_cflags in_cflags_dbg in_cflags
Set_Target_Properties(${in_name} PROPERTIES COMPILE_FLAGS ${in_cflags} ${in_cflags_rel}) Set_Target_Properties(${in_name} PROPERTIES COMPILE_FLAGS ${in_cflags} ${in_cflags_rel})
EndIf() EndIf()
Else() Else()
Target_Compile_Options(${in_name} PUBLIC Target_Compile_Options(${in_name} PUBLIC ${in_cflags}
${in_cflags}
$<$<CONFIG:Debug>:${in_cflags_dbg}> $<$<CONFIG:Debug>:${in_cflags_dbg}>
$<$<NOT:$<CONFIG:Debug>>:${in_cflags_rel}>) $<$<NOT:$<CONFIG:Debug>>:${in_cflags_rel}>)
EndIf() EndIf()
@@ -228,6 +235,7 @@ AsmJit_AddSource(ASMJIT_SRC asmjit/base
func.h func.h
globals.cpp globals.cpp
globals.h globals.h
intutil.cpp
intutil.h intutil.h
lock.h lock.h
logger.cpp logger.cpp
@@ -269,10 +277,12 @@ AsmJit_AddSource(ASMJIT_SRC asmjit/x86
x86util.h x86util.h
) )
If(ASMJIT_BUILD_CONTRIB)
AsmJit_AddSource(ASMJIT_SRC asmjit/contrib AsmJit_AddSource(ASMJIT_SRC asmjit/contrib
winremoteruntime.cpp winremoteruntime.cpp
winremoteruntime.h winremoteruntime.h
) )
EndIf()
# ============================================================================= # =============================================================================
# [AsmJit - Headers] # [AsmJit - Headers]
@@ -305,6 +315,41 @@ If(NOT ASMJIT_EMBED)
) )
EndIf() EndIf()
# =============================================================================
# [Asmjit - Testing]
# =============================================================================
# AsmJit library is always embedded into the tests executable. This way it's
# much easier to test private functions compared to just linking to AsmJit.
If(ASMJIT_BUILD_TEST)
AsmJit_AddSource(ASMJIT_TEST_SRC asmjit/test
main.cpp
test.cpp
test.h)
Set(ASMJIT_TEST_CFLAGS
${ASMJIT_CFLAGS}
${ASMJIT_DEFINE}ASMJIT_STATIC
${ASMJIT_DEFINE}ASMJIT_TEST)
Add_Executable(asmjit_test ${ASMJIT_SRC} ${ASMJIT_TEST_SRC})
Target_Link_Libraries(asmjit_test ${ASMJIT_DEPS})
If(${CMAKE_BUILD_TYPE})
If(${CMAKE_BUILD_TYPE} MATCHES "Debug")
Set_Target_Properties(asmjit_test PROPERTIES COMPILE_FLAGS ${ASMJIT_TEST_CFLAGS} ${ASMJIT_CFLAGS_DBG})
Else()
Set_Target_Properties(asmjit_test PROPERTIES COMPILE_FLAGS ${ASMJIT_TEST_CFLAGS} ${ASMJIT_CFLAGS_REL})
EndIf()
Else()
Target_Compile_Options(asmjit_test PUBLIC ${ASMJIT_TEST_CFLAGS}
$<$<CONFIG:Debug>:${ASMJIT_CFLAGS_DBG}>
$<$<NOT:$<CONFIG:Debug>>:${ASMJIT_CFLAGS_REL}>)
EndIf()
Set_Target_Properties(asmjit_test PROPERTIES LINK_FLAGS "${ASMJIT_LFLAGS}")
EndIf()
# ============================================================================= # =============================================================================
# [Asmjit - Samples] # [Asmjit - Samples]
# ============================================================================= # =============================================================================
@@ -312,12 +357,7 @@ EndIf()
If(ASMJIT_BUILD_SAMPLES) If(ASMJIT_BUILD_SAMPLES)
Set(ASMJIT_SRC_SAMPLES Set(ASMJIT_SRC_SAMPLES
benchx86 benchx86
testcpu
testdummy
testmem
testopcode testopcode
testpool
testsizeof
testx86 testx86
) )

View File

@@ -1,114 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Dependencies - AsmJit]
#include <asmjit/asmjit.h>
// [Dependencies - C]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace asmjit;
struct CpuFeature {
uint32_t feature;
const char* description;
};
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
static const CpuFeature x86x64Features[] = {
{ x86x64::kCpuFeatureMultithreading , "Multithreading" },
{ x86x64::kCpuFeatureExecuteDisableBit , "Execute-Disable Bit" },
{ x86x64::kCpuFeatureRdtsc , "Rdtsc" },
{ x86x64::kCpuFeatureRdtscp , "Rdtscp" },
{ x86x64::kCpuFeatureCmov , "Cmov" },
{ x86x64::kCpuFeatureCmpXchg8B , "Cmpxchg8b" },
{ x86x64::kCpuFeatureCmpXchg16B , "Cmpxchg16b" },
{ x86x64::kCpuFeatureClflush , "Clflush" },
{ x86x64::kCpuFeaturePrefetch , "Prefetch" },
{ x86x64::kCpuFeatureLahfSahf , "Lahf/Sahf" },
{ x86x64::kCpuFeatureFxsr , "Fxsave/Fxrstor" },
{ x86x64::kCpuFeatureFfxsr , "Fxsave/Fxrstor Opt." },
{ x86x64::kCpuFeatureMmx , "Mmx" },
{ x86x64::kCpuFeatureMmxExt , "MmxExt" },
{ x86x64::kCpuFeature3dNow , "3dnow" },
{ x86x64::kCpuFeature3dNowExt , "3dnowExt" },
{ x86x64::kCpuFeatureSse , "Sse" },
{ x86x64::kCpuFeatureSse2 , "Sse2" },
{ x86x64::kCpuFeatureSse3 , "Sse3" },
{ x86x64::kCpuFeatureSsse3 , "Ssse3" },
{ x86x64::kCpuFeatureSse4A , "Sse4a" },
{ x86x64::kCpuFeatureSse41 , "Sse4.1" },
{ x86x64::kCpuFeatureSse42 , "Sse4.2" },
{ x86x64::kCpuFeatureMsse , "Misaligned SSE" },
{ x86x64::kCpuFeatureMonitorMWait , "Monitor/MWait" },
{ x86x64::kCpuFeatureMovbe , "Movbe" },
{ x86x64::kCpuFeaturePopcnt , "Popcnt" },
{ x86x64::kCpuFeatureLzcnt , "Lzcnt" },
{ x86x64::kCpuFeatureAesni , "AesNI" },
{ x86x64::kCpuFeaturePclmulqdq , "Pclmulqdq" },
{ x86x64::kCpuFeatureRdrand , "Rdrand" },
{ x86x64::kCpuFeatureAvx , "Avx" },
{ x86x64::kCpuFeatureAvx2 , "Avx2" },
{ x86x64::kCpuFeatureF16C , "F16C" },
{ x86x64::kCpuFeatureFma3 , "Fma3" },
{ x86x64::kCpuFeatureFma4 , "Fma4" },
{ x86x64::kCpuFeatureXop , "Xop" },
{ x86x64::kCpuFeatureBmi , "Bmi" },
{ x86x64::kCpuFeatureBmi2 , "Bmi2" },
{ x86x64::kCpuFeatureHle , "Hle" },
{ x86x64::kCpuFeatureRtm , "Rtm" },
{ x86x64::kCpuFeatureFsGsBase , "FsGsBase" },
{ x86x64::kCpuFeatureRepMovsbStosbExt , "RepMovsbStosbExt" }
};
#endif // ASMJIT_HOST || ASMJIT_HOST_X64
static void printFeatures(const char* prefix, const BaseCpuInfo* cpuInfo, const CpuFeature* data) {
for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(x86x64Features); i++) {
if (cpuInfo->hasFeature(data[i].feature)) {
printf("%s%s\n", prefix, data[i].description);
}
}
}
int main(int argc, char* argv[]) {
const BaseCpuInfo* cpuInfo_ = BaseCpuInfo::getHost();
// --------------------------------------------------------------------------
// [Core Features]
// --------------------------------------------------------------------------
printf("Host CPU\n");
printf("========\n");
printf("\nBasic info\n");
printf(" Vendor string : %s\n", cpuInfo_->getVendorString());
printf(" Brand string : %s\n", cpuInfo_->getBrandString());
printf(" Family : %u\n", cpuInfo_->getFamily());
printf(" Model : %u\n", cpuInfo_->getModel());
printf(" Stepping : %u\n", cpuInfo_->getStepping());
printf(" Cores Count : %u\n", cpuInfo_->getCoresCount());
// --------------------------------------------------------------------------
// [X86 Features]
// --------------------------------------------------------------------------
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
const x86x64::CpuInfo* cpuInfo = static_cast<const x86x64::CpuInfo*>(cpuInfo_);
printf("\nX86/X64 Extended Info:\n");
printf(" Processor Type : %u\n", cpuInfo->getProcessorType());
printf(" Brand Index : %u\n", cpuInfo->getBrandIndex());
printf(" CL Flush Cache Line : %u\n", cpuInfo->getFlushCacheLineSize());
printf(" Max logical Processors: %u\n", cpuInfo->getMaxLogicalProcessors());
printf("\nX86/X64 Features:\n");
printFeatures(" ", cpuInfo, x86x64Features);
#endif // ASMJIT_HOST || ASMJIT_HOST_X64
return 0;
}

View File

@@ -1,38 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// This file is used as a dummy test. It's changed during development.
// [Dependencies - AsmJit]
#include <asmjit/asmjit.h>
// [Dependencies - C]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int (*MyFunc)(void);
int main(int argc, char* argv[]) {
using namespace asmjit;
using namespace asmjit::host;
JitRuntime runtime;
FileLogger logger(stderr);
logger.setOption(kLoggerOptionBinaryForm, true);
Compiler c(&runtime);
c.setLogger(&logger);
c.addFunc(kFuncConvHost, FuncBuilder0<int>());
c.endFunc();
MyFunc func = asmjit_cast<MyFunc>(c.make());
func();
runtime.release((void*)func);
return 0;
}

View File

@@ -1,176 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Dependencies - AsmJit]
#include <asmjit/asmjit.h>
// [Dependencies - C]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace asmjit;
static int problems = 0;
static void gen(void* a, void* b, int i) {
int pattern = rand() % 256;
*(int *)a = i;
*(int *)b = i;
::memset((char*)a + sizeof(int), pattern, i - sizeof(int));
::memset((char*)b + sizeof(int), pattern, i - sizeof(int));
}
static void verify(void* a, void* b) {
int ai = *(int*)a;
int bi = *(int*)b;
if (ai != bi || ::memcmp(a, b, ai) != 0) {
printf("Failed to verify %p\n", a);
problems++;
}
}
static void die() {
printf("Couldn't allocate virtual memory, this test needs at least 100MB of free virtual memory.\n");
exit(1);
}
static void stats(VMemMgr& memmgr) {
printf("-- Used: %d\n",
static_cast<int>(memmgr.getUsedBytes()));
printf("-- Allocated: %d\n",
static_cast<int>(memmgr.getAllocatedBytes()));
}
static void shuffle(void **a, void **b, size_t count) {
for (size_t i = 0; i < count; ++i) {
size_t si = (size_t)rand() % count;
void *ta = a[i];
void *tb = b[i];
a[i] = a[si];
b[i] = b[si];
a[si] = ta;
b[si] = tb;
}
}
int main(int argc, char* argv[]) {
VMemMgr memmgr;
size_t i;
size_t count = 200000;
printf("Memory alloc/free test - %d allocations.\n\n",
static_cast<int>(count));
void** a = (void**)::malloc(sizeof(void*) * count);
void** b = (void**)::malloc(sizeof(void*) * count);
if (!a || !b) die();
srand(100);
printf("Allocating virtual memory...");
for (i = 0; i < count; i++) {
int r = (rand() % 1000) + 4;
a[i] = memmgr.alloc(r);
if (a[i] == NULL) die();
::memset(a[i], 0, r);
}
printf("Done.\n");
stats(memmgr);
printf("\n");
printf("Freeing virtual memory...");
for (i = 0; i < count; i++) {
if (memmgr.release(a[i]) != kErrorOk) {
printf("Failed to free %p.\n", b[i]);
problems++;
}
}
printf("Done.\n");
stats(memmgr);
printf("\n");
printf("Verified alloc/free test - %d allocations.\n\n", (int)count);
printf("Alloc...");
for (i = 0; i < count; i++) {
int r = (rand() % 1000) + 4;
a[i] = memmgr.alloc(r);
b[i] = ::malloc(r);
if (a[i] == NULL || b[i] == NULL) die();
gen(a[i], b[i], r);
}
printf("Done.\n");
stats(memmgr);
printf("\n");
printf("Shuffling...");
shuffle(a, b, count);
printf("Done.\n");
printf("\n");
printf("Verify and free...");
for (i = 0; i < count / 2; i++) {
verify(a[i], b[i]);
if (memmgr.release(a[i]) != kErrorOk) {
printf("Failed to free %p.\n", a[i]);
problems++;
}
::free(b[i]);
}
printf("Done.\n");
stats(memmgr);
printf("\n");
printf("Alloc...");
for (i = 0; i < count / 2; i++) {
int r = (rand() % 1000) + 4;
a[i] = memmgr.alloc(r);
b[i] = ::malloc(r);
if (a[i] == NULL || b[i] == NULL) die();
gen(a[i], b[i], r);
}
printf("Done.\n");
stats(memmgr);
printf("\n");
printf("Verify and free...");
for (i = 0; i < count; i++) {
verify(a[i], b[i]);
if (memmgr.release(a[i]) != kErrorOk) {
printf("Failed to free %p.\n", a[i]);
problems++;
}
::free(b[i]);
}
printf("Done.\n");
stats(memmgr);
printf("\n");
if (problems)
printf("Status: Failure: %d problems found\n", problems);
else
printf("Status: Success\n");
::free(a);
::free(b);
return 0;
}

View File

@@ -1,204 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Dependencies - AsmJit]
#include <asmjit/asmjit.h>
// [Dependencies - C]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace asmjit;
// ============================================================================
// [EXPECT]
// ============================================================================
static void expectFailed(const char* msg) {
printf("Failure: %s\n", msg);
abort();
}
#define EXPECT(_Exp_, _Msg_) \
do { \
if (!(_Exp_)) { \
expectFailed(_Msg_); \
} \
} while(0)
// ============================================================================
// [Main]
// ============================================================================
int main(int argc, char* argv[]) {
Zone zone(16192);
ConstPool pool(&zone);
uint32_t i;
uint32_t kCount = 1000000;
printf("Adding %u constants to the pool.\n", kCount);
{
size_t prevOffset;
size_t curOffset;
uint64_t c = ASMJIT_UINT64_C(0x0101010101010101);
EXPECT(pool.add(&c, 8, prevOffset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(prevOffset == 0,
"pool.add() - First constant should have zero offset.");
for (i = 1; i < kCount; i++) {
c++;
EXPECT(pool.add(&c, 8, curOffset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(prevOffset + 8 == curOffset,
"pool.add() - Returned incorrect curOffset.");
EXPECT(pool.getSize() == (i + 1) * 8,
"pool.getSize() - Reports incorrect size.");
prevOffset = curOffset;
}
EXPECT(pool.getAlignment() == 8,
"pool.getAlignment() - Expected 8-byte alignment.");
}
printf("Done.\n");
printf("Retrieving %u constants from the pool.\n", kCount);
{
uint64_t c = ASMJIT_UINT64_C(0x0101010101010101);
for (i = 0; i < kCount; i++) {
size_t offset;
EXPECT(pool.add(&c, 8, offset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(offset == i * 8,
"pool.add() - Should have reused constant.");
c++;
}
}
printf("Done.\n");
printf("Checking if the constants were split into 4-byte patterns.\n");
{
uint32_t c = 0x01010101;
for (i = 0; i < kCount; i++) {
size_t offset;
EXPECT(pool.add(&c, 4, offset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(offset == i * 8,
"pool.add() - Should reuse existing constant.");
c++;
}
}
printf("Done.\n");
printf("Adding 2 byte constant to misalign the current offset.\n");
{
uint16_t c = 0xFFFF;
size_t offset;
EXPECT(pool.add(&c, 2, offset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(offset == kCount * 8,
"pool.add() - Didn't return expected position.");
EXPECT(pool.getAlignment() == 8,
"pool.getAlignment() - Expected 8-byte alignment.");
}
printf("Done.\n");
printf("Adding 8 byte constant to check if pool gets aligned again.\n");
{
uint64_t c = ASMJIT_UINT64_C(0xFFFFFFFFFFFFFFFF);
size_t offset;
EXPECT(pool.add(&c, 8, offset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(offset == kCount * 8 + 8,
"pool.add() - Didn't return aligned offset.");
}
printf("Done.\n");
printf("Adding 2 byte constant verify the gap is filled.\n");
{
uint16_t c = 0xFFFE;
size_t offset;
EXPECT(pool.add(&c, 2, offset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(offset == kCount * 8 + 2,
"pool.add() - Didn't fill the gap.");
EXPECT(pool.getAlignment() == 8,
"pool.getAlignment() - Expected 8-byte alignment.");
}
printf("Done.\n");
printf("Checking reset functionality.\n");
{
pool.reset();
EXPECT(pool.getSize() == 0,
"pool.getSize() - Expected pool size to be zero.");
EXPECT(pool.getAlignment() == 0,
"pool.getSize() - Expected pool alignment to be zero.");
}
printf("Done.\n");
printf("Checking pool alignment when combined constants are added.\n");
{
uint8_t bytes[32] = { 0 };
uint64_t c = 0;
size_t offset;
pool.add(bytes, 1, offset);
EXPECT(pool.getSize() == 1,
"pool.getSize() - Expected pool size to be 1 byte.");
EXPECT(pool.getAlignment() == 1,
"pool.getSize() - Expected pool alignment to be 1 byte.");
EXPECT(offset == 0,
"pool.getSize() - Expected offset returned to be zero.");
pool.add(bytes, 2, offset);
EXPECT(pool.getSize() == 4,
"pool.getSize() - Expected pool size to be 4 bytes.");
EXPECT(pool.getAlignment() == 2,
"pool.getSize() - Expected pool alignment to be 2 bytes.");
EXPECT(offset == 2,
"pool.getSize() - Expected offset returned to be 2.");
pool.add(bytes, 4, offset);
EXPECT(pool.getSize() == 8,
"pool.getSize() - Expected pool size to be 8 bytes.");
EXPECT(pool.getAlignment() == 4,
"pool.getSize() - Expected pool alignment to be 4 bytes.");
EXPECT(offset == 4,
"pool.getSize() - Expected offset returned to be 4.");
pool.add(bytes, 4, offset);
EXPECT(pool.getSize() == 8,
"pool.getSize() - Expected pool size to be 8 bytes.");
EXPECT(pool.getAlignment() == 4,
"pool.getSize() - Expected pool alignment to be 4 bytes.");
EXPECT(offset == 4,
"pool.getSize() - Expected offset returned to be 8.");
pool.add(bytes, 32, offset);
EXPECT(pool.getSize() == 64,
"pool.getSize() - Expected pool size to be 64 bytes.");
EXPECT(pool.getAlignment() == 32,
"pool.getSize() - Expected pool alignment to be 32 bytes.");
EXPECT(offset == 32,
"pool.getSize() - Expected offset returned to be 32.");
}
printf("Done.\n");
return 0;
}

View File

@@ -1,106 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Dependencies - AsmJit]
#include <asmjit/base.h>
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
#include <asmjit/x86.h>
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
// [Dependencies - C]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace asmjit;
int main(int argc, char* argv[]) {
// --------------------------------------------------------------------------
// [Runtime]
// --------------------------------------------------------------------------
printf("Sizeof[Runtime]:\n");
printf(" int8_t : %u\n", static_cast<uint32_t>(sizeof(int8_t)));
printf(" int16_t : %u\n", static_cast<uint32_t>(sizeof(int16_t)));
printf(" int32_t : %u\n", static_cast<uint32_t>(sizeof(int32_t)));
printf(" int64_t : %u\n", static_cast<uint32_t>(sizeof(int64_t)));
printf(" long : %u\n", static_cast<uint32_t>(sizeof(long)));
printf(" size_t : %u\n", static_cast<uint32_t>(sizeof(size_t)));
printf(" intptr_t : %u\n", static_cast<uint32_t>(sizeof(intptr_t)));
printf(" float : %u\n", static_cast<uint32_t>(sizeof(float)));
printf(" double : %u\n", static_cast<uint32_t>(sizeof(double)));
printf(" void* : %u\n", static_cast<uint32_t>(sizeof(void*)));
printf("\n");
// --------------------------------------------------------------------------
// [Core]
// --------------------------------------------------------------------------
printf("Sizeof[Base]:\n");
printf(" asmjit::CodeGen : %u\n", static_cast<uint32_t>(sizeof(CodeGen)));
printf(" asmjit::BaseAssembler : %u\n", static_cast<uint32_t>(sizeof(BaseAssembler)));
printf(" asmjit::BaseCompiler : %u\n", static_cast<uint32_t>(sizeof(BaseCompiler)));
printf(" asmjit::Runtime : %u\n", static_cast<uint32_t>(sizeof(Runtime)));
printf("\n");
printf(" asmjit::Operand : %u\n", static_cast<uint32_t>(sizeof(Operand)));
printf(" asmjit::BaseReg : %u\n", static_cast<uint32_t>(sizeof(BaseReg)));
printf(" asmjit::BaseVar : %u\n", static_cast<uint32_t>(sizeof(BaseVar)));
printf(" asmjit::BaseMem : %u\n", static_cast<uint32_t>(sizeof(BaseMem)));
printf(" asmjit::Imm : %u\n", static_cast<uint32_t>(sizeof(Imm)));
printf(" asmjit::Label : %u\n", static_cast<uint32_t>(sizeof(Label)));
printf("\n");
printf(" asmjit::Ptr : %u\n", static_cast<uint32_t>(sizeof(Ptr)));
printf(" asmjit::SignedPtr : %u\n", static_cast<uint32_t>(sizeof(SignedPtr)));
printf("\n");
printf(" asmjit::LabelData : %u\n", static_cast<uint32_t>(sizeof(LabelData)));
printf(" asmjit::RelocData : %u\n", static_cast<uint32_t>(sizeof(RelocData)));
printf("\n");
printf(" asmjit::Node : %u\n", static_cast<uint32_t>(sizeof(Node)));
printf(" asmjit::AlignNode : %u\n", static_cast<uint32_t>(sizeof(AlignNode)));
printf(" asmjit::CallNode : %u\n", static_cast<uint32_t>(sizeof(CallNode)));
printf(" asmjit::CommentNode : %u\n", static_cast<uint32_t>(sizeof(CommentNode)));
printf(" asmjit::EmbedNode : %u\n", static_cast<uint32_t>(sizeof(EmbedNode)));
printf(" asmjit::FuncNode : %u\n", static_cast<uint32_t>(sizeof(FuncNode)));
printf(" asmjit::EndNode : %u\n", static_cast<uint32_t>(sizeof(EndNode)));
printf(" asmjit::InstNode : %u\n", static_cast<uint32_t>(sizeof(InstNode)));
printf(" asmjit::JumpNode : %u\n", static_cast<uint32_t>(sizeof(JumpNode)));
printf(" asmjit::TargetNode : %u\n", static_cast<uint32_t>(sizeof(TargetNode)));
printf("\n");
printf(" asmjit::FuncDecl : %u\n", static_cast<uint32_t>(sizeof(FuncDecl)));
printf(" asmjit::FuncInOut : %u\n", static_cast<uint32_t>(sizeof(FuncInOut)));
printf(" asmjit::FuncPrototype : %u\n", static_cast<uint32_t>(sizeof(FuncPrototype)));
printf("\n");
printf(" asmjit::VarAttr : %u\n", static_cast<uint32_t>(sizeof(VarAttr)));
printf(" asmjit::VarData : %u\n", static_cast<uint32_t>(sizeof(VarData)));
printf(" asmjit::BaseVarInst : %u\n", static_cast<uint32_t>(sizeof(BaseVarInst)));
printf(" asmjit::BaseVarState : %u\n", static_cast<uint32_t>(sizeof(BaseVarState)));
printf("\n");
// --------------------------------------------------------------------------
// [X86/X64]
// --------------------------------------------------------------------------
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
printf("Sizeof[X86/X64]:\n");
printf(" asmjit::x86x64::X86X64Assembler: %u\n", static_cast<uint32_t>(sizeof(x86x64::X86X64Assembler)));
printf(" asmjit::x86x64::X86X64Compiler : %u\n", static_cast<uint32_t>(sizeof(x86x64::X86X64Compiler)));
printf("\n");
printf(" asmjit::x86x64::X86X64CallNode : %u\n", static_cast<uint32_t>(sizeof(x86x64::X86X64CallNode)));
printf(" asmjit::x86x64::X86X64FuncNode : %u\n", static_cast<uint32_t>(sizeof(x86x64::X86X64FuncNode)));
printf("\n");
printf(" asmjit::x86x64::X86X64FuncDecl : %u\n", static_cast<uint32_t>(sizeof(x86x64::X86X64FuncDecl)));
printf("\n");
printf(" asmjit::x86x64::VarInst : %u\n", static_cast<uint32_t>(sizeof(x86x64::VarInst)));
printf(" asmjit::x86x64::VarState : %u\n", static_cast<uint32_t>(sizeof(x86x64::VarState)));
printf("\n");
printf(" asmjit::x86x64::InstInfo : %u\n", static_cast<uint32_t>(sizeof(x86x64::InstInfo)));
printf(" asmjit::x86x64::VarInfo : %u\n", static_cast<uint32_t>(sizeof(x86x64::VarInfo)));
printf("\n");
#endif // ASMJIT_BUILD_X86
return 0;
}

View File

@@ -366,6 +366,171 @@ void ConstPool::fill(void* dst) {
} }
} }
// ============================================================================
// [asmjit::ConstPool - Test]
// ============================================================================
#if defined(ASMJIT_TEST)
UNIT(base_constpool) {
Zone zone(16192);
ConstPool pool(&zone);
uint32_t i;
uint32_t kCount = 1000000;
INFO("Adding %u constants to the pool.", kCount);
{
size_t prevOffset;
size_t curOffset;
uint64_t c = ASMJIT_UINT64_C(0x0101010101010101);
EXPECT(pool.add(&c, 8, prevOffset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(prevOffset == 0,
"pool.add() - First constant should have zero offset.");
for (i = 1; i < kCount; i++) {
c++;
EXPECT(pool.add(&c, 8, curOffset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(prevOffset + 8 == curOffset,
"pool.add() - Returned incorrect curOffset.");
EXPECT(pool.getSize() == (i + 1) * 8,
"pool.getSize() - Reports incorrect size.");
prevOffset = curOffset;
}
EXPECT(pool.getAlignment() == 8,
"pool.getAlignment() - Expected 8-byte alignment.");
}
INFO("Retrieving %u constants from the pool.", kCount);
{
uint64_t c = ASMJIT_UINT64_C(0x0101010101010101);
for (i = 0; i < kCount; i++) {
size_t offset;
EXPECT(pool.add(&c, 8, offset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(offset == i * 8,
"pool.add() - Should have reused constant.");
c++;
}
}
INFO("Checking if the constants were split into 4-byte patterns.");
{
uint32_t c = 0x01010101;
for (i = 0; i < kCount; i++) {
size_t offset;
EXPECT(pool.add(&c, 4, offset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(offset == i * 8,
"pool.add() - Should reuse existing constant.");
c++;
}
}
INFO("Adding 2 byte constant to misalign the current offset.");
{
uint16_t c = 0xFFFF;
size_t offset;
EXPECT(pool.add(&c, 2, offset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(offset == kCount * 8,
"pool.add() - Didn't return expected position.");
EXPECT(pool.getAlignment() == 8,
"pool.getAlignment() - Expected 8-byte alignment.");
}
INFO("Adding 8 byte constant to check if pool gets aligned again.");
{
uint64_t c = ASMJIT_UINT64_C(0xFFFFFFFFFFFFFFFF);
size_t offset;
EXPECT(pool.add(&c, 8, offset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(offset == kCount * 8 + 8,
"pool.add() - Didn't return aligned offset.");
}
INFO("Adding 2 byte constant verify the gap is filled.");
{
uint16_t c = 0xFFFE;
size_t offset;
EXPECT(pool.add(&c, 2, offset) == kErrorOk,
"pool.add() - Returned error.");
EXPECT(offset == kCount * 8 + 2,
"pool.add() - Didn't fill the gap.");
EXPECT(pool.getAlignment() == 8,
"pool.getAlignment() - Expected 8-byte alignment.");
}
INFO("Checking reset functionality.");
{
pool.reset();
EXPECT(pool.getSize() == 0,
"pool.getSize() - Expected pool size to be zero.");
EXPECT(pool.getAlignment() == 0,
"pool.getSize() - Expected pool alignment to be zero.");
}
INFO("Checking pool alignment when combined constants are added.");
{
uint8_t bytes[32] = { 0 };
uint64_t c = 0;
size_t offset;
pool.add(bytes, 1, offset);
EXPECT(pool.getSize() == 1,
"pool.getSize() - Expected pool size to be 1 byte.");
EXPECT(pool.getAlignment() == 1,
"pool.getSize() - Expected pool alignment to be 1 byte.");
EXPECT(offset == 0,
"pool.getSize() - Expected offset returned to be zero.");
pool.add(bytes, 2, offset);
EXPECT(pool.getSize() == 4,
"pool.getSize() - Expected pool size to be 4 bytes.");
EXPECT(pool.getAlignment() == 2,
"pool.getSize() - Expected pool alignment to be 2 bytes.");
EXPECT(offset == 2,
"pool.getSize() - Expected offset returned to be 2.");
pool.add(bytes, 4, offset);
EXPECT(pool.getSize() == 8,
"pool.getSize() - Expected pool size to be 8 bytes.");
EXPECT(pool.getAlignment() == 4,
"pool.getSize() - Expected pool alignment to be 4 bytes.");
EXPECT(offset == 4,
"pool.getSize() - Expected offset returned to be 4.");
pool.add(bytes, 4, offset);
EXPECT(pool.getSize() == 8,
"pool.getSize() - Expected pool size to be 8 bytes.");
EXPECT(pool.getAlignment() == 4,
"pool.getSize() - Expected pool alignment to be 4 bytes.");
EXPECT(offset == 4,
"pool.getSize() - Expected offset returned to be 8.");
pool.add(bytes, 32, offset);
EXPECT(pool.getSize() == 64,
"pool.getSize() - Expected pool size to be 64 bytes.");
EXPECT(pool.getAlignment() == 32,
"pool.getSize() - Expected pool alignment to be 32 bytes.");
EXPECT(offset == 32,
"pool.getSize() - Expected offset returned to be 32.");
}
}
#endif // ASMJIT_TEST
} // asmjit namespace } // asmjit namespace
// [Api-End] // [Api-End]

View File

@@ -114,9 +114,9 @@ struct ErrorHandler {
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Create a new `ErrorHandler`. //! Create a new `ErrorHandler` instance.
ASMJIT_API ErrorHandler(); ASMJIT_API ErrorHandler();
//! Destroy the `ErrorHandler`. //! Destroy the `ErrorHandler` instance.
ASMJIT_API virtual ~ErrorHandler(); ASMJIT_API virtual ~ErrorHandler();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -142,17 +142,18 @@ struct ErrorHandler {
//! //!
//! Error handler is called when an error happened. An error can happen in //! Error handler is called when an error happened. An error can happen in
//! many places, but error handler is mostly used by `BaseAssembler` and //! many places, but error handler is mostly used by `BaseAssembler` and
//! `BaseCompiler` classes to report anything that may prevent correct code //! `BaseCompiler` classes to report anything that may cause incorrect code
//! generation. There are multiple ways how the error handler can be used //! generation. There are multiple ways how the error handler can be used
//! and each has it's pros/cons. //! and each has it's pros/cons.
//! //!
//! AsmJit library doesn't use exceptions and can be compiled with or without //! AsmJit library doesn't use exceptions and can be compiled with or without
//! exception feature support. Even if the AsmJit library is compiled without //! exception handling support. Even if the AsmJit library is compiled without
//! exceptions it is exception-safe and handleError() can report an incoming //! exceptions it is exception-safe and handleError() can report an incoming
//! error by throwing an exception of any type. It's guaranteed that the //! 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 //! exception won't be catched by AsmJit and will be propagated to the code
//! calling AsmJit `BaseAssembler` or `BaseCompiler`. Alternative to throwing //! calling AsmJit `BaseAssembler` or `BaseCompiler` methods. Alternative to
//! exception is using setjmp() / longjmp() pair from the standard C library. //! 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 //! If the exception or setjmp() / longjmp() mechanism is used, the state of
//! the `BaseAssember` or `BaseCompiler` is unchanged and if it's possible the //! the `BaseAssember` or `BaseCompiler` is unchanged and if it's possible the
@@ -162,13 +163,12 @@ struct ErrorHandler {
//! done by `BaseCompiler`) the execution can't continue and the error will //! done by `BaseCompiler`) the execution can't continue and the error will
//! be also stored in `BaseAssembler` or `BaseCompiler`. //! be also stored in `BaseAssembler` or `BaseCompiler`.
//! //!
//! Finally, if exceptions nor setjmp() / longjmp() mechanisms were used, //! Finally, if no exceptions nor setjmp() / longjmp() mechanisms were used,
//! you can still implement a compatible design by returning from your error //! you can still implement a compatible handling by returning from your
//! handler. Returning `true` means that error was reported and AsmJit //! error handler. Returning `true` means that error was reported and AsmJit
//! should continue execution. When `false` is returned, AsmJit sets the //! should continue execution, but `false` sets the rror immediately to the
//! error immediately to the `BaseAssembler` or `BaseCompiler` and execution //! `BaseAssembler` or `BaseCompiler` and execution shouldn't continue (this
//! shouldn't continue (this is the default behavior in case no error handler //! is the default behavior in case no error handler is used).
//! is used).
virtual bool handleError(Error code, const char* message) = 0; virtual bool handleError(Error code, const char* message) = 0;
}; };

178
src/asmjit/base/intutil.cpp Normal file
View File

@@ -0,0 +1,178 @@
// [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::isInt?().");
EXPECT(IntUtil::isInt8<int>(-128) == true,
"IntUtil::isInt8<int> should return true if >= -128.");
EXPECT(IntUtil::isInt8<int>(127) == true,
"IntUtil::isInt8<int> should return true if <= 127.");
EXPECT(IntUtil::isInt8<int>(-129) == false,
"IntUtil::isInt8<int> should return false if < -128.");
EXPECT(IntUtil::isInt8<int>(128) == false,
"IntUtil::isInt8<int> should return false if > 127.");
EXPECT(IntUtil::isInt16<int>(-32768) == true,
"IntUtil::isInt16<int> should return true if >= -32768.");
EXPECT(IntUtil::isInt16<int>(32767) == true,
"IntUtil::isInt16<int> should return true if <= 32767.");
EXPECT(IntUtil::isInt16<int>(-32769) == false,
"IntUtil::isInt16<int> should return false if < -32768.");
EXPECT(IntUtil::isInt16<int>(32768) == false,
"IntUtil::isInt16<int> should return false if > 32767.");
EXPECT(IntUtil::isInt32(ASMJIT_UINT64_C(0x100000000)) == false,
"IntUtil::isInt32<int> should return false if outside.");
EXPECT(IntUtil::isInt32(ASMJIT_UINT64_C(0x100000000)) == false,
"IntUtil::isInt32<int> should return false if outside.");
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"

View File

@@ -31,7 +31,7 @@ namespace asmjit {
template<typename T> template<typename T>
struct IntTraits { struct IntTraits {
enum { enum {
kIsSigned = (~static_cast<T>(0)) < static_cast<T>(0), kIsSigned = static_cast<T>(~static_cast<T>(0)) < static_cast<T>(0),
kIsUnsigned = !kIsSigned, kIsUnsigned = !kIsSigned,
kIs8Bit = sizeof(T) == 1, kIs8Bit = sizeof(T) == 1,
@@ -402,31 +402,11 @@ struct IntUtil {
return (base + (alignment - 1)) & ~(alignment - 1); return (base + (alignment - 1)) & ~(alignment - 1);
} }
//! Get delta required to align `base` to `alignment`.
template<typename T> template<typename T>
static ASMJIT_INLINE T deltaTo(T base, T alignment) { static ASMJIT_INLINE T alignToPowerOf2(T base) {
return alignTo(base, alignment) - base; // Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.
}
// --------------------------------------------------------------------------
// [AsmJit - Round]
// --------------------------------------------------------------------------
template<typename T>
static ASMJIT_INLINE T roundUp(T base, T alignment) {
T over = base % alignment;
return base + (over > 0 ? alignment - over : 0);
}
template<typename T>
static ASMJIT_INLINE T roundUpToPowerOf2(T base) {
// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
// figure 3-3, page 48, where the function is called clp2.
base -= 1; base -= 1;
// I'm trying to make this portable and MSVC strikes me the warning C4293:
// "Shift count negative or too big, undefined behavior"
// Fixing...
#if defined(_MSC_VER) #if defined(_MSC_VER)
# pragma warning(push) # pragma warning(push)
# pragma warning(disable: 4293) # pragma warning(disable: 4293)
@@ -448,6 +428,12 @@ struct IntUtil {
return base + 1; 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;
}
}; };
// ============================================================================ // ============================================================================

View File

@@ -78,7 +78,7 @@ struct VMemLocal {
hProcess = GetCurrentProcess(); hProcess = GetCurrentProcess();
alignment = info.dwAllocationGranularity; alignment = info.dwAllocationGranularity;
pageSize = IntUtil::roundUpToPowerOf2<uint32_t>(info.dwPageSize); pageSize = IntUtil::alignToPowerOf2<uint32_t>(info.dwPageSize);
} }
HANDLE hProcess; HANDLE hProcess;
@@ -99,27 +99,38 @@ size_t VMemUtil::getPageSize() {
return vm().pageSize; return vm().pageSize;
} }
void* VMemUtil::alloc(size_t length, size_t* allocated, bool canExecute) { void* VMemUtil::alloc(size_t length, size_t* allocated, uint32_t flags) {
return allocProcessMemory(static_cast<HANDLE>(0), length, allocated, canExecute); return allocProcessMemory(static_cast<HANDLE>(0), length, allocated, flags);
} }
void VMemUtil::release(void* addr, size_t length) { void VMemUtil::release(void* addr, size_t length) {
return releaseProcessMemory(static_cast<HANDLE>(0), addr, length); return releaseProcessMemory(static_cast<HANDLE>(0), addr, length);
} }
void* VMemUtil::allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, bool canExecute) { void* VMemUtil::allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, uint32_t flags) {
VMemLocal& vmLocal = vm(); VMemLocal& vmLocal = vm();
if (hProcess == static_cast<HANDLE>(0)) if (hProcess == static_cast<HANDLE>(0))
hProcess = vmLocal.hProcess; hProcess = vmLocal.hProcess;
// VirtualAlloc rounds allocated size to a page size automatically. // VirtualAlloc rounds allocated size to a page size automatically.
size_t mSize = IntUtil::roundUp(length, vmLocal.pageSize); size_t mSize = IntUtil::alignTo(length, vmLocal.pageSize);
// Windows XP SP2 / Vista allow Data Excution Prevention (DEP). // Windows XP SP2 / Vista allow Data Excution Prevention (DEP).
WORD protect = canExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; DWORD protectFlags = 0;
LPVOID mBase = VirtualAllocEx(hProcess, NULL, mSize, MEM_COMMIT | MEM_RESERVE, protect);
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) if (mBase == NULL)
return NULL; return NULL;
@@ -170,9 +181,12 @@ size_t VMemUtil::getPageSize() {
return vm().pageSize; return vm().pageSize;
} }
void* VMemUtil::alloc(size_t length, size_t* allocated, bool canExecute) { void* VMemUtil::alloc(size_t length, size_t* allocated, uint32_t flags) {
size_t msize = IntUtil::roundUp<size_t>(length, vm().pageSize); size_t msize = IntUtil::alignTo<size_t>(length, vm().pageSize);
int protection = PROT_READ | PROT_WRITE | (canExecute ? PROT_EXEC : 0); 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); void* mbase = ::mmap(NULL, msize, protection, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mbase == MAP_FAILED) if (mbase == MAP_FAILED)
@@ -360,10 +374,11 @@ struct VMemPrivate {
// Helpers to avoid ifdefs in the code. // Helpers to avoid ifdefs in the code.
ASMJIT_INLINE uint8_t* allocVirtualMemory(size_t size, size_t* vsize) { ASMJIT_INLINE uint8_t* allocVirtualMemory(size_t size, size_t* vsize) {
uint32_t flags = kVMemFlagWritable | kVMemFlagExecutable;
#if !defined(ASMJIT_OS_WINDOWS) #if !defined(ASMJIT_OS_WINDOWS)
return (uint8_t*)VMemUtil::alloc(size, vsize, true); return (uint8_t*)VMemUtil::alloc(size, vsize, flags);
#else #else
return (uint8_t*)VMemUtil::allocProcessMemory(_hProcess, size, vsize, true); return (uint8_t*)VMemUtil::allocProcessMemory(_hProcess, size, vsize, flags);
#endif #endif
} }
@@ -1204,4 +1219,141 @@ Error VMemMgr::shrink(void* address, size_t used) {
return d->shrink(address, used); return d->shrink(address, used);
} }
// ============================================================================
// [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**)::malloc(sizeof(void*) * kCount);
void** b = (void**)::malloc(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] = ::malloc(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]);
::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] = ::malloc(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]);
::free(b[i]);
}
VMemTest_stats(memmgr);
::free(a);
::free(b);
}
#endif // ASMJIT_TEST
} // asmjit namespace } // asmjit namespace

View File

@@ -31,6 +31,18 @@ ASMJIT_ENUM(kVMemAlloc) {
kVMemAllocPermanent = 1 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] // [asmjit::VMemUtil]
// ============================================================================ // ============================================================================
@@ -58,7 +70,7 @@ struct VMemUtil {
//! Pages are readable/writeable, but they are not guaranteed to be //! Pages are readable/writeable, but they are not guaranteed to be
//! executable unless 'canExecute' is true. Returns the address of //! executable unless 'canExecute' is true. Returns the address of
//! allocated memory, or NULL on failure. //! allocated memory, or NULL on failure.
static ASMJIT_API void* alloc(size_t length, size_t* allocated, bool canExecute); static ASMJIT_API void* alloc(size_t length, size_t* allocated, uint32_t flags);
//! Free memory allocated by `alloc()`. //! Free memory allocated by `alloc()`.
static ASMJIT_API void release(void* addr, size_t length); static ASMJIT_API void release(void* addr, size_t length);
@@ -67,7 +79,7 @@ struct VMemUtil {
//! Allocate virtual memory of `hProcess`. //! Allocate virtual memory of `hProcess`.
//! //!
//! \note This function is Windows specific. //! \note This function is Windows specific.
static ASMJIT_API void* allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, bool canExecute); static ASMJIT_API void* allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, uint32_t flags);
//! Free virtual memory of `hProcess`. //! Free virtual memory of `hProcess`.
//! //!
@@ -164,7 +176,7 @@ struct VMemMgr {
//! \internal //! \internal
//! //!
//! Pointer to private data hidden out of the public API. //! Pointer to a private data hidden from the public API.
void* _d; void* _d;
}; };

View File

@@ -10,7 +10,7 @@
// [Include] // [Include]
#if !defined(ASMJIT_CONFIG_FILE) #if !defined(ASMJIT_CONFIG_FILE)
#include "config.h" #include "./config.h"
#endif // !ASMJIT_CONFIG_FILE #endif // !ASMJIT_CONFIG_FILE
// Turn off deprecation warnings when compiling AsmJit. // Turn off deprecation warnings when compiling AsmJit.
@@ -303,5 +303,14 @@ typedef unsigned __int64 uint64_t;
#endif // ASMJIT_OS_WINDOWS && !ASMJIT_SUPRESS_WINDOWS_H #endif // ASMJIT_OS_WINDOWS && !ASMJIT_SUPRESS_WINDOWS_H
// ============================================================================
// [asmjit::build - Test]
// ============================================================================
// Include test if building for unit testing.
#if defined(ASMJIT_TEST)
#include "./test/test.h"
#endif // ASMJIT_TEST
// [Guard] // [Guard]
#endif // _ASMJIT_BUILD_H #endif // _ASMJIT_BUILD_H

View File

@@ -8,10 +8,7 @@
#ifndef _ASMJIT_CONTRIB_WINREMOTERUNTIME_H #ifndef _ASMJIT_CONTRIB_WINREMOTERUNTIME_H
#define _ASMJIT_CONTRIB_WINREMOTERUNTIME_H #define _ASMJIT_CONTRIB_WINREMOTERUNTIME_H
// [Dependencies]
#include "../base.h" #include "../base.h"
// [Guard - Windows]
#if defined(ASMJIT_OS_WINDOWS) #if defined(ASMJIT_OS_WINDOWS)
namespace asmjit { namespace asmjit {
@@ -72,8 +69,6 @@ struct WinRemoteRuntime : public Runtime {
} // contrib namespace } // contrib namespace
} // asmjit namespace } // asmjit namespace
// [Guard - Windows]
#endif // ASMJIT_OS_WINDOWS
// [Guard] // [Guard]
#endif // ASMJIT_OS_WINDOWS
#endif // _ASMJIT_CONTRIB_WINREMOTERUNTIME_H #endif // _ASMJIT_CONTRIB_WINREMOTERUNTIME_H

206
src/asmjit/test/main.cpp Normal file
View File

@@ -0,0 +1,206 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Dependencies - MiniUnit]
#include "./test.h"
#include "../asmjit.h"
using namespace asmjit;
// ============================================================================
// [DumpCpu]
// ============================================================================
struct DumpCpuFeature {
uint32_t feature;
const char* name;
};
static void dumpCpuFeatures(const BaseCpuInfo* cpuInfo, const DumpCpuFeature* data, size_t count) {
for (size_t i = 0; i < count; i++)
if (cpuInfo->hasFeature(data[i].feature))
INFO(" %s", data[i].name);
}
static void dumpCpu() {
const BaseCpuInfo* cpuInfo_ = BaseCpuInfo::getHost();
INFO("Host CPU Info:");
INFO(" Vendor string : %s", cpuInfo_->getVendorString());
INFO(" Brand string : %s", cpuInfo_->getBrandString());
INFO(" Family : %u", cpuInfo_->getFamily());
INFO(" Model : %u", cpuInfo_->getModel());
INFO(" Stepping : %u", cpuInfo_->getStepping());
INFO(" Cores Count : %u", cpuInfo_->getCoresCount());
INFO("");
// --------------------------------------------------------------------------
// [X86]
// --------------------------------------------------------------------------
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
const x86x64::CpuInfo* cpuInfo = static_cast<const x86x64::CpuInfo*>(cpuInfo_);
static const DumpCpuFeature featuresList[] = {
{ x86x64::kCpuFeatureMultithreading , "Multithreading" },
{ x86x64::kCpuFeatureExecuteDisableBit , "Execute-Disable Bit" },
{ x86x64::kCpuFeatureRdtsc , "Rdtsc" },
{ x86x64::kCpuFeatureRdtscp , "Rdtscp" },
{ x86x64::kCpuFeatureCmov , "Cmov" },
{ x86x64::kCpuFeatureCmpXchg8B , "Cmpxchg8b" },
{ x86x64::kCpuFeatureCmpXchg16B , "Cmpxchg16b" },
{ x86x64::kCpuFeatureClflush , "Clflush" },
{ x86x64::kCpuFeaturePrefetch , "Prefetch" },
{ x86x64::kCpuFeatureLahfSahf , "Lahf/Sahf" },
{ x86x64::kCpuFeatureFxsr , "Fxsave/Fxrstor" },
{ x86x64::kCpuFeatureFfxsr , "Fxsave/Fxrstor Opt." },
{ x86x64::kCpuFeatureMmx , "Mmx" },
{ x86x64::kCpuFeatureMmxExt , "MmxExt" },
{ x86x64::kCpuFeature3dNow , "3dnow" },
{ x86x64::kCpuFeature3dNowExt , "3dnowExt" },
{ x86x64::kCpuFeatureSse , "Sse" },
{ x86x64::kCpuFeatureSse2 , "Sse2" },
{ x86x64::kCpuFeatureSse3 , "Sse3" },
{ x86x64::kCpuFeatureSsse3 , "Ssse3" },
{ x86x64::kCpuFeatureSse4A , "Sse4a" },
{ x86x64::kCpuFeatureSse41 , "Sse4.1" },
{ x86x64::kCpuFeatureSse42 , "Sse4.2" },
{ x86x64::kCpuFeatureMsse , "Misaligned SSE" },
{ x86x64::kCpuFeatureMonitorMWait , "Monitor/MWait" },
{ x86x64::kCpuFeatureMovbe , "Movbe" },
{ x86x64::kCpuFeaturePopcnt , "Popcnt" },
{ x86x64::kCpuFeatureLzcnt , "Lzcnt" },
{ x86x64::kCpuFeatureAesni , "AesNI" },
{ x86x64::kCpuFeaturePclmulqdq , "Pclmulqdq" },
{ x86x64::kCpuFeatureRdrand , "Rdrand" },
{ x86x64::kCpuFeatureAvx , "Avx" },
{ x86x64::kCpuFeatureAvx2 , "Avx2" },
{ x86x64::kCpuFeatureF16C , "F16C" },
{ x86x64::kCpuFeatureFma3 , "Fma3" },
{ x86x64::kCpuFeatureFma4 , "Fma4" },
{ x86x64::kCpuFeatureXop , "Xop" },
{ x86x64::kCpuFeatureBmi , "Bmi" },
{ x86x64::kCpuFeatureBmi2 , "Bmi2" },
{ x86x64::kCpuFeatureHle , "Hle" },
{ x86x64::kCpuFeatureRtm , "Rtm" },
{ x86x64::kCpuFeatureFsGsBase , "FsGsBase" },
{ x86x64::kCpuFeatureRepMovsbStosbExt , "RepMovsbStosbExt" }
};
INFO("Host CPU Info (X86/X64):");
INFO(" Processor Type : %u", cpuInfo->getProcessorType());
INFO(" Brand Index : %u", cpuInfo->getBrandIndex());
INFO(" CL Flush Cache Line : %u", cpuInfo->getFlushCacheLineSize());
INFO(" Max logical Processors: %u", cpuInfo->getMaxLogicalProcessors());
INFO("");
INFO("Host CPU Features (X86/X64):");
dumpCpuFeatures(cpuInfo, featuresList, ASMJIT_ARRAY_SIZE(featuresList));
INFO("");
#endif // ASMJIT_HOST || ASMJIT_HOST_X64
}
// ============================================================================
// [DumpSizeOf]
// ============================================================================
#define DUMP_SIZE(_Type_) \
INFO(" %-31s: %u", #_Type_, static_cast<uint32_t>(sizeof(_Type_)))
static void dumpSizeOf() {
INFO("SizeOf Types:");
DUMP_SIZE(int8_t);
DUMP_SIZE(int16_t);
DUMP_SIZE(int32_t);
DUMP_SIZE(int64_t);
DUMP_SIZE(int);
DUMP_SIZE(long);
DUMP_SIZE(size_t);
DUMP_SIZE(intptr_t);
DUMP_SIZE(float);
DUMP_SIZE(double);
DUMP_SIZE(void*);
DUMP_SIZE(asmjit::Ptr);
DUMP_SIZE(asmjit::SignedPtr);
INFO("");
INFO("SizeOf Base:");
DUMP_SIZE(asmjit::CodeGen);
DUMP_SIZE(asmjit::ConstPool);
DUMP_SIZE(asmjit::Logger);
DUMP_SIZE(asmjit::Runtime);
DUMP_SIZE(asmjit::Zone);
INFO("");
INFO("SizeOf Operand:");
DUMP_SIZE(asmjit::Operand);
DUMP_SIZE(asmjit::BaseReg);
DUMP_SIZE(asmjit::BaseVar);
DUMP_SIZE(asmjit::BaseMem);
DUMP_SIZE(asmjit::Imm);
DUMP_SIZE(asmjit::Label);
INFO("");
INFO("SizeOf Assembler:");
DUMP_SIZE(asmjit::BaseAssembler);
DUMP_SIZE(asmjit::LabelData);
DUMP_SIZE(asmjit::RelocData);
INFO("");
INFO("SizeOf Compiler:");
DUMP_SIZE(asmjit::BaseCompiler);
DUMP_SIZE(asmjit::Node);
DUMP_SIZE(asmjit::AlignNode);
DUMP_SIZE(asmjit::CallNode);
DUMP_SIZE(asmjit::CommentNode);
DUMP_SIZE(asmjit::EmbedNode);
DUMP_SIZE(asmjit::FuncNode);
DUMP_SIZE(asmjit::EndNode);
DUMP_SIZE(asmjit::InstNode);
DUMP_SIZE(asmjit::JumpNode);
DUMP_SIZE(asmjit::TargetNode);
DUMP_SIZE(asmjit::FuncDecl);
DUMP_SIZE(asmjit::FuncInOut);
DUMP_SIZE(asmjit::FuncPrototype);
DUMP_SIZE(asmjit::VarAttr);
DUMP_SIZE(asmjit::VarData);
DUMP_SIZE(asmjit::BaseVarInst);
DUMP_SIZE(asmjit::BaseVarState);
INFO("");
// --------------------------------------------------------------------------
// [X86/X64]
// --------------------------------------------------------------------------
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
INFO("SizeOf X86/X64:");
DUMP_SIZE(asmjit::x86x64::X86X64Assembler);
DUMP_SIZE(asmjit::x86x64::X86X64Compiler);
DUMP_SIZE(asmjit::x86x64::X86X64CallNode);
DUMP_SIZE(asmjit::x86x64::X86X64FuncNode);
DUMP_SIZE(asmjit::x86x64::X86X64FuncDecl);
DUMP_SIZE(asmjit::x86x64::VarInst);
DUMP_SIZE(asmjit::x86x64::VarState);
DUMP_SIZE(asmjit::x86x64::InstInfo);
DUMP_SIZE(asmjit::x86x64::VarInfo);
INFO("");
#endif // ASMJIT_BUILD_X86
}
// ============================================================================
// [Main]
// ============================================================================
int main(int argc, const char* argv[]) {
if (MiniUnit::init(argc, argv)) {
dumpCpu();
dumpSizeOf();
MiniUnit::run();
}
return 0;
}

112
src/asmjit/test/test.cpp Normal file
View File

@@ -0,0 +1,112 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Dependencies - MiniUnit]
#include "./test.h"
// ============================================================================
// [MiniUnit - Statics]
// ============================================================================
int MiniUnit::argc;
const char** MiniUnit::argv;
FILE* MiniUnit::outFile;
MiniUnit::Unit* MiniUnit::unitList;
MiniUnit::Unit* MiniUnit::unitRunning;
// ============================================================================
// [MiniUnit - Init]
// ============================================================================
bool MiniUnit::init(int argc, const char* argv[]) {
MiniUnit::argc = argc;
MiniUnit::argv = argv;
MiniUnit::outFile = stdout;
return unitList != NULL;
}
// ============================================================================
// [MiniUnit - Add]
// ============================================================================
void MiniUnit::addUnit(Unit* unit) {
Unit** pPrev = &unitList;
Unit* current = *pPrev;
while (current != NULL) {
if (::strcmp(current->name, unit->name) >= 0)
break;
pPrev = &current->next;
current = *pPrev;
}
*pPrev = unit;
unit->next = current;
}
// ============================================================================
// [MiniUnit - Run]
// ============================================================================
void MiniUnit::run() {
MiniUnit::Unit* unit = unitList;
while (unit != NULL) {
runUnit(unit);
unit = unit->next;
}
}
void MiniUnit::runUnit(Unit* unit) {
info("[Unit] %s", unit->name);
unitRunning = unit;
unit->entry();
unitRunning = NULL;
}
// ============================================================================
// [MiniUnit - Info]
// ============================================================================
void MiniUnit::info(const char* fmt, ...) {
const char* prefix = unitRunning ? " " : "";
size_t len = ::strlen(fmt);
if (len != 0) {
va_list ap;
va_start(ap, fmt);
::fputs(prefix, outFile);
::vfprintf(outFile, fmt, ap);
va_end(ap);
}
if (len == 0 || fmt[len - 1] != '\n')
::fputs("\n", outFile);
::fflush(outFile);
}
void MiniUnit::fail(const char* file, int line, const char* fmt, ...) {
size_t len = ::strlen(fmt);
if (len != 0) {
va_list ap;
va_start(ap, fmt);
::fputs("[Fail] ", outFile);
::vfprintf(outFile, fmt, ap);
va_end(ap);
}
if (len > 0 && fmt[len - 1] != '\n')
::fputs("\n", outFile);
::fprintf(outFile, "[File] %s (Line: %d)\n", file, line);
::fflush(outFile);
::exit(1);
}

99
src/asmjit/test/test.h Normal file
View File

@@ -0,0 +1,99 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef MINIUNIT_H
#define MINIUNIT_H
// [Dependencies - C]
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
//! \internal
//! \{
// ============================================================================
// [MiniUnit]
// ============================================================================
//! Define a unit.
//!
//! `_Name_` can only contain ASCII characters, numbers and underscore.
#define UNIT(_Name_) \
static void unit_##_Name_##_entry(void); \
static ::MiniUnit::AutoUnit unit_##_Name_##_autoinit(#_Name_, unit_##_Name_##_entry); \
static void unit_##_Name_##_entry(void)
//! Informative message printed to stdout.
#define INFO(...) \
::MiniUnit::info(__VA_ARGS__)
//! Expect `_Exp_` to be truthy, fail otherwise.
#define EXPECT(_Exp_, ...) \
do { \
if (!(_Exp_)) ::MiniUnit::fail(__FILE__, __LINE__, __VA_ARGS__); \
} while(0)
struct MiniUnit {
//! Test entry point.
typedef void (*Entry)(void);
//! Test unit.
struct Unit {
const char* name;
Entry entry;
size_t finished;
Unit* next;
};
//! Automatic unit registration by using static initialization.
struct AutoUnit : Unit {
inline AutoUnit(const char* _name, Entry _entry) {
name = _name;
entry = _entry;
finished = false;
next = NULL;
MiniUnit::addUnit(this);
}
};
//! Test arguments count.
static int argc;
//! Test arguments list.
static const char** argv;
//! File where to log.
static FILE* outFile;
//! Test unit list.
static Unit* unitList;
//! Running test reference.
static Unit* unitRunning;
//! Initialize MiniUnit framework.
//!
//! Returns `true` if `run()` should be called.
static bool init(int argc, const char* argv[]);
//! Register a new test.
static void addUnit(Unit* unit);
//! Run all units.
static void run();
//! Run a single unit.
static void runUnit(Unit* unit);
//! Log message, adds automatically new line if not present.
static void info(const char* fmt, ...);
//! Called on `EXPECT()` failure.
static void fail(const char* file, int line, const char* fmt, ...);
};
//! \}
// [Guard]
#endif // MINIUNIT_H

View File

@@ -309,8 +309,8 @@ const char _instName[] =
"minsd\0" "minsd\0"
"minss\0" "minss\0"
"monitor\0" "monitor\0"
"mov_ptr\0"
"mov\0" "mov\0"
"mov_ptr\0"
"movapd\0" "movapd\0"
"movaps\0" "movaps\0"
"movbe\0" "movbe\0"
@@ -1376,8 +1376,8 @@ enum kInstData_NameIndex {
kInstMinsd_NameIndex = 1746, kInstMinsd_NameIndex = 1746,
kInstMinss_NameIndex = 1752, kInstMinss_NameIndex = 1752,
kInstMonitor_NameIndex = 1758, kInstMonitor_NameIndex = 1758,
kInstMovPtr_NameIndex = 1766, kInstMov_NameIndex = 1766,
kInstMov_NameIndex = 1774, kInstMovPtr_NameIndex = 1770,
kInstMovapd_NameIndex = 1778, kInstMovapd_NameIndex = 1778,
kInstMovaps_NameIndex = 1785, kInstMovaps_NameIndex = 1785,
kInstMovbe_NameIndex = 1792, kInstMovbe_NameIndex = 1792,
@@ -2452,8 +2452,8 @@ const InstInfo _instInfo[] = {
INST(kInstMinsd , "minsd" , G(ExtRm) , F(None) , 0 , O(Xmm) , O(XmmMem) , U , U , O_F20F00(5D,U) , U ), INST(kInstMinsd , "minsd" , G(ExtRm) , F(None) , 0 , O(Xmm) , O(XmmMem) , U , U , O_F20F00(5D,U) , U ),
INST(kInstMinss , "minss" , G(ExtRm) , F(None) , 0 , O(Xmm) , O(XmmMem) , U , U , O_F30F00(5D,U) , U ), INST(kInstMinss , "minss" , G(ExtRm) , F(None) , 0 , O(Xmm) , O(XmmMem) , U , U , O_F30F00(5D,U) , U ),
INST(kInstMonitor , "monitor" , G(X86Op) , F(None)|F(Special) , 0 , U , U , U , U , O_000F01(C8,U) , U ), INST(kInstMonitor , "monitor" , G(X86Op) , F(None)|F(Special) , 0 , U , U , U , U , O_000F01(C8,U) , U ),
INST(kInstMovPtr , "mov_ptr" , G(X86MovPtr) , F(Move)|F(Special) , 0 , O(Gqdwb) , O(Imm) , U , U , O_000000(A0,U) , O_000000(A2,U) ),
INST(kInstMov , "mov" , G(X86Mov) , F(Move) , 0 , O(GqdwbMem) , O(GqdwbMem)|O(Imm) , U , U , U , U ), INST(kInstMov , "mov" , G(X86Mov) , F(Move) , 0 , O(GqdwbMem) , O(GqdwbMem)|O(Imm) , U , U , U , U ),
INST(kInstMovPtr , "mov_ptr" , G(X86MovPtr) , F(Move)|F(Special) , 0 , O(Gqdwb) , O(Imm) , U , U , O_000000(A0,U) , O_000000(A2,U) ),
INST(kInstMovapd , "movapd" , G(ExtMov) , F(Move) , 16, O(XmmMem) , O(XmmMem) , U , U , O_660F00(28,U) , O_660F00(29,U) ), INST(kInstMovapd , "movapd" , G(ExtMov) , F(Move) , 16, O(XmmMem) , O(XmmMem) , U , U , O_660F00(28,U) , O_660F00(29,U) ),
INST(kInstMovaps , "movaps" , G(ExtMov) , F(Move) , 16, O(XmmMem) , O(XmmMem) , U , U , O_000F00(28,U) , O_000F00(29,U) ), INST(kInstMovaps , "movaps" , G(ExtMov) , F(Move) , 16, O(XmmMem) , O(XmmMem) , U , U , O_000F00(28,U) , O_000F00(29,U) ),
INST(kInstMovbe , "movbe" , G(ExtMovBe) , F(Move) , 0 , O(GqdwMem) , O(GqdwMem) , U , U , O_000F38(F0,U) , O_000F38(F1,U) ), INST(kInstMovbe , "movbe" , G(ExtMovBe) , F(Move) , 0 , O(GqdwMem) , O(GqdwMem) , U , U , O_000F38(F0,U) , O_000F38(F1,U) ),
@@ -3324,6 +3324,37 @@ uint32_t X86InstUtil::getInstIdByName(const char* name, size_t len) {
return kInstNone; return kInstNone;
} }
// ============================================================================
// [asmjit::x86x64::X86Util - Test]
// ============================================================================
#if defined(ASMJIT_TEST)
UNIT(x86_inst_name) {
// All known instructions should be matched.
for (uint32_t a = 0; a < _kInstCount; a++) {
uint32_t b = X86InstUtil::getInstIdByName(_instInfo[a].getName());
EXPECT(a == b,
"Should match existing instruction \"%s\" {id:%u} != \"%s\" {id:%u}.",
_instInfo[a].getName(), a,
_instInfo[b].getName(), b);
}
// Everything else should return kInstNone
EXPECT(X86InstUtil::getInstIdByName(NULL) == kInstNone,
"Should return kInstNone for NULL input.");
EXPECT(X86InstUtil::getInstIdByName("") == kInstNone,
"Should return kInstNone for empty string.");
EXPECT(X86InstUtil::getInstIdByName("_") == kInstNone,
"Should return kInstNone for unknown instruction.");
EXPECT(X86InstUtil::getInstIdByName("123xyz") == kInstNone,
"Should return kInstNone for unknown instruction.");
}
#endif // ASMJIT_TEST
} // x86x64 namespace } // x86x64 namespace
} // asmjit namespace } // asmjit namespace

View File

@@ -334,8 +334,8 @@ ASMJIT_ENUM(kInstCode) {
kInstMinsd, // SSE2 kInstMinsd, // SSE2
kInstMinss, // SSE kInstMinss, // SSE
kInstMonitor, // SSE3 kInstMonitor, // SSE3
kInstMovPtr, // X86/X64
kInstMov, // X86/X64 kInstMov, // X86/X64
kInstMovPtr, // X86/X64
kInstMovapd, // SSE2 kInstMovapd, // SSE2
kInstMovaps, // SSE kInstMovaps, // SSE
kInstMovbe, // SSE3 - Intel-Atom kInstMovbe, // SSE3 - Intel-Atom

View File

@@ -159,7 +159,7 @@ ASMJIT_ENUM(kRegIndex) {
//! X86/X64 segment codes. //! X86/X64 segment codes.
ASMJIT_ENUM(kSeg) { ASMJIT_ENUM(kSeg) {
//! No segment. //! No/Default segment.
kSegDefault = 0, kSegDefault = 0,
//! Es segment. //! Es segment.
kSegEs = 1, kSegEs = 1,

View File

@@ -5,5 +5,5 @@ ASMJIT_BUILD_DIR="build_xcode"
mkdir ../${ASMJIT_BUILD_DIR} mkdir ../${ASMJIT_BUILD_DIR}
cd ../${ASMJIT_BUILD_DIR} cd ../${ASMJIT_BUILD_DIR}
cmake .. -G"Xcode" -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Xcode" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd ${ASMJIT_CURRENT_DIR} cd ${ASMJIT_CURRENT_DIR}

View File

@@ -5,5 +5,5 @@ ASMJIT_BUILD_DIR="build_makefiles_dbg"
mkdir ../${ASMJIT_BUILD_DIR} mkdir ../${ASMJIT_BUILD_DIR}
cd ../${ASMJIT_BUILD_DIR} cd ../${ASMJIT_BUILD_DIR}
cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd ${ASMJIT_CURRENT_DIR} cd ${ASMJIT_CURRENT_DIR}

View File

@@ -5,5 +5,5 @@ ASMJIT_BUILD_DIR="build_makefiles_rel"
mkdir ../${ASMJIT_BUILD_DIR} mkdir ../${ASMJIT_BUILD_DIR}
cd ../${ASMJIT_BUILD_DIR} cd ../${ASMJIT_BUILD_DIR}
cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd ${ASMJIT_CURRENT_DIR} cd ${ASMJIT_CURRENT_DIR}

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_mingw_dbg"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_mingw_rel"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2005_x64"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 8 2005 Win64" -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Visual Studio 8 2005 Win64" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2005_x86"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 8 2005" -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Visual Studio 8 2005" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2008_x64"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 9 2008 Win64" -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Visual Studio 9 2008 Win64" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2008_x86"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 9 2008" -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Visual Studio 9 2008" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2010_x64"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 10 Win64" -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Visual Studio 10 Win64" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2010_x86"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 10" -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Visual Studio 10" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2013_x64"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 12 Win64" -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Visual Studio 12 Win64" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2013_x86"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 12" -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Visual Studio 12" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%