(I’ve created a minimal project to reproduce the issue, attached bellow)
I’m syncing the entity reference to MonoBehaviour script for creating a user interface.
Originally I needed both the entity and the buffer reference from MonoBehaviour so this was working as expected, but then I removed the buffer and suddenly the error started being thrown.
Here is the SystemBase code from the .unitypackage attached:
using UnityEngine;
using Unity.Entities;
public class TestSystem : SystemBase
{
protected override void OnUpdate()
{
Test test = GameObject.Find("Test").GetComponent<Test>();
Entity matchedEntity = Entity.Null;
Entities
.WithAll<TestTag>()
.ForEach((
Entity entity) =>
{
// should be only one TestTag entity in the scene
matchedEntity = entity;
}
)
.Run();
// this is what I want to sync and it works but only if there is
// a step of copying to native array like bellow
test.testEntity = matchedEntity;
if (matchedEntity == Entity.Null) return;
// THIS HERE: if the following is commented, the error is thrown
// "InvalidProgramException: Invalid IL code in TestSystem:OnUpdate () ..."
GetBufferFromEntity<TestBufferData>(true)[matchedEntity]
.ToNativeArray(Unity.Collections.Allocator.Temp)
.CopyTo(test.testBuffer);
}
}
So when the copying to NativeArray is commented, the error is thrown.
I’m not sure how to debug this further. Any suggestions?
6450075–724054–Reproduce_ECS_Bug.unitypackage (3.49 KB)
Setting InternalBufferCapacity to 0 still works, so copying to an empty NativeArray makes it work, but without copying it throws
Seems that the buffer is not necessary, copying like this works too:
(new NativeArray<int>(0, Allocator.Temp))
.CopyTo(test._fakeArrayToMakeECSWork);
tertle
October 23, 2020, 10:26pm
4
I’m curious what the code gen looks like and how its screwed it up, can you post it?
Sure, where can I find generated code?
tertle
October 26, 2020, 4:22am
6
DOTS → Dots Compiler → Open inspector
Here is the diff with the working code:
109:(-) Test component = GameObject.Find("Test").GetComponent<Test>();
109:(+) GameObject.Find("Test").GetComponent<Test>();
127:(-) component.testEntity = displayClass.matchedEntity;
128:(-) if (!(displayClass.matchedEntity == Entity.Null))
129:(-) {
130:(-) new NativeArray<int>(0, Allocator.Temp).CopyTo(component.intNativeArray);
131:(-) }
127:(+) Entity matchedEntity = displayClass.matchedEntity;
128:(+) ((Test)/*Error near IL_00b7: Stack underflow*/).testEntity = matchedEntity;
129:(+) _ = (displayClass.matchedEntity == Entity.Null);
And here is the full failing code:
#define ENABLE_PROFILER
using System.Runtime.CompilerServices;
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Entities;
using Unity.Entities.CodeGeneratedJobForEach;
using Unity.Jobs.LowLevel.Unsafe;
using Unity.Profiling;
using UnityEngine;
public class TestSystem : SystemBase
{
[Unity.Entities.DOTSCompilerGenerated]
[BurstCompile]
[NoAlias]
private struct <>c__DisplayClass_OnUpdate_LambdaJob0 : IJobChunk
{
private struct LambdaParameterValueProviders
{
[NoAlias]
public struct Runtimes
{
[NoAlias]
public LambdaParameterValueProvider_Entity.Runtime runtime_entity;
}
[ReadOnly]
[NoAlias]
private LambdaParameterValueProvider_Entity forParameter_entity;
public void ScheduleTimeInitialize(TestSystem componentSystem)
{
forParameter_entity.ScheduleTimeInitialize(componentSystem, isReadOnly: true);
}
public Runtimes PrepareToExecuteOnEntitiesInMethod(ref ArchetypeChunk p0, int p1, int p2)
{
Runtimes result = default(Runtimes);
result.runtime_entity = forParameter_entity.PrepareToExecuteOnEntitiesIn(ref p0);
return result;
}
}
public Entity matchedEntity;
private LambdaParameterValueProviders _lambdaParameterValueProviders;
[NativeDisableUnsafePtrRestriction]
private unsafe LambdaParameterValueProviders.Runtimes* _runtimes;
private static InternalCompilerInterface.JobChunkRunWithoutJobSystemDelegate s_RunWithoutJobSystemDelegateFieldNoBurst;
private static InternalCompilerInterface.JobChunkRunWithoutJobSystemDelegate s_RunWithoutJobSystemDelegateFieldBurst;
internal void OriginalLambdaBody(Entity entity)
{
matchedEntity = entity;
}
public void ReadFromDisplayClass(ref <>c__DisplayClass0_0 displayClass)
{
matchedEntity = displayClass.matchedEntity;
}
public void WriteToDisplayClass(ref <>c__DisplayClass0_0 displayClass)
{
displayClass.matchedEntity = matchedEntity;
}
public unsafe void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
{
LambdaParameterValueProviders.Runtimes runtimes = _lambdaParameterValueProviders.PrepareToExecuteOnEntitiesInMethod(ref chunk, chunkIndex, firstEntityIndex);
_runtimes = &runtimes;
IterateEntities(ref chunk, ref *_runtimes);
}
[MethodImpl(MethodImplOptions.NoInlining)]
public void IterateEntities(ref ArchetypeChunk chunk, [NoAlias] ref LambdaParameterValueProviders.Runtimes runtimes)
{
int count = chunk.Count;
for (int i = 0; i < count; i++)
{
OriginalLambdaBody(runtimes.runtime_entity.For(i));
}
}
public void ScheduleTimeInitialize(TestSystem componentSystem, ref <>c__DisplayClass0_0 displayClass)
{
_lambdaParameterValueProviders.ScheduleTimeInitialize(componentSystem);
ReadFromDisplayClass(ref displayClass);
}
[BurstCompile]
[Unity.Entities.MonoPInvokeCallback(typeof(InternalCompilerInterface.JobChunkRunWithoutJobSystemDelegate))]
public unsafe static void RunWithoutJobSystem(ArchetypeChunkIterator* archetypeChunkIterator, void* jobData)
{
UnsafeUtility.AsRef<<>c__DisplayClass_OnUpdate_LambdaJob0>(jobData).RunWithoutJobs(ref *archetypeChunkIterator);
}
}
private EntityQuery <>OnUpdate_LambdaJob0_entityQuery;
private ProfilerMarker <>OnUpdate_LambdaJob0_profilerMarker;
protected unsafe override void OnUpdate()
{
<>c__DisplayClass0_0 displayClass = default(<>c__DisplayClass0_0);
Test component = GameObject.Find("Test").GetComponent<Test>();
GameObject.Find("Test").GetComponent<Test>();
displayClass.matchedEntity = Entity.Null;
_ = base.Entities;
<>c__DisplayClass_OnUpdate_LambdaJob0 jobData = default(<>c__DisplayClass_OnUpdate_LambdaJob0);
jobData.ScheduleTimeInitialize(this, ref displayClass);
CompleteDependency();
EntityQuery query = <>OnUpdate_LambdaJob0_entityQuery;
InternalCompilerInterface.JobChunkRunWithoutJobSystemDelegate functionPointer = JobsUtility.JobCompilerEnabled ? <>c__DisplayClass_OnUpdate_LambdaJob0.s_RunWithoutJobSystemDelegateFieldBurst : <>c__DisplayClass_OnUpdate_LambdaJob0.s_RunWithoutJobSystemDelegateFieldNoBurst;
<>OnUpdate_LambdaJob0_profilerMarker.Begin();
try
{
InternalCompilerInterface.RunJobChunk(ref jobData, query, functionPointer);
}
finally
{
<>OnUpdate_LambdaJob0_profilerMarker.End();
}
jobData.WriteToDisplayClass(ref displayClass);
Entity matchedEntity = displayClass.matchedEntity;
((Test)/*Error near IL_00b7: Stack underflow*/).testEntity = matchedEntity;
_ = (displayClass.matchedEntity == Entity.Null);
}
protected internal unsafe override void OnCreateForCompiler()
{
base.OnCreateForCompiler();
<>OnUpdate_LambdaJob0_entityQuery = <>GetEntityQuery_ForOnUpdate_LambdaJob0_From(this);
<>c__DisplayClass_OnUpdate_LambdaJob0.s_RunWithoutJobSystemDelegateFieldNoBurst = <>c__DisplayClass_OnUpdate_LambdaJob0.RunWithoutJobSystem;
<>c__DisplayClass_OnUpdate_LambdaJob0.s_RunWithoutJobSystemDelegateFieldBurst = InternalCompilerInterface.BurstCompile(<>c__DisplayClass_OnUpdate_LambdaJob0.s_RunWithoutJobSystemDelegateFieldNoBurst);
<>OnUpdate_LambdaJob0_profilerMarker = new ProfilerMarker("OnUpdate_LambdaJob0");
}
public static EntityQuery <>GetEntityQuery_ForOnUpdate_LambdaJob0_From(ComponentSystemBase componentSystem)
{
EntityQueryDesc[] array = new EntityQueryDesc[1];
(array[0] = new EntityQueryDesc()).All = new ComponentType[1]
{
ComponentType.ReadOnly<TestTag>()
};
return componentSystem.GetEntityQuery(array);
}
}
Unity.Entities version: "com.unity.entities": "0.14.0-preview.19"
Tested on Unity 2020.1.7f1
and 2020.1.10f1