protected IMethodBlock CreateBody() { var methodBlock = new Method.BlockCollection(); methodBlock.Children.Add(CreateBodyPrologue()); foreach (var memberToken in Members) { GenerateMemberBlock(memberToken, Instance, methodBlock); } methodBlock.Children.Add(CreateBodyEpilogue()); // Now add all possible extras foreach (var requestedParameter in Variables) { methodBlock.Variables.Add(requestedParameter); } #if DEBUG var expr = methodBlock.ToExpression(); Console.WriteLine(expr.AsString()); #endif return(methodBlock); }
private void GenerateMemberBlock(MemberToken memberToken, IMethodBlock declaringInstanceAccess, Method.BlockCollection block) { var memberAccess = new Method.MemberAccess(declaringInstanceAccess, memberToken); if (memberToken.IsArray) { GenerateArrayMemberBlock(memberToken, memberAccess, block); } else { GenerateValueMemberBlock(memberToken.TypeToken, memberAccess, block); } }
private void GenerateArrayMemberBlock(MemberToken memberToken, IMethodBlock memberAccess, Method.BlockCollection block) { var elementTypeToken = memberToken.TypeToken.GetElementTypeToken(); var arraySize = GetCardinality(memberToken); var arraySizeExpression = Expr.Constant(arraySize); // Give the generator a chance to create the array var arrayInitializer = CreateArrayInitializer(memberToken, memberAccess); var defaultArrayInitializer = arrayInitializer == default(IMethodBlock); if (defaultArrayInitializer) // Otherwise just assign new T[N]; { arrayInitializer = elementTypeToken.NewArrayBounds(arraySizeExpression).ToMethodBlock(); } if (arrayInitializer != null) { block.Children.Add(new Method.Assignment(memberAccess, arrayInitializer)); // If the generator provided a specialized initializer, exit now. if (!defaultArrayInitializer) { return; } } var loopUnrollingNeeded = OnLoopGenerationStart(memberToken) != UnrollingMode.Never; if (!loopUnrollingNeeded) // Fast path to reduce allocations { arraySize = 1; } var elementAccesses = ArrayPool <Method.DelegatedArrayAccess> .Shared.Rent(arraySize); var loopBodyBlocks = ArrayPool <Method.BlockCollection> .Shared.Rent(arraySize); for (var i = 0; i < arraySize; ++i) { elementAccesses[i] = new Method.DelegatedArrayAccess(memberAccess); loopBodyBlocks[i] = new Method.BlockCollection(); // Classes need a public default ctor if (elementTypeToken.IsClass && elementTypeToken != typeof(string)) { var newElementBlock = elementTypeToken.NewExpression().ToMethodBlock(); loopBodyBlocks[i].Children.Add(new Method.Assignment(elementAccesses[i], newElementBlock)); } GenerateValueMemberBlock(elementTypeToken, elementAccesses[i], loopBodyBlocks[i]); // If the implementation decides we never need to unroll this loop, save ourselves the trouble var unrollingMode = OnLoopGenerationIteration(i, memberToken); if (unrollingMode == UnrollingMode.Never) { break; } // If unrolling state was decided to be unknown, we determine if we needed to unroll // This is technically legacy code if (unrollingMode == UnrollingMode.Unknown) { if (i > 0 && !loopUnrollingNeeded) { loopUnrollingNeeded = !loopBodyBlocks[i].Equals(loopBodyBlocks[0]); } } } OnLoopGenerationEnd(memberToken); // If all the invocation bodies are equal, we can just loop. Otherwise, we need to unroll it. if (loopUnrollingNeeded) { for (var i = 0; i < arraySize; ++i) { elementAccesses[i].Index = Expr.Constant(i).ToMethodBlock(); foreach (var variable in loopBodyBlocks[i].Variables) { block.Variables.Add(variable); } block.Children.AddRange(loopBodyBlocks[i].Children); } } else { var iterationCounter = _iteratorProvider.Rent(); elementAccesses[0].Index = iterationCounter; block.Variables.Add(iterationCounter); var arraySizeBlock = arraySizeExpression.ToMethodBlock(); block.Children.Add(new Method.Assignment(iterationCounter, Expr.Constant(0).ToMethodBlock())); block.Children.Add(new Method.Loop(iterationCounter, arraySizeBlock, loopBodyBlocks[0])); _iteratorProvider.Return(iterationCounter); } ArrayPool <Method.DelegatedArrayAccess> .Shared.Return(elementAccesses); ArrayPool <Method.BlockCollection> .Shared.Return(loopBodyBlocks); }
private void GenerateValueMemberBlock(TypeToken typeToken, IMethodBlock memberAccess, Method.BlockCollection block) { var instanceInitializer = CreateInstanceInitializer(typeToken, memberAccess); var defaultInstanceInitializer = instanceInitializer == default(IMethodBlock); if (defaultInstanceInitializer && typeToken.IsClass) { instanceInitializer = new Method.Assignment(memberAccess, typeToken.NewExpression().ToMethodBlock()); } if (instanceInitializer != default) { block.Children.Add(instanceInitializer); } if (!defaultInstanceInitializer) { return; } foreach (var subMemberToken in MemberProvider(typeToken)) { GenerateMemberBlock(subMemberToken, memberAccess, block); } }