示例#1
0
        internal static SyntaxNode SchedulingInvocationFor(LambdaJobDescription description)
        {
            string ExecuteMethodArgs()
            {
                var argStrings = description.VariablesCaptured.Where(variable => !variable.IsThis)
                                 .Select(variable => (description.ScheduleMode == ScheduleMode.Run && variable.IsWritable)
                        ? $"ref {variable.OriginalVariableName}" : variable.OriginalVariableName).ToList();

                if (description.DependencyArgument != null)
                {
                    argStrings.Add($@"{description.DependencyArgument.ToString()}");
                }
                if (description.WithFilter_EntityArray != null)
                {
                    argStrings.Add($@"{description.WithFilter_EntityArray.ToString()}");
                }

                foreach (var argumentSyntax in description.WithSharedComponentFilterArgumentSyntaxes)
                {
                    if (argumentSyntax.Expression is IdentifierNameSyntax && description.VariablesCaptured.All(variable => variable.OriginalVariableName != argumentSyntax.ToString()))
                    {
                        argStrings.Add(argumentSyntax.ToString());
                    }
                }

                return(argStrings.Distinct().SeparateByComma());
            }

            var template = $@"{description.ExecuteInSystemMethodName}{GenericArguments(description)}({ExecuteMethodArgs()}));";

            return(SyntaxFactory.ParseStatement(template).DescendantNodes().OfType <InvocationExpressionSyntax>().FirstOrDefault());
        }
示例#2
0
 static string RunWithoutJobSystemMethod(LambdaJobDescription description)
 {
     if (description.LambdaJobKind == LambdaJobKind.Entities)
     {
         var type = description.NeedsEntityInQueryIndex ? "Unity.Entities.JobEntityBatchIndexExtensions" : "Unity.Entities.JobEntityBatchExtensions";
         if (description.WithFilter_EntityArray != null)
         {
             return($@"
             {BurstCompileAttribute(description)}
             public static unsafe void RunWithoutJobSystem(EntityQuery* query, Entity* limitToEntityArray, int limitToEntityArrayLength, void* jobPtr)
             {{
                 {type}.RunWithoutJobsInternal(ref Unity.Collections.LowLevel.Unsafe.UnsafeUtility.AsRef<{description.JobStructName}>(jobPtr), ref *query, limitToEntityArray, limitToEntityArrayLength);
             }}");
         }
         else
         {
             return($@"
             {BurstCompileAttribute(description)}
             public static unsafe void RunWithoutJobSystem(ArchetypeChunkIterator* archetypeChunkIterator, void* jobPtr)
             {{
                 {type}.RunWithoutJobsInternal(ref Unity.Collections.LowLevel.Unsafe.UnsafeUtility.AsRef<{description.JobStructName}>(jobPtr), ref *archetypeChunkIterator);
             }}");
         }
     }
     else
     {
         return($@"
             {BurstCompileAttribute(description)}
             public static unsafe void RunWithoutJobSystem(void* jobPtr)
             {{
                 Unity.Collections.LowLevel.Unsafe.UnsafeUtility.AsRef<{description.JobStructName}>(jobPtr).Execute();
             }}");
     }
 }
示例#3
0
        internal static ClassDeclarationSyntax GenericEntityQueryWrapperFor(LambdaJobDescription description)
        {
            // TODO: Need to handle multiple generic parameters
            var template = $@"
                public static class EntityQueryWrapper{description.Name}<T> {GenericParameterConstraints(description)}
                {{
                    public static bool _created = false;
                    public static EntityQuery {description.QueryName};

                    static EntityQueryWrapper{description.Name}()
                    {{
                        _created = false;
                    }}

                    public static EntityQuery GetQuery(SystemBase system)
                    {{
                        if (!_created)
                        {{
                            {description.QueryName} = system.{EntityQuerySetupStatementFor(description)}
                            _created = true;
                        }}
                        return {description.QueryName};
                    }}
                }}";

            return((ClassDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration(template));
        }
示例#4
0
        internal static MethodDeclarationSyntax LambdaBodyMethodFor(LambdaJobDescription description)
        {
            var template = $@"void {description.LambdaBodyMethodName}({description.LambdaParameters.Select(
                param => param.LambdaBodyMethodParameter(description.UsesBurst)).SeparateByComma()})
            {description.RewrittenLambdaBody.ToString()}";

            return((MethodDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration(template));
        }
示例#5
0
        static string GenericParameterConstraints(LambdaJobDescription description)
        {
            string ParamConstraintFor(ITypeSymbol symbol) => $@"{symbol.Name}";
            string GenericParameterFor(LambdaParamDescription_Generic param) =>
            $@" where T : unmanaged, {param.Constraints.Select(constraint => ParamConstraintFor(constraint)).SeparateByComma()}";

            return(description.LambdaParameters.OfType <LambdaParamDescription_Generic>()
                   .Select(GenericParameterFor).SeparateByComma());
        }
示例#6
0
        static string SharedComponentFilterInvocations(LambdaJobDescription description)
        {
            var sb = new StringBuilder();

            foreach (var argumentSyntax in description.WithSharedComponentFilterArgumentSyntaxes)
            {
                sb.AppendLine($@"{description.QueryName}.SetSharedComponentFilter({argumentSyntax});");
            }
            return(sb.ToString());
        }
示例#7
0
        static IEnumerable <string> DistinctQueryTypesFor(LambdaJobDescription description)
        {
            var readOnlyTypeNames  = new HashSet <string>();
            var readWriteTypeNames = new HashSet <string>();

            void AddQueryType(ITypeSymbol queryType, bool isReadOnly)
            {
                if (queryType != null)
                {
                    if (!isReadOnly)
                    {
                        readOnlyTypeNames.Remove(queryType.ToFullName());
                        readWriteTypeNames.Add(queryType.ToFullName());
                    }
                    else
                    {
                        if (!readWriteTypeNames.Contains(queryType.ToFullName()) &&
                            !readOnlyTypeNames.Contains(queryType.ToFullName()))
                        {
                            readOnlyTypeNames.Add(queryType.ToFullName());
                        }
                    }
                }
            }

            foreach (var param in description.LambdaParameters)
            {
                var queryType = param.QueryType();
                if (queryType != null)
                {
                    AddQueryType(queryType, param.QueryTypeIsReadOnly());
                }
            }

            foreach (var allComponentType in description.WithAllTypes)
            {
                AddQueryType(allComponentType, true);
            }

            foreach (var sharedComponentType in description.WithSharedComponentFilterTypes)
            {
                AddQueryType(sharedComponentType, true);
            }

            foreach (var changeFilterType in description.WithChangeFilterTypes)
            {
                AddQueryType(changeFilterType, true);
            }

            return(readOnlyTypeNames.Select(type => $@"ComponentType.ReadOnly<{type}>()").Concat(
                       readWriteTypeNames.Select(type => $@"ComponentType.ReadWrite<{type}>()")));
        }
示例#8
0
 static string EntityQuerySetupStatementFor(LambdaJobDescription description)
 {
     return
         ($@"GetEntityQuery(
             new EntityQueryDesc
             {{
                 All = new ComponentType[] {{
                     {DistinctQueryTypesFor(description).Distinct().SeparateByCommaAndNewLine()}
                 }},
                 Any = new ComponentType[] {{
                     {description.WithAnyTypes.Select(type => type.QueryTypeForType()).Distinct().SeparateByCommaAndNewLine()}
                 }},
                 None = new ComponentType[] {{
                     {description.WithNoneTypes.Select(type => type.QueryTypeForType()).Distinct().SeparateByCommaAndNewLine()}
                 }},
                 Options = {description.EntityQueryOptions.GetFlags().Select(flag => $"EntityQueryOptions.{flag.ToString()}").SeparateByBinaryOr()}
             }});");
 }
示例#9
0
 static string RunWithoutJobSystemDelegateFields(LambdaJobDescription description)
 {
     if (description.LambdaJobKind == LambdaJobKind.Entities)
     {
         if (description.WithFilter_EntityArray != null)
         {
             return($@"
             internal static InternalCompilerInterface.JobEntityBatchRunWithoutJobSystemDelegateLimitEntities s_RunWithoutJobSystemDelegateFieldNoBurst;
             {"internal static InternalCompilerInterface.JobEntityBatchRunWithoutJobSystemDelegateLimitEntities s_RunWithoutJobSystemDelegateFieldBurst;".EmitIfTrue(description.UsesBurst)}");
         }
         else
         {
             return($@"
             internal static InternalCompilerInterface.JobChunkRunWithoutJobSystemDelegate s_RunWithoutJobSystemDelegateFieldNoBurst;
             {"internal static InternalCompilerInterface.JobChunkRunWithoutJobSystemDelegate s_RunWithoutJobSystemDelegateFieldBurst;".EmitIfTrue(description.UsesBurst)}");
         }
     }
     else
     {
         return($@"
             internal static InternalCompilerInterface.JobRunWithoutJobSystemDelegate s_RunWithoutJobSystemDelegateFieldNoBurst;
             {"internal static InternalCompilerInterface.JobRunWithoutJobSystemDelegate s_RunWithoutJobSystemDelegateFieldBurst;".EmitIfTrue(description.UsesBurst)}");
     }
 }
示例#10
0
        internal static MethodDeclarationSyntax ExecuteMethodFor(LambdaJobDescription description)
        {
            string ExecuteMethodParams()
            {
                string ParamsForCapturedVariable(LambdaCapturedVariableDescription variable)
                {
                    return((description.ScheduleMode == ScheduleMode.Run && variable.IsWritable)
                        ? $@"ref {variable.Symbol.GetSymbolTypeName()} {variable.Symbol.Name}"
                        : $@"{variable.Symbol.GetSymbolTypeName()} {variable.Symbol.Name}");
                }

                var paramStrings = new List <string>();

                paramStrings.AddRange(description.VariablesCaptured.Where(variable => !variable.IsThis).Select(ParamsForCapturedVariable));
                if (description.DependencyArgument != null)
                {
                    paramStrings.Add($@"Unity.Jobs.JobHandle __inputDependency");
                }
                if (description.WithFilter_EntityArray != null)
                {
                    paramStrings.Add($@"Unity.Collections.NativeArray<Entity> __entityArray");
                }
                foreach (var argumentSyntax in description.WithSharedComponentFilterArgumentSyntaxes)
                {
                    if (argumentSyntax.Expression is IdentifierNameSyntax argumentIdentifier &&
                        description.VariablesCaptured.All(variable => variable.OriginalVariableName != argumentSyntax.ToString()))
                    {
                        var argumentSymbol = description.Model.GetSymbolInfo(argumentIdentifier);
                        paramStrings.Add($@"{argumentSymbol.Symbol.GetSymbolTypeName()} {argumentSyntax.ToString()}");
                    }
                }

                return(paramStrings.Distinct().SeparateByComma());
            }

            string JobStructFieldAssignment()
            {
                var allAssignments = new List <string>();

                allAssignments.AddRange(description.VariablesCaptured.Select(variable => $@"{variable.VariableFieldName} = {variable.OriginalVariableName}"));
                if (!description.WithStructuralChanges)
                {
                    allAssignments.AddRange(description.LambdaParameters.Select(param => param.TypeHandleAssign()));
                }
                allAssignments.AddRange(description.AdditionalFields.Select(field => field.JobStructAssign()));
                return(allAssignments.SeparateByCommaAndNewLine());
            }

            string ScheduleJobInvocation()
            {
                switch (description.ScheduleMode)
                {
                case ScheduleMode.Run:
                {
                    if (description.UsesBurst)
                    {
                        return($@"
                            {"CompleteDependency();".EmitIfTrue(description.ContainingSystemType == ContainingSystemType.SystemBase)}
                            var __functionPointer = Unity.Jobs.LowLevel.Unsafe.JobsUtility.JobCompilerEnabled
                                ? {description.JobStructName}.s_RunWithoutJobSystemDelegateFieldBurst
                                : {description.JobStructName}.s_RunWithoutJobSystemDelegateFieldNoBurst;
                            var __jobPtr = Unity.Collections.LowLevel.Unsafe.UnsafeUtility.AddressOf(ref __job);
                            Unity.Entities.InternalCompilerInterface.UnsafeRunIJob(__jobPtr, __functionPointer);");
                    }
                    else
                    {
                        return($@"
                            {"CompleteDependency();".EmitIfTrue(description.ContainingSystemType == ContainingSystemType.SystemBase)}
                            __job.Execute();");
                    }
                }

                case ScheduleMode.Schedule:
                {
                    if (description.DependencyArgument != null)
                    {
                        return($@"var __jobHandle = Unity.Jobs.IJobExtensions.Schedule(__job, __inputDependency);");
                    }
                    else
                    {
                        return($@"Dependency = Unity.Jobs.IJobExtensions.Schedule(__job, Dependency);");
                    }
                }
                }
                throw new InvalidOperationException("Can't create ScheduleJobInvocation for invalid lambda description");
            }

            string ScheduleEntitiesInvocation()
            {
                string EntityQueryParameter(ArgumentSyntax entityArray, bool parallel)
                {
                    if (description.HasGenericParameters)
                    {
                        if (entityArray != null)
                        {
                            return($"EntityQueryWrapper{description.Name}<T>.GetQuery(this), __entityArray");
                        }
                        else if (parallel)
                        {
                            return($"EntityQueryWrapper{description.Name}<T>.GetQuery(this), 1");
                        }
                        else
                        {
                            return($"EntityQueryWrapper{description.Name}<T>.GetQuery(this)");
                        }
                    }
                    else
                    {
                        if (entityArray != null)
                        {
                            return($"{description.QueryName}, __entityArray");
                        }
                        else if (parallel)
                        {
                            return($"{description.QueryName}, 1");
                        }
                        else
                        {
                            return($"{description.QueryName}");
                        }
                    }
                }

                string JobEntityBatchExtensionType() =>
                description.NeedsEntityInQueryIndex ? "Unity.Entities.JobEntityBatchIndexExtensions": "Unity.Entities.JobEntityBatchExtensions";

                switch (description.ScheduleMode)
                {
                case ScheduleMode.Run:
                    if (description.WithStructuralChanges)
                    {
                        var entityArray = ", __entityArray".EmitIfTrue(description.WithFilter_EntityArray != null);

                        return($@"
                            {"CompleteDependency();".EmitIfTrue(description.ContainingSystemType == ContainingSystemType.SystemBase)}
                            __job.RunWithStructuralChange({description.QueryName}{entityArray});");
                    }
                    else if (description.UsesBurst)
                    {
                        var entityArray = ", __entityArray".EmitIfTrue(description.WithFilter_EntityArray != null);

                        return($@"
                            {"CompleteDependency();".EmitIfTrue(description.ContainingSystemType == ContainingSystemType.SystemBase)}
                            var __functionPointer = Unity.Jobs.LowLevel.Unsafe.JobsUtility.JobCompilerEnabled
                                ? {description.JobStructName}.s_RunWithoutJobSystemDelegateFieldBurst
                                : {description.JobStructName}.s_RunWithoutJobSystemDelegateFieldNoBurst;
                            var __jobPtr = Unity.Collections.LowLevel.Unsafe.UnsafeUtility.AddressOf(ref __job);
                            Unity.Entities.InternalCompilerInterface.UnsafeRunJobEntityBatch(__jobPtr, {description.QueryName}{entityArray}, __functionPointer);");
                    }
                    else
                    {
                        if (description.WithFilter_EntityArray != null)
                        {
                            return($@"
                                {"CompleteDependency();".EmitIfTrue(description.ContainingSystemType == ContainingSystemType.SystemBase)}
                                {JobEntityBatchExtensionType()}.RunWithoutJobs(ref __job, {description.QueryName}, __entityArray);");
                        }
                        else
                        {
                            return($@"
                                {"CompleteDependency();".EmitIfTrue(description.ContainingSystemType == ContainingSystemType.SystemBase)}
                                {JobEntityBatchExtensionType()}.RunWithoutJobs(ref __job, {description.QueryName});");
                        }
                    }

                // Special case where we treat Schedule as ScheduleParallel in JobComponentSystem
                case ScheduleMode.Schedule
                    when description.ContainingSystemType == ContainingSystemType.JobComponentSystem:
                {
                    return
                        ($@"var __jobHandle = {JobEntityBatchExtensionType()}.ScheduleParallel(__job, {EntityQueryParameter(description.WithFilter_EntityArray, true)}, __inputDependency);");
                }

                case ScheduleMode.Schedule:
                {
                    if (description.DependencyArgument != null)
                    {
                        return($@"var __jobHandle = {JobEntityBatchExtensionType()}.Schedule(__job, {EntityQueryParameter(description.WithFilter_EntityArray, false)}, __inputDependency);");
                    }
                    else
                    {
                        return($@"Dependency = {JobEntityBatchExtensionType()}.Schedule(__job, {EntityQueryParameter(description.WithFilter_EntityArray, false)}, Dependency);");
                    }
                }

                case ScheduleMode.ScheduleParallel:
                {
                    if (description.DependencyArgument != null)
                    {
                        return($@"var __jobHandle = {JobEntityBatchExtensionType()}.ScheduleParallel(__job, {EntityQueryParameter(description.WithFilter_EntityArray, true)}, __inputDependency);");
                    }
                    else
                    {
                        return($@"Dependency = {JobEntityBatchExtensionType()}.ScheduleParallel(__job, {EntityQueryParameter(description.WithFilter_EntityArray, true)}, Dependency);");
                    }
                }
                }

                throw new InvalidOperationException("Can't create ScheduleJobInvocation for invalid lambda description");
            }

            string ScheduleInvocation()
            {
                return(description.LambdaJobKind == LambdaJobKind.Entities
                ? ScheduleEntitiesInvocation()
                : ScheduleJobInvocation());
            }

            string WriteBackCapturedVariablesAssignments()
            {
                if (description.ScheduleMode == ScheduleMode.Run)
                {
                    var writeBackStatements = new List <string>();
                    writeBackStatements.AddRange(description.VariablesCaptured.Where(variable => !variable.IsThis && variable.IsWritable)
                                                 .Select(variable => $@"{variable.OriginalVariableName} = __job.{variable.VariableFieldName};"));
                    return(writeBackStatements.SeparateByNewLine());
                }

                return(string.Empty);
            }

            string DisposeOnCompletionInvocation()
            {
                if (!description.DisposeOnJobCompletionVariables.Any())
                {
                    return(string.Empty);
                }

                if (description.ScheduleMode == ScheduleMode.Run)
                {
                    return($@"__job.DisposeOnCompletion();");
                }
                else if (description.DependencyArgument != null)
                {
                    return($@"__jobHandle = __job.DisposeOnCompletion(__jobHandle);");
                }
                else
                {
                    return($@"Dependency = __job.DisposeOnCompletion(Dependency);");
                }
            }

            string ReturnType() => (description.DependencyArgument != null) ? "Unity.Jobs.JobHandle" : "void";


            var template = $@"
            {ReturnType()} {description.ExecuteInSystemMethodName}{GenericArguments(description)}({ExecuteMethodParams()}){GenericParameterConstraints(description)}
            {{
                var __job = new {description.JobStructName}{GenericArguments(description)}
                {{
                    {JobStructFieldAssignment()}
                }};
                {SharedComponentFilterInvocations(description)}
                {ScheduleInvocation()}
                {DisposeOnCompletionInvocation()}
                {WriteBackCapturedVariablesAssignments()}
                {"return __jobHandle;".EmitIfTrue(description.DependencyArgument != null)}
            }}";

            return((MethodDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration(template));
        }
示例#11
0
 static string NoAliasAttribute(LambdaJobDescription description) =>
 description.UsesBurst ? $@"[Unity.Burst.NoAlias]" : string.Empty;
示例#12
0
        internal static FieldDeclarationSyntax EntityQueryFieldFor(LambdaJobDescription description)
        {
            var template = $@"EntityQuery {description.QueryName};";

            return((FieldDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration(template));
        }
示例#13
0
 // var componentArray1 = (ComponentType1*)chunk.GetNativeArray(_componentTypeAccessor1).GetUnsafePtr();
 static string GetChunkNativeArrays(LambdaJobDescription description) =>
 description.LambdaParameters.Select(param => param.GetNativeArray()).SeparateByNewLine();
示例#14
0
 static string BurstCompileAttribute(LambdaJobDescription description) =>
 description.UsesBurst ? $@"
         [Unity.Burst.BurstCompile(FloatMode=Unity.Burst.FloatMode.{description.FloatMode.ToString()}, FloatPrecision=Unity.Burst.FloatPrecision.{description.FloatPrecision.ToString()}, CompileSynchronously={description.BurstSynchronousCompilation.ToString().ToLower()})]" : string.Empty;
示例#15
0
        internal static StructDeclarationSyntax JobStructFor(LambdaJobDescription description)
        {
            // public [ReadOnly] CapturedFieldType capturedFieldName;
            // Need to also declare these for variables used by local methods
            string CapturedVariableFields()
            {
                string FieldForCapturedVariable(LambdaCapturedVariableDescription variable) =>
                $@"{variable.Attributes.JoinAttributes()}public {variable.Symbol.GetSymbolTypeName()} {variable.VariableFieldName};";

                return(description.VariablesCaptured.Concat(description.VariablesCapturedOnlyByLocals).Select(FieldForCapturedVariable).SeparateByNewLine());
            }

            // public ComponentTypeHandle<ComponentType> _rotationTypeAccessor;
            string TypeHandleFields() => description.LambdaParameters.Select(param => param.TypeHandleField()).SeparateByNewLine();

            // public ComponentDataFromEntity<ComponentType> _rotationDataFromEntity;
            string AdditionalDataFromEntityFields() => description.AdditionalFields.Select(dataFromEntityField => dataFromEntityField.ToFieldDeclaration().ToString()).SeparateByNewLine();

            // void OriginalLambdaBody(ref ComponentType1 component1, in ComponentType2 component2) {}";
            string OriginalLambdaBody() => $@"
            {"[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]".EmitIfTrue(description.UsesBurst)}
            void OriginalLambdaBody({description.LambdaParameters.Select(param => param.LambdaBodyMethodParameter(description.UsesBurst)).SeparateByComma()}) {{}}
            {GeneratedLineTriviaToGeneratedSource()}";

            // OriginalLambdaBody(ref Unity.Collections.LowLevel.Unsafe.UnsafeUtility.AsRef<ComponentType1>(componentArray1 + i), *(componentArray2 + i));
            string PerformLambda()
            {
                var result = string.Empty;

                result += description.LambdaParameters.Select(param => param.LambdaBodyParameterSetup()).SeparateBySemicolonAndNewLine();

                if (description.WithStructuralChangesAndLambdaBodyInSystem)
                {
                    result += $@"__this.{description.LambdaBodyMethodName}({description.LambdaParameters.Select(param => param.StructuralChanges_LambdaBodyParameter()).SeparateByComma()});";
                }
                else if (description.WithStructuralChanges)
                {
                    result += $@"OriginalLambdaBody({description.LambdaParameters.Select(param => param.StructuralChanges_LambdaBodyParameter()).SeparateByComma()});";
                }
                else
                {
                    result += $@"OriginalLambdaBody({description.LambdaParameters.Select(param => param.LambdaBodyParameter()).SeparateByComma()});";
                }

                return(result);
            }

            string MethodsForLocalFunctions() => description.MethodsForLocalFunctions.Select(method => method.ToString()).SeparateByNewLine();

            string ExecuteMethodForJob() => $@"
            public unsafe void Execute()
            {{
                {PerformLambda()}
            }}";

            string ExecuteMethodDefault() => $@"
            public unsafe void Execute(ArchetypeChunk chunk, int batchIndex)
            {{
                {GetChunkNativeArrays(description)}

                int count = chunk.Count;
                for (int entityIndex = 0; entityIndex != count; entityIndex++)
                {{
                    {PerformLambda()}
                }}
            }}";

            string ExecuteMethodWithEntityInQueryIndex() => $@"
            public unsafe void Execute(ArchetypeChunk chunk, int batchIndex, int indexOfFirstEntityInQuery)
            {{
                {GetChunkNativeArrays(description)}

                int count = chunk.Count;
                for (int entityIndex = 0; entityIndex != count; entityIndex++)
                {{
                    int entityInQueryIndex = indexOfFirstEntityInQuery + entityIndex;
                    {PerformLambda()}
                }}
            }}";

            string ExecuteMethodForStructuralChanges() => $@"
            public unsafe void RunWithStructuralChange(EntityQuery query)
            {{
                {GeneratedLineTriviaToGeneratedSource()}
                var mask = __this.EntityManager.GetEntityQueryMask(query);
                Unity.Entities.InternalCompilerInterface.UnsafeCreateGatherEntitiesResult(ref query, out var gatherEntitiesResult);
                {StructuralChanges_GetTypeIndices(description)}

                try
                {{
                    int entityCount = gatherEntitiesResult.EntityCount;
                    for (int entityIndex = 0; entityIndex != entityCount; entityIndex++)
                    {{
                        var entity = gatherEntitiesResult.EntityBuffer[entityIndex];
                        if (mask.Matches(entity))
                        {{
                            {StructuralChanges_ReadLambdaParams(description)}
                            {PerformLambda()}
                            {StructuralChanges_WriteBackLambdaParams(description)}
                        }}
                    }}
                }}
                finally
                {{
                    Unity.Entities.InternalCompilerInterface.UnsafeReleaseGatheredEntities(ref query, ref gatherEntitiesResult);
                }}
            }}";

            string ExecuteMethodForStructuralChangesWithEntities() => $@"
            public unsafe void RunWithStructuralChange(EntityQuery query, NativeArray<Entity> withEntities)
            {{
                {GeneratedLineTriviaToGeneratedSource()}
                var mask = __this.EntityManager.GetEntityQueryMask(query);
                {StructuralChanges_GetTypeIndices(description)}

                int entityCount = withEntities.Length;
                for (int entityIndex = 0; entityIndex != entityCount; entityIndex++)
                {{
                    var entity = withEntities[entityIndex];
                    if (mask.Matches(entity))
                    {{
                        {StructuralChanges_ReadLambdaParams(description)}
                        {PerformLambda()}
                        {StructuralChanges_WriteBackLambdaParams(description)}
                    }}
                }}
            }}";

            string ExecuteMethod()
            {
                if (description.LambdaJobKind == LambdaJobKind.Job)
                {
                    return(ExecuteMethodForJob());
                }
                else if (description.WithStructuralChanges && description.WithFilter_EntityArray == null)
                {
                    return(ExecuteMethodForStructuralChanges());
                }
                else if (description.WithStructuralChanges && description.WithFilter_EntityArray != null)
                {
                    return(ExecuteMethodForStructuralChangesWithEntities());
                }
                else if (description.NeedsEntityInQueryIndex)
                {
                    return(ExecuteMethodWithEntityInQueryIndex());
                }
                else
                {
                    return(ExecuteMethodDefault());
                }
            }

            string DisposeOnCompletionMethod()
            {
                if (!description.DisposeOnJobCompletionVariables.Any())
                {
                    return(string.Empty);
                }

                var allDisposableFieldsAndChildren = new List <string>();

                foreach (var variable in description.DisposeOnJobCompletionVariables)
                {
                    allDisposableFieldsAndChildren.AddRange(variable.NamesOfAllDisposableMembersIncludingOurselves());
                }

                if (description.ScheduleMode == ScheduleMode.Run)
                {
                    return($@"
                    public void DisposeOnCompletion()
				    {{
                        {allDisposableFieldsAndChildren.Select(disposable => $"{disposable}.Dispose();").SeparateByNewLine()}
                    }}");
                }
                else
                {
                    return($@"
                    public Unity.Jobs.JobHandle DisposeOnCompletion(Unity.Jobs.JobHandle jobHandle)
				    {{
                        {allDisposableFieldsAndChildren.Select(disposable => $"jobHandle = {disposable}.Dispose(jobHandle);").SeparateByNewLine()}
                        return jobHandle;
                    }}");
                }
            }

            string JobInterface()
            {
                if (description.LambdaJobKind == LambdaJobKind.Job)
                {
                    return(" : Unity.Jobs.IJob");
                }
                else
                {
                    if (!description.WithStructuralChanges)
                    {
                        return(description.NeedsEntityInQueryIndex ? " : Unity.Entities.IJobEntityBatchWithIndex" : " : Unity.Entities.IJobEntityBatch");
                    }
                }
                return(string.Empty);
            }

            var template = $@"
			{GeneratedLineTriviaToGeneratedSource()}
            {NoAliasAttribute(description)}
            {BurstCompileAttribute(description)}
            struct {description.JobStructName}{GenericArguments(description)}
            {JobInterface()}
            {GenericParameterConstraints(description)}
            {{
                {RunWithoutJobSystemDelegateFields(description).EmitIfTrue(description.NeedsJobDelegateFields)}
                {CapturedVariableFields()}
                {TypeHandleFields().EmitIfTrue(!description.WithStructuralChanges)}
                {AdditionalDataFromEntityFields()}
                {MethodsForLocalFunctions()}

                {(!description.WithStructuralChangesAndLambdaBodyInSystem ? OriginalLambdaBody() : string.Empty)}

                {ExecuteMethod()}
                {DisposeOnCompletionMethod()}

                {RunWithoutJobSystemMethod(description).EmitIfTrue(description.NeedsJobDelegateFields)}
            }}";

            var jobStructDeclaration = (StructDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration(template);

            // Find lambda body in job struct template and replace rewritten lambda body into method
            if (!description.WithStructuralChangesAndLambdaBodyInSystem)
            {
                var templateLambdaMethodBody = jobStructDeclaration.DescendantNodes().OfType <MethodDeclarationSyntax>().First(
                    method => method.Identifier.ValueText == "OriginalLambdaBody").DescendantNodes().OfType <BlockSyntax>().First();
                jobStructDeclaration = jobStructDeclaration.ReplaceNode(templateLambdaMethodBody, description.RewrittenLambdaBody.WithoutPreprocessorTrivia());
            }

            return(jobStructDeclaration);
        }
        Rewrite(LambdaJobDescription description)
        {
            SemanticModel model = description.Model;
            SyntaxNode    originalLambdaExpression = description.OriginalLambdaExpression;
            List <LambdaCapturedVariableDescription> variablesCapturedOnlyByLocals = description.VariablesCapturedOnlyByLocals;

            var lambdaBodyRewriter = new LambdaBodyRewriter();

            // Find all locations where we are accessing a member on the declaring SystemBase
            // and change them to access through "__this" instead.
            // This also annotates the changed nodes so that we can find them later for patching (and get their original symbols).
            var rewrittenLambdaBodyData   = LambdaBodySyntaxReplacer.Rewrite(model, originalLambdaExpression);
            var rewrittenLambdaExpression = rewrittenLambdaBodyData.rewrittenLambdaExpression;

            // Go through all changed nodes and check to see if they are a component access method that we need to patch (GetComponent/SetComponent/etc)
            // Only need to do this if we are not doing structural changes (in which case we can't as structural changes will invalidate)
            if (!description.WithStructuralChanges)
            {
                foreach (var originalNode in rewrittenLambdaBodyData.thisAccessNodesNeedingReplacement)
                {
                    var originalInvocation = originalNode.Ancestors().OfType <InvocationExpressionSyntax>().First();

                    var currentNode = rewrittenLambdaExpression.GetCurrentNode(originalNode);
                    var currentMemberAccessExpression   = currentNode.Ancestors().OfType <MemberAccessExpressionSyntax>().First();
                    var currentNodeInvocationExpression = currentNode.Ancestors().OfType <InvocationExpressionSyntax>().FirstOrDefault();
                    if (currentNodeInvocationExpression == null)
                    {
                        continue;
                    }

                    var replacementMemberAccessExpression = lambdaBodyRewriter.GenerateReplacementMemberAccessExpression(originalInvocation,
                                                                                                                         currentMemberAccessExpression, model);
                    if (replacementMemberAccessExpression != null)
                    {
                        rewrittenLambdaExpression = rewrittenLambdaExpression.ReplaceNode(currentNodeInvocationExpression, replacementMemberAccessExpression);
                    }
                }
            }

            // Go through all local declaration nodes and replace them with assignment nodes (or remove) if they are now captured variables that live in job struct
            // This is needed for variables captured for local methods
            foreach (var localDeclarationSyntax in rewrittenLambdaExpression.DescendantNodes().OfType <LocalDeclarationStatementSyntax>())
            {
                var variableDeclaration = localDeclarationSyntax.DescendantNodes().OfType <VariableDeclarationSyntax>().FirstOrDefault();
                if (variableDeclaration != null &&
                    variablesCapturedOnlyByLocals.Any(variable => variable.OriginalVariableName == variableDeclaration.Variables.First().Identifier.Text))
                {
                    if (variableDeclaration.DescendantTokens().Any(token => token.Kind() == SyntaxKind.EqualsToken))
                    {
                        var variableIdentifier = variableDeclaration.Variables.First().Identifier;
                        var nodeAfter          = variableDeclaration.NodeAfter(node => node.Kind() == SyntaxKind.EqualsToken);
                        rewrittenLambdaExpression = rewrittenLambdaExpression.ReplaceNode(localDeclarationSyntax,
                                                                                          SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(
                                                                                                                                SyntaxKind.SimpleAssignmentExpression,
                                                                                                                                SyntaxFactory.IdentifierName(variableIdentifier.Text),
                                                                                                                                (ExpressionSyntax)nodeAfter)));
                    }
                    else
                    {
                        rewrittenLambdaExpression = rewrittenLambdaExpression.RemoveNode(localDeclarationSyntax, SyntaxRemoveOptions.KeepExteriorTrivia);
                    }
                }
            }

            // Go through all local function statements and omit them as method declarations on the job struct
            // (local methods accessing fields on this are not allowed in C#)
            // https://sharplab.io/#v2:EYLgtghgzgLgpgJwDQxNGAfAAgJgIwCwAUFgMwAEu5AwuQN7HlOUVYAs5AsgBQCU9jZgF9BTUeVgIArgGMY5AKIA7GAEsYAT3oiizCTGlyaAezAAHY0rgqAKhrNwAEhCUATADZwAPDYB828UlZeWpTCysVABEIGAgAMQRTZTVNH386HT0gowUZKBs4WGjY5PUtcQZdPWYyRRUy8gA3CHcpODwAbnFM5mz5XPzCmGKIASrqlkU8gqKYiG5VFSaWtv4M7vFN8fJF+AQAMwgZOHIASQApY2BqAAspJQBrAO2+8gAZCDBgVwhL4AB9AAM/z+5BAZz+t3uDwq4j0tVC5ks1hgdgczjcni8AxmwzmpU0/n+MFccDRThcHjgXW28IoiPCKJGCSS9VSOKGIyJ/w5s1i/xZYAJGhpEzEtJqHAA8ghVABzRYtD5fH4AIWMrg03GF5BRZSQOyUU0GfIgOpJcF4cOYlTF1V25AA4nAYMKAGorODatlaS3Wia2u1irAAdnI/x5005cwFiSFPoA2nAALoAOmarWp/uqOmz8I4AGUXe7Pd6Ur6DQ6M6s8zbaxMI7y8fzBcKk8nyABechWADuxtxI241ctoqDTB64/r5CLrp9Hsz3D1mgNzrn5YXbW4FvTnrwvF4Y4muYlTAA9AAqbO1e5QCD7E7sRQADzgMik8G4AEEEDIbi77DgKFHnIP9oUrJYwMeU43DgZ8IPkfZVAQWBhRg0lnytU8xnHJhmgQXUfQABQMLtyDLMoL14KCHlTNcADkYlURo4B/BAIC1f5lw0ckMSpXg6JdABVJQ7wfAAlOAIFcKUlHcDQSIQPgjyDfDyAtL8ZGOKAoGMAju21KNTWFKiaMEmBGLUFi2I47hiVJXjKU8AS1xEsS4Ek6TZPkxTlOnB1uNCe55G7MygpUFS7X2PTyIdVQyMBDodnIABCbtAuMYKktUABqHKsNwnDCuYGV5UVdxlW+CB1U1bgLyXYjSJynZeANeqNK0wpdII5rVAPSKxUnHNswvM8NiIIQgA===
            var localFunctions = rewrittenLambdaExpression.DescendantNodes().OfType <LocalFunctionStatementSyntax>();

            rewrittenLambdaExpression = rewrittenLambdaExpression.RemoveNodes(localFunctions, SyntaxRemoveOptions.KeepNoTrivia);
            var methodsForLocalFunctions = new List <MethodDeclarationSyntax>();

            foreach (var localFunction in localFunctions)
            {
                methodsForLocalFunctions.Add((MethodDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration(localFunction.ToString()));
            }

            return(rewrittenLambdaExpression, lambdaBodyRewriter.DataFromEntityFields.Values.ToList(), methodsForLocalFunctions);
        }
示例#17
0
 // TODO: Fix to allow for more than one
 static string GenericArguments(LambdaJobDescription description) => description.HasGenericParameters ? "<T>" : "";
示例#18
0
 static string GenericParameterConstraints(LambdaJobDescription description) => string.Empty;
示例#19
0
 static string GenericArguments(LambdaJobDescription description) => string.Empty;
示例#20
0
 // WriteComponentData<Rotation>(__this.EntityManager, entity, rotationTypeIndex, ref rotation, ref T originalrotation);";
 static string StructuralChanges_WriteBackLambdaParams(LambdaJobDescription description) =>
 description.LambdaParameters.Select(param => param.StructuralChanges_WriteBackLambdaParam()).SeparateByNewLine();
        public void Execute(GeneratorExecutionContext context)
        {
            try
            {
                if (context.Compilation.ReferencedAssemblyNames.All(n => n.Name != "Unity.Entities") ||
                    context.Compilation.Assembly.Name.Contains("CodeGen.Tests"))
                {
                    return;
                }

                SourceGenHelpers.LogInfo($"Source generating assembly {context.Compilation.Assembly.Name} for lambda jobs...");
                var stopwatch = Stopwatch.StartNew();;
                //context.WaitForDebugger("HelloCube");

                // Setup project path for logging and emitting debug source
                // This isn't fantastic but I haven't come up with a better way to get the project path since we might be running out of process
                if (context.AdditionalFiles.Any())
                {
                    SourceGenHelpers.SetProjectPath(context.AdditionalFiles[0].Path);
                }

                // Do initial filter for early out
                var entitiesSyntaxReceiver = (EntitiesSyntaxReceiver)context.SyntaxReceiver;
                var lambdaJobCandidates    = FilterCandidates(context, entitiesSyntaxReceiver.EntitiesGetterCandidates.Concat(entitiesSyntaxReceiver.JobGetterCandidates));
                if (!lambdaJobCandidates.Any())
                {
                    return;
                }

                // Create map from SyntaxTrees to candidates
                var syntaxTreeToCandidates = lambdaJobCandidates.GroupBy(c => c.SyntaxTree).ToDictionary(group => group.Key, group => group.ToList());

                // Outer loop - iterate over syntax tree
                foreach (var treeKVP in syntaxTreeToCandidates)
                {
                    var syntaxTree     = treeKVP.Key;
                    var treeCandidates = treeKVP.Value;

                    try
                    {
                        // Build up list of job descriptions inside of containing class declarations
                        var classDeclarationToDescriptions = new Dictionary <ClassDeclarationSyntax, List <LambdaJobDescription> >();
                        var jobIndex = 0;
                        foreach (var candidate in treeCandidates)
                        {
                            var declaringType    = candidate.Ancestors().OfType <ClassDeclarationSyntax>().FirstOrDefault();
                            var containingMethod = candidate.Ancestors().OfType <MethodDeclarationSyntax>().FirstOrDefault();
                            if (declaringType == null || containingMethod == null)
                            {
                                continue;
                            }

                            SourceGenHelpers.LogInfo($"Parsing LambdaJobDescription in {declaringType.Identifier}.{containingMethod.Identifier}");
                            var jobDescription = LambdaJobDescription.From(candidate, context, jobIndex++);
                            if (jobDescription == null)
                            {
                                continue;
                            }

                            if (classDeclarationToDescriptions.ContainsKey(declaringType))
                            {
                                classDeclarationToDescriptions[declaringType].Add(jobDescription);
                            }
                            else
                            {
                                classDeclarationToDescriptions[declaringType] = new List <LambdaJobDescription>()
                                {
                                    jobDescription
                                }
                            };
                        }

                        // Inner loop - iterate through class descriptions with lambda jobs and generate new class declaration nodes
                        var originalToGeneratedNode = new Dictionary <SyntaxNode, MemberDeclarationSyntax>();
                        foreach (var kvp in classDeclarationToDescriptions)
                        {
                            var classDeclaration    = kvp.Key;
                            var descriptionsInClass = kvp.Value;
                            SourceGenHelpers.LogInfo($"Generating code for system type: {classDeclaration.Identifier}");
                            var newClassDeclaration = GenerateNewClassDeclarationForDescriptions(classDeclaration, descriptionsInClass);
                            //SourceGenHelpers.LogInfo(newClassDeclaration.ToString());
                            originalToGeneratedNode[classDeclaration] = newClassDeclaration;
                        }

                        // recurse and create nodes down to our created system nodes
                        var rootNodesWithGenerated = new List <MemberDeclarationSyntax>();
                        foreach (var child in syntaxTree.GetRoot().ChildNodes())
                        {
                            if (child is NamespaceDeclarationSyntax || child is ClassDeclarationSyntax)
                            {
                                var generatedRootNode = ConstructTreeWithGeneratedNodes(child, originalToGeneratedNode);
                                if (generatedRootNode != null)
                                {
                                    rootNodesWithGenerated.Add(generatedRootNode);
                                }
                            }
                        }

                        if (rootNodesWithGenerated.Any())
                        {
                            OutputGeneratedSyntaxTreeNodes(context, syntaxTree, rootNodesWithGenerated);
                        }
                    }
                    catch (Exception exception)
                    {
                        context.LogError("SGICE001", "LambdaJobs", exception.ToString(), syntaxTree.GetRoot().GetLocation());
                    }
                }

                stopwatch.Stop();
                SourceGenHelpers.LogInfo($"TIME : LambdaJobs : {context.Compilation.Assembly.Name} : {stopwatch.ElapsedMilliseconds}ms");
            }
            catch (Exception exception)
            {
                context.LogError("SGICE001", "LambdaJobs", exception.ToString(), context.Compilation.SyntaxTrees.First().GetRoot().GetLocation());
            }
        }
示例#22
0
 //var rotationTypeIndex = TypeManager.GetTypeIndex<Rotation>();
 static string StructuralChanges_GetTypeIndices(LambdaJobDescription description) =>
 description.LambdaParameters.Select(param => param.StructuralChanges_GetTypeIndex()).SeparateByNewLine();