Merge pull request #819 from brendanzagaeski/patch-1
[mono.git] / mcs / class / Mono.Debugger.Soft / Mono.Debugger.Soft / TypeMirror.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Reflection;
4 using C = Mono.Cecil;
5 using Mono.Cecil.Metadata;
6 #if NET_4_5
7 using System.Threading.Tasks;
8 #endif
9
10 namespace Mono.Debugger.Soft
11 {
12         /*
13          * Represents a type in the remote virtual machine.
14          * It might be better to make this a subclass of Type, but that could be
15          * difficult as some of our methods like GetMethods () return Mirror objects.
16          */
17         public class TypeMirror : Mirror
18         {
19                 MethodMirror[] methods;
20                 AssemblyMirror ass;
21                 ModuleMirror module;
22                 C.TypeDefinition meta;
23                 FieldInfoMirror[] fields;
24                 PropertyInfoMirror[] properties;
25                 TypeInfo info;
26                 TypeMirror base_type, element_type, gtd;
27                 TypeMirror[] nested;
28                 CustomAttributeDataMirror[] cattrs;
29                 TypeMirror[] ifaces;
30                 Dictionary<TypeMirror, InterfaceMappingMirror> iface_map;
31                 TypeMirror[] type_args;
32                 bool cached_base_type;
33                 bool inited;
34
35                 internal const BindingFlags DefaultBindingFlags =
36                 BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
37
38                 internal TypeMirror (VirtualMachine vm, long id) : base (vm, id) {
39                 }
40
41                 public string Name {
42                         get {
43                                 return GetInfo ().name;
44                         }
45                 }
46
47                 public string Namespace {
48                         get {
49                                 return GetInfo ().ns;
50                         }
51                 }
52
53                 public AssemblyMirror Assembly {
54                         get {
55                                 if (ass == null) {
56                                         ass = vm.GetAssembly (GetInfo ().assembly);
57                                 }
58                                 return ass;
59                         }
60                 }
61
62                 public ModuleMirror Module {
63                         get {
64                                 if (module == null) {
65                                         module = vm.GetModule (GetInfo ().module);
66                                 }                                                                                  
67                                 return module;
68                         }
69                 }
70
71                 public int MetadataToken {
72                         get {
73                                 return GetInfo ().token;
74                         }
75                 }
76
77                 public TypeAttributes Attributes {
78                         get {
79                                 return (TypeAttributes)GetInfo ().attributes;
80                         }
81                 }
82
83                 public TypeMirror BaseType {
84                         get {
85                                 if (!cached_base_type) {
86                                         base_type = vm.GetType (GetInfo ().base_type);
87                                         cached_base_type = true;
88                                 }
89                                 return base_type;
90                         }
91                 }
92
93                 public int GetArrayRank () {
94                         GetInfo ();
95                         if (info.rank == 0)
96                                 throw new ArgumentException ("Type must be an array type.");
97                         return info.rank;
98                 }
99
100
101                 public bool IsAbstract {
102                         get {
103                                 return (Attributes & TypeAttributes.Abstract) != 0;
104                         }
105                 }
106
107                 public bool IsAnsiClass {
108                         get {
109                                 return (Attributes & TypeAttributes.StringFormatMask)
110                                 == TypeAttributes.AnsiClass;
111                         }
112                 }
113
114                 public bool IsArray {
115                         get {
116                                 return IsArrayImpl ();
117                         }
118                 }
119
120                 public bool IsAutoClass {
121                         get {
122                                 return (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.AutoClass;
123                         }
124                 }
125
126                 public bool IsAutoLayout {
127                         get {
128                                 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.AutoLayout;
129                         }
130                 }
131
132                 public bool IsByRef {
133                         get {
134                                 return IsByRefImpl ();
135                         }
136                 }
137
138                 public bool IsClass {
139                         get {
140                                 if (IsInterface)
141                                         return false;
142
143                                 return !IsValueType;
144                         }
145                 }
146
147                 public bool IsCOMObject {
148                         get {
149                                 return IsCOMObjectImpl ();
150                         }
151                 }
152
153                 public bool IsContextful {
154                         get {
155                                 return IsContextfulImpl ();
156                         }
157                 }
158
159                 public bool IsEnum {
160                         get {
161                                 return GetInfo ().is_enum;
162                         }
163                 }
164
165                 public bool IsExplicitLayout {
166                         get {
167                                 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.ExplicitLayout;
168                         }
169                 }
170
171                 public bool IsImport {
172                         get {
173                                 return (Attributes & TypeAttributes.Import) != 0;
174                         }
175                 }
176
177                 public bool IsInterface {
178                         get {
179                                 return (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface;
180                         }
181                 }
182
183                 public bool IsLayoutSequential {
184                         get {
185                                 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.SequentialLayout;
186                         }
187                 }
188
189                 public bool IsMarshalByRef {
190                         get {
191                                 return IsMarshalByRefImpl ();
192                         }
193                 }
194
195                 public bool IsNestedAssembly {
196                         get {
197                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedAssembly;
198                         }
199                 }
200
201                 public bool IsNestedFamANDAssem {
202                         get {
203                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamANDAssem;
204                         }
205                 }
206
207                 public bool IsNestedFamily {
208                         get {
209                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily;
210                         }
211                 }
212
213                 public bool IsNestedFamORAssem {
214                         get {
215                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem;
216                         }
217                 }
218
219                 public bool IsNestedPrivate {
220                         get {
221                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPrivate;
222                         }
223                 }
224
225                 public bool IsNestedPublic {
226                         get {
227                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic;
228                         }
229                 }
230
231                 public bool IsNotPublic {
232                         get {
233                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NotPublic;
234                         }
235                 }
236
237                 public bool IsPointer {
238                         get {
239                                 return IsPointerImpl ();
240                         }
241                 }
242
243                 public bool IsPrimitive {
244                         get {
245                                 return IsPrimitiveImpl ();
246                         }
247                 }
248
249                 public bool IsPublic {
250                         get {
251                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public;
252                         }
253                 }
254
255                 public bool IsSealed {
256                         get {
257                                 return (Attributes & TypeAttributes.Sealed) != 0;
258                         }
259                 }
260
261                 public bool IsSerializable {
262                         get {
263                                 if ((Attributes & TypeAttributes.Serializable) != 0)
264                                         return true;
265
266                                 // FIXME:
267                                 return false;
268                         }
269                 }
270
271                 public bool IsSpecialName {
272                         get {
273                                 return (Attributes & TypeAttributes.SpecialName) != 0;
274                         }
275                 }
276
277                 public bool IsUnicodeClass {
278                         get {
279                                 return (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.UnicodeClass;
280                         }
281                 }
282
283                 public bool IsValueType {
284                         get {
285                                 return IsValueTypeImpl ();
286                         }
287                 }
288
289                 public bool HasElementType {
290                         get {
291                                 return HasElementTypeImpl ();
292                         }
293                 }
294
295                 // Since protocol version 2.12
296                 public bool IsGenericTypeDefinition {
297                         get {
298                                 vm.CheckProtocolVersion (2, 12);
299                                 GetInfo ();
300                                 return info.is_gtd;
301                         }
302                 }
303
304                 public bool IsGenericType {
305                         get {
306                                 if (vm.Version.AtLeast (2, 12)) {
307                                         return GetInfo ().is_generic_type;
308                                 } else {
309                                         return Name.IndexOf ('`') != -1;
310                                 }
311                         }
312                 }
313
314                 public TypeMirror GetElementType () {
315                         GetInfo ();
316                         if (element_type == null && info.element_type != 0)
317                                 element_type = vm.GetType (info.element_type);
318                         return element_type;
319                 }
320
321                 public TypeMirror GetGenericTypeDefinition () {
322                         vm.CheckProtocolVersion (2, 12);
323                         GetInfo ();
324                         if (gtd == null) {
325                                 if (info.gtd == 0)
326                                         throw new InvalidOperationException ();
327                                 gtd = vm.GetType (info.gtd);
328                         }
329                         return gtd;
330                 }
331
332                 // Since protocol version 2.15
333                 public TypeMirror[] GetGenericArguments () {
334                         vm.CheckProtocolVersion (2, 15);
335                         if (type_args == null)
336                                 type_args = vm.GetTypes (GetInfo ().type_args);
337                         return type_args;
338                 }
339
340                 public string FullName {
341                         get {
342                                 return GetInfo ().full_name;
343                         }
344                 }
345
346                 public string CSharpName {
347                         get {
348                                 if (IsArray) {
349                                         if (GetArrayRank () == 1)
350                                                 return GetElementType ().CSharpName + "[]";
351                                         else {
352                                                 string ranks = "";
353                                                 for (int i = 0; i < GetArrayRank (); ++i)
354                                                         ranks += ',';
355                                                 return GetElementType ().CSharpName + "[" + ranks + "]";
356                                         }
357                                 }
358                                 if (IsPrimitive) {
359                                         switch (Name) {
360                                         case "Byte":
361                                                 return "byte";
362                                         case "Sbyte":
363                                                 return "sbyte";
364                                         case "Char":
365                                                 return "char";
366                                         case "UInt16":
367                                                 return "ushort";
368                                         case "Int16":
369                                                 return "short";
370                                         case "UInt32":
371                                                 return "uint";
372                                         case "Int32":
373                                                 return "int";
374                                         case "UInt64":
375                                                 return "ulong";
376                                         case "Int64":
377                                                 return "long";
378                                         case "Single":
379                                                 return "float";
380                                         case "Double":
381                                                 return "double";
382                                         case "Boolean":
383                                                 return "bool";
384                                         default:
385                                                 return FullName;
386                                         }
387                                 }
388                                 // FIXME: Only do this for real corlib types
389                                 if (Namespace == "System") {
390                                         string s = Name;
391                                         switch (s) {
392                                         case "Decimal":
393                                                 return "decimal";
394                                         case "Object":
395                                                 return "object";
396                                         case "String":
397                                                 return "string";
398                                         default:
399                                                 return FullName;
400                                         }
401                                 } else {
402                                         return FullName;
403                                 }
404                         }
405                 }
406
407                 public MethodMirror[] GetMethods () {
408                         if (methods == null) {
409                                 long[] ids = vm.conn.Type_GetMethods (id);
410                                 MethodMirror[] m = new MethodMirror [ids.Length];
411                                 for (int i = 0; i < ids.Length; ++i) {
412                                         m [i] = vm.GetMethod (ids [i]);
413                                 }
414                                 methods = m;
415                         }
416                         return methods;
417                 }
418
419                 // FIXME: Sync this with Type
420                 public MethodMirror GetMethod (string name) {
421                         foreach (var m in GetMethods ())
422                                 if (m.Name == name)
423                                         return m;
424                         return null;
425                 }
426
427                 public FieldInfoMirror[] GetFields () {
428                         if (fields != null)
429                                 return fields;
430
431                         string[] names;
432                         long[] types;
433                         int[] attrs;
434                         long[] ids = vm.conn.Type_GetFields (id, out names, out types, out attrs);
435
436                         FieldInfoMirror[] res = new FieldInfoMirror [ids.Length];
437                         for (int i = 0; i < res.Length; ++i)
438                                 res [i] = new FieldInfoMirror (this, ids [i], names [i], vm.GetType (types [i]), (FieldAttributes)attrs [i]);
439
440                         fields = res;
441                         return fields;
442                 }
443
444                 public FieldInfoMirror GetField (string name) {
445                         if (name == null)
446                                 throw new ArgumentNullException ("name");
447                         foreach (var f in GetFields ())
448                                 if (f.Name == name)
449                                         return f;
450                         return null;
451                 }
452
453                 public TypeMirror[] GetNestedTypes ()
454                 {
455                         return GetNestedTypes (DefaultBindingFlags);
456                 }
457
458                 public TypeMirror[] GetNestedTypes (BindingFlags bindingAttr) {
459                         if (nested != null)
460                                 return nested;
461
462                         // FIXME: bindingAttr
463                         GetInfo ();
464                         var arr = new TypeMirror [info.nested.Length];
465                         for (int i = 0; i < arr.Length; ++i)
466                                 arr [i] = vm.GetType (info.nested [i]);
467                         nested = arr;
468
469                         return nested;
470                 }
471
472                 public PropertyInfoMirror[] GetProperties () {
473                         return GetProperties (DefaultBindingFlags);
474                 }
475
476                 public PropertyInfoMirror[] GetProperties (BindingFlags bindingAttr) {
477                         if (properties != null)
478                                 return properties;
479
480                         PropInfo[] info = vm.conn.Type_GetProperties (id);
481
482                         PropertyInfoMirror[] res = new PropertyInfoMirror [info.Length];
483                         for (int i = 0; i < res.Length; ++i)
484                                 res [i] = new PropertyInfoMirror (this, info [i].id, info [i].name, vm.GetMethod (info [i].get_method), vm.GetMethod (info [i].set_method), (PropertyAttributes)info [i].attrs);
485
486                         properties = res;
487                         return properties;
488                 }
489
490                 public PropertyInfoMirror GetProperty (string name) {
491                         if (name == null)
492                                 throw new ArgumentNullException ("name");
493                         foreach (var p in GetProperties ())
494                                 if (p.Name == name)
495                                         return p;
496                         return null;
497                 }
498
499                 public virtual bool IsAssignableFrom (TypeMirror c) {
500                         if (c == null)
501                                 throw new ArgumentNullException ("c");
502
503                         CheckMirror (c);
504
505                         // This is complex so do it in the debuggee
506                         return vm.conn.Type_IsAssignableFrom (id, c.Id);
507                 }
508
509                 public Value GetValue (FieldInfoMirror field) {
510                         return GetValues (new FieldInfoMirror [] { field }) [0];
511                 }
512
513                 public Value[] GetValues (IList<FieldInfoMirror> fields, ThreadMirror thread) {
514                         if (fields == null)
515                                 throw new ArgumentNullException ("fields");
516                         foreach (FieldInfoMirror f in fields) {
517                                 if (f == null)
518                                         throw new ArgumentNullException ("field");
519                                 CheckMirror (f);
520                         }
521                         long[] ids = new long [fields.Count];
522                         for (int i = 0; i < fields.Count; ++i)
523                                 ids [i] = fields [i].Id;
524                         try {
525                                 return vm.DecodeValues (vm.conn.Type_GetValues (id, ids, thread !=  null ? thread.Id : 0));
526                         } catch (CommandException ex) {
527                                 if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
528                                         throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
529                                 else
530                                         throw;
531                         }
532                 }
533
534                 public Value[] GetValues (IList<FieldInfoMirror> fields) {
535                         return GetValues (fields, null);
536                 }
537
538                 /*
539                  * Return the value of the [ThreadStatic] field FIELD on the thread THREAD.
540                  */
541                 public Value GetValue (FieldInfoMirror field, ThreadMirror thread) {
542                         if (thread == null)
543                                 throw new ArgumentNullException ("thread");
544                         CheckMirror (thread);
545                         return GetValues (new FieldInfoMirror [] { field }, thread) [0];
546                 }
547
548                 public void SetValues (IList<FieldInfoMirror> fields, Value[] values) {
549                         if (fields == null)
550                                 throw new ArgumentNullException ("fields");
551                         if (values == null)
552                                 throw new ArgumentNullException ("values");
553                         foreach (FieldInfoMirror f in fields) {
554                                 if (f == null)
555                                         throw new ArgumentNullException ("field");
556                                 CheckMirror (f);
557                         }
558                         foreach (Value v in values) {
559                                 if (v == null)
560                                         throw new ArgumentNullException ("values");
561                                 CheckMirror (v);
562                         }
563                         long[] ids = new long [fields.Count];
564                         for (int i = 0; i < fields.Count; ++i)
565                                 ids [i] = fields [i].Id;
566                         try {
567                                 vm.conn.Type_SetValues (id, ids, vm.EncodeValues (values));
568                         } catch (CommandException ex) {
569                                 if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
570                                         throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
571                                 else
572                                         throw;
573                         }
574                 }
575
576                 public void SetValue (FieldInfoMirror field, Value value) {
577                         SetValues (new FieldInfoMirror [] { field }, new Value [] { value });
578                 }
579
580                 public ObjectMirror GetTypeObject () {
581                         return vm.GetObject (vm.conn.Type_GetObject (id));
582                 }
583
584                 /*
585                  * Return a list of source files without path info, where methods of 
586                  * this type are defined. Return an empty list if the information is not 
587                  * available. 
588                  * This can be used by a debugger to find out which types occur in a 
589                  * given source file, to filter the list of methods whose locations
590                  * have to be checked when placing breakpoints.
591                  */
592                 public string[] GetSourceFiles () {
593                         return GetSourceFiles (false);
594                 }
595
596                 string[] source_files;
597                 string[] source_files_full_path;
598                 public string[] GetSourceFiles (bool returnFullPaths) {
599                         string[] res = returnFullPaths ? source_files_full_path : source_files;
600                         if (res == null) {
601                                 res = vm.conn.Type_GetSourceFiles (id, returnFullPaths);
602                                 if (returnFullPaths)
603                                         source_files_full_path = res;
604                                 else
605                                         source_files = res;
606                         }
607                         return res;
608                 }
609
610                 public C.TypeDefinition Metadata {
611                         get {
612                                 if (meta == null) {
613                                         if (Assembly.Metadata == null || MetadataToken == 0)
614                                                 return null;
615                                         meta = (C.TypeDefinition)Assembly.Metadata.MainModule.LookupToken (MetadataToken);
616                                 }
617                                 return meta;
618                         }
619                 }
620
621                 TypeInfo GetInfo () {
622                         if (info == null)
623                                 info = vm.conn.Type_GetInfo (id);
624                         return info;
625                 }
626
627                 protected virtual TypeAttributes GetAttributeFlagsImpl () {
628                         return (TypeAttributes)GetInfo ().attributes;
629                 }
630
631                 protected virtual bool HasElementTypeImpl () {
632                         return IsArray || IsByRef || IsPointer;
633                 }
634
635                 protected virtual bool IsArrayImpl () {
636                         return GetInfo ().rank > 0;
637                 }
638
639                 protected virtual bool IsByRefImpl () {
640                         return GetInfo ().is_byref;
641                 }
642
643                 protected virtual bool IsCOMObjectImpl () {
644                         return false;
645                 }
646
647                 protected virtual bool IsPointerImpl () {
648                         return GetInfo ().is_pointer;
649                 }
650
651                 protected virtual bool IsPrimitiveImpl () {
652                         return GetInfo ().is_primitive;
653                 }
654
655                 protected virtual bool IsValueTypeImpl ()
656                 {
657                         return GetInfo ().is_valuetype;
658                 }
659                 
660                 protected virtual bool IsContextfulImpl ()
661                 {
662                         // FIXME:
663                         return false;
664                 }
665
666                 protected virtual bool IsMarshalByRefImpl ()
667                 {
668                         // FIXME:
669                         return false;
670                 }
671
672                 // Same as Enum.GetUnderlyingType ()
673                 public TypeMirror EnumUnderlyingType {
674                         get {
675                                 if (!IsEnum)
676                                         throw new ArgumentException ("Type is not an enum type.");
677                                 foreach (FieldInfoMirror f in GetFields ()) {
678                                         if (!f.IsStatic)
679                                                 return f.FieldType;
680                                 }
681                                 throw new NotImplementedException ();
682                         }
683                 }
684
685                 /*
686                  * Creating the custom attributes themselves could modify the behavior of the
687                  * debuggee, so we return objects similar to the CustomAttributeData objects
688                  * used by the reflection-only functionality on .net.
689                  */
690                 public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
691                         return GetCustomAttrs (null, inherit);
692                 }
693
694                 public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
695                         if (attributeType == null)
696                                 throw new ArgumentNullException ("attributeType");
697                         return GetCustomAttrs (attributeType, inherit);
698                 }
699
700                 void AppendCustomAttrs (IList<CustomAttributeDataMirror> attrs, TypeMirror type, bool inherit)
701                 {
702                         if (cattrs == null && Metadata != null && !Metadata.HasCustomAttributes)
703                                 cattrs = new CustomAttributeDataMirror [0];
704
705                         if (cattrs == null) {
706                                 CattrInfo[] info = vm.conn.Type_GetCustomAttributes (id, 0, false);
707                                 cattrs = CustomAttributeDataMirror.Create (vm, info);
708                         }
709
710                         foreach (var attr in cattrs) {
711                                 if (type == null || attr.Constructor.DeclaringType == type)
712                                         attrs.Add (attr);
713                         }
714
715                         if (inherit && BaseType != null)
716                                 BaseType.AppendCustomAttrs (attrs, type, inherit);
717                 }
718
719                 CustomAttributeDataMirror[] GetCustomAttrs (TypeMirror type, bool inherit) {
720                         var attrs = new List<CustomAttributeDataMirror> ();
721                         AppendCustomAttrs (attrs, type, inherit);
722                         return attrs.ToArray ();
723                 }
724
725                 public MethodMirror[] GetMethodsByNameFlags (string name, BindingFlags flags, bool ignoreCase) {
726                         if (vm.conn.Version.AtLeast (2, 6)) {
727                                 long[] ids = vm.conn.Type_GetMethodsByNameFlags (id, name, (int)flags, ignoreCase);
728                                 MethodMirror[] m = new MethodMirror [ids.Length];
729                                 for (int i = 0; i < ids.Length; ++i)
730                                         m [i] = vm.GetMethod (ids [i]);
731                                 return m;
732                         } else {
733                                 if ((flags & BindingFlags.IgnoreCase) != 0) {
734                                         flags &= ~BindingFlags.IgnoreCase;
735                                         ignoreCase = true;
736                                 }
737                                 
738                                 if (flags == BindingFlags.Default)
739                                         flags = BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static;
740                                 
741                                 MethodAttributes access = (MethodAttributes) 0;
742                                 bool matchInstance = false;
743                                 bool matchStatic = false;
744                                 
745                                 if ((flags & BindingFlags.NonPublic) != 0) {
746                                         access |= MethodAttributes.Private;
747                                         flags &= ~BindingFlags.NonPublic;
748                                 }
749                                 if ((flags & BindingFlags.Public) != 0) {
750                                         access |= MethodAttributes.Public;
751                                         flags &= ~BindingFlags.Public;
752                                 }
753                                 if ((flags & BindingFlags.Instance) != 0) {
754                                         flags &= ~BindingFlags.Instance;
755                                         matchInstance = true;
756                                 }
757                                 if ((flags & BindingFlags.Static) != 0) {
758                                         flags &= ~BindingFlags.Static;
759                                         matchStatic = true;
760                                 }
761                                 
762                                 if ((int) flags != 0)
763                                         throw new NotImplementedException ();
764                                 
765                                 var res = new List<MethodMirror> ();
766                                 foreach (MethodMirror m in GetMethods ()) {
767                                         if ((m.Attributes & access) == (MethodAttributes) 0)
768                                                 continue;
769                                         
770                                         if (!((matchStatic && m.IsStatic) || (matchInstance && !m.IsStatic)))
771                                                 continue;
772                                         
773                                         if ((!ignoreCase && m.Name == name) || (ignoreCase && m.Name.Equals (name, StringComparison.CurrentCultureIgnoreCase)))
774                                                 res.Add (m);
775                                 }
776                                 return res.ToArray ();
777                         }
778                 }
779
780                 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
781                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
782                 }
783
784                 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
785                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
786                 }
787
788                 [Obsolete ("Use the overload without the 'vm' argument")]
789                 public IAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
790                         return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
791                 }
792
793                 public IAsyncResult BeginInvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
794                         return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
795                 }
796
797                 public Value EndInvokeMethod (IAsyncResult asyncResult) {
798                         return ObjectMirror.EndInvokeMethodInternal (asyncResult);
799                 }
800
801 #if NET_4_5
802                 public Task<Value> InvokeMethodAsync (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options = InvokeOptions.None) {
803                         var tcs = new TaskCompletionSource<Value> ();
804                         BeginInvokeMethod (thread, method, arguments, options, iar =>
805                                         {
806                                                 try {
807                                                         tcs.SetResult (EndInvokeMethod (iar));
808                                                 } catch (OperationCanceledException) {
809                                                         tcs.TrySetCanceled ();
810                                                 } catch (Exception ex) {
811                                                         tcs.TrySetException (ex);
812                                                 }
813                                         }, null);
814                         return tcs.Task;
815                 }
816 #endif
817
818                 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
819                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
820                 }                       
821
822                 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
823                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
824                 }
825
826                 // Since protocol version 2.11
827                 public TypeMirror[] GetInterfaces () {
828                         if (ifaces == null)
829                                 ifaces = vm.GetTypes (vm.conn.Type_GetInterfaces (id));
830                         return ifaces;
831                 }
832
833                 // Since protocol version 2.11
834                 public InterfaceMappingMirror GetInterfaceMap (TypeMirror interfaceType) {
835                         if (interfaceType == null)
836                                 throw new ArgumentNullException ("interfaceType");
837                         if (!interfaceType.IsInterface)
838                                 throw new ArgumentException ("Argument must be an interface.", "interfaceType");
839                         if (IsInterface)
840                                 throw new ArgumentException ("'this' type cannot be an interface itself");
841
842                         if (iface_map == null) {
843                                 // Query the info in bulk
844                                 GetInterfaces ();
845                                 var ids = new long [ifaces.Length];
846                                 for (int i = 0; i < ifaces.Length; ++i)
847                                         ids [i] = ifaces [i].Id;
848
849                                 var ifacemap = vm.conn.Type_GetInterfaceMap (id, ids);
850
851                                 var imap = new Dictionary<TypeMirror, InterfaceMappingMirror> ();
852                                 for (int i = 0; i < ifacemap.Length; ++i) {
853                                         IfaceMapInfo info = ifacemap [i];
854
855                                         MethodMirror[] imethods = new MethodMirror [info.iface_methods.Length];
856                                         for (int j = 0; j < info.iface_methods.Length; ++j)
857                                                 imethods [j] = vm.GetMethod (info.iface_methods [j]);
858
859                                         MethodMirror[] tmethods = new MethodMirror [info.iface_methods.Length];
860                                         for (int j = 0; j < info.target_methods.Length; ++j)
861                                                 tmethods [j] = vm.GetMethod (info.target_methods [j]);
862
863                                         InterfaceMappingMirror map = new InterfaceMappingMirror (vm, this, vm.GetType (info.iface_id), imethods, tmethods);
864
865                                         imap [map.InterfaceType] = map;
866                                 }
867
868                                 iface_map = imap;
869                         }
870
871                         InterfaceMappingMirror res;
872                         if (!iface_map.TryGetValue (interfaceType, out res))
873                                 throw new ArgumentException ("Interface not found", "interfaceType");
874                         return res;
875                 }
876
877                 // Return whenever the type initializer of this type has ran
878                 // Since protocol version 2.23
879                 public bool IsInitialized {
880                         get {
881                                 vm.CheckProtocolVersion (2, 23);
882                                 if (!inited)
883                                         inited = vm.conn.Type_IsInitialized (id);
884                                 return inited;
885                         }
886                 }
887     }
888 }