diff --git a/CMakeLists.txt b/CMakeLists.txt index 1939d51..afeca75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,12 @@ CMake_Minimum_Required(VERSION 2.8.12) # Whether to build static library (default 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). # Set(ASMJIT_BUILD_SAMPLES FALSE) @@ -73,9 +79,13 @@ Set(ASMJIT_CFLAGS) Set(ASMJIT_CFLAGS_DBG) Set(ASMJIT_CFLAGS_REL) +Set(ASMJIT_DEFINE "-D") + # MSVC. If(MSVC) Message("-- Using MSVC") + + Set(ASMJIT_DEFINE "/D") Set(ASMJIT_LFLAGS "/OPT:REF /OPT:ICF") Set(ASMJIT_CFLAGS /GF) Set(ASMJIT_CFLAGS_DBG /DASMJIT_DEBUG /GS /GR-) @@ -86,10 +96,6 @@ If(MSVC) List(APPEND ASMJIT_CFLAGS /D_UNICODE) EndIf() - If(ASMJIT_STATIC) - List(APPEND ASMJIT_CFLAGS /DASMJIT_STATIC) - EndIf() - # Enable multi-process compilation. If(NOT MSVC60 AND NOT MSVC70 AND NOT MSVC71) List(APPEND ASMJIT_CFLAGS /MP) @@ -99,6 +105,7 @@ EndIf() # GCC. If(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) Message("-- Using GCC") + Set(ASMJIT_CFLAGS -fno-exceptions) Set(ASMJIT_CFLAGS_DBG -DASMJIT_DEBUG -O0 @@ -113,10 +120,11 @@ If(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) If(WIN32) List(APPEND ASMJIT_CFLAGS -D_UNICODE) EndIf() +EndIf() - If(ASMJIT_STATIC) - List(APPEND ASMJIT_CFLAGS -DASMJIT_STATIC) - EndIf() +# Static library. +If(ASMJIT_STATIC) + List(APPEND ASMJIT_CFLAGS "${ASMJIT_DEFINE}ASMJIT_STATIC") EndIf() # 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}) EndIf() Else() - Target_Compile_Options(${in_name} PUBLIC - ${in_cflags} + Target_Compile_Options(${in_name} PUBLIC ${in_cflags} $<$:${in_cflags_dbg}> $<$>:${in_cflags_rel}>) EndIf() @@ -228,6 +235,7 @@ AsmJit_AddSource(ASMJIT_SRC asmjit/base func.h globals.cpp globals.h + intutil.cpp intutil.h lock.h logger.cpp @@ -269,10 +277,12 @@ AsmJit_AddSource(ASMJIT_SRC asmjit/x86 x86util.h ) +If(ASMJIT_BUILD_CONTRIB) AsmJit_AddSource(ASMJIT_SRC asmjit/contrib winremoteruntime.cpp winremoteruntime.h ) +EndIf() # ============================================================================= # [AsmJit - Headers] @@ -305,6 +315,41 @@ If(NOT ASMJIT_EMBED) ) 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} + $<$:${ASMJIT_CFLAGS_DBG}> + $<$>:${ASMJIT_CFLAGS_REL}>) + EndIf() + + Set_Target_Properties(asmjit_test PROPERTIES LINK_FLAGS "${ASMJIT_LFLAGS}") +EndIf() + # ============================================================================= # [Asmjit - Samples] # ============================================================================= @@ -312,12 +357,7 @@ EndIf() If(ASMJIT_BUILD_SAMPLES) Set(ASMJIT_SRC_SAMPLES benchx86 - testcpu - testdummy - testmem testopcode - testpool - testsizeof testx86 ) diff --git a/src/app/test/testcpu.cpp b/src/app/test/testcpu.cpp deleted file mode 100644 index 19455a7..0000000 --- a/src/app/test/testcpu.cpp +++ /dev/null @@ -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 - -// [Dependencies - C] -#include -#include -#include - -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(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; -} diff --git a/src/app/test/testdummy.cpp b/src/app/test/testdummy.cpp deleted file mode 100644 index 88de4e6..0000000 --- a/src/app/test/testdummy.cpp +++ /dev/null @@ -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 - -// [Dependencies - C] -#include -#include -#include - -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()); - c.endFunc(); - - MyFunc func = asmjit_cast(c.make()); - func(); - - runtime.release((void*)func); - return 0; -} diff --git a/src/app/test/testmem.cpp b/src/app/test/testmem.cpp deleted file mode 100644 index 313585b..0000000 --- a/src/app/test/testmem.cpp +++ /dev/null @@ -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 - -// [Dependencies - C] -#include -#include -#include - -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(memmgr.getUsedBytes())); - printf("-- Allocated: %d\n", - static_cast(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(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; -} diff --git a/src/app/test/testpool.cpp b/src/app/test/testpool.cpp deleted file mode 100644 index 4d612f6..0000000 --- a/src/app/test/testpool.cpp +++ /dev/null @@ -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 - -// [Dependencies - C] -#include -#include -#include - -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; -} diff --git a/src/app/test/testsizeof.cpp b/src/app/test/testsizeof.cpp deleted file mode 100644 index 61582c5..0000000 --- a/src/app/test/testsizeof.cpp +++ /dev/null @@ -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 - -#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64) -#include -#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64 - -// [Dependencies - C] -#include -#include -#include - -using namespace asmjit; - -int main(int argc, char* argv[]) { - // -------------------------------------------------------------------------- - // [Runtime] - // -------------------------------------------------------------------------- - - printf("Sizeof[Runtime]:\n"); - printf(" int8_t : %u\n", static_cast(sizeof(int8_t))); - printf(" int16_t : %u\n", static_cast(sizeof(int16_t))); - printf(" int32_t : %u\n", static_cast(sizeof(int32_t))); - printf(" int64_t : %u\n", static_cast(sizeof(int64_t))); - printf(" long : %u\n", static_cast(sizeof(long))); - printf(" size_t : %u\n", static_cast(sizeof(size_t))); - printf(" intptr_t : %u\n", static_cast(sizeof(intptr_t))); - printf(" float : %u\n", static_cast(sizeof(float))); - printf(" double : %u\n", static_cast(sizeof(double))); - printf(" void* : %u\n", static_cast(sizeof(void*))); - printf("\n"); - - // -------------------------------------------------------------------------- - // [Core] - // -------------------------------------------------------------------------- - - printf("Sizeof[Base]:\n"); - printf(" asmjit::CodeGen : %u\n", static_cast(sizeof(CodeGen))); - printf(" asmjit::BaseAssembler : %u\n", static_cast(sizeof(BaseAssembler))); - printf(" asmjit::BaseCompiler : %u\n", static_cast(sizeof(BaseCompiler))); - printf(" asmjit::Runtime : %u\n", static_cast(sizeof(Runtime))); - printf("\n"); - printf(" asmjit::Operand : %u\n", static_cast(sizeof(Operand))); - printf(" asmjit::BaseReg : %u\n", static_cast(sizeof(BaseReg))); - printf(" asmjit::BaseVar : %u\n", static_cast(sizeof(BaseVar))); - printf(" asmjit::BaseMem : %u\n", static_cast(sizeof(BaseMem))); - printf(" asmjit::Imm : %u\n", static_cast(sizeof(Imm))); - printf(" asmjit::Label : %u\n", static_cast(sizeof(Label))); - printf("\n"); - printf(" asmjit::Ptr : %u\n", static_cast(sizeof(Ptr))); - printf(" asmjit::SignedPtr : %u\n", static_cast(sizeof(SignedPtr))); - printf("\n"); - printf(" asmjit::LabelData : %u\n", static_cast(sizeof(LabelData))); - printf(" asmjit::RelocData : %u\n", static_cast(sizeof(RelocData))); - printf("\n"); - printf(" asmjit::Node : %u\n", static_cast(sizeof(Node))); - printf(" asmjit::AlignNode : %u\n", static_cast(sizeof(AlignNode))); - printf(" asmjit::CallNode : %u\n", static_cast(sizeof(CallNode))); - printf(" asmjit::CommentNode : %u\n", static_cast(sizeof(CommentNode))); - printf(" asmjit::EmbedNode : %u\n", static_cast(sizeof(EmbedNode))); - printf(" asmjit::FuncNode : %u\n", static_cast(sizeof(FuncNode))); - printf(" asmjit::EndNode : %u\n", static_cast(sizeof(EndNode))); - printf(" asmjit::InstNode : %u\n", static_cast(sizeof(InstNode))); - printf(" asmjit::JumpNode : %u\n", static_cast(sizeof(JumpNode))); - printf(" asmjit::TargetNode : %u\n", static_cast(sizeof(TargetNode))); - printf("\n"); - printf(" asmjit::FuncDecl : %u\n", static_cast(sizeof(FuncDecl))); - printf(" asmjit::FuncInOut : %u\n", static_cast(sizeof(FuncInOut))); - printf(" asmjit::FuncPrototype : %u\n", static_cast(sizeof(FuncPrototype))); - printf("\n"); - printf(" asmjit::VarAttr : %u\n", static_cast(sizeof(VarAttr))); - printf(" asmjit::VarData : %u\n", static_cast(sizeof(VarData))); - printf(" asmjit::BaseVarInst : %u\n", static_cast(sizeof(BaseVarInst))); - printf(" asmjit::BaseVarState : %u\n", static_cast(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(sizeof(x86x64::X86X64Assembler))); - printf(" asmjit::x86x64::X86X64Compiler : %u\n", static_cast(sizeof(x86x64::X86X64Compiler))); - printf("\n"); - printf(" asmjit::x86x64::X86X64CallNode : %u\n", static_cast(sizeof(x86x64::X86X64CallNode))); - printf(" asmjit::x86x64::X86X64FuncNode : %u\n", static_cast(sizeof(x86x64::X86X64FuncNode))); - printf("\n"); - printf(" asmjit::x86x64::X86X64FuncDecl : %u\n", static_cast(sizeof(x86x64::X86X64FuncDecl))); - printf("\n"); - printf(" asmjit::x86x64::VarInst : %u\n", static_cast(sizeof(x86x64::VarInst))); - printf(" asmjit::x86x64::VarState : %u\n", static_cast(sizeof(x86x64::VarState))); - printf("\n"); - printf(" asmjit::x86x64::InstInfo : %u\n", static_cast(sizeof(x86x64::InstInfo))); - printf(" asmjit::x86x64::VarInfo : %u\n", static_cast(sizeof(x86x64::VarInfo))); - printf("\n"); -#endif // ASMJIT_BUILD_X86 - - return 0; -} diff --git a/src/asmjit/base/constpool.cpp b/src/asmjit/base/constpool.cpp index 51ad806..d89f6cc 100644 --- a/src/asmjit/base/constpool.cpp +++ b/src/asmjit/base/constpool.cpp @@ -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 // [Api-End] diff --git a/src/asmjit/base/error.h b/src/asmjit/base/error.h index 11d135a..47cace3 100644 --- a/src/asmjit/base/error.h +++ b/src/asmjit/base/error.h @@ -114,9 +114,9 @@ struct ErrorHandler { // [Construction / Destruction] // -------------------------------------------------------------------------- - //! Create a new `ErrorHandler`. + //! Create a new `ErrorHandler` instance. ASMJIT_API ErrorHandler(); - //! Destroy the `ErrorHandler`. + //! Destroy the `ErrorHandler` instance. ASMJIT_API virtual ~ErrorHandler(); // -------------------------------------------------------------------------- @@ -142,17 +142,18 @@ struct ErrorHandler { //! //! Error handler is called when an error happened. An error can happen in //! 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 //! and each has it's pros/cons. //! //! AsmJit library doesn't use exceptions and can be compiled with or without - //! exception feature support. Even if the AsmJit library is compiled without + //! 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 `BaseAssembler` or `BaseCompiler`. Alternative to throwing - //! exception is using setjmp() / longjmp() pair from the standard C library. + //! calling AsmJit `BaseAssembler` or `BaseCompiler` 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 `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 //! be also stored in `BaseAssembler` or `BaseCompiler`. //! - //! Finally, if exceptions nor setjmp() / longjmp() mechanisms were used, - //! you can still implement a compatible design by returning from your error - //! handler. Returning `true` means that error was reported and AsmJit - //! should continue execution. When `false` is returned, AsmJit sets the - //! error immediately to the `BaseAssembler` or `BaseCompiler` and execution - //! shouldn't continue (this is the default behavior in case no error handler - //! is used). + //! 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 + //! `BaseAssembler` or `BaseCompiler` 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; }; diff --git a/src/asmjit/base/intutil.cpp b/src/asmjit/base/intutil.cpp new file mode 100644 index 0000000..c377399 --- /dev/null +++ b/src/asmjit/base/intutil.cpp @@ -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::kIsSigned, + "IntTraits should report signed."); + EXPECT(IntTraits::kIsUnsigned, + "IntTraits should report unsigned."); + + EXPECT(IntTraits::kIsSigned, + "IntTraits should report signed."); + EXPECT(IntTraits::kIsUnsigned, + "IntTraits should report unsigned."); + + EXPECT(IntTraits::kIsSigned, + "IntTraits should report signed."); + EXPECT(IntTraits::kIsUnsigned, + "IntTraits should report unsigned."); + + EXPECT(IntTraits::kIsSigned, + "IntTraits should report signed."); + EXPECT(IntTraits::kIsUnsigned, + "IntTraits should report unsigned."); + + EXPECT(IntTraits::kIsSigned, + "IntTraits should report signed."); + EXPECT(IntTraits::kIsUnsigned, + "IntTraits should report unsigned."); + + EXPECT(IntTraits::kIsIntPtr, + "IntTraits should report intptr_t type."); + EXPECT(IntTraits::kIsIntPtr, + "IntTraits should report intptr_t type."); + + INFO("IntUtil::iMin()/iMax()."); + EXPECT(IntUtil::iMin(0, -1) == -1, + "IntUtil::iMin should return a minimum value."); + EXPECT(IntUtil::iMin(-1, -2) == -2, + "IntUtil::iMin should return a minimum value."); + EXPECT(IntUtil::iMin(1, 2) == 1, + "IntUtil::iMin should return a minimum value."); + + EXPECT(IntUtil::iMax(0, -1) == 0, + "IntUtil::iMax should return a maximum value."); + EXPECT(IntUtil::iMax(-1, -2) == -1, + "IntUtil::iMax should return a maximum value."); + EXPECT(IntUtil::iMax(1, 2) == 2, + "IntUtil::iMax should return a maximum value."); + + INFO("IntUtil::inInterval()."); + EXPECT(IntUtil::inInterval(11, 10, 20) == true, + "IntUtil::inInterval should return true if inside."); + EXPECT(IntUtil::inInterval(101, 10, 20) == false, + "IntUtil::inInterval should return false if outside."); + + INFO("IntUtil::isInt?()."); + EXPECT(IntUtil::isInt8(-128) == true, + "IntUtil::isInt8 should return true if >= -128."); + EXPECT(IntUtil::isInt8(127) == true, + "IntUtil::isInt8 should return true if <= 127."); + EXPECT(IntUtil::isInt8(-129) == false, + "IntUtil::isInt8 should return false if < -128."); + EXPECT(IntUtil::isInt8(128) == false, + "IntUtil::isInt8 should return false if > 127."); + + EXPECT(IntUtil::isInt16(-32768) == true, + "IntUtil::isInt16 should return true if >= -32768."); + EXPECT(IntUtil::isInt16(32767) == true, + "IntUtil::isInt16 should return true if <= 32767."); + EXPECT(IntUtil::isInt16(-32769) == false, + "IntUtil::isInt16 should return false if < -32768."); + EXPECT(IntUtil::isInt16(32768) == false, + "IntUtil::isInt16 should return false if > 32767."); + + EXPECT(IntUtil::isInt32(ASMJIT_UINT64_C(0x100000000)) == false, + "IntUtil::isInt32 should return false if outside."); + EXPECT(IntUtil::isInt32(ASMJIT_UINT64_C(0x100000000)) == false, + "IntUtil::isInt32 should return false if outside."); + + INFO("IntUtil::isPower2()."); + for (i = 0; i < 64; i++) { + EXPECT(IntUtil::isPowerOf2(static_cast(1) << i) == true, + "IntUtil::isPower2() didn't report power of 2."); + EXPECT(IntUtil::isPowerOf2((static_cast(1) << i) ^ 0x001101) == false, + "IntUtil::isPower2() didn't report not power of 2."); + } + + INFO("IntUtil::mask()."); + for (i = 0; i < 32; i++) { + EXPECT(IntUtil::mask(i) == (1 << i), + "IntUtil::mask(%u) should return %X.", i, (1 << i)); + } + + INFO("IntUtil::bits()."); + for (i = 0; i < 32; i++) { + uint32_t expectedBits = 0; + + for (uint32_t b = 0; b < i; b++) + expectedBits |= static_cast(1) << b; + + EXPECT(IntUtil::bits(i) == expectedBits, + "IntUtil::bits(%u) should return %X.", i, expectedBits); + } + + INFO("IntUtil::hasBit()."); + for (i = 0; i < 32; i++) { + EXPECT(IntUtil::hasBit((1 << i), i) == true, + "IntUtil::hasBit(%X, %u) should return true.", (1 << i), i); + } + + INFO("IntUtil::bitCount()."); + for (i = 0; i < 32; i++) { + EXPECT(IntUtil::bitCount((1 << i)) == 1, + "IntUtil::bitCount(%X) should return true.", (1 << i)); + } + EXPECT(IntUtil::bitCount(0x000000F0) == 4, ""); + EXPECT(IntUtil::bitCount(0x10101010) == 4, ""); + EXPECT(IntUtil::bitCount(0xFF000000) == 8, ""); + EXPECT(IntUtil::bitCount(0xFFFFFFF7) == 31, ""); + EXPECT(IntUtil::bitCount(0x7FFFFFFF) == 31, ""); + + INFO("IntUtil::findFirstBit()."); + for (i = 0; i < 32; i++) { + EXPECT(IntUtil::findFirstBit((1 << i)) == i, + "IntUtil::findFirstBit(%X) should return %u.", (1 << i), i); + } + + INFO("IntUtil::isAligned()."); + EXPECT(IntUtil::isAligned(0xFFFF, 4) == false, ""); + EXPECT(IntUtil::isAligned(0xFFF4, 4) == true , ""); + EXPECT(IntUtil::isAligned(0xFFF8, 8) == true , ""); + EXPECT(IntUtil::isAligned(0xFFF0, 16) == true , ""); + + INFO("IntUtil::alignTo()."); + EXPECT(IntUtil::alignTo(0xFFFF, 4) == 0x10000, ""); + EXPECT(IntUtil::alignTo(0xFFF4, 4) == 0x0FFF4, ""); + EXPECT(IntUtil::alignTo(0xFFF8, 8) == 0x0FFF8, ""); + EXPECT(IntUtil::alignTo(0xFFF0, 16) == 0x0FFF0, ""); + EXPECT(IntUtil::alignTo(0xFFF0, 32) == 0x10000, ""); + + INFO("IntUtil::alignToPowerOf2()."); + EXPECT(IntUtil::alignToPowerOf2(0xFFFF) == 0x10000, ""); + EXPECT(IntUtil::alignToPowerOf2(0xF123) == 0x10000, ""); + EXPECT(IntUtil::alignToPowerOf2(0x0F00) == 0x01000, ""); + EXPECT(IntUtil::alignToPowerOf2(0x0100) == 0x00100, ""); + EXPECT(IntUtil::alignToPowerOf2(0x1001) == 0x02000, ""); + + INFO("IntUtil::deltaTo()."); + EXPECT(IntUtil::deltaTo(0xFFFF, 4) == 1, ""); + EXPECT(IntUtil::deltaTo(0xFFF4, 4) == 0, ""); + EXPECT(IntUtil::deltaTo(0xFFF8, 8) == 0, ""); + EXPECT(IntUtil::deltaTo(0xFFF0, 16) == 0, ""); + EXPECT(IntUtil::deltaTo(0xFFF0, 32) == 16, ""); +} +#endif // ASMJIT_TEST + +} // asmjit namespace + +// [Api-End] +#include "../apiend.h" diff --git a/src/asmjit/base/intutil.h b/src/asmjit/base/intutil.h index 83114f5..4214d4b 100644 --- a/src/asmjit/base/intutil.h +++ b/src/asmjit/base/intutil.h @@ -31,7 +31,7 @@ namespace asmjit { template struct IntTraits { enum { - kIsSigned = (~static_cast(0)) < static_cast(0), + kIsSigned = static_cast(~static_cast(0)) < static_cast(0), kIsUnsigned = !kIsSigned, kIs8Bit = sizeof(T) == 1, @@ -402,31 +402,11 @@ struct IntUtil { return (base + (alignment - 1)) & ~(alignment - 1); } - //! Get delta required to align `base` to `alignment`. template - static ASMJIT_INLINE T deltaTo(T base, T alignment) { - return alignTo(base, alignment) - base; - } - - // -------------------------------------------------------------------------- - // [AsmJit - Round] - // -------------------------------------------------------------------------- - - template - static ASMJIT_INLINE T roundUp(T base, T alignment) { - T over = base % alignment; - return base + (over > 0 ? alignment - over : 0); - } - - template - 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. + static ASMJIT_INLINE T alignToPowerOf2(T base) { + // Implementation is from "Hacker's Delight" by Henry S. Warren, Jr. base -= 1; - // I'm trying to make this portable and MSVC strikes me the warning C4293: - // "Shift count negative or too big, undefined behavior" - // Fixing... #if defined(_MSC_VER) # pragma warning(push) # pragma warning(disable: 4293) @@ -448,6 +428,12 @@ struct IntUtil { return base + 1; } + + //! Get delta required to align `base` to `alignment`. + template + static ASMJIT_INLINE T deltaTo(T base, T alignment) { + return alignTo(base, alignment) - base; + } }; // ============================================================================ diff --git a/src/asmjit/base/vmem.cpp b/src/asmjit/base/vmem.cpp index 31a9f50..a8f96b6 100644 --- a/src/asmjit/base/vmem.cpp +++ b/src/asmjit/base/vmem.cpp @@ -78,7 +78,7 @@ struct VMemLocal { hProcess = GetCurrentProcess(); alignment = info.dwAllocationGranularity; - pageSize = IntUtil::roundUpToPowerOf2(info.dwPageSize); + pageSize = IntUtil::alignToPowerOf2(info.dwPageSize); } HANDLE hProcess; @@ -99,27 +99,38 @@ size_t VMemUtil::getPageSize() { return vm().pageSize; } -void* VMemUtil::alloc(size_t length, size_t* allocated, bool canExecute) { - return allocProcessMemory(static_cast(0), length, allocated, canExecute); +void* VMemUtil::alloc(size_t length, size_t* allocated, uint32_t flags) { + return allocProcessMemory(static_cast(0), length, allocated, flags); } void VMemUtil::release(void* addr, size_t length) { return releaseProcessMemory(static_cast(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(); if (hProcess == static_cast(0)) hProcess = vmLocal.hProcess; // 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). - WORD protect = canExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; - LPVOID mBase = VirtualAllocEx(hProcess, NULL, mSize, MEM_COMMIT | MEM_RESERVE, protect); + 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; @@ -170,9 +181,12 @@ size_t VMemUtil::getPageSize() { return vm().pageSize; } -void* VMemUtil::alloc(size_t length, size_t* allocated, bool canExecute) { - size_t msize = IntUtil::roundUp(length, vm().pageSize); - int protection = PROT_READ | PROT_WRITE | (canExecute ? PROT_EXEC : 0); +void* VMemUtil::alloc(size_t length, size_t* allocated, uint32_t flags) { + size_t msize = IntUtil::alignTo(length, vm().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) @@ -360,10 +374,11 @@ struct VMemPrivate { // Helpers to avoid ifdefs in the code. ASMJIT_INLINE uint8_t* allocVirtualMemory(size_t size, size_t* vsize) { + uint32_t flags = kVMemFlagWritable | kVMemFlagExecutable; #if !defined(ASMJIT_OS_WINDOWS) - return (uint8_t*)VMemUtil::alloc(size, vsize, true); + return (uint8_t*)VMemUtil::alloc(size, vsize, flags); #else - return (uint8_t*)VMemUtil::allocProcessMemory(_hProcess, size, vsize, true); + return (uint8_t*)VMemUtil::allocProcessMemory(_hProcess, size, vsize, flags); #endif } @@ -1204,4 +1219,141 @@ Error VMemMgr::shrink(void* address, size_t 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(memmgr.getUsedBytes())); + INFO("Allocated: %u", static_cast(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(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(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 diff --git a/src/asmjit/base/vmem.h b/src/asmjit/base/vmem.h index 5a5ee18..0b115b6 100644 --- a/src/asmjit/base/vmem.h +++ b/src/asmjit/base/vmem.h @@ -31,6 +31,18 @@ ASMJIT_ENUM(kVMemAlloc) { 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] // ============================================================================ @@ -58,7 +70,7 @@ struct VMemUtil { //! Pages are readable/writeable, but they are not guaranteed to be //! executable unless 'canExecute' is true. Returns the address of //! allocated memory, or NULL on failure. - static ASMJIT_API void* alloc(size_t length, size_t* allocated, bool canExecute); + static ASMJIT_API void* alloc(size_t length, size_t* allocated, uint32_t flags); //! Free memory allocated by `alloc()`. static ASMJIT_API void release(void* addr, size_t length); @@ -67,7 +79,7 @@ struct VMemUtil { //! Allocate virtual memory of `hProcess`. //! //! \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`. //! @@ -164,7 +176,7 @@ struct VMemMgr { //! \internal //! - //! Pointer to private data hidden out of the public API. + //! Pointer to a private data hidden from the public API. void* _d; }; diff --git a/src/asmjit/build.h b/src/asmjit/build.h index 03b904a..c3d26b5 100644 --- a/src/asmjit/build.h +++ b/src/asmjit/build.h @@ -10,7 +10,7 @@ // [Include] #if !defined(ASMJIT_CONFIG_FILE) -#include "config.h" +#include "./config.h" #endif // !ASMJIT_CONFIG_FILE // Turn off deprecation warnings when compiling AsmJit. @@ -303,5 +303,14 @@ typedef unsigned __int64 uint64_t; #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] #endif // _ASMJIT_BUILD_H diff --git a/src/asmjit/contrib/winremoteruntime.h b/src/asmjit/contrib/winremoteruntime.h index 69cd09e..da39344 100644 --- a/src/asmjit/contrib/winremoteruntime.h +++ b/src/asmjit/contrib/winremoteruntime.h @@ -8,10 +8,7 @@ #ifndef _ASMJIT_CONTRIB_WINREMOTERUNTIME_H #define _ASMJIT_CONTRIB_WINREMOTERUNTIME_H -// [Dependencies] #include "../base.h" - -// [Guard - Windows] #if defined(ASMJIT_OS_WINDOWS) namespace asmjit { @@ -72,8 +69,6 @@ struct WinRemoteRuntime : public Runtime { } // contrib namespace } // asmjit namespace -// [Guard - Windows] -#endif // ASMJIT_OS_WINDOWS - // [Guard] +#endif // ASMJIT_OS_WINDOWS #endif // _ASMJIT_CONTRIB_WINREMOTERUNTIME_H diff --git a/src/asmjit/test/main.cpp b/src/asmjit/test/main.cpp new file mode 100644 index 0000000..4b13b8e --- /dev/null +++ b/src/asmjit/test/main.cpp @@ -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(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(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; +} diff --git a/src/asmjit/test/test.cpp b/src/asmjit/test/test.cpp new file mode 100644 index 0000000..9627c35 --- /dev/null +++ b/src/asmjit/test/test.cpp @@ -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 = ¤t->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); +} diff --git a/src/asmjit/test/test.h b/src/asmjit/test/test.h new file mode 100644 index 0000000..6c8398c --- /dev/null +++ b/src/asmjit/test/test.h @@ -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 +#include +#include +#include + +//! \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 diff --git a/src/asmjit/x86/x86inst.cpp b/src/asmjit/x86/x86inst.cpp index d2cf363..6124fd3 100644 --- a/src/asmjit/x86/x86inst.cpp +++ b/src/asmjit/x86/x86inst.cpp @@ -309,8 +309,8 @@ const char _instName[] = "minsd\0" "minss\0" "monitor\0" - "mov_ptr\0" "mov\0" + "mov_ptr\0" "movapd\0" "movaps\0" "movbe\0" @@ -1376,8 +1376,8 @@ enum kInstData_NameIndex { kInstMinsd_NameIndex = 1746, kInstMinss_NameIndex = 1752, kInstMonitor_NameIndex = 1758, - kInstMovPtr_NameIndex = 1766, - kInstMov_NameIndex = 1774, + kInstMov_NameIndex = 1766, + kInstMovPtr_NameIndex = 1770, kInstMovapd_NameIndex = 1778, kInstMovaps_NameIndex = 1785, 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(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(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(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(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) ), @@ -3324,6 +3324,37 @@ uint32_t X86InstUtil::getInstIdByName(const char* name, size_t len) { 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 } // asmjit namespace diff --git a/src/asmjit/x86/x86inst.h b/src/asmjit/x86/x86inst.h index ca81825..8eb0f98 100644 --- a/src/asmjit/x86/x86inst.h +++ b/src/asmjit/x86/x86inst.h @@ -334,8 +334,8 @@ ASMJIT_ENUM(kInstCode) { kInstMinsd, // SSE2 kInstMinss, // SSE kInstMonitor, // SSE3 - kInstMovPtr, // X86/X64 kInstMov, // X86/X64 + kInstMovPtr, // X86/X64 kInstMovapd, // SSE2 kInstMovaps, // SSE kInstMovbe, // SSE3 - Intel-Atom diff --git a/src/asmjit/x86/x86regs.h b/src/asmjit/x86/x86regs.h index 6b13734..98e72a1 100644 --- a/src/asmjit/x86/x86regs.h +++ b/src/asmjit/x86/x86regs.h @@ -159,7 +159,7 @@ ASMJIT_ENUM(kRegIndex) { //! X86/X64 segment codes. ASMJIT_ENUM(kSeg) { - //! No segment. + //! No/Default segment. kSegDefault = 0, //! Es segment. kSegEs = 1, diff --git a/tools/configure-mac-xcode.sh b/tools/configure-mac-xcode.sh index 2ed9b71..e86b356 100644 --- a/tools/configure-mac-xcode.sh +++ b/tools/configure-mac-xcode.sh @@ -5,5 +5,5 @@ ASMJIT_BUILD_DIR="build_xcode" mkdir ../${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} diff --git a/tools/configure-unix-makefiles-dbg.sh b/tools/configure-unix-makefiles-dbg.sh index e83283c..84ca80a 100644 --- a/tools/configure-unix-makefiles-dbg.sh +++ b/tools/configure-unix-makefiles-dbg.sh @@ -5,5 +5,5 @@ ASMJIT_BUILD_DIR="build_makefiles_dbg" mkdir ../${ASMJIT_BUILD_DIR} cd ../${ASMJIT_BUILD_DIR} -cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_SAMPLES=1 +cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cd ${ASMJIT_CURRENT_DIR} diff --git a/tools/configure-unix-makefiles-rel.sh b/tools/configure-unix-makefiles-rel.sh index b15b157..d999f2a 100644 --- a/tools/configure-unix-makefiles-rel.sh +++ b/tools/configure-unix-makefiles-rel.sh @@ -5,5 +5,5 @@ ASMJIT_BUILD_DIR="build_makefiles_rel" mkdir ../${ASMJIT_BUILD_DIR} cd ../${ASMJIT_BUILD_DIR} -cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_SAMPLES=1 +cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cd ${ASMJIT_CURRENT_DIR} diff --git a/tools/configure-win-mingw-dbg.bat b/tools/configure-win-mingw-dbg.bat index bf18899..c68740b 100644 --- a/tools/configure-win-mingw-dbg.bat +++ b/tools/configure-win-mingw-dbg.bat @@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_mingw_dbg" mkdir ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR% -cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_SAMPLES=1 +cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cd %ASMJIT_CURRENT_DIR% diff --git a/tools/configure-win-mingw-rel.bat b/tools/configure-win-mingw-rel.bat index fc98213..047a60e 100644 --- a/tools/configure-win-mingw-rel.bat +++ b/tools/configure-win-mingw-rel.bat @@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_mingw_rel" mkdir ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR% -cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_SAMPLES=1 +cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cd %ASMJIT_CURRENT_DIR% diff --git a/tools/configure-win-vs2005-x64.bat b/tools/configure-win-vs2005-x64.bat index 65b2cf0..3542bb4 100644 --- a/tools/configure-win-vs2005-x64.bat +++ b/tools/configure-win-vs2005-x64.bat @@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2005_x64" mkdir ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR% -cmake .. -G"Visual Studio 8 2005 Win64" -DASMJIT_BUILD_SAMPLES=1 +cmake .. -G"Visual Studio 8 2005 Win64" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cd %ASMJIT_CURRENT_DIR% diff --git a/tools/configure-win-vs2005-x86.bat b/tools/configure-win-vs2005-x86.bat index 9482087..693cd26 100644 --- a/tools/configure-win-vs2005-x86.bat +++ b/tools/configure-win-vs2005-x86.bat @@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2005_x86" mkdir ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR% -cmake .. -G"Visual Studio 8 2005" -DASMJIT_BUILD_SAMPLES=1 +cmake .. -G"Visual Studio 8 2005" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cd %ASMJIT_CURRENT_DIR% diff --git a/tools/configure-win-vs2008-x64.bat b/tools/configure-win-vs2008-x64.bat index 7b1f81d..fc88c64 100644 --- a/tools/configure-win-vs2008-x64.bat +++ b/tools/configure-win-vs2008-x64.bat @@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2008_x64" mkdir ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR% -cmake .. -G"Visual Studio 9 2008 Win64" -DASMJIT_BUILD_SAMPLES=1 +cmake .. -G"Visual Studio 9 2008 Win64" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cd %ASMJIT_CURRENT_DIR% diff --git a/tools/configure-win-vs2008-x86.bat b/tools/configure-win-vs2008-x86.bat index 12d4bb3..f252b83 100644 --- a/tools/configure-win-vs2008-x86.bat +++ b/tools/configure-win-vs2008-x86.bat @@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2008_x86" mkdir ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR% -cmake .. -G"Visual Studio 9 2008" -DASMJIT_BUILD_SAMPLES=1 +cmake .. -G"Visual Studio 9 2008" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cd %ASMJIT_CURRENT_DIR% diff --git a/tools/configure-win-vs2010-x64.bat b/tools/configure-win-vs2010-x64.bat index b7c5eb4..10623f9 100644 --- a/tools/configure-win-vs2010-x64.bat +++ b/tools/configure-win-vs2010-x64.bat @@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2010_x64" mkdir ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR% -cmake .. -G"Visual Studio 10 Win64" -DASMJIT_BUILD_SAMPLES=1 +cmake .. -G"Visual Studio 10 Win64" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cd %ASMJIT_CURRENT_DIR% diff --git a/tools/configure-win-vs2010-x86.bat b/tools/configure-win-vs2010-x86.bat index ec07acd..3db715a 100644 --- a/tools/configure-win-vs2010-x86.bat +++ b/tools/configure-win-vs2010-x86.bat @@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2010_x86" mkdir ..\%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% diff --git a/tools/configure-win-vs2013-x64.bat b/tools/configure-win-vs2013-x64.bat index 13d7318..f79cbff 100644 --- a/tools/configure-win-vs2013-x64.bat +++ b/tools/configure-win-vs2013-x64.bat @@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2013_x64" mkdir ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR% -cmake .. -G"Visual Studio 12 Win64" -DASMJIT_BUILD_SAMPLES=1 +cmake .. -G"Visual Studio 12 Win64" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cd %ASMJIT_CURRENT_DIR% diff --git a/tools/configure-win-vs2013-x86.bat b/tools/configure-win-vs2013-x86.bat index a068f8e..1cc8b1d 100644 --- a/tools/configure-win-vs2013-x86.bat +++ b/tools/configure-win-vs2013-x86.bat @@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2013_x86" mkdir ..\%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%