2
0
mirror of https://github.com/rehlds/rehlds.git synced 2024-12-29 08:05:50 +03:00

Delta JIT improvements.

This commit is contained in:
Andrey 2015-05-22 02:38:25 +03:00
parent 31bfe3db78
commit 7fdb4f73bc
5 changed files with 343 additions and 137 deletions

View File

@ -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)

View File

@ -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);

View File

@ -107,7 +107,7 @@ void DELTAJIT_CreateDescription(delta_t* delta, deltajitdata_t &jitdesc) {
}
class CDeltaClearMarkFieldsJIT : public jitasm::function<int, CDeltaClearMarkFieldsJIT, void*, void*, void*> {
class CDeltaClearMarkFieldsJIT : public jitasm::function<int, CDeltaClearMarkFieldsJIT, void*, void*, void*, void*, void*, int> {
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() {

View File

@ -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);

View File

@ -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);
}