From 7fdb4f73bc87d1cbfa45b8d2dfc7fe9efd97c861 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 22 May 2015 02:38:25 +0300 Subject: [PATCH 1/3] Delta JIT improvements. --- rehlds/engine/delta.cpp | 103 ++++++++++++++-- rehlds/engine/delta.h | 13 +- rehlds/engine/delta_jit.cpp | 161 +++++++++++++++++-------- rehlds/engine/delta_jit.h | 4 +- rehlds/unittests/delta_tests.cpp | 199 ++++++++++++++++++++----------- 5 files changed, 343 insertions(+), 137 deletions(-) diff --git a/rehlds/engine/delta.cpp b/rehlds/engine/delta.cpp index 9c47c84..a57e69a 100644 --- a/rehlds/engine/delta.cpp +++ b/rehlds/engine/delta.cpp @@ -349,41 +349,69 @@ int DELTA_FindFieldIndex(struct delta_s *pFields, const char *fieldname) } Con_Printf(__FUNCTION__ ": Warning, couldn't find %s\n", fieldname); - return NULL; + return -1; } /* <24032> ../engine/delta.c:393 */ void DELTA_SetField(struct delta_s *pFields, const char *fieldname) { +#if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) + int index = DELTA_FindFieldIndex(pFields, fieldname); + + if (index != -1) + DELTA_SetFieldByIndex(pFields, index); +#else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES delta_description_t *pTest = DELTA_FindField(pFields, fieldname); - + if (pTest) { pTest->flags |= FDT_MARK; } +#endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES } /* <240b2> ../engine/delta.c:411 */ void DELTA_UnsetField(struct delta_s *pFields, const char *fieldname) { +#if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) + int index = DELTA_FindFieldIndex(pFields, fieldname); + + if (index != -1) + DELTA_UnsetFieldByIndex(pFields, index); +#else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES delta_description_t *pTest = DELTA_FindField(pFields, fieldname); - + if (pTest) { pTest->flags &= ~FDT_MARK; } +#endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES } /* <24132> ../engine/delta.c:429 */ void DELTA_SetFieldByIndex(struct delta_s *pFields, int fieldNumber) { +#if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) + if (fieldNumber > 31) + pFields->markbits[1] |= (1 << (fieldNumber & 0x1F)); + else + pFields->markbits[0] |= (1 << fieldNumber); +#else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES pFields->pdd[fieldNumber].flags |= FDT_MARK; +#endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES } /* <2416a> ../engine/delta.c:441 */ void DELTA_UnsetFieldByIndex(struct delta_s *pFields, int fieldNumber) { +#if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) + if (fieldNumber > 31) + pFields->markbits[1] &= ~(1 << (fieldNumber & 0x1F)); + else + pFields->markbits[0] &= ~(1 << fieldNumber); +#else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES pFields->pdd[fieldNumber].flags &= ~FDT_MARK; +#endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES } /* <23cc4> ../engine/delta.c:453 */ @@ -439,6 +467,9 @@ int DELTA_TestDelta(unsigned char *from, unsigned char *to, delta_t *pFields) st2 = (char*)&to[pTest->fieldOffset]; if (!(!*st1 && !*st2 || *st1 && *st2 && !Q_stricmp(st1, st2))) // Not sure why it is case insensitive, but it looks so { +#ifdef REHLDS_FIXES + different = TRUE; +#endif // REHLDS_FIXES length = Q_strlen(st2); } break; @@ -563,7 +594,25 @@ void DELTA_SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount) lastbit = bitnumber; } } + +#ifdef REHLDS_FIXES + // fix potencial buffer overflow in force mode if lastbit == -1 + *bytecount = ((lastbit + 7) & ~7) >> 3; +#else // REHLDS_FIXES *bytecount = (lastbit >> 3) + 1; +#endif // REHLDS_FIXES +} + +qboolean DELTA_IsFieldMarked(delta_t* pFields, int fieldNumber) +{ +#ifdef REHLDS_FIXES + if (fieldNumber > 31) + return pFields->markbits[1] & (1 << (fieldNumber & 0x1F)); + + return pFields->markbits[0] & (1 << fieldNumber); +#else // REHLDS_FIXES + return pFields->pdd[fieldNumber].flags & FDT_MARK; +#endif // REHLDS_FIXES } /* <2456d> ../engine/delta.c:782 */ @@ -579,8 +628,13 @@ void DELTA_WriteMarkedFields(unsigned char *from, unsigned char *to, delta_t *pF for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) { +#ifndef REHLDS_FIXES if (!(pTest->flags & FDT_MARK)) continue; +#else // REHLDS_FIXES + if (!DELTA_IsFieldMarked(pFields, i)) + continue; +#endif // REHLDS_FIXES fieldSign = pTest->fieldType & DT_SIGNED; fieldType = pTest->fieldType & ~DT_SIGNED; @@ -678,7 +732,7 @@ void DELTA_WriteMarkedFields(unsigned char *from, unsigned char *to, delta_t *pF } /* <2467e> ../engine/delta.c:924 */ -int DELTA_CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields) +qboolean DELTA_CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields) { int sendfields; @@ -694,25 +748,43 @@ int DELTA_CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields) } /* <247f5> ../engine/delta.c:949 */ -NOINLINE int DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void)) +NOINLINE qboolean DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void)) { - int sendfields; + qboolean sendfields; + int bytecount; #if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) - sendfields = DELTAJit_Feilds_Clear_Mark_Check(from, to, pFields); -#else + DELTAJit_ClearAndMarkSendFields(from, to, pFields, pFields->markbits, &bytecount, force); + _DELTA_WriteDelta(from, to, pFields, pFields->markbits, bytecount); + sendfields = bytecount; +#else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES + int bits[2]; DELTA_ClearFlags(pFields); DELTA_MarkSendFields(from, to, pFields); sendfields = DELTA_CountSendFields(pFields); -#endif - - //sendfields = DELTA_CountSendFields(pFields); _DELTA_WriteDelta(from, to, force, pFields, callback, sendfields); +#endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES + return sendfields; } +#if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) +int _DELTA_WriteDelta(unsigned char *from, unsigned char *to, delta_t *pFields, int* bits, int bytecount) +{ + int i; + + MSG_WriteBits(bytecount, 3); + for (i = 0; i < bytecount; i++) + { + MSG_WriteBits(( (byte*)bits )[i], 8); + } + + DELTA_WriteMarkedFields(from, to, pFields); + return 1; +} +#else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES /* <24760> ../engine/delta.c:963 */ -int _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void), int sendfields) +int _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)( void ), int sendfields) { int i; int bytecount; @@ -725,10 +797,14 @@ int _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, de if (callback) callback(); +#ifdef REHLDS_FIXES + bytecount &= 7; // max fields is 56, not 64 +#endif // REHLDS_FIXES + MSG_WriteBits(bytecount, 3); for (i = 0; i < bytecount; i++) { - MSG_WriteBits(((byte*)bits)[i], 8); + MSG_WriteBits(( (byte*)bits )[i], 8); } DELTA_WriteMarkedFields(from, to, pFields); @@ -736,6 +812,7 @@ int _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, de return 1; } +#endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES /* <24aa0> ../engine/delta.c:1010 */ int DELTA_ParseDelta(unsigned char *from, unsigned char *to, delta_t *pFields) diff --git a/rehlds/engine/delta.h b/rehlds/engine/delta.h index de253c3..23cb4e0 100644 --- a/rehlds/engine/delta.h +++ b/rehlds/engine/delta.h @@ -81,6 +81,8 @@ typedef struct delta_s #ifdef REHLDS_FIXES CDeltaJit* jit; + int markbits[2]; + int sse_highbits[2]; #endif } delta_t; @@ -134,10 +136,15 @@ int DELTA_TestDelta(unsigned char *from, unsigned char *to, delta_t *pFields); int DELTA_CountSendFields(delta_t *pFields); void DELTA_MarkSendFields(unsigned char *from, unsigned char *to, delta_t *pFields); void DELTA_SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount); +qboolean DELTA_IsFieldMarked(delta_t* pFields, int fieldNumber); void DELTA_WriteMarkedFields(unsigned char *from, unsigned char *to, delta_t *pFields); -int DELTA_CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields); -int DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void)); -int _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void), int sendfields); +qboolean DELTA_CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields); +qboolean DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)( void )); +#if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) +qboolean _DELTA_WriteDelta(unsigned char *from, unsigned char *to, delta_t *pFields, int* bits, int bytecount); +#else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES +qboolean _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void), int sendfields); +#endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES int DELTA_ParseDelta(unsigned char *from, unsigned char *to, delta_t *pFields); void DELTA_AddEncoder(char *name, void(*conditionalencode)(struct delta_s *, const unsigned char *, const unsigned char *)); void DELTA_ClearEncoders(void); diff --git a/rehlds/engine/delta_jit.cpp b/rehlds/engine/delta_jit.cpp index b50f759..77e65aa 100644 --- a/rehlds/engine/delta_jit.cpp +++ b/rehlds/engine/delta_jit.cpp @@ -107,7 +107,7 @@ void DELTAJIT_CreateDescription(delta_t* delta, deltajitdata_t &jitdesc) { } -class CDeltaClearMarkFieldsJIT : public jitasm::function { +class CDeltaClearMarkFieldsJIT : public jitasm::function { public: deltajitdata_t *jitdesc; deltajit_marked_count_type_t countType; @@ -118,16 +118,16 @@ public: } void checkFieldMask(jitasm::Frontend::Reg32& mask, deltajit_memblock_field* jitField); - Result main(Addr src, Addr dst, Addr delta); + Result main(Addr src, Addr dst, Addr delta, Addr bits, Addr bytecount, Addr force); void processStrings(Addr src, Addr dst, Addr delta); void callConditionalEncoder(Addr src, Addr dst, Addr delta); - void countMarkedFields(); + void calculateBytecount(Addr bits, Addr bytecount); }; void CDeltaClearMarkFieldsJIT::checkFieldMask(jitasm::Frontend::Reg32& mask, deltajit_memblock_field* jitField) { test(mask, (uint16)jitField->mask); setnz(al); - movzx(dx, al); + movzx(edx, al); } void CDeltaClearMarkFieldsJIT::callConditionalEncoder(Addr src, Addr dst, Addr delta) { @@ -137,7 +137,7 @@ void CDeltaClearMarkFieldsJIT::callConditionalEncoder(Addr src, Addr dst, Addr d int condEncoderOffset = (offsetof(delta_t, conditionalencode)); mov(eax, ptr[delta]); - mov(ecx, dword_ptr[eax + condEncoderOffset]); + or_(ecx, dword_ptr[eax + condEncoderOffset]); If(ecx != 0); push(edi); push(esi); @@ -148,53 +148,82 @@ void CDeltaClearMarkFieldsJIT::callConditionalEncoder(Addr src, Addr dst, Addr d EndIf(); } -void CDeltaClearMarkFieldsJIT::countMarkedFields() { - //This generator expects that following registers are already initialized: - // ebx = delta->pdd - // - //Returns value: 'changed flag' or count in eax +void CDeltaClearMarkFieldsJIT::calculateBytecount(Addr bits, Addr bytecount) { + mov(eax, ptr[bits]); + xor_(ecx, ecx); + xor_(edi, edi); - xor_(eax, eax); + // 0-7 + inc(ecx); + test(eax, 0xFF); + cmovnz(edi, ecx); - if (countType == DJ_M_DONT_COUNT) { - return; + // 8-15 + if (jitdesc->numFields > 7) + { + inc(ecx); + test(eax, 0xFF00); + cmovnz(edi, ecx); } - for (unsigned int i = 0; i < jitdesc->numFields; i++) { - int fieldId = jitdesc->fields[i].id; - int flagsOffset = (fieldId * sizeof(delta_description_t) + offsetof(delta_description_t, flags)); + // 16-23 + if (jitdesc->numFields > 15) + { + inc(ecx); + test(eax, 0xFF0000); + cmovnz(edi, ecx); + } - if (i & 1) { //rotate between cx and dx to decrease instruction result dependencies - mov(cx, word_ptr[ebx + flagsOffset]); - and_(cx, 1); - or_(ax, cx); - } else { - mov(dx, word_ptr[ebx + flagsOffset]); - and_(dx, 1); - or_(ax, dx); + // 24-31 + if (jitdesc->numFields > 23) + { + inc(ecx); + test(eax, 0xFF000000); + cmovnz(edi, ecx); + } + + if (jitdesc->numFields > 31) + { + mov(eax, ptr[bits + 4]); + + // 32-39 + inc(ecx); + test(eax, 0xFF); + cmovnz(edi, ecx); + + // 40-47 + if (jitdesc->numFields > 39) + { + inc(ecx); + test(eax, 0xFF00); + cmovnz(edi, ecx); } - //insert 'is changed' check every 8 fields - if ((i & 7) == 0) { - jnz("countMarkedFields_finish"); + // 48-55 + if (jitdesc->numFields > 47) + { + inc(ecx); + test(eax, 0xFF0000); + cmovnz(edi, ecx); } } - L("countMarkedFields_finish"); + mov(eax, ptr[bytecount]); + mov(ptr[eax], edi); + mov(eax, edi); } -CDeltaClearMarkFieldsJIT::Result CDeltaClearMarkFieldsJIT::main(Addr src, Addr dst, Addr delta) +CDeltaClearMarkFieldsJIT::Result CDeltaClearMarkFieldsJIT::main(Addr src, Addr dst, Addr delta, Addr bits, Addr bytecount, Addr force) { - #ifndef REHLDS_FIXES sub(esp, 12); //some local storage is required for precise DT_TIMEWINDOW marking #endif mov(esi, ptr[src]); mov(edi, ptr[dst]); - mov(ebx, ptr[delta]); - int fieldsOffset = (offsetof(delta_t, pdd)); - mov(ebx, dword_ptr[ebx + fieldsOffset]); + //mov(ebx, ptr[delta]); + //int fieldsOffset = (offsetof(delta_t, pdd)); + //mov(ebx, dword_ptr[ebx + fieldsOffset]); movdqu(xmm3, xmmword_ptr[esi]); movdqu(xmm4, xmmword_ptr[edi]); @@ -203,22 +232,25 @@ CDeltaClearMarkFieldsJIT::Result CDeltaClearMarkFieldsJIT::main(Addr src, Addr d auto mask = ecx; xor_(mask, mask); + + auto mark = xmm5; + pxor(mark, mark); + for (unsigned int i = 0; i < jitdesc->numblocks; i++) { movdqa(xmm0, xmm3); movdqa(xmm1, xmm4); //prefetch next blocks - if (i < jitdesc->numblocks) { + if (i + 1 < jitdesc->numblocks) { movdqu(xmm3, xmmword_ptr[esi + ((i + 1) * 16)]); movdqu(xmm4, xmmword_ptr[edi + ((i + 1) * 16)]); } pxor(xmm0, xmm1); - pcmpeqb(xmm0, xmm2); + pcmpeqb(xmm0, zero_xmm); pmovmskb(mask, xmm0); not_(mask); - auto block = &jitdesc->blocks[i]; for (unsigned int j = 0; j < block->numFields; j++) { auto jitField = &block->fields[j]; @@ -245,7 +277,7 @@ CDeltaClearMarkFieldsJIT::Result CDeltaClearMarkFieldsJIT::main(Addr src, Addr d cmp(eax, edx); setne(al); - movzx(dx, al); + movzx(edx, al); } else { continue; @@ -253,29 +285,51 @@ CDeltaClearMarkFieldsJIT::Result CDeltaClearMarkFieldsJIT::main(Addr src, Addr d } else { checkFieldMask(mask, jitField); } -#else - checkFieldMask(mask, jitField); -#endif - int flagsOffset = (jitField->field->id * sizeof(delta_description_t) + offsetof(delta_description_t, flags)); + /*int flagsOffset = ( jitField->field->id * sizeof(delta_description_t) + offsetof(delta_description_t, flags) ); if (jitField->first) { mov(word_ptr[ebx + flagsOffset], dx); } else { or_(word_ptr[ebx + flagsOffset], dx); - } + }*/ +#else + checkFieldMask(mask, jitField); +#endif + + // set bit in send mask + movd(xmm0, edx); + pslldq(xmm0, j); + por(mark, xmm0); } } processStrings(src, dst, delta); - callConditionalEncoder(src, dst, delta); + size_t markbits_offset = offsetof(delta_t, markbits); - countMarkedFields(); + mov(eax, ptr[delta]); + movdqu(xmmword_ptr[eax + markbits_offset], mark); + pcmpeqq(mark, zero_xmm); // SSE 4.1 instruction + cvttss2si(eax, mark); + or_(eax, ptr[force]); // if(sendfields || force) + + If(eax != 0); + callConditionalEncoder(src, dst, delta); + EndIf(); + + mov(eax, ptr[delta]); + movdqu(mark, xmmword_ptr[eax + markbits_offset]); + pcmpeqq(mark, zero_xmm); + cvttss2si(eax, mark); + + If(eax != 0); + calculateBytecount(bits, bytecount); + EndIf(); #ifndef REHLDS_FIXES add(esp, 12); //some local storage is required for precise DT_TIMEWINDOW marking -#endif +#endif // REHLDS_FIXES return eax; } @@ -304,11 +358,16 @@ void CDeltaClearMarkFieldsJIT::processStrings(Addr src, Addr dst, Addr delta) { add(esp, 8); test(eax, eax); setnz(cl); - movzx(cx, cl); - + movzx(ecx, cl); +#ifndef REHLDS_FIXES int flagsOffset = (jitField->id * sizeof(delta_description_t) + offsetof(delta_description_t, flags)); mov(word_ptr[ebx + flagsOffset], cx); +#else // REHLDS_FIXES + movd(xmm0, ecx); + pslldq(xmm0, i); + por(xmm5, xmm0); +#endif // REHLDS_FIXES } } @@ -365,7 +424,7 @@ void CDeltaJitRegistry::CreateAndRegisterDeltaJIT(delta_t* delta) { RegisterDeltaJit(delta, deltaJit); } -NOINLINE void DELTAJit_ClearAndMarkSendFields(unsigned char *from, unsigned char *to, delta_t *pFields) { +NOINLINE void DELTAJit_ClearAndMarkSendFields(unsigned char *from, unsigned char *to, delta_t *pFields, int* bits, int* bytecount, int force) { CDeltaJit* deltaJit = g_DeltaJitRegistry.GetJITByDelta(pFields); if (!deltaJit) { rehlds_syserror("%s: JITted delta encoder not found for delta %p", __FUNCTION__, pFields); @@ -373,7 +432,8 @@ NOINLINE void DELTAJit_ClearAndMarkSendFields(unsigned char *from, unsigned char } CDeltaClearMarkFieldsJIT &func = *deltaJit->cleanMarkCheckFunc; - func(from, to, pFields); + + func(from, to, pFields, bits, bytecount, force); } NOINLINE int DELTAJit_Feilds_Clear_Mark_Check(unsigned char *from, unsigned char *to, delta_t *pFields) { @@ -383,8 +443,9 @@ NOINLINE int DELTAJit_Feilds_Clear_Mark_Check(unsigned char *from, unsigned char return 0; } + int bits[2], bytecount; CDeltaClearMarkFieldsJIT &func = *deltaJit->cleanMarkCheckFunc; - return func(from, to, pFields); + return func(from, to, pFields, bits, &bytecount, false); } void CDeltaJitRegistry::Cleanup() { diff --git a/rehlds/engine/delta_jit.h b/rehlds/engine/delta_jit.h index b2e9597..45fac1d 100644 --- a/rehlds/engine/delta_jit.h +++ b/rehlds/engine/delta_jit.h @@ -3,7 +3,7 @@ #include "maintypes.h" #define DELTAJIT_MAX_BLOCKS 32 -#define DELTAJIT_MAX_FIELDS 96 +#define DELTAJIT_MAX_FIELDS 56 struct deltajit_field { unsigned int id; @@ -57,5 +57,5 @@ public: extern CDeltaJitRegistry g_DeltaJitRegistry; -extern void DELTAJit_ClearAndMarkSendFields(unsigned char *from, unsigned char *to, delta_t *pFields); +extern void DELTAJit_ClearAndMarkSendFields(unsigned char *from, unsigned char *to, delta_t *pFields, int* bits, int* bytecount, int force); extern int DELTAJit_Feilds_Clear_Mark_Check(unsigned char *from, unsigned char *to, delta_t *pFields); diff --git a/rehlds/unittests/delta_tests.cpp b/rehlds/unittests/delta_tests.cpp index f771db2..6a1a2cf 100644 --- a/rehlds/unittests/delta_tests.cpp +++ b/rehlds/unittests/delta_tests.cpp @@ -52,16 +52,22 @@ NOINLINE void _FillTestDelta(delta_test_struct_t* data, char val) { data->wb_20 = (float)val; } -NOINLINE void _DoMarkFields(void* src, void* dst, delta_t* delta, bool useJit) { +NOINLINE qboolean _DoMarkFields(void* src, void* dst, delta_t* delta, int* bits, int* bytecount, bool force, bool useJit) { + qboolean sendfields; if (useJit) { - DELTAJit_ClearAndMarkSendFields((unsigned char*)src, (unsigned char*)dst, delta); + DELTAJit_ClearAndMarkSendFields((unsigned char*)src, (unsigned char*)dst, delta, bits, bytecount, force); + sendfields = *bytecount; } else { DELTA_ClearFlags(delta); DELTA_MarkSendFields((unsigned char*)src, (unsigned char*)dst, delta); + sendfields = DELTA_CountSendFields(delta); + DELTA_SetSendFlagBits(delta, bits, bytecount); } + + return sendfields; } -NOINLINE void _EnsureFieldsChanged(const char* callsite, const char* action, bool changed, delta_t* delta, ...) { +NOINLINE void _EnsureFieldsChanged(const char* callsite, const char* action, bool changed, bool markmask, delta_t* delta, ...) { va_list vargs; va_start(vargs, delta); const char* fieldName = va_arg(vargs, const char*); @@ -82,8 +88,16 @@ NOINLINE void _EnsureFieldsChanged(const char* callsite, const char* action, boo rehlds_syserror("%s: %s: Field '%s' is marked as processed", callsite, action, fieldName); } - if ((field->flags == 1) ^ changed) { - rehlds_syserror("%s: %s: Field '%s' is expected to be marked", callsite, action, fieldName); + if (markmask) { + int index = field - delta->pdd; + if ((DELTA_IsFieldMarked(delta, index)?1:0) ^ changed) { + rehlds_syserror("%s: %s: Field '%s' is expected to be marked", callsite, action, fieldName); + } + } + else { + if ((field->flags == 1) ^ changed) { + rehlds_syserror("%s: %s: Field '%s' is expected to be marked", callsite, action, fieldName); + } } field->flags |= 0x80; @@ -96,8 +110,16 @@ NOINLINE void _EnsureFieldsChanged(const char* callsite, const char* action, boo if (field->flags & 0x80) continue; - if ((field->flags == 1) ^ !changed) { - rehlds_syserror("%s: %s: Field '%s' is expected to be unmarked", callsite, action, field->fieldName); + if (markmask) { + int index = field - delta->pdd; + if ((DELTA_IsFieldMarked(delta, index)?1:0) ^ !changed) { + rehlds_syserror("%s: %s: Field '%s' is expected to be unmarked", callsite, action, field->fieldName); + } + } + else { + if ((field->flags == 1) ^ !changed) { + rehlds_syserror("%s: %s: Field '%s' is expected to be unmarked", callsite, action, field->fieldName); + } } } } @@ -150,145 +172,167 @@ NOINLINE delta_t* _CreateTestDeltaDesc() { }; TEST(MarkFieldsTest_Simple_Primitives, Delta, 1000) { +#ifdef REHLDS_FIXES + bool rehds_fixes = true; +#else + bool rehds_fixes = false; +#endif + delta_t* delta = _CreateTestDeltaDesc(); delta_test_struct_t d1; delta_test_struct_t d2; + int bits[2], bytecount; + int *pbits; + for (int usejit = 0; usejit <= 1; usejit++) { + pbits = usejit ? delta->markbits : bits; + _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "SimpleUnchangedAll", true, delta, NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "SimpleUnchangedAll", true, usejit, delta, NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x72); - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "SimpleUnchangedAll", false, delta, NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "SimpleUnchangedAll", false, usejit, delta, NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_01 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Byte_0BlockCheck", true, delta, "b_01", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Byte_0BlockCheck", true, usejit, delta, "b_01", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_11 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Byte_1BlockCheck", true, delta, "b_11", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Byte_1BlockCheck", true, usejit, delta, "b_11", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.s_02 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Short_0BlockCheck", true, delta, "s_02", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Short_0BlockCheck", true, usejit, delta, "s_02", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.s_12 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Short_1BlockCheck", true, delta, "s_12", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Short_1BlockCheck", true, usejit, delta, "s_12", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_04 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Int_0BlockCheck", true, delta, "i_04", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Int_0BlockCheck", true, usejit, delta, "i_04", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_14 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Int_1BlockCheck", true, delta, "i_14", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Int_1BlockCheck", true, usejit, delta, "i_14", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.f_08 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Float_0BlockCheck", true, delta, "f_08", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Float_0BlockCheck", true, usejit, delta, "f_08", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.f_18 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Float_0BlockCheck", true, delta, "f_18", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Float_0BlockCheck", true, usejit, delta, "f_18", NULL); } SV_Shutdown(); } TEST(MarkFieldsTest_InterBlock, Delta, 1000) { +#ifdef REHLDS_FIXES + bool rehds_fixes = true; +#else + bool rehds_fixes = false; +#endif + delta_t* delta = _CreateTestDeltaDesc(); delta_test_struct_t d1; delta_test_struct_t d2; + int bits[2], bytecount; + int *pbits; + for (int usejit = 0; usejit <= 1; usejit++) { + pbits = usejit ? delta->markbits : bits; + _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_4D = d2.b_52 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_guards", true, delta, "b_4D", "b_52", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_guards", true, usejit, delta, "b_4D", "b_52", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_4D = d2.b_52 = 0; d2.i_4E = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_guards_and_val", true, delta, "b_4D", "b_52", "i_4E", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_guards_and_val", true, usejit, delta, "b_4D", "b_52", "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val", true, delta, "i_4E", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val", true, usejit, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E &= 0xFFFFFF00; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_0b", true, delta, "i_4E", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_0b", true, usejit, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E &= 0xFFFF00FF; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_1b", true, delta, "i_4E", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_1b", true, usejit, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E &= 0xFF00FFFF; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_2b", true, delta, "i_4E", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_2b", true, usejit, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E &= 0x00FFFFFF; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_3b", true, delta, "i_4E", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_3b", true, usejit, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_5C = d2.b_61 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_guards", true, delta, "b_5C", "b_61", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_guards", true, usejit, delta, "b_5C", "b_61", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_5C = d2.b_61 = 0; d2.i_5D = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_guards_and_val", true, delta, "b_5C", "b_61", "i_5D", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_guards_and_val", true, usejit, delta, "b_5C", "b_61", "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val", true, delta, "i_5D", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val", true, usejit, delta, "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D &= 0xFFFFFF00; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_0b", true, delta, "i_5D", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_0b", true, usejit, delta, "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D &= 0xFFFF00FF; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_1b", true, delta, "i_5D", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_1b", true, usejit, delta, "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D &= 0xFF00FFFF; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_2b", true, delta, "i_5D", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_2b", true, usejit, delta, "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D &= 0x00FFFFFF; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_3b", true, delta, "i_5D", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_3b", true, usejit, delta, "i_5D", NULL); } @@ -296,32 +340,44 @@ TEST(MarkFieldsTest_InterBlock, Delta, 1000) { } TEST(MarkFieldsTest_Strings, Delta, 1000) { +#ifdef REHLDS_FIXES + bool rehds_fixes = true; +#else + bool rehds_fixes = false; +#endif + delta_t* delta = _CreateTestDeltaDesc(); delta_test_struct_t d1; delta_test_struct_t d2; + int *pbits; + + int bits[2], bytecount; for (int usejit = 0; usejit <= 1; usejit++) { + + pbits = usejit ? delta->markbits : bits; + _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d2.s_24[0] = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Str_empty", true, delta, "s_24", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Str_empty", true, usejit, delta, "s_24", NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d1.s_24[0] = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Str_empty2", true, delta, "s_24", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Str_empty2", true, usejit, delta, "s_24", NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d1.s_24[0] = d2.s_24[0] = 0; d1.s_24[1] = 'd'; d2.s_24[1] = 'e'; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Str_both_empty_with_garbage", true, delta, NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Str_both_empty_with_garbage", true, usejit, delta, NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d1.s_24[1] = 'C'; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Str_case_check", true, delta, NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Str_case_check", true, usejit, delta, NULL); } SV_Shutdown(); @@ -339,22 +395,27 @@ TEST(MarkFieldsTest_TimeWindow, Delta, 1000) { delta_test_struct_t d1; delta_test_struct_t d2; + int bits[2], bytecount; + int* pbits; + for (int usejit = 0; usejit <= 1; usejit++) { + pbits = usejit ? delta->markbits : bits; + _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d2.w8_1C = 0.001f; d1.w8_1C = 0.0011f; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Below_Precision", true, delta, rehds_fixes ? "w8_1C" : NULL, NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Below_Precision", true, usejit, delta, rehds_fixes ? "w8_1C" : NULL, NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d2.w8_1C = 0.1f; d1.w8_1C = 0.11f; //precision check, 0.11f is actually 0.10999 - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Above_Precision", true, delta, rehds_fixes ? "w8_1C" : NULL, NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Above_Precision", true, usejit, delta, rehds_fixes ? "w8_1C" : NULL, NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d2.w8_1C = 0.1f; d1.w8_1C = 0.12f; - _DoMarkFields(&d1, &d2, delta, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Above_Precision", true, delta, "w8_1C", NULL); + _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Above_Precision", true, usejit, delta, "w8_1C", NULL); } From 5bb896dcee4d101fa8a6480aca17777ec2b38e88 Mon Sep 17 00:00:00 2001 From: dreamstalker Date: Fri, 22 May 2015 02:50:39 +0400 Subject: [PATCH 2/3] Refactoring DeltaJIT passes tests now --- rehlds/engine/delta.cpp | 81 ++++------- rehlds/engine/delta.h | 6 - rehlds/engine/delta_jit.cpp | 242 ++++++++++++++++++------------- rehlds/engine/delta_jit.h | 5 +- rehlds/unittests/delta_tests.cpp | 197 +++++++++++-------------- 5 files changed, 256 insertions(+), 275 deletions(-) diff --git a/rehlds/engine/delta.cpp b/rehlds/engine/delta.cpp index a57e69a..5bc7ab3 100644 --- a/rehlds/engine/delta.cpp +++ b/rehlds/engine/delta.cpp @@ -360,14 +360,14 @@ void DELTA_SetField(struct delta_s *pFields, const char *fieldname) if (index != -1) DELTA_SetFieldByIndex(pFields, index); -#else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES +#else delta_description_t *pTest = DELTA_FindField(pFields, fieldname); if (pTest) { pTest->flags |= FDT_MARK; } -#endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES +#endif } /* <240b2> ../engine/delta.c:411 */ @@ -378,40 +378,34 @@ void DELTA_UnsetField(struct delta_s *pFields, const char *fieldname) if (index != -1) DELTA_UnsetFieldByIndex(pFields, index); -#else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES +#else delta_description_t *pTest = DELTA_FindField(pFields, fieldname); if (pTest) { pTest->flags &= ~FDT_MARK; } -#endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES +#endif } /* <24132> ../engine/delta.c:429 */ void DELTA_SetFieldByIndex(struct delta_s *pFields, int fieldNumber) { #if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) - if (fieldNumber > 31) - pFields->markbits[1] |= (1 << (fieldNumber & 0x1F)); - else - pFields->markbits[0] |= (1 << fieldNumber); -#else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES + DELTAJit_SetFieldByIndex(pFields, fieldNumber); +#else pFields->pdd[fieldNumber].flags |= FDT_MARK; -#endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES +#endif } /* <2416a> ../engine/delta.c:441 */ void DELTA_UnsetFieldByIndex(struct delta_s *pFields, int fieldNumber) { #if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) - if (fieldNumber > 31) - pFields->markbits[1] &= ~(1 << (fieldNumber & 0x1F)); - else - pFields->markbits[0] &= ~(1 << fieldNumber); -#else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES + DELTA_UnsetFieldByIndex(pFields, fieldNumber); +#else pFields->pdd[fieldNumber].flags &= ~FDT_MARK; -#endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES +#endif } /* <23cc4> ../engine/delta.c:453 */ @@ -596,23 +590,23 @@ void DELTA_SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount) } #ifdef REHLDS_FIXES - // fix potencial buffer overflow in force mode if lastbit == -1 - *bytecount = ((lastbit + 7) & ~7) >> 3; -#else // REHLDS_FIXES + // fix for bad bytecount when no fields are marked + if (lastbit == -1) { + *bytecount = 0; + return; + } +#endif + *bytecount = (lastbit >> 3) + 1; -#endif // REHLDS_FIXES } qboolean DELTA_IsFieldMarked(delta_t* pFields, int fieldNumber) { -#ifdef REHLDS_FIXES - if (fieldNumber > 31) - return pFields->markbits[1] & (1 << (fieldNumber & 0x1F)); - - return pFields->markbits[0] & (1 << fieldNumber); -#else // REHLDS_FIXES +#if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) + return DELTAJit_IsFieldMarked(pFields, fieldNumber); +#else return pFields->pdd[fieldNumber].flags & FDT_MARK; -#endif // REHLDS_FIXES +#endif } /* <2456d> ../engine/delta.c:782 */ @@ -754,36 +748,17 @@ NOINLINE qboolean DELTA_WriteDelta(unsigned char *from, unsigned char *to, qbool int bytecount; #if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) - DELTAJit_ClearAndMarkSendFields(from, to, pFields, pFields->markbits, &bytecount, force); - _DELTA_WriteDelta(from, to, pFields, pFields->markbits, bytecount); - sendfields = bytecount; + sendfields = DELTAJit_Feilds_Clear_Mark_Check(from, to, pFields); #else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES - int bits[2]; DELTA_ClearFlags(pFields); DELTA_MarkSendFields(from, to, pFields); sendfields = DELTA_CountSendFields(pFields); - _DELTA_WriteDelta(from, to, force, pFields, callback, sendfields); #endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES + _DELTA_WriteDelta(from, to, force, pFields, callback, sendfields); return sendfields; } -#if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) -int _DELTA_WriteDelta(unsigned char *from, unsigned char *to, delta_t *pFields, int* bits, int bytecount) -{ - int i; - - MSG_WriteBits(bytecount, 3); - for (i = 0; i < bytecount; i++) - { - MSG_WriteBits(( (byte*)bits )[i], 8); - } - - DELTA_WriteMarkedFields(from, to, pFields); - return 1; -} -#else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES -/* <24760> ../engine/delta.c:963 */ int _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)( void ), int sendfields) { int i; @@ -792,15 +767,15 @@ int _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, de if (sendfields || force) { +#if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) + DELTAJit_SetSendFlagBits(pFields, bits, &bytecount); +#else DELTA_SetSendFlagBits(pFields, bits, &bytecount); +#endif if (callback) callback(); -#ifdef REHLDS_FIXES - bytecount &= 7; // max fields is 56, not 64 -#endif // REHLDS_FIXES - MSG_WriteBits(bytecount, 3); for (i = 0; i < bytecount; i++) { @@ -812,7 +787,7 @@ int _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, de return 1; } -#endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES + /* <24aa0> ../engine/delta.c:1010 */ int DELTA_ParseDelta(unsigned char *from, unsigned char *to, delta_t *pFields) diff --git a/rehlds/engine/delta.h b/rehlds/engine/delta.h index 23cb4e0..cc9cb75 100644 --- a/rehlds/engine/delta.h +++ b/rehlds/engine/delta.h @@ -81,8 +81,6 @@ typedef struct delta_s #ifdef REHLDS_FIXES CDeltaJit* jit; - int markbits[2]; - int sse_highbits[2]; #endif } delta_t; @@ -140,11 +138,7 @@ qboolean DELTA_IsFieldMarked(delta_t* pFields, int fieldNumber); void DELTA_WriteMarkedFields(unsigned char *from, unsigned char *to, delta_t *pFields); qboolean DELTA_CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields); qboolean DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)( void )); -#if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) -qboolean _DELTA_WriteDelta(unsigned char *from, unsigned char *to, delta_t *pFields, int* bits, int bytecount); -#else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES qboolean _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void), int sendfields); -#endif // REHLDS_OPT_PEDANTIC || REHLDS_FIXES int DELTA_ParseDelta(unsigned char *from, unsigned char *to, delta_t *pFields); void DELTA_AddEncoder(char *name, void(*conditionalencode)(struct delta_s *, const unsigned char *, const unsigned char *)); void DELTA_ClearEncoders(void); diff --git a/rehlds/engine/delta_jit.cpp b/rehlds/engine/delta_jit.cpp index 77e65aa..4c971d7 100644 --- a/rehlds/engine/delta_jit.cpp +++ b/rehlds/engine/delta_jit.cpp @@ -107,21 +107,40 @@ void DELTAJIT_CreateDescription(delta_t* delta, deltajitdata_t &jitdesc) { } -class CDeltaClearMarkFieldsJIT : public jitasm::function { +class CDeltaClearMarkFieldsJIT; + +class CDeltaJit { +public: + CDeltaClearMarkFieldsJIT* cleanMarkCheckFunc; + delta_t* delta; + + int markedFieldsMaskSize; + + int marked_fields_mask[2]; + int sse_highbits[2]; //High 64 bits for manipulating marked_fields_mask via SSE registers + + CDeltaJit(delta_t* _delta, CDeltaClearMarkFieldsJIT* _cleanMarkCheckFunc); + + virtual ~CDeltaJit(); +}; + +class CDeltaClearMarkFieldsJIT : public jitasm::function { public: deltajitdata_t *jitdesc; deltajit_marked_count_type_t countType; + XmmReg marked_fields_mask = xmm5; + CDeltaClearMarkFieldsJIT(deltajitdata_t *_jitdesc, deltajit_marked_count_type_t _countType) : jitdesc(_jitdesc), countType(_countType) { } void checkFieldMask(jitasm::Frontend::Reg32& mask, deltajit_memblock_field* jitField); - Result main(Addr src, Addr dst, Addr delta, Addr bits, Addr bytecount, Addr force); - void processStrings(Addr src, Addr dst, Addr delta); - void callConditionalEncoder(Addr src, Addr dst, Addr delta); - void calculateBytecount(Addr bits, Addr bytecount); + Result main(Addr src, Addr dst, Addr deltaJit); + void processStrings(Addr src, Addr dst); + void callConditionalEncoder(Addr src, Addr dst, Addr deltaJit); + void calculateBytecount(); }; void CDeltaClearMarkFieldsJIT::checkFieldMask(jitasm::Frontend::Reg32& mask, deltajit_memblock_field* jitField) { @@ -130,14 +149,16 @@ void CDeltaClearMarkFieldsJIT::checkFieldMask(jitasm::Frontend::Reg32& mask, del movzx(edx, al); } -void CDeltaClearMarkFieldsJIT::callConditionalEncoder(Addr src, Addr dst, Addr delta) { +void CDeltaClearMarkFieldsJIT::callConditionalEncoder(Addr src, Addr dst, Addr deltaJit) { //This generator expects that following registers are already initialized: // esi = src // edi = dst + int deltaOffset = (offsetof(CDeltaJit, delta)); int condEncoderOffset = (offsetof(delta_t, conditionalencode)); - mov(eax, ptr[delta]); - or_(ecx, dword_ptr[eax + condEncoderOffset]); + mov(eax, ptr[deltaJit]); + mov(eax, ptr[eax + deltaOffset]); + mov(ecx, dword_ptr[eax + condEncoderOffset]); If(ecx != 0); push(edi); push(esi); @@ -148,72 +169,81 @@ void CDeltaClearMarkFieldsJIT::callConditionalEncoder(Addr src, Addr dst, Addr d EndIf(); } -void CDeltaClearMarkFieldsJIT::calculateBytecount(Addr bits, Addr bytecount) { - mov(eax, ptr[bits]); - xor_(ecx, ecx); - xor_(edi, edi); +void CDeltaClearMarkFieldsJIT::calculateBytecount() { + //This generator expects that following registers are already initialized: + //ebx = delta + + size_t delta_markbits_offset = offsetof(CDeltaJit, marked_fields_mask); + mov(eax, dword_ptr[ebx + delta_markbits_offset]); + xor_(edx, edx); // 0-7 - inc(ecx); + mov(ecx, 1); test(eax, 0xFF); - cmovnz(edi, ecx); + cmovnz(edx, ecx); // 8-15 if (jitdesc->numFields > 7) { - inc(ecx); + mov(ecx, 2); test(eax, 0xFF00); - cmovnz(edi, ecx); + cmovnz(edx, ecx); } // 16-23 if (jitdesc->numFields > 15) { - inc(ecx); + mov(ecx, 3); test(eax, 0xFF0000); - cmovnz(edi, ecx); + cmovnz(edx, ecx); } // 24-31 if (jitdesc->numFields > 23) { - inc(ecx); + mov(ecx, 4); test(eax, 0xFF000000); - cmovnz(edi, ecx); + cmovnz(edx, ecx); } if (jitdesc->numFields > 31) { - mov(eax, ptr[bits + 4]); + mov(eax, dword_ptr[ebx + delta_markbits_offset + 4]); // 32-39 - inc(ecx); + mov(ecx, 5); test(eax, 0xFF); - cmovnz(edi, ecx); + cmovnz(edx, ecx); // 40-47 if (jitdesc->numFields > 39) { - inc(ecx); + mov(ecx, 6); test(eax, 0xFF00); - cmovnz(edi, ecx); + cmovnz(edx, ecx); } // 48-55 if (jitdesc->numFields > 47) { - inc(ecx); + mov(ecx, 7); test(eax, 0xFF0000); - cmovnz(edi, ecx); + cmovnz(edx, ecx); + } + + if (jitdesc->numFields > 55) + { + mov(ecx, 8); + test(eax, 0xFF000000); + cmovnz(edx, ecx); } } - mov(eax, ptr[bytecount]); - mov(ptr[eax], edi); - mov(eax, edi); + size_t delta_masksize_offset = offsetof(CDeltaJit, markedFieldsMaskSize); + mov(dword_ptr[ebx + delta_masksize_offset], edx); } -CDeltaClearMarkFieldsJIT::Result CDeltaClearMarkFieldsJIT::main(Addr src, Addr dst, Addr delta, Addr bits, Addr bytecount, Addr force) +CDeltaClearMarkFieldsJIT::Result CDeltaClearMarkFieldsJIT::main(Addr src, Addr dst, Addr deltaJit) { #ifndef REHLDS_FIXES sub(esp, 12); //some local storage is required for precise DT_TIMEWINDOW marking @@ -227,14 +257,11 @@ CDeltaClearMarkFieldsJIT::Result CDeltaClearMarkFieldsJIT::main(Addr src, Addr d movdqu(xmm3, xmmword_ptr[esi]); movdqu(xmm4, xmmword_ptr[edi]); - auto zero_xmm = xmm2; - pxor(zero_xmm, zero_xmm); - auto mask = ecx; xor_(mask, mask); - auto mark = xmm5; - pxor(mark, mark); + + pxor(marked_fields_mask, marked_fields_mask); for (unsigned int i = 0; i < jitdesc->numblocks; i++) { movdqa(xmm0, xmm3); @@ -246,8 +273,7 @@ CDeltaClearMarkFieldsJIT::Result CDeltaClearMarkFieldsJIT::main(Addr src, Addr d movdqu(xmm4, xmmword_ptr[edi + ((i + 1) * 16)]); } - pxor(xmm0, xmm1); - pcmpeqb(xmm0, zero_xmm); + pcmpeqb(xmm0, xmm1); pmovmskb(mask, xmm0); not_(mask); @@ -285,58 +311,51 @@ CDeltaClearMarkFieldsJIT::Result CDeltaClearMarkFieldsJIT::main(Addr src, Addr d } else { checkFieldMask(mask, jitField); } - - /*int flagsOffset = ( jitField->field->id * sizeof(delta_description_t) + offsetof(delta_description_t, flags) ); - if (jitField->first) { - mov(word_ptr[ebx + flagsOffset], dx); - } - else { - or_(word_ptr[ebx + flagsOffset], dx); - }*/ #else checkFieldMask(mask, jitField); #endif // set bit in send mask movd(xmm0, edx); - pslldq(xmm0, j); - por(mark, xmm0); + psllq(xmm0, jitField->field->id); + por(marked_fields_mask, xmm0); } } - processStrings(src, dst, delta); + processStrings(src, dst); - size_t markbits_offset = offsetof(delta_t, markbits); + size_t delta_markbits_offset = offsetof(CDeltaJit, marked_fields_mask); - mov(eax, ptr[delta]); - movdqu(xmmword_ptr[eax + markbits_offset], mark); - pcmpeqq(mark, zero_xmm); // SSE 4.1 instruction - cvttss2si(eax, mark); - or_(eax, ptr[force]); // if(sendfields || force) + //Before calling the condition encoder we have to save 'marked fields' mask + //from SSE register into the CDeltaJit::marked_fields_mask, because conditional encoder can modify the mask + mov(ebx, ptr[deltaJit]); + movdqu(xmmword_ptr[ebx + delta_markbits_offset], marked_fields_mask); - If(eax != 0); - callConditionalEncoder(src, dst, delta); - EndIf(); + //emit conditional encoder call + callConditionalEncoder(src, dst, deltaJit); + + // check if mask is empty + mov(edi, dword_ptr[ebx + delta_markbits_offset]); + mov(edx, dword_ptr[ebx + delta_markbits_offset + 4]); + or_(edi, edx); - mov(eax, ptr[delta]); - movdqu(mark, xmmword_ptr[eax + markbits_offset]); - pcmpeqq(mark, zero_xmm); - cvttss2si(eax, mark); - - If(eax != 0); - calculateBytecount(bits, bytecount); + If(edi != 0); + calculateBytecount(); + Else(); + //set maskSize to 0 if there are no marked fields + size_t delta_masksize_offset = offsetof(CDeltaJit, markedFieldsMaskSize); + mov(dword_ptr[ebx + delta_masksize_offset], 0); EndIf(); #ifndef REHLDS_FIXES add(esp, 12); //some local storage is required for precise DT_TIMEWINDOW marking #endif // REHLDS_FIXES - return eax; + return edi; } -void CDeltaClearMarkFieldsJIT::processStrings(Addr src, Addr dst, Addr delta) { +void CDeltaClearMarkFieldsJIT::processStrings(Addr src, Addr dst) { //This generator expects that following registers are already initialized: - // ebx = delta->pdd // esi = src // edi = dst @@ -360,34 +379,23 @@ void CDeltaClearMarkFieldsJIT::processStrings(Addr src, Addr dst, Addr delta) { setnz(cl); movzx(ecx, cl); -#ifndef REHLDS_FIXES - int flagsOffset = (jitField->id * sizeof(delta_description_t) + offsetof(delta_description_t, flags)); - mov(word_ptr[ebx + flagsOffset], cx); -#else // REHLDS_FIXES movd(xmm0, ecx); - pslldq(xmm0, i); + psllq(xmm0, jitField->id); por(xmm5, xmm0); -#endif // REHLDS_FIXES } } -class CDeltaJit { -public: - CDeltaClearMarkFieldsJIT* cleanMarkCheckFunc; - delta_t* delta; +CDeltaJit::CDeltaJit(delta_t* _delta, CDeltaClearMarkFieldsJIT* _cleanMarkCheckFunc) { + delta = _delta; + cleanMarkCheckFunc = _cleanMarkCheckFunc; +} - CDeltaJit(delta_t* _delta, CDeltaClearMarkFieldsJIT* _cleanMarkCheckFunc) { - delta = _delta; - cleanMarkCheckFunc = _cleanMarkCheckFunc; +CDeltaJit::~CDeltaJit() { + if (cleanMarkCheckFunc) { + delete cleanMarkCheckFunc; + cleanMarkCheckFunc = NULL; } - - virtual ~CDeltaJit() { - if (cleanMarkCheckFunc) { - delete cleanMarkCheckFunc; - cleanMarkCheckFunc = NULL; - } - } -}; +} CDeltaJitRegistry::CDeltaJitRegistry() { @@ -424,28 +432,56 @@ void CDeltaJitRegistry::CreateAndRegisterDeltaJIT(delta_t* delta) { RegisterDeltaJit(delta, deltaJit); } -NOINLINE void DELTAJit_ClearAndMarkSendFields(unsigned char *from, unsigned char *to, delta_t *pFields, int* bits, int* bytecount, int force) { +CDeltaJit* DELTAJit_LookupDeltaJit(const char* callsite, delta_t *pFields) { CDeltaJit* deltaJit = g_DeltaJitRegistry.GetJITByDelta(pFields); if (!deltaJit) { - rehlds_syserror("%s: JITted delta encoder not found for delta %p", __FUNCTION__, pFields); - return; + rehlds_syserror("%s: JITted delta encoder not found for delta %p", callsite, pFields); + return NULL; } - CDeltaClearMarkFieldsJIT &func = *deltaJit->cleanMarkCheckFunc; - - func(from, to, pFields, bits, bytecount, force); + return deltaJit; } NOINLINE int DELTAJit_Feilds_Clear_Mark_Check(unsigned char *from, unsigned char *to, delta_t *pFields) { - CDeltaJit* deltaJit = g_DeltaJitRegistry.GetJITByDelta(pFields); - if (!deltaJit) { - rehlds_syserror("%s: JITted delta encoder not found for delta %p", __FUNCTION__, pFields); - return 0; - } - - int bits[2], bytecount; + CDeltaJit* deltaJit = DELTAJit_LookupDeltaJit(__FUNCTION__, pFields); CDeltaClearMarkFieldsJIT &func = *deltaJit->cleanMarkCheckFunc; - return func(from, to, pFields, bits, &bytecount, false); + return func(from, to, deltaJit); +} + +void DELTAJit_SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount) { + CDeltaJit* deltaJit = DELTAJit_LookupDeltaJit(__FUNCTION__, pFields); + + bits[0] = deltaJit->marked_fields_mask[0]; + bits[1] = deltaJit->marked_fields_mask[1]; + *bytecount = deltaJit->markedFieldsMaskSize; +} + +void DELTAJit_SetFieldByIndex(struct delta_s *pFields, int fieldNumber) { + CDeltaJit* deltaJit = DELTAJit_LookupDeltaJit(__FUNCTION__, pFields); + + if (fieldNumber > 31) + deltaJit->marked_fields_mask[1] |= (1 << (fieldNumber & 0x1F)); + else + deltaJit->marked_fields_mask[0] |= (1 << fieldNumber); + +} + +void DELTAJit_UnsetFieldByIndex(struct delta_s *pFields, int fieldNumber) { + CDeltaJit* deltaJit = DELTAJit_LookupDeltaJit(__FUNCTION__, pFields); + + if (fieldNumber > 31) + deltaJit->marked_fields_mask[1] &= ~(1 << (fieldNumber & 0x1F)); + else + deltaJit->marked_fields_mask[0] &= ~(1 << fieldNumber); +} + +qboolean DELTAJit_IsFieldMarked(delta_t* pFields, int fieldNumber) { + CDeltaJit* deltaJit = DELTAJit_LookupDeltaJit(__FUNCTION__, pFields); + + if (fieldNumber > 31) + return deltaJit->marked_fields_mask[1] & (1 << (fieldNumber & 0x1F)); + + return deltaJit->marked_fields_mask[0] & (1 << fieldNumber); } void CDeltaJitRegistry::Cleanup() { diff --git a/rehlds/engine/delta_jit.h b/rehlds/engine/delta_jit.h index 45fac1d..0c3666e 100644 --- a/rehlds/engine/delta_jit.h +++ b/rehlds/engine/delta_jit.h @@ -57,5 +57,8 @@ public: extern CDeltaJitRegistry g_DeltaJitRegistry; -extern void DELTAJit_ClearAndMarkSendFields(unsigned char *from, unsigned char *to, delta_t *pFields, int* bits, int* bytecount, int force); extern int DELTAJit_Feilds_Clear_Mark_Check(unsigned char *from, unsigned char *to, delta_t *pFields); +extern void DELTAJit_SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount); +extern void DELTAJit_SetFieldByIndex(struct delta_s *pFields, int fieldNumber); +extern void DELTAJit_UnsetFieldByIndex(struct delta_s *pFields, int fieldNumber); +extern qboolean DELTAJit_IsFieldMarked(delta_t* pFields, int fieldNumber); \ No newline at end of file diff --git a/rehlds/unittests/delta_tests.cpp b/rehlds/unittests/delta_tests.cpp index 6a1a2cf..4337aff 100644 --- a/rehlds/unittests/delta_tests.cpp +++ b/rehlds/unittests/delta_tests.cpp @@ -52,30 +52,38 @@ NOINLINE void _FillTestDelta(delta_test_struct_t* data, char val) { data->wb_20 = (float)val; } -NOINLINE qboolean _DoMarkFields(void* src, void* dst, delta_t* delta, int* bits, int* bytecount, bool force, bool useJit) { +NOINLINE qboolean _DoMarkFields(void* src, void* dst, delta_t* delta, bool useJit) { qboolean sendfields; if (useJit) { - DELTAJit_ClearAndMarkSendFields((unsigned char*)src, (unsigned char*)dst, delta, bits, bytecount, force); - sendfields = *bytecount; + DELTA_ClearFlags(delta); + return DELTAJit_Feilds_Clear_Mark_Check((unsigned char*)src, (unsigned char*)dst, delta); } else { DELTA_ClearFlags(delta); DELTA_MarkSendFields((unsigned char*)src, (unsigned char*)dst, delta); sendfields = DELTA_CountSendFields(delta); - DELTA_SetSendFlagBits(delta, bits, bytecount); } return sendfields; } -NOINLINE void _EnsureFieldsChanged(const char* callsite, const char* action, bool changed, bool markmask, delta_t* delta, ...) { +NOINLINE bool _CheckFieldMarked(delta_t* delta, int fieldIdx, int usejit) { + if (usejit) { + return DELTAJit_IsFieldMarked(delta, fieldIdx) != 0; + } else { + return delta->pdd[fieldIdx].flags & FDT_MARK; + } +} + +NOINLINE void _EnsureFieldsChanged(const char* callsite, const char* action, int usejit, bool changed, delta_t* delta, ...) { va_list vargs; va_start(vargs, delta); const char* fieldName = va_arg(vargs, const char*); while (fieldName) { delta_description_t* field = NULL; - for (int i = 0; i < delta->fieldCount; i++) { - if (!strcmp(fieldName, delta->pdd[i].fieldName)) { - field = &delta->pdd[i]; + int idx = 0; + for (; idx < delta->fieldCount; idx++) { + if (!strcmp(fieldName, delta->pdd[idx].fieldName)) { + field = &delta->pdd[idx]; break; } } @@ -88,16 +96,9 @@ NOINLINE void _EnsureFieldsChanged(const char* callsite, const char* action, boo rehlds_syserror("%s: %s: Field '%s' is marked as processed", callsite, action, fieldName); } - if (markmask) { - int index = field - delta->pdd; - if ((DELTA_IsFieldMarked(delta, index)?1:0) ^ changed) { - rehlds_syserror("%s: %s: Field '%s' is expected to be marked", callsite, action, fieldName); - } - } - else { - if ((field->flags == 1) ^ changed) { - rehlds_syserror("%s: %s: Field '%s' is expected to be marked", callsite, action, fieldName); - } + + if (_CheckFieldMarked(delta, idx, usejit) ^ changed) { + rehlds_syserror("%s: %s: Field '%s' is expected to be marked", callsite, action, fieldName); } field->flags |= 0x80; @@ -110,23 +111,16 @@ NOINLINE void _EnsureFieldsChanged(const char* callsite, const char* action, boo if (field->flags & 0x80) continue; - if (markmask) { - int index = field - delta->pdd; - if ((DELTA_IsFieldMarked(delta, index)?1:0) ^ !changed) { - rehlds_syserror("%s: %s: Field '%s' is expected to be unmarked", callsite, action, field->fieldName); - } - } - else { - if ((field->flags == 1) ^ !changed) { - rehlds_syserror("%s: %s: Field '%s' is expected to be unmarked", callsite, action, field->fieldName); - } + if (_CheckFieldMarked(delta, i, usejit) ^ !changed) { + rehlds_syserror("%s: %s: Field '%s' is expected to be unmarked", callsite, action, field->fieldName); } + } } NOINLINE delta_t* _CreateTestDeltaDesc() { - delta_test_struct_t d; static delta_description_t _fields[32]; + delta_test_struct_t d; _InitDeltaField(&_fields[0], 0x00, DT_BYTE, "b_00", offsetof(delta_test_struct_t, b_00), 1, 8, 1.0f, 1.0f); _InitDeltaField(&_fields[1], 0x01, DT_BYTE, "b_01", offsetof(delta_test_struct_t, b_01), 1, 8, 1.0f, 1.0f); @@ -183,60 +177,55 @@ TEST(MarkFieldsTest_Simple_Primitives, Delta, 1000) { delta_test_struct_t d1; delta_test_struct_t d2; - int bits[2], bytecount; - int *pbits; - for (int usejit = 0; usejit <= 1; usejit++) { - pbits = usejit ? delta->markbits : bits; - _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "SimpleUnchangedAll", true, usejit, delta, NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "SimpleUnchangedAll", usejit, true, delta, NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x72); - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "SimpleUnchangedAll", false, usejit, delta, NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "SimpleUnchangedAll", usejit, false, delta, NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_01 = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Byte_0BlockCheck", true, usejit, delta, "b_01", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Byte_0BlockCheck", usejit, true, delta, "b_01", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_11 = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Byte_1BlockCheck", true, usejit, delta, "b_11", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Byte_1BlockCheck", usejit, true, delta, "b_11", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.s_02 = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Short_0BlockCheck", true, usejit, delta, "s_02", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Short_0BlockCheck", usejit, true, delta, "s_02", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.s_12 = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Short_1BlockCheck", true, usejit, delta, "s_12", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Short_1BlockCheck", usejit, true, delta, "s_12", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_04 = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Int_0BlockCheck", true, usejit, delta, "i_04", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Int_0BlockCheck", usejit, true, delta, "i_04", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_14 = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Int_1BlockCheck", true, usejit, delta, "i_14", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Int_1BlockCheck", usejit, true, delta, "i_14", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.f_08 = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Float_0BlockCheck", true, usejit, delta, "f_08", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Float_0BlockCheck", usejit, true, delta, "f_08", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.f_18 = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, false, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Float_0BlockCheck", true, usejit, delta, "f_18", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Float_0BlockCheck", usejit, true, delta, "f_18", NULL); } SV_Shutdown(); @@ -254,85 +243,79 @@ TEST(MarkFieldsTest_InterBlock, Delta, 1000) { delta_test_struct_t d1; delta_test_struct_t d2; - int bits[2], bytecount; - int *pbits; - for (int usejit = 0; usejit <= 1; usejit++) { - - pbits = usejit ? delta->markbits : bits; - _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_4D = d2.b_52 = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_guards", true, usejit, delta, "b_4D", "b_52", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_guards", usejit, true, delta, "b_4D", "b_52", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_4D = d2.b_52 = 0; d2.i_4E = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_guards_and_val", true, usejit, delta, "b_4D", "b_52", "i_4E", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_guards_and_val", usejit, true, delta, "b_4D", "b_52", "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val", true, usejit, delta, "i_4E", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val", usejit, true, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E &= 0xFFFFFF00; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_0b", true, usejit, delta, "i_4E", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_0b", usejit, true, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E &= 0xFFFF00FF; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_1b", true, usejit, delta, "i_4E", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_1b", usejit, true, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E &= 0xFF00FFFF; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_2b", true, usejit, delta, "i_4E", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_2b", usejit, true, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E &= 0x00FFFFFF; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_3b", true, usejit, delta, "i_4E", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_3b", usejit, true, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_5C = d2.b_61 = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_guards", true, usejit, delta, "b_5C", "b_61", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_guards", usejit, true, delta, "b_5C", "b_61", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_5C = d2.b_61 = 0; d2.i_5D = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_guards_and_val", true, usejit, delta, "b_5C", "b_61", "i_5D", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_guards_and_val", usejit, true, delta, "b_5C", "b_61", "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val", true, usejit, delta, "i_5D", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val", usejit, true, delta, "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D &= 0xFFFFFF00; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_0b", true, usejit, delta, "i_5D", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_0b", usejit, true, delta, "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D &= 0xFFFF00FF; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_1b", true, usejit, delta, "i_5D", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_1b", usejit, true, delta, "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D &= 0xFF00FFFF; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_2b", true, usejit, delta, "i_5D", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_2b", usejit, true, delta, "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D &= 0x00FFFFFF; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_3b", true, usejit, delta, "i_5D", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_3b", usejit, true, delta, "i_5D", NULL); } @@ -350,34 +333,29 @@ TEST(MarkFieldsTest_Strings, Delta, 1000) { delta_test_struct_t d1; delta_test_struct_t d2; - int *pbits; - - int bits[2], bytecount; for (int usejit = 0; usejit <= 1; usejit++) { - pbits = usejit ? delta->markbits : bits; - _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d2.s_24[0] = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Str_empty", true, usejit, delta, "s_24", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Str_empty", usejit, true, delta, "s_24", NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d1.s_24[0] = 0; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Str_empty2", true, usejit, delta, "s_24", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Str_empty2", usejit, true, delta, "s_24", NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d1.s_24[0] = d2.s_24[0] = 0; d1.s_24[1] = 'd'; d2.s_24[1] = 'e'; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Str_both_empty_with_garbage", true, usejit, delta, NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Str_both_empty_with_garbage", usejit, true, delta, NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d1.s_24[1] = 'C'; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "Str_case_check", true, usejit, delta, NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "Str_case_check", usejit, true, delta, NULL); } SV_Shutdown(); @@ -395,27 +373,22 @@ TEST(MarkFieldsTest_TimeWindow, Delta, 1000) { delta_test_struct_t d1; delta_test_struct_t d2; - int bits[2], bytecount; - int* pbits; - for (int usejit = 0; usejit <= 1; usejit++) { - pbits = usejit ? delta->markbits : bits; - _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d2.w8_1C = 0.001f; d1.w8_1C = 0.0011f; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Below_Precision", true, usejit, delta, rehds_fixes ? "w8_1C" : NULL, NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Below_Precision", usejit, true, delta, rehds_fixes ? "w8_1C" : NULL, NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d2.w8_1C = 0.1f; d1.w8_1C = 0.11f; //precision check, 0.11f is actually 0.10999 - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Above_Precision", true, usejit, delta, rehds_fixes ? "w8_1C" : NULL, NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Above_Precision1", usejit, true, delta, rehds_fixes ? "w8_1C" : NULL, NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d2.w8_1C = 0.1f; d1.w8_1C = 0.12f; - _DoMarkFields(&d1, &d2, delta, pbits, &bytecount, true, usejit != 0); - _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Above_Precision", true, usejit, delta, "w8_1C", NULL); + _DoMarkFields(&d1, &d2, delta, usejit != 0); + _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Above_Precision2", usejit, true, delta, "w8_1C", NULL); } From 4071c13e3a31c85fe1fa72fc8313dbfa4c468261 Mon Sep 17 00:00:00 2001 From: asmodai Date: Sat, 23 May 2015 00:55:26 +0300 Subject: [PATCH 3/3] Fixed demo tests passing. Don't generate any JIT code for empty delta memblocks. Added bits, bytecount and sendfields checks to delta unit tests. Small optimizations and fixes. --- rehlds/engine/delta.cpp | 44 +++++---- rehlds/engine/delta.h | 6 +- rehlds/engine/delta_jit.cpp | 93 +++++++++++------- rehlds/engine/delta_jit.h | 3 +- rehlds/engine/sv_main.cpp | 10 +- rehlds/unittests/delta_tests.cpp | 163 +++++++++++++++++++++---------- 6 files changed, 210 insertions(+), 109 deletions(-) diff --git a/rehlds/engine/delta.cpp b/rehlds/engine/delta.cpp index 5bc7ab3..c126ecb 100644 --- a/rehlds/engine/delta.cpp +++ b/rehlds/engine/delta.cpp @@ -402,7 +402,7 @@ void DELTA_SetFieldByIndex(struct delta_s *pFields, int fieldNumber) void DELTA_UnsetFieldByIndex(struct delta_s *pFields, int fieldNumber) { #if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) - DELTA_UnsetFieldByIndex(pFields, fieldNumber); + DELTAJit_UnsetFieldByIndex(pFields, fieldNumber); #else pFields->pdd[fieldNumber].flags &= ~FDT_MARK; #endif @@ -450,12 +450,20 @@ int DELTA_TestDelta(unsigned char *from, unsigned char *to, delta_t *pFields) case DT_ANGLE: different = *(uint32 *)&from[pTest->fieldOffset] != *(uint32 *)&to[pTest->fieldOffset]; break; +#ifdef REHLDS_FIXES + // don't use multiplier when checking, to increase performance + case DT_TIMEWINDOW_8: + case DT_TIMEWINDOW_BIG: + different = (int32)(*(float *)&from[pTest->fieldOffset]) != (int32)(*(float *)&to[pTest->fieldOffset]); + break; +#else case DT_TIMEWINDOW_8: different = (int32)(*(float *)&from[pTest->fieldOffset] * 100.0) != (int32)(*(float *)&to[pTest->fieldOffset] * 100.0); break; case DT_TIMEWINDOW_BIG: different = (int32)(*(float *)&from[pTest->fieldOffset] * 1000.0) != (int32)(*(float *)&to[pTest->fieldOffset] * 1000.0); break; +#endif case DT_STRING: st1 = (char*)&from[pTest->fieldOffset]; st2 = (char*)&to[pTest->fieldOffset]; @@ -571,21 +579,17 @@ void DELTA_SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount) delta_description_t *pTest; int i; int lastbit = -1; - int bitnumber; int fieldCount = pFields->fieldCount; Q_memset(bits, 0, 8); - lastbit = -1; - bitnumber = -1; for (i = fieldCount - 1, pTest = &pFields->pdd[i]; i >= 0; i--, pTest--) { if (pTest->flags & FDT_MARK) { if (lastbit == -1) - bitnumber = i; + lastbit = i; bits[i > 31 ? 1 : 0] |= 1 << (i & 0x1F); - lastbit = bitnumber; } } @@ -622,13 +626,13 @@ void DELTA_WriteMarkedFields(unsigned char *from, unsigned char *to, delta_t *pF for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) { -#ifndef REHLDS_FIXES - if (!(pTest->flags & FDT_MARK)) - continue; -#else // REHLDS_FIXES +#if defined (REHLDS_OPT_PEDANTIC) || defined (REHLDS_FIXES) if (!DELTA_IsFieldMarked(pFields, i)) continue; -#endif // REHLDS_FIXES +#else + if (!(pTest->flags & FDT_MARK)) + continue; +#endif fieldSign = pTest->fieldType & DT_SIGNED; fieldType = pTest->fieldType & ~DT_SIGNED; @@ -728,15 +732,15 @@ void DELTA_WriteMarkedFields(unsigned char *from, unsigned char *to, delta_t *pF /* <2467e> ../engine/delta.c:924 */ qboolean DELTA_CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields) { - int sendfields; + qboolean sendfields; #if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) - sendfields = DELTAJit_Feilds_Clear_Mark_Check(from, to, pFields); + sendfields = DELTAJit_Fields_Clear_Mark_Check(from, to, pFields); #else DELTA_ClearFlags(pFields); DELTA_MarkSendFields(from, to, pFields); -#endif sendfields = DELTA_CountSendFields(pFields); +#endif return sendfields; } @@ -748,7 +752,7 @@ NOINLINE qboolean DELTA_WriteDelta(unsigned char *from, unsigned char *to, qbool int bytecount; #if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) - sendfields = DELTAJit_Feilds_Clear_Mark_Check(from, to, pFields); + sendfields = DELTAJit_Fields_Clear_Mark_Check(from, to, pFields); #else // REHLDS_OPT_PEDANTIC || REHLDS_FIXES DELTA_ClearFlags(pFields); DELTA_MarkSendFields(from, to, pFields); @@ -759,11 +763,11 @@ NOINLINE qboolean DELTA_WriteDelta(unsigned char *from, unsigned char *to, qbool return sendfields; } -int _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)( void ), int sendfields) +qboolean _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)( void ), qboolean sendfields) { int i; int bytecount; - int bits[2]; // this is a limit with 64 fields max in delta + int bits[2]; if (sendfields || force) { @@ -1090,6 +1094,12 @@ delta_t *DELTA_BuildFromLinks(delta_link_t **pplinks) DELTA_ReverseLinks(pplinks); count = DELTA_CountLinks(*pplinks); + +#ifdef REHLDS_FIXES + if (count > DELTA_MAX_FIELDS) + Sys_Error(__FUNCTION__ ": Too many fields in delta description %i (MAX %i)\n", count, DELTA_MAX_FIELDS); +#endif + pdesc = (delta_description_t *)Mem_ZeroMalloc(sizeof(delta_description_t) * count); for (p = *pplinks, pcur = pdesc; p != NULL; p = p->next, pcur++) diff --git a/rehlds/engine/delta.h b/rehlds/engine/delta.h index cc9cb75..893e908 100644 --- a/rehlds/engine/delta.h +++ b/rehlds/engine/delta.h @@ -29,6 +29,8 @@ #include "maintypes.h" +#define DELTA_MAX_FIELDS 56 // 7*8 + #define DT_BYTE BIT(0) // A byte #define DT_SHORT BIT(1) // 2 byte field #define DT_FLOAT BIT(2) // A floating point field @@ -137,8 +139,8 @@ void DELTA_SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount); qboolean DELTA_IsFieldMarked(delta_t* pFields, int fieldNumber); void DELTA_WriteMarkedFields(unsigned char *from, unsigned char *to, delta_t *pFields); qboolean DELTA_CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields); -qboolean DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)( void )); -qboolean _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void), int sendfields); +qboolean DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void)); +qboolean _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void), qboolean sendfields); int DELTA_ParseDelta(unsigned char *from, unsigned char *to, delta_t *pFields); void DELTA_AddEncoder(char *name, void(*conditionalencode)(struct delta_s *, const unsigned char *, const unsigned char *)); void DELTA_ClearEncoders(void); diff --git a/rehlds/engine/delta_jit.cpp b/rehlds/engine/delta_jit.cpp index 4c971d7..6358701 100644 --- a/rehlds/engine/delta_jit.cpp +++ b/rehlds/engine/delta_jit.cpp @@ -3,6 +3,20 @@ CDeltaJitRegistry g_DeltaJitRegistry; +bool deltajit_memblock::isEmpty() const +{ + if (numFields == 0) + return true; + + for (size_t i = 0; i < numFields; i++) + { + if (fields[i].mask != 0) + return false; + } + + return true; +} + uint32 DELTAJIT_CreateMask(int startBit, int endBit) { if (startBit < 0) startBit = 0; if (endBit < 0) endBit = 0; @@ -185,9 +199,9 @@ void CDeltaClearMarkFieldsJIT::calculateBytecount() { // 8-15 if (jitdesc->numFields > 7) { - mov(ecx, 2); + mov(esi, 2); test(eax, 0xFF00); - cmovnz(edx, ecx); + cmovnz(edx, esi); } // 16-23 @@ -201,9 +215,9 @@ void CDeltaClearMarkFieldsJIT::calculateBytecount() { // 24-31 if (jitdesc->numFields > 23) { - mov(ecx, 4); + mov(esi, 4); test(eax, 0xFF000000); - cmovnz(edx, ecx); + cmovnz(edx, esi); } if (jitdesc->numFields > 31) @@ -218,9 +232,9 @@ void CDeltaClearMarkFieldsJIT::calculateBytecount() { // 40-47 if (jitdesc->numFields > 39) { - mov(ecx, 6); + mov(esi, 6); test(eax, 0xFF00); - cmovnz(edx, ecx); + cmovnz(edx, esi); } // 48-55 @@ -231,12 +245,7 @@ void CDeltaClearMarkFieldsJIT::calculateBytecount() { cmovnz(edx, ecx); } - if (jitdesc->numFields > 55) - { - mov(ecx, 8); - test(eax, 0xFF000000); - cmovnz(edx, ecx); - } + // maxfields is 56 } size_t delta_masksize_offset = offsetof(CDeltaJit, markedFieldsMaskSize); @@ -251,33 +260,42 @@ CDeltaClearMarkFieldsJIT::Result CDeltaClearMarkFieldsJIT::main(Addr src, Addr d mov(esi, ptr[src]); mov(edi, ptr[dst]); - //mov(ebx, ptr[delta]); - //int fieldsOffset = (offsetof(delta_t, pdd)); - //mov(ebx, dword_ptr[ebx + fieldsOffset]); - movdqu(xmm3, xmmword_ptr[esi]); - movdqu(xmm4, xmmword_ptr[edi]); + + for (unsigned int i = 0; i < jitdesc->numblocks; i++) { + if (!jitdesc->blocks[i].isEmpty()) { + movdqu(xmm3, xmmword_ptr[esi + (i * 16)]); + movdqu(xmm4, xmmword_ptr[edi + (i * 16)]); + break; + } + } auto mask = ecx; xor_(mask, mask); - pxor(marked_fields_mask, marked_fields_mask); for (unsigned int i = 0; i < jitdesc->numblocks; i++) { + auto block = &jitdesc->blocks[i]; + + if (block->isEmpty()) + continue; + movdqa(xmm0, xmm3); movdqa(xmm1, xmm4); //prefetch next blocks - if (i + 1 < jitdesc->numblocks) { - movdqu(xmm3, xmmword_ptr[esi + ((i + 1) * 16)]); - movdqu(xmm4, xmmword_ptr[edi + ((i + 1) * 16)]); + for (unsigned int j = i + 1; j < jitdesc->numblocks; j++) { + if (!jitdesc->blocks[j].isEmpty()) { + movdqu(xmm3, xmmword_ptr[esi + (j * 16)]); + movdqu(xmm4, xmmword_ptr[edi + (j * 16)]); + break; + } } pcmpeqb(xmm0, xmm1); pmovmskb(mask, xmm0); not_(mask); - auto block = &jitdesc->blocks[i]; for (unsigned int j = 0; j < block->numFields; j++) { auto jitField = &block->fields[j]; @@ -322,8 +340,6 @@ CDeltaClearMarkFieldsJIT::Result CDeltaClearMarkFieldsJIT::main(Addr src, Addr d } } - processStrings(src, dst); - size_t delta_markbits_offset = offsetof(CDeltaJit, marked_fields_mask); //Before calling the condition encoder we have to save 'marked fields' mask @@ -331,33 +347,38 @@ CDeltaClearMarkFieldsJIT::Result CDeltaClearMarkFieldsJIT::main(Addr src, Addr d mov(ebx, ptr[deltaJit]); movdqu(xmmword_ptr[ebx + delta_markbits_offset], marked_fields_mask); + processStrings(src, dst); + //emit conditional encoder call callConditionalEncoder(src, dst, deltaJit); // check if mask is empty mov(edi, dword_ptr[ebx + delta_markbits_offset]); - mov(edx, dword_ptr[ebx + delta_markbits_offset + 4]); - or_(edi, edx); + or_(edi, dword_ptr[ebx + delta_markbits_offset + 4]); If(edi != 0); calculateBytecount(); Else(); //set maskSize to 0 if there are no marked fields size_t delta_masksize_offset = offsetof(CDeltaJit, markedFieldsMaskSize); - mov(dword_ptr[ebx + delta_masksize_offset], 0); + xor_(edx, edx); + mov(dword_ptr[ebx + delta_masksize_offset], edx); EndIf(); #ifndef REHLDS_FIXES add(esp, 12); //some local storage is required for precise DT_TIMEWINDOW marking #endif // REHLDS_FIXES - return edi; + return edx; } void CDeltaClearMarkFieldsJIT::processStrings(Addr src, Addr dst) { //This generator expects that following registers are already initialized: // esi = src // edi = dst + // ebx = deltaJit + + size_t delta_markbits_offset = offsetof(CDeltaJit, marked_fields_mask); //strings for (unsigned int i = 0; i < jitdesc->numFields; i++) { @@ -365,23 +386,21 @@ void CDeltaClearMarkFieldsJIT::processStrings(Addr src, Addr dst) { if (jitField->type != DT_STRING) continue; - mov(eax, esi); - mov(edx, edi); - add(eax, jitField->offset); - add(edx, jitField->offset); + // will be parallel + lea(eax, ptr[esi + jitField->offset]); + lea(edx, ptr[edi + jitField->offset]); push(eax); push(edx); mov(ecx, (size_t)&Q_stricmp); call(ecx); add(esp, 8); + xor_(ecx, ecx); test(eax, eax); setnz(cl); - movzx(ecx, cl); - movd(xmm0, ecx); - psllq(xmm0, jitField->id); - por(xmm5, xmm0); + shl(ecx, jitField->id & 31); + or_(ptr[ebx + delta_markbits_offset + ((jitField->id > 31) ? 4 : 0)], ecx); } } @@ -442,7 +461,7 @@ CDeltaJit* DELTAJit_LookupDeltaJit(const char* callsite, delta_t *pFields) { return deltaJit; } -NOINLINE int DELTAJit_Feilds_Clear_Mark_Check(unsigned char *from, unsigned char *to, delta_t *pFields) { +NOINLINE int DELTAJit_Fields_Clear_Mark_Check(unsigned char *from, unsigned char *to, delta_t *pFields) { CDeltaJit* deltaJit = DELTAJit_LookupDeltaJit(__FUNCTION__, pFields); CDeltaClearMarkFieldsJIT &func = *deltaJit->cleanMarkCheckFunc; return func(from, to, deltaJit); diff --git a/rehlds/engine/delta_jit.h b/rehlds/engine/delta_jit.h index 0c3666e..cdd9c50 100644 --- a/rehlds/engine/delta_jit.h +++ b/rehlds/engine/delta_jit.h @@ -23,6 +23,7 @@ struct deltajit_memblock_field { struct deltajit_memblock { unsigned int numFields; deltajit_memblock_field fields[24]; + bool isEmpty() const; }; struct deltajitdata_t { @@ -57,7 +58,7 @@ public: extern CDeltaJitRegistry g_DeltaJitRegistry; -extern int DELTAJit_Feilds_Clear_Mark_Check(unsigned char *from, unsigned char *to, delta_t *pFields); +extern int DELTAJit_Fields_Clear_Mark_Check(unsigned char *from, unsigned char *to, delta_t *pFields); extern void DELTAJit_SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount); extern void DELTAJit_SetFieldByIndex(struct delta_s *pFields, int fieldNumber); extern void DELTAJit_UnsetFieldByIndex(struct delta_s *pFields, int fieldNumber); diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index dd394be..a74e8f9 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -1387,11 +1387,17 @@ void SV_WriteClientdataToMessage(client_t *client, sizebuf_t *msg) else fdata = &host_client->frames[bits].weapondata[i]; - if (DELTA_CheckDelta((byte *)fdata, (byte *)tdata, (delta_t *)g_pweapondelta)) + if (DELTA_CheckDelta((byte *)fdata, (byte *)tdata, g_pweapondelta)) { MSG_WriteBits(1, 1); MSG_WriteBits(i, 6); - DELTA_WriteDelta((byte *)fdata, (byte *)tdata, TRUE, (delta_t *)g_pweapondelta, NULL); + +#if defined (REHLDS_OPT_PEDANTIC) || defined (REHLDS_FIXES) + // all calculations are already done + _DELTA_WriteDelta((byte *)fdata, (byte *)tdata, TRUE, g_pweapondelta, NULL, TRUE); +#else + DELTA_WriteDelta((byte *)fdata, (byte *)tdata, TRUE, g_pweapondelta, NULL); +#endif } } } diff --git a/rehlds/unittests/delta_tests.cpp b/rehlds/unittests/delta_tests.cpp index 4337aff..5bfc56d 100644 --- a/rehlds/unittests/delta_tests.cpp +++ b/rehlds/unittests/delta_tests.cpp @@ -27,6 +27,13 @@ struct delta_test_struct_t { }; #pragma pack(pop) +struct delta_res_t +{ + qboolean sendfields; + int bits[2]; + int bytecount; +}; + NOINLINE void _InitDeltaField(delta_description_t* fieldDesc, int expectedOffset, int type, const char* name, int off, short sz, int bits, float preMult, float postMult) { if (expectedOffset != off) { rehlds_syserror("%s: Expected and real offset mismatch (%d != %d)", expectedOffset, off); @@ -56,7 +63,7 @@ NOINLINE qboolean _DoMarkFields(void* src, void* dst, delta_t* delta, bool useJi qboolean sendfields; if (useJit) { DELTA_ClearFlags(delta); - return DELTAJit_Feilds_Clear_Mark_Check((unsigned char*)src, (unsigned char*)dst, delta); + return DELTAJit_Fields_Clear_Mark_Check((unsigned char*)src, (unsigned char*)dst, delta); } else { DELTA_ClearFlags(delta); DELTA_MarkSendFields((unsigned char*)src, (unsigned char*)dst, delta); @@ -118,9 +125,31 @@ NOINLINE void _EnsureFieldsChanged(const char* callsite, const char* action, int } } +NOINLINE void _GetBitmaskAndBytecount(delta_t* delta, int* bits, int* bytecount, int usejit) { + if (usejit) { + DELTAJit_SetSendFlagBits(delta, bits, bytecount); + } + else { + DELTA_SetSendFlagBits(delta, bits, bytecount); + } +} + +NOINLINE void _CompareDeltaResults(const char* callsite, delta_res_t* def, delta_res_t* jit, int testscount) +{ + for (int i = 0; i < testscount; i++) + { + if (!!def[i].sendfields != !!jit[i].sendfields) + rehlds_syserror("%s: Test %i: !!sendfields not equals %i|%i", callsite, i, !!def[i].sendfields, !!jit[i].sendfields); + if (memcmp(def[i].bits, jit[i].bits, 8)) + rehlds_syserror("%s: Test %i: bits not equals %p.%p|%p.%p", callsite, i, def[i].bits[0], def[i].bits[1], jit[i].bits[0], jit[i].bits[1]); + if (def[i].bytecount != jit[i].bytecount) + rehlds_syserror("%s: Test %i: bytecount not equal %i|%i", callsite, i, def[i].bytecount, jit[i].bytecount); + } +} + NOINLINE delta_t* _CreateTestDeltaDesc() { static delta_description_t _fields[32]; - delta_test_struct_t d; + delta_test_struct_t d; d; // "use" d variable _InitDeltaField(&_fields[0], 0x00, DT_BYTE, "b_00", offsetof(delta_test_struct_t, b_00), 1, 8, 1.0f, 1.0f); _InitDeltaField(&_fields[1], 0x01, DT_BYTE, "b_01", offsetof(delta_test_struct_t, b_01), 1, 8, 1.0f, 1.0f); @@ -166,198 +195,225 @@ NOINLINE delta_t* _CreateTestDeltaDesc() { }; TEST(MarkFieldsTest_Simple_Primitives, Delta, 1000) { -#ifdef REHLDS_FIXES - bool rehds_fixes = true; -#else - bool rehds_fixes = false; -#endif delta_t* delta = _CreateTestDeltaDesc(); delta_test_struct_t d1; delta_test_struct_t d2; + delta_res_t res[2][10]; + + memset(res[0], 0xCC, sizeof(res) / 2); + memset(res[1], 0xDD, sizeof(res) / 2); for (int usejit = 0; usejit <= 1; usejit++) { _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][0].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][0].bits, &res[usejit][0].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "SimpleUnchangedAll", usejit, true, delta, NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x72); - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][1].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][1].bits, &res[usejit][1].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "SimpleUnchangedAll", usejit, false, delta, NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_01 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][2].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][2].bits, &res[usejit][2].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Byte_0BlockCheck", usejit, true, delta, "b_01", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_11 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][3].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][3].bits, &res[usejit][3].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Byte_1BlockCheck", usejit, true, delta, "b_11", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.s_02 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][4].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][4].bits, &res[usejit][4].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Short_0BlockCheck", usejit, true, delta, "s_02", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.s_12 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][5].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][5].bits, &res[usejit][5].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Short_1BlockCheck", usejit, true, delta, "s_12", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_04 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][6].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][6].bits, &res[usejit][6].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Int_0BlockCheck", usejit, true, delta, "i_04", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_14 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][7].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][7].bits, &res[usejit][7].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Int_1BlockCheck", usejit, true, delta, "i_14", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.f_08 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][8].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][8].bits, &res[usejit][8].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Float_0BlockCheck", usejit, true, delta, "f_08", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.f_18 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][9].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][9].bits, &res[usejit][9].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Float_0BlockCheck", usejit, true, delta, "f_18", NULL); } + _CompareDeltaResults(__FUNCTION__, res[0], res[1], 10); SV_Shutdown(); } TEST(MarkFieldsTest_InterBlock, Delta, 1000) { -#ifdef REHLDS_FIXES - bool rehds_fixes = true; -#else - bool rehds_fixes = false; -#endif delta_t* delta = _CreateTestDeltaDesc(); delta_test_struct_t d1; delta_test_struct_t d2; + delta_res_t res[2][14]; + + memset(res[0], 0xCC, sizeof(res) / 2); + memset(res[1], 0xDD, sizeof(res) / 2); for (int usejit = 0; usejit <= 1; usejit++) { _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_4D = d2.b_52 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][0].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][0].bits, &res[usejit][0].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock1_guards", usejit, true, delta, "b_4D", "b_52", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_4D = d2.b_52 = 0; d2.i_4E = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][1].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][1].bits, &res[usejit][1].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock1_guards_and_val", usejit, true, delta, "b_4D", "b_52", "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][2].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][2].bits, &res[usejit][2].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val", usejit, true, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E &= 0xFFFFFF00; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][3].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][3].bits, &res[usejit][3].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_0b", usejit, true, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E &= 0xFFFF00FF; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][4].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][4].bits, &res[usejit][4].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_1b", usejit, true, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E &= 0xFF00FFFF; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][5].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][5].bits, &res[usejit][5].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_2b", usejit, true, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_4E &= 0x00FFFFFF; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][6].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][6].bits, &res[usejit][6].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock1_val_3b", usejit, true, delta, "i_4E", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_5C = d2.b_61 = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][7].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][7].bits, &res[usejit][7].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock2_guards", usejit, true, delta, "b_5C", "b_61", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.b_5C = d2.b_61 = 0; d2.i_5D = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][8].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][8].bits, &res[usejit][8].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock2_guards_and_val", usejit, true, delta, "b_5C", "b_61", "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][9].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][9].bits, &res[usejit][9].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val", usejit, true, delta, "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D &= 0xFFFFFF00; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][10].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][10].bits, &res[usejit][10].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_0b", usejit, true, delta, "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D &= 0xFFFF00FF; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][11].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][11].bits, &res[usejit][11].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_1b", usejit, true, delta, "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D &= 0xFF00FFFF; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][12].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][12].bits, &res[usejit][12].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_2b", usejit, true, delta, "i_5D", NULL); _FillTestDelta(&d1, 0x71); _FillTestDelta(&d2, 0x71); d2.i_5D &= 0x00FFFFFF; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][13].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][13].bits, &res[usejit][13].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Interblock2_val_3b", usejit, true, delta, "i_5D", NULL); - } + _CompareDeltaResults(__FUNCTION__, res[0], res[1], 14); SV_Shutdown(); } TEST(MarkFieldsTest_Strings, Delta, 1000) { -#ifdef REHLDS_FIXES - bool rehds_fixes = true; -#else - bool rehds_fixes = false; -#endif delta_t* delta = _CreateTestDeltaDesc(); delta_test_struct_t d1; delta_test_struct_t d2; + delta_res_t res[2][4]; + + memset(res[0], 0xCC, sizeof(res) / 2); + memset(res[1], 0xDD, sizeof(res) / 2); for (int usejit = 0; usejit <= 1; usejit++) { _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d2.s_24[0] = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][0].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][0].bits, &res[usejit][0].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Str_empty", usejit, true, delta, "s_24", NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d1.s_24[0] = 0; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][1].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][1].bits, &res[usejit][1].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Str_empty2", usejit, true, delta, "s_24", NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d1.s_24[0] = d2.s_24[0] = 0; d1.s_24[1] = 'd'; d2.s_24[1] = 'e'; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][2].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][2].bits, &res[usejit][2].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Str_both_empty_with_garbage", usejit, true, delta, NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d1.s_24[1] = 'C'; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][3].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][3].bits, &res[usejit][3].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "Str_case_check", usejit, true, delta, NULL); } + _CompareDeltaResults(__FUNCTION__, res[0], res[1], 4); SV_Shutdown(); } @@ -372,25 +428,32 @@ TEST(MarkFieldsTest_TimeWindow, Delta, 1000) { delta_test_struct_t d1; delta_test_struct_t d2; + delta_res_t res[2][3]; + + memset(res[0], 0xCC, sizeof(res) / 2); + memset(res[1], 0xDD, sizeof(res) / 2); for (int usejit = 0; usejit <= 1; usejit++) { _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d2.w8_1C = 0.001f; d1.w8_1C = 0.0011f; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][0].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][0].bits, &res[usejit][0].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Below_Precision", usejit, true, delta, rehds_fixes ? "w8_1C" : NULL, NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d2.w8_1C = 0.1f; d1.w8_1C = 0.11f; //precision check, 0.11f is actually 0.10999 - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][1].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][1].bits, &res[usejit][1].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Above_Precision1", usejit, true, delta, rehds_fixes ? "w8_1C" : NULL, NULL); _FillTestDelta(&d1, 'c'); _FillTestDelta(&d2, 'c'); d2.w8_1C = 0.1f; d1.w8_1C = 0.12f; - _DoMarkFields(&d1, &d2, delta, usejit != 0); + res[usejit][2].sendfields = _DoMarkFields(&d1, &d2, delta, usejit != 0); + _GetBitmaskAndBytecount(delta, res[usejit][2].bits, &res[usejit][2].bytecount, usejit); _EnsureFieldsChanged(__FUNCTION__, "TimeWindow_Above_Precision2", usejit, true, delta, "w8_1C", NULL); - } + _CompareDeltaResults(__FUNCTION__, res[0], res[1], 3); SV_Shutdown(); }