[sgen] Reenable gc-altstack test
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Actions / RuleCache.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
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.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 using System.ComponentModel;
17 using System.Diagnostics;
18 using System.Dynamic.Utils;
19
20 namespace System.Runtime.CompilerServices {
21     /// <summary>
22     /// This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.
23     /// Represents a cache of runtime binding rules.
24     /// </summary>
25     /// <typeparam name="T">The delegate type.</typeparam>
26     [EditorBrowsable(EditorBrowsableState.Never), DebuggerStepThrough]
27     public class RuleCache<T> where T : class {
28         private T[] _rules = new T[0];
29         private readonly Object cacheLock = new Object();
30
31         private const int MaxRules = 128;
32
33         internal RuleCache() { }
34
35         internal T[] GetRules() {
36             return _rules;
37         }
38
39         // move the rule +2 up.
40         // this is called on every successful rule.
41         internal void MoveRule(T rule, int i) {
42             // limit search to MaxSearch elements. 
43             // Rule should not get too far unless it has been already moved up.
44             // need a lock to make sure we are moving the right rule and not loosing any.
45             lock (cacheLock) {
46                 const int MaxSearch = 8;
47                 int count = _rules.Length - i;
48                 if (count > MaxSearch) {
49                     count = MaxSearch;
50                 }
51
52                 int oldIndex = -1;
53                 int max = Math.Min(_rules.Length, i + count);
54                 for (int index = i; index < max; index++) {
55                     if (_rules[index] == rule) {
56                         oldIndex = index;
57                         break;
58                     }
59                 }
60                 if (oldIndex < 0) {
61                     return;
62                 }
63                 T oldRule = _rules[oldIndex];
64                 _rules[oldIndex] = _rules[oldIndex - 1];
65                 _rules[oldIndex - 1] = _rules[oldIndex - 2];
66                 _rules[oldIndex - 2] = oldRule;
67             }
68         }
69
70         internal void AddRule(T newRule) {
71             // need a lock to make sure we are not loosing rules.
72             lock (cacheLock) {
73                 _rules = AddOrInsert(_rules, newRule);
74             }
75         }
76
77         internal void ReplaceRule(T oldRule, T newRule) {
78             // need a lock to make sure we are replacing the right rule
79             lock (cacheLock) {
80                 int i = Array.IndexOf(_rules, oldRule);
81                 if (i >= 0) {
82                     _rules[i] = newRule;
83                     return; // DONE
84                 }
85
86                 // could not find it.
87                 _rules = AddOrInsert(_rules, newRule);
88             }
89         }
90
91
92         // Adds to end or or inserts items at InsertPosition
93         private const int InsertPosition = MaxRules / 2;
94
95         private static T[] AddOrInsert(T[] rules, T item) {
96             if (rules.Length < InsertPosition) {
97                 return rules.AddLast(item);
98             }
99
100             T[] newRules;
101
102             int newLength = rules.Length + 1;
103             if (newLength > MaxRules) {
104                 newLength = MaxRules;
105                 newRules = rules;
106             } else {
107                 newRules = new T[newLength];
108             }
109
110             Array.Copy(rules, 0, newRules, 0, InsertPosition);
111             newRules[InsertPosition] = item;
112             Array.Copy(rules, InsertPosition, newRules, InsertPosition + 1, newLength - InsertPosition - 1);
113             return newRules;
114         }
115     }
116 }