Merge pull request #2921 from lewurm/lower-typechecks-later
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Messaging / MonoMethodMessage.cs
1 //
2 // System.Runtime.Remoting.Messaging.MonoMethodMessage.cs
3 //
4 // Author:
5 //   Dietmar Maurer (dietmar@ximian.com)
6 //   Patrik Torstensson
7 //
8 // (C) Ximian, Inc.  http://www.ximian.com
9 //
10
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System;
35 using System.Collections;
36 using System.Reflection;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.InteropServices;
39
40 namespace System.Runtime.Remoting.Messaging {
41         
42         [Serializable]
43         [StructLayout (LayoutKind.Sequential)]
44         internal class MonoMethodMessage : IMethodCallMessage, IMethodReturnMessage, IInternalMessage {
45
46 #pragma warning disable 649
47                 #region keep in sync with MonoMessage in object-internals.h
48                 MonoMethod method;
49                 object []  args;
50                 string []  names;
51                 byte [] arg_types; /* 1 == IN; 2 == OUT; 3 == INOUT; 4 == COPY OUT */
52                 public LogicalCallContext ctx;
53                 public object rval;
54                 public Exception exc;
55                 AsyncResult asyncResult;
56                 CallType call_type;
57                 #endregion
58 #pragma warning restore 649
59
60                 string uri;
61
62                 MCMDictionary properties;
63
64                 Type[] methodSignature;
65
66                 Identity identity;
67
68                 internal static String CallContextKey = "__CallContext";
69                 internal static String UriKey           = "__Uri";
70
71                 internal void InitMessage (MonoMethod method, object [] out_args)
72                 {
73                         this.method = method;
74                         ParameterInfo[] paramInfo = method.GetParametersInternal ();
75                         int param_count = paramInfo.Length;
76                         args = new object[param_count];
77                         arg_types = new byte[param_count];
78                         asyncResult = null;
79                         call_type = CallType.Sync;
80                         names = new string[param_count];
81                         for (int i = 0; i < param_count; i++) {
82                                 names[i] = paramInfo[i].Name;
83                         }
84                         bool hasOutArgs = out_args != null;
85                         int j = 0;
86                         for (int i = 0; i < param_count; i++) {
87                                 byte arg_type;
88                                 bool isOut = paramInfo[i].IsOut;
89                                 if (paramInfo[i].ParameterType.IsByRef) {
90                                         if (hasOutArgs)
91                                                 args[i] = out_args[j++];
92                                         arg_type = 2; // OUT
93                                         if (!isOut)
94                                                 arg_type |= 1; // INOUT
95                                 } else {
96                                         arg_type = 1; // IN
97                                         if (isOut)
98                                                 arg_type |= 4; // IN, COPY OUT
99                                 }
100                                 arg_types[i] = arg_type;
101                         }
102                 }
103
104                 public MonoMethodMessage (MethodBase method, object [] out_args)
105                 {
106                         if (method != null)
107                                 InitMessage ((MonoMethod)method, out_args);
108                         else
109                                 args = null;
110                 }
111
112                 public MonoMethodMessage (Type type, string method_name, object [] in_args)
113                 {
114                         // fixme: consider arg types
115                         MethodInfo minfo = type.GetMethod (method_name);
116                         
117                         InitMessage ((MonoMethod)minfo, null);
118
119                         int len = in_args.Length;
120                         for (int i = 0; i < len; i++) {
121                                 args [i] = in_args [i];
122                         }
123                 }
124                 
125                 public IDictionary Properties {
126                         get {
127                                 if (properties == null) properties = new MCMDictionary (this);
128                                 return properties;
129                         }
130                 }
131
132                 public int ArgCount {
133                         get {
134                                 if (CallType == CallType.EndInvoke)
135                                         return -1;
136                                         
137                                 if (null == args)
138                                         return 0;
139
140                                 return args.Length;
141                         }
142                 }
143                 
144                 public object [] Args {
145                         get {
146                                 return args;
147                         }
148                 }
149                 
150                 public bool HasVarArgs {
151                         get {
152                                 return false;
153                         }
154                 }
155
156                 public LogicalCallContext LogicalCallContext {
157                         get {
158                                 return ctx;
159                         }
160
161                         set {
162                                 ctx = value;
163                         }
164                 }
165
166                 public MethodBase MethodBase {
167                         get {
168                                 return method;
169                         }
170                 }
171
172                 public string MethodName {
173                         get {
174                                 if (null == method)
175                                         return String.Empty;
176
177                                 return method.Name;
178                         }
179                 }
180
181                 public object MethodSignature {
182                         get {
183                                 if (methodSignature == null) {
184                                         ParameterInfo[] parameters = method.GetParameters();
185                                         methodSignature = new Type[parameters.Length];
186                                         for (int n=0; n<parameters.Length; n++)
187                                                 methodSignature[n] = parameters[n].ParameterType;
188                                 }
189                                 return methodSignature;
190                         }
191                 }
192
193                 public string TypeName {
194                         get {
195                                 if (null == method)
196                                         return String.Empty;
197
198                                 return method.DeclaringType.AssemblyQualifiedName;
199                         }
200                 }
201
202                 public string Uri {
203                         get {
204                                 return uri;
205                         }
206
207                         set {
208                                 uri = value;
209                         }
210                 }
211
212                 public object GetArg (int arg_num)
213                 {
214                         if (null == args)
215                                 return null;
216
217                         return args [arg_num];
218                 }
219                 
220                 public string GetArgName (int arg_num)
221                 {
222                         if (null == args)
223                                 return String.Empty;
224
225                         return names [arg_num];
226                 }
227
228                 public int InArgCount {
229                         get {
230                                 if (CallType == CallType.EndInvoke)
231                                         return -1;
232
233                                 if (null == args)
234                                         return 0;
235
236                                 int count = 0;
237
238                                 foreach (byte t in arg_types) {
239                                         if ((t & 1) != 0) count++;
240                                                 
241                                 }
242                                 return count;
243                         }
244                 }
245                 
246                 public object [] InArgs {
247                         get {                
248                                 int i, j, count = InArgCount;
249                                 object [] inargs = new object [count];
250
251                                 i = j = 0;
252                                 foreach (byte t in arg_types) {
253                                         if ((t & 1) != 0)
254                                                 inargs [j++] = args [i];
255                                         i++;
256                                 }
257                                 
258                                 return inargs;
259                         }
260                 }
261                 
262                 public object GetInArg (int arg_num)
263                 {
264                         int i = 0, j = 0;
265                         foreach (byte t in arg_types) {
266                                 if ((t & 1) != 0) {
267                                         if (j++ == arg_num)
268                                                 return args [i]; 
269                                 }
270                                 i++;
271                         }
272                         return null;
273                 }
274                 
275                 public string GetInArgName (int arg_num)
276                 {
277                         int i = 0, j = 0;
278                         foreach (byte t in arg_types) {
279                                 if ((t & 1) != 0) {
280                                         if (j++ == arg_num)
281                                                 return names [i]; 
282                                 }
283                                 i++;
284                         }
285                         return null;
286                 }
287
288                 public Exception Exception {
289                         get {
290                                 return exc;
291                         }
292                 }
293                 
294                 public int OutArgCount {
295                         get {
296                                 if (null == args)
297                                         return 0;
298                                 
299                                 int count = 0;
300
301                                 foreach (byte t in arg_types) {
302                                         if ((t & 2) != 0) count++;
303                                                 
304                                 }
305                                 return count;
306                         }
307                 }
308                 
309                 public object [] OutArgs {
310                         get {
311                                 if (null == args)
312                                         return null;
313
314                                 int i, j, count = OutArgCount;
315                                 object [] outargs = new object [count];
316
317                                 i = j = 0;
318                                 foreach (byte t in arg_types) {
319                                         if ((t & 2) != 0)
320                                                 outargs [j++] = args [i];
321                                         i++;
322                                 }
323                                 
324                                 return outargs;
325                         }
326                 }
327                 
328                 public object ReturnValue {
329                         get {
330                                 return rval;
331                         }
332                 }
333
334                 public object GetOutArg (int arg_num)
335                 {
336                         int i = 0, j = 0;
337                         foreach (byte t in arg_types) {
338                                 if ((t & 2) != 0) {
339                                         if (j++ == arg_num)
340                                                 return args [i]; 
341                                 }
342                                 i++;
343                         }
344                         return null;
345                 }
346                 
347                 public string GetOutArgName (int arg_num)
348                 {
349                         int i = 0, j = 0;
350                         foreach (byte t in arg_types) {
351                                 if ((t & 2) != 0) {
352                                         if (j++ == arg_num)
353                                                 return names [i]; 
354                                 }
355                                 i++;
356                         }
357                         return null;
358                 }
359
360                 Identity IInternalMessage.TargetIdentity
361                 {
362                         get { return identity; }
363                         set { identity = value; }
364                 }
365
366                 bool IInternalMessage.HasProperties()
367                 {
368                         return properties != null;
369                 }
370
371                 public bool IsAsync
372                 {
373                         get { return asyncResult != null; }
374                 }
375
376                 public AsyncResult AsyncResult
377                 {
378                         get { return asyncResult; }
379                 }
380
381                 internal CallType CallType
382                 {
383                         get
384                         {
385                                 // FIXME: ideally, the OneWay type would be set by the runtime
386                                 
387                                 if (call_type == CallType.Sync && RemotingServices.IsOneWay (method))
388                                         call_type = CallType.OneWay;
389                                 return call_type;
390                         }
391                 }
392                 
393                 public bool NeedsOutProcessing (out int outCount) {
394                         bool res = false;
395                         outCount = 0;
396                         foreach (byte t in arg_types) {
397                                 if ((t & 2) != 0)
398                                         outCount++;
399                                 else if ((t & 4) != 0)
400                                         res = true;
401                         }
402                         return outCount > 0 || res;
403                 }
404                 
405         }
406
407         internal enum CallType: int
408         {
409                 Sync = 0,
410                 BeginInvoke = 1,
411                 EndInvoke = 2,
412                 OneWay = 3
413         }
414 }
415