Merge pull request #4155 from BrzVlad/fix-tls-lmf-addr
[mono-project.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / IArgumentProvider.cs
blobaf67d2bebb6a0c033e9472d88ed26da6108998cd
1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
6 * copy of the license can be found in the License.html file at the root of this distribution. If
7 * you cannot locate the Apache License, Version 2.0, please send an email to
8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
9 * by the terms of the Apache License, Version 2.0.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
16 using System;
17 using System.Collections.Generic;
18 using System.Text;
20 #if !FEATURE_CORE_DLR
21 namespace Microsoft.Scripting.Ast {
22 using Microsoft.Scripting.Utils;
23 #else
24 namespace System.Linq.Expressions {
25 #endif
26 /// <summary>
27 /// Provides an internal interface for accessing the arguments that multiple tree
28 /// nodes (DynamicExpression, ElementInit, MethodCallExpression, InvocationExpression, NewExpression,
29 /// and InexExpression).
30 ///
31 /// This enables two optimizations which reduce the size of the trees. The first is it enables
32 /// the nodes to hold onto an IList of T instead of a ReadOnlyCollection. This saves the cost
33 /// of allocating the ReadOnlyCollection for each node. The second is that it enables specialized
34 /// subclasses to be created which hold onto a specific number of arguments. For example Block2,
35 /// Block3, Block4. These nodes can therefore avoid allocating both a ReadOnlyCollection and an
36 /// array for storing their elements saving 32 bytes per node.
37 ///
38 /// Meanwhile the nodes can continue to expose the original LINQ properties of ReadOnlyCollections. They
39 /// do this by re-using 1 field for storing both the array or an element that would normally be stored
40 /// in the array.
41 ///
42 /// For the array case the collection is typed to IList of T instead of ReadOnlyCollection of T.
43 /// When the node is initially constructed it is an array. When the compiler accesses the members it
44 /// uses this interface. If a user accesses the members the array is promoted to a ReadOnlyCollection.
45 ///
46 /// For the object case we store the 1st argument in a field typed to object and when the node is initially
47 /// constructed this holds directly onto the Expression. When the compiler accesses the members
48 /// it again uses this interface and the accessor for the 1st argument uses Expression.ReturnObject to
49 /// return the object which handles the Expression or ReadOnlyCollection case. When the user accesses
50 /// the ReadOnlyCollection then the object field is updated to hold directly onto the ReadOnlyCollection.
51 ///
52 /// It is important that the Expressions consistently return the same ReadOnlyCollection otherwise the
53 /// re-writer will be broken and it would be a breaking change from LINQ v1. The problem is that currently
54 /// users can rely on object identity to tell if the node has changed. Storing the readonly collection in
55 /// an overloaded field enables us to both reduce memory usage as well as maintain compatibility and an
56 /// easy to use external API.
57 /// </summary>
58 internal interface IArgumentProvider {
59 Expression GetArgument(int index);
60 int ArgumentCount {
61 get;
65 static class ArgumentProviderOps {
66 internal static T[] Map<T>(this IArgumentProvider collection, Func<Expression, T> select) {
67 int count = collection.ArgumentCount;
68 T[] result = new T[count];
69 count = 0;
70 for (int i = 0; i < count; i++) {
71 result[i] = select(collection.GetArgument(i));
73 return result;