2 // support.cs: Support routines to work around the fact that System.Reflection.Emit
3 // can not introspect types that are being constructed
6 // Miguel de Icaza (miguel@ximian.com)
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
14 using System.Reflection;
15 using System.Collections;
16 using System.Reflection.Emit;
17 using System.Globalization;
19 namespace Mono.CSharp {
21 public interface ParameterData {
22 Type ParameterType (int pos);
24 bool HasParams { get; }
25 string ParameterName (int pos);
26 string ParameterDesc (int pos);
27 Parameter.Modifier ParameterModifier (int pos);
28 string GetSignatureForError ();
31 public class ReflectionParameters : ParameterData {
33 bool last_arg_is_params = false;
34 bool is_varargs = false;
36 public ReflectionParameters (MethodBase mb)
40 ParameterInfo [] pi = mb.GetParameters ();
41 is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
44 int count = pi.Length-1;
47 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
52 if (attrs.Length == 0)
55 last_arg_is_params = true;
59 public string GetSignatureForError ()
61 StringBuilder sb = new StringBuilder ("(");
62 for (int i = 0; i < pi.Length; ++i) {
65 sb.Append (ParameterDesc (i));
70 sb.Append ("__arglist");
73 return sb.ToString ();
76 public Type ParameterType (int pos)
78 if (last_arg_is_params && pos >= pi.Length - 1)
79 return pi [pi.Length - 1].ParameterType;
80 else if (is_varargs && pos >= pi.Length)
81 return TypeManager.runtime_argument_handle_type;
83 Type t = pi [pos].ParameterType;
89 public string ParameterName (int pos)
91 if (last_arg_is_params && pos >= pi.Length - 1)
92 return pi [pi.Length - 1].Name;
93 else if (is_varargs && pos >= pi.Length)
99 public string ParameterDesc (int pos)
101 if (is_varargs && pos >= pi.Length)
104 StringBuilder sb = new StringBuilder ();
109 Type partype = ParameterType (pos);
110 if (partype.IsByRef){
111 partype = TypeManager.GetElementType (partype);
118 if (pos >= pi.Length - 1 && last_arg_is_params)
119 sb.Append ("params ");
121 sb.Append (TypeManager.CSharpName (partype).Replace ("&", ""));
123 return sb.ToString ();
127 public Parameter.Modifier ParameterModifier (int pos)
129 if (last_arg_is_params && pos >= pi.Length - 1)
130 return Parameter.Modifier.PARAMS;
131 else if (is_varargs && pos >= pi.Length)
132 return Parameter.Modifier.ARGLIST;
134 Type t = pi [pos].ParameterType;
136 if ((pi [pos].Attributes & (ParameterAttributes.Out|ParameterAttributes.In)) == ParameterAttributes.Out)
137 return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
139 return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
142 return Parameter.Modifier.NONE;
147 return is_varargs ? pi.Length + 1 : pi.Length;
151 public bool HasParams {
153 return this.last_arg_is_params;
159 public class InternalParameters : ParameterData {
164 public readonly Parameters Parameters;
166 public InternalParameters (Type [] param_types, Parameters parameters)
168 this.param_types = param_types;
169 this.Parameters = parameters;
171 has_varargs = parameters.HasArglist;
173 if (param_types == null)
176 count = param_types.Length;
181 return has_varargs ? count + 1 : count;
185 public bool HasParams {
187 return Parameters.ArrayParameter != null;
191 Parameter GetParameter (int pos)
193 Parameter [] fixed_pars = Parameters.FixedParameters;
194 if (fixed_pars != null){
195 int len = fixed_pars.Length;
197 return Parameters.FixedParameters [pos];
200 return Parameters.ArrayParameter;
203 public string GetSignatureForError ()
205 StringBuilder sb = new StringBuilder ("(");
206 for (int i = 0; i < count; ++i) {
209 sb.Append (ParameterDesc (i));
214 sb.Append ("__arglist");
217 return sb.ToString ();
220 public Type ParameterType (int pos)
222 if (has_varargs && pos >= count)
223 return TypeManager.runtime_argument_handle_type;
225 if (param_types == null)
228 return GetParameter (pos).ExternalType ();
232 public string ParameterName (int pos)
234 if (has_varargs && pos >= count)
237 return GetParameter (pos).Name;
240 public string ParameterDesc (int pos)
242 if (has_varargs && pos >= count)
245 Type t = ParameterType (pos);
246 return (ModifierDesc (pos) + " " + TypeManager.CSharpName (t).Replace ("&", "")).TrimStart ();
249 public string ModifierDesc (int pos)
251 Parameter p = GetParameter (pos);
254 // We need to and for REF/OUT, because if either is set the
255 // extra flag ISBYREF will be set as well
257 if ((p.ModFlags & Parameter.Modifier.REF) != 0)
259 if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
261 if (p.ModFlags == Parameter.Modifier.PARAMS)
266 public Parameter.Modifier ParameterModifier (int pos)
268 if (has_varargs && pos >= count)
269 return Parameter.Modifier.ARGLIST;
271 Parameter.Modifier mod = GetParameter (pos).ModFlags;
273 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
274 mod |= Parameter.Modifier.ISBYREF;
281 class PtrHashtable : Hashtable {
282 sealed class PtrComparer : IComparer {
283 private PtrComparer () {}
285 public static PtrComparer Instance = new PtrComparer ();
287 public int Compare (object x, object y)
296 public PtrHashtable ()
298 comparer = PtrComparer.Instance;
303 * Hashtable whose keys are character arrays with the same length
305 class CharArrayHashtable : Hashtable {
306 sealed class ArrComparer : IComparer {
309 public ArrComparer (int len) {
313 public int Compare (object x, object y)
315 char[] a = (char[])x;
316 char[] b = (char[])y;
318 for (int i = 0; i < len; ++i)
327 protected override int GetHash (Object key)
329 char[] arr = (char[])key;
332 for (int i = 0; i < len; ++i)
333 h = (h << 5) - h + arr [i];
338 public CharArrayHashtable (int len)
341 comparer = new ArrComparer (len);
347 public object Second;
349 public Pair (object f, object s)
357 /// This is a wrapper around StreamReader which is seekable backwards
358 /// within a window of around 2048 chars.
360 public class SeekableStreamReader
362 public SeekableStreamReader (StreamReader reader)
364 this.reader = reader;
365 this.buffer = new char [AverageReadLength * 3];
367 // Let the StreamWriter autodetect the encoder
371 public SeekableStreamReader (Stream stream, Encoding encoding)
372 : this (new StreamReader (stream, encoding, true))
377 private const int AverageReadLength = 1024;
380 int buffer_start; // in chars
381 int char_count; // count buffer[] valid characters
382 int pos; // index into buffer[]
385 /// This value corresponds to the current position in a stream of characters.
386 /// The StreamReader hides its manipulation of the underlying byte stream and all
387 /// character set/decoding issues. Thus, we cannot use this position to guess at
388 /// the corresponding position in the underlying byte stream even though there is
389 /// a correlation between them.
391 public int Position {
392 get { return buffer_start + pos; }
395 if (value < buffer_start || value > buffer_start + char_count)
396 throw new InternalErrorException ("can't seek that far back: " + (pos - value));
397 pos = value - buffer_start;
401 private bool ReadBuffer ()
403 int slack = buffer.Length - char_count;
404 if (slack <= AverageReadLength / 2) {
405 // shift the buffer to make room for AverageReadLength number of characters
406 int shift = AverageReadLength - slack;
407 Array.Copy (buffer, shift, buffer, 0, char_count - shift);
410 buffer_start += shift;
411 slack += shift; // slack == AverageReadLength
414 int chars_read = reader.Read (buffer, char_count, slack);
415 char_count += chars_read;
417 return pos < char_count;
422 if ((pos >= char_count) && !ReadBuffer ())
430 if ((pos >= char_count) && !ReadBuffer ())
433 return buffer [pos++];
437 public class DoubleHash {
438 const int DEFAULT_INITIAL_BUCKETS = 100;
440 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
442 public DoubleHash (int size)
445 buckets = new Entry [size];
459 public Entry (object key1, object key2, int hash, object value, Entry next)
469 public bool Lookup (object a, object b, out object res)
471 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
473 for (Entry e = buckets [h % count]; e != null; e = e.next) {
474 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
483 public void Insert (object a, object b, object value)
485 // Is it an existing one?
487 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
489 for (Entry e = buckets [h % count]; e != null; e = e.next) {
490 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
494 int bucket = h % count;
495 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
497 // Grow whenever we double in size
498 if (size++ == count) {
502 Entry [] newBuckets = new Entry [count];
503 foreach (Entry root in buckets) {
506 int newLoc = e.hash % count;
508 e.next = newBuckets [newLoc];
509 newBuckets [newLoc] = e;
514 buckets = newBuckets;