Description
openedon Mar 21, 2024
Description
We are embeding mono in UnrealEngine, when we upgrade .ne8.0(v8.0.2), we found sgen-gc will not set static field back after object move when enable hotreloadcomponent.
Reproduction Steps
We have not separate code to reproduct it, but I will describe it as detailed as possible.
we have restore object in static field, when next pass it to internal call the object address after the gc have move it, the value not set back.
I show the code first:
public partial class FTicker : ScriptingWrapperOfType
{
public static FTicker Internal_GetCoreTicker_Cache = null;
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern FTicker Internal_GetCoreTicker();
public static FTicker GetCoreTicker()
{
if(Internal_GetCoreTicker_Cache == null)
{
Internal_GetCoreTicker_Cache = Internal_GetCoreTicker();
}
return Internal_GetCoreTicker_Cache;
}
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void TearDownCoreTicker();
[MethodImpl(MethodImplOptions.InternalCall)]
public extern FDelegateHandle AddTicker(TDelegate__float_Ret_bool InDelegate, float InDelay = 0.0f);
}
the internal call
static FDelegateHandle_Proxy Internal_FTicker_AddTicker(MonoObject* self, MonoDelegate* InDelegate, float InDelay)
{
// these code is use for debug this problem
MonoImage* EngineImage = GetScriptingAssemblyManager().FindImage("UnrealEngine");
if (EngineImage)
{
MonoClass* TickerClass = mono_class_from_name(EngineImage, "UnrealEngine", "FTicker");
if (TickerClass)
{
MonoClassField* Internal_GetCoreTicker_Cache = mono_class_get_field_from_name(TickerClass, "Internal_GetCoreTicker_Cache");
if (Internal_GetCoreTicker_Cache)
{
MonoObject* data = nullptr;
MONO_ENTER_GC_UNSAFE
mono_field_static_get_value(mono_class_vtable(mono_domain_get(), TickerClass), Internal_GetCoreTicker_Cache, &data);
MONO_EXIT_GC_UNSAFE
}
}
}
// below is the real logic
TRACE_INTERALCALL_PROFILER_EVENT_SCOPE
TDelegate<bool(float)> InDelegate__Temp;
BindScriptIfException<bool, float>(InDelegate__Temp, InDelegate, true);
return FDelegateHandle_Proxy::Proxy(ReadonlyScriptingObjectConverter<FTicker>(self)->AddTicker(InDelegate__Temp, InDelay));
}
the code logic execute as below :
tickHandle = FTicker.GetCoreTicker().AddTicker(OnTick);
// gc occured
tickHandle1 = FTicker.GetCoreTicker().AddTicker(OnTick1);
// but the second call `Internal_FTicker_AddTicker` the `self` object the vtable have set null and then can't get the object class.
I show the behaviors with hotreload component enable or not.
if we not enable hotreload component, just use jit execute mode, it work correctly:
the first call AddTicker
, we can checkout the self
object:
and we check the Internal_GetCoreTicker_Cache
static field:
the second call the self
object address have changed:
if we enable hotreload component, the static field will not write back:
the first call:
the second call: the self object address have not been changed but the vtable
is null
Expected behavior
work correctly
Actual behavior
crash
Regression?
.net7.0 work correctly
Known Workarounds
no
Configuration
windows
build v8.0.2 tag
set excute mode mono_jit_set_aot_mode(MONO_AOT_MODE_INTERP_ONLY);
Other information
No response