https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119314

--- Comment #8 from Novel <root at hsnovel dot net> ---
(In reply to Sam James from comment #7)
> Please try to reduce the relevant functions and we can take a look with a
> testcase.

I am not sure to what extend it is possible for you to make a testcase for it
because as much as I try to reduce the functions around it, everything is kind
of interconnected to each other but, the following code does still produce the
same anomaly, even tough a large portion of the actual code is removed. I am
not sure if you can make a testcase, but regardless the following is the code:
(I stripped some api prefixes and renamed some types and variables that might
revel something, so there might be a typo)

Also note that the program code gets loaded by Java virtual machine over JNI.
So the types jobject and jstring are Java Native Interface's types. And the
function GetPlayerName doesn't get called in anywhere in the codebase.

Here is the code:

/* 
=======================
LUT is a struct that merely contains pointers to fixed sized arrays.
playerObjects variable are: (will make sense later)

typedef struct {
    UINT slotGenerationCounter;
    jobject Object;
} LUT_OBJECT;

UINT is typedef to uint32_t
=======================
*/

static LUT GlobalLookupTable;
__thread LUT *ThreadLocalLUT; // This points to GlobalLookupTable in this
particular case

typedef struct {
    UINT slot;
    UINT SlotGenerationCounter;
} PLAYER_HANDLE __aligned(8);

__force_inline static jobject
IsPlayerHandleValid(
    PLAYER_HANDLE PlayerHandle
    )
{
    LUT_OBJECT Slot = ThreadLocalLUT->playerObjects[PlayerHandle.slot];

    if (likely(PlayerHandle.slot <= MAX_PLAYER_COUNT))
    {
        UINT ExistingSlotGenerationCounter = Slot.SlotGenerationCounter;
        jobject PlayerObject = Slot.Object;

        if(likely(ExistingSlotGenerationCounter ==
PlayerHandle.SlotGenerationCounter)
           && likely(PlayerObject))
        {
            return PlayerObject;
        }
        else
        {
            return NULL;
        }
    }
    else
    {
        return NULL;
    }
}

// The calls to writeJStringToMemory and getJStringUTFSize call
// a function that is executed by the Java virtual machine.
static void
LUT_UpdateStringWithJString(
    LUT_STRING *dest,
    jstring newString,
    STRING dup
    )
{
    if(lut_shouldCacheResult())
    {
        UINT nameSize = getJStringUTFSize( newString );
        THREAD_LOCAL_STORAGE *tctx = GetThreadLocalStorage();
        STRING result = {
            .Size = nameSize,
            .Data = PoolPush(&tctx->TempArena, nameSize),
        };

        writeJStringToMemory( newString, result.Size, result.Data );
        memcpy(dup.Data, result.Data, dup.Size);
        dest->string = result;
        dest->eventGenerationCounter = ThreadLocalLUT->eventGenerationCounter;
    }
    else
    {
        writeJStringToMemory( newString, dup.Size, dup.Data );
    }
}


static UINT
GetPlayerName(
    PLAYER_HANDLE Player,
    VSP_STRING dest
    )
{
    PLAYER_HANDLE PlayerHandle = Player;

    if(IsPlayerHandleValid(PlayerHandle))
    {
        // LUT_GoThroughCache is a tail function, that doesn't have any
sidefects nor any special attributes. It doesn't modify any global state, nor
does it mutate anything.
       
if(!LUT_GoThroughCache(ThreadLocalLUT->PlayerNames[PlayerHandle.slot].EventGenerationCounter))
        {
            jobject Player =
ThreadLocalLUT->playerObjects[PlayerHandle.slot].Object;
            jstring PlayerName = GetPlayerName(Player);
           
LUT_UpdateStringWithJString(&ThreadLocalLUT->PlayerNames[playerHandle.slot],
PlayerName, dest);
        }

        STRING CachedName =
ThreadLocalLUT->PlayerNames[PlayerHandle.slot].String;

        DEBUG_LOG_INFO("2 Data %p\n", dest.Data);
        DEBUG_LOG_INFO("2 Size %d\n", dest.Size);

        if (dest.Data)
        {
            DEBUG_LOG_INFO("3 Data %p\n", dest.Data);
            U32 CopySize = Min(CachedName.Size, dest.Size);
            memcpy(dest.Data, CachedName.Data, CopySize);
            return CopySize;
        }
        else
        {
            return CachedName.Size;
        }
    }
    else
    {
        // This is not relevant same thing happens even if this is removed.
        INVALID_ARGUMENT_PASSED_CALLBACK("Invalid Player handle");
    }

    return 0;
}

This is as much code as I can share. I am not allowed to reveal more.

Reply via email to