1 Runtime support for Remoting
2 ============================
4 The runtime supports a special objects called "TransparentProxy". You can
5 create objects of this type by calling GetTransparentProxy() on a "RealProxy"
8 LDFLD/STFLD for transparent proxies
9 ===================================
11 Access to fields must be redirected to the remote object. System.Object has
12 some special methods for that:
14 void FieldGetter (string typeName, string fieldName, ref object val);
16 void FieldSetter (string typeName, string fieldName, object val);
18 This methods are never called on actual object. The are only used to pack
19 LDFLD/STFLD operations into method call messages, which are then passed to the
20 RealProxy::Invoke() method.
22 There are two helper methods which can be used by the JIT and the interpreter
23 to convert LDFLD/STFLD operations into messages and then call
24 RealProxy::Invoke(): mono_store_remote_field() and mono_load_remote_field().
26 Cross app domain optimizations
27 ==============================
29 The new implementation of the cross app domain channel makes a minimal use of
30 the remoting infrastructure. The idea is to create remoting wrappers specific
31 for cross app domain calls, which take the input paramers, switch the domain
32 and dispatch the call in the new domain.
34 When an vtable for a proxy needs to be created, the runtime checks if the proxy
35 is referencing an object that belongs to another domain in the same process.
36 In such case, the fast xdomain wrapper is returned instead of the regular one.
38 The xdomain wrapper will have a different structure depending on the signature
39 of the method it wraps, since different types have different marshalling needs.
40 There are four types of marshalling, the first one is the fastest, the last one
43 1) No marshalling at all: this is for primitive types.
45 2) Internal copy of the object in the new domain: some system types can
46 be copied from one domain to the other by the runtime. This currently
47 applies to arrays of primitive types (or arrays of values that can be
48 internally copied), String and StringBuilder. We can add more types in
51 3) Internal copy for Out parameters. It is a specific case of the previous
52 type, when an input parameter has the [Out] attribute, which means that the
53 content of the object that is marshalled into the new domain, needs to be
54 copied over the instance of the original object. This applies to arrays
55 of primitive types and StringBuilder. This is used, for example, to be able
56 to call methods such as Stream.Read ([Out]buffer, pos, lengh) across domains.
58 4) Serialization. The value is serialized in one domain and deserialized in the
61 The xdomain wrapper will be generated according to the marshalling needs of
64 The cross domain wrapper is divided in two methods. The first method (the
65 wrapper itself) takes the input parameters and serializes those that need to
66 be serialized. After that, sets the new domain and calls to a second method
67 in the new domain, which deserializes the parameters, makes a local copy of
68 those that don't need serialization, and dispatches the call to the real
69 object. Then, the inverse sequence is followed: return values are serialized,
70 flow returns to the first method, which changes the domain again and
71 deserializes the values.
76 This are examples of cross domain wrappers in pseudo-C# code.
77 The first example is for a method with the following signature:
79 ArrayList Test (int a, string b, ArrayList c, ref ArrayList d, ref string e, ref int f)
81 Of course, the wrapper has the same signature:
83 ArrayList Test_xdomain_invoke (int a, string b, ArrayList c, ref ArrayList d, ref string e, ref int f)
85 int loc_new_domainid, loc_old_domainid;
87 byte[] loc_serialized_array;
89 // Save thread domain data
90 Context loc_context = Thread.CurrentContext;
91 if (loc_context.IsDefaultContext) {
92 return Test_remoting_invoke (a, b, c, ref d, ref e, ref f);
94 object loc_datastore = Thread.ResetDataStoreStatus ();
96 // Create the array that will hold the parameters to be serialized
97 object[] loc_array = new object [3]; // +1 to store the return value
101 // Serialize parameters
102 loc_serialized_array = RemotingServices.SerializeCallData (loc_Array);
104 // Get the target domain id and change the domain
105 RealProxy loc_real_proxy = ((TransparentProxy)this).rp;
106 loc_new_domainid = loc_real_proxy->target_domain_id;
108 loc_old_domainid = mono_remoting_set_domain_by_id (loc_new_domainid);
111 /* The following is an indirect call made into the target domain */
112 Test_xdomain_dispatch (rp, ref loc_serialized_array, out loc_serialized_exc, a, b, ref e_copy, ref f);
115 mono_remoting_set_domain_by_id (loc_old_domainid);
117 // Restore thread domain data
118 mono_context_set (loc_context);
119 Thread.RestoreDataStoreStatus (loc_datastore);
121 if (loc_serialized_exc != null) {
122 Exception ex = (Exception) RemotingServices.DeserializeCallData (loc_serialized_exc);
123 ex.FixRemotingException ();
127 // copy back non-serialized output parametars
128 e = mono_marshal_xdomain_copy_value (e_copy);
130 // Deserialize out parameters
131 loc_serialized_array = mono_marshal_xdomain_copy_value (loc_serialized_array);
132 loc_array = RemotingServices.DeserializeObject (loc_serialized_array);
134 mono_thread_force_interruption_checkpoint ();
135 return loc_array [2];
138 void Test_xdomain_dispatch (RealProxy rp, ref byte[] loc_call_data, out byte[] loc_exc_data, int a, string b, ref string e, ref int f)
140 // Deserialize parameters
142 // Clean the call context
143 CallContext.SetCurrentCallContext (null);
145 // Deserialize call data
146 if (loc_call_data != null) {
147 loc_call_data = mono_marshal_xdomain_copy_value (loc_call_data);
148 loc_array = RemotingServices.DeserializeCallData (loc_call_data);
151 // Get the target object
152 object target = rp.GetAppDomainTarget ();
154 // Load the arguments
155 b = mono_marshal_xdomain_copy_value (b);
157 // Make the call to the real object
158 mono_thread_force_interruption_checkpoint ();
159 loc_return = target.Test (a, b, loc_array[0], ref loc_array[1], ref e, ref f);
161 // Serialize the return values
162 // Reset parameters in the array that don't need to be serialized back
163 loc_array [0] = null;
164 // Add the return value to the array
165 loc_array [2] = loc_return;
167 loc_call_data = RemotingServices.SerializeCallData (loc_array);
170 catch (Exception ex) {
171 loc_exc_data = RemotingServices.SerializeExceptionData (ex);
179 This is another example of a method with more simple parameters:
181 int SimpleTest_xdomain_invoke (int a)
183 int loc_new_domainid, loc_old_domainid;
185 byte[] loc_serialized_array;
187 // Save thread domain data
188 Context loc_context = Thread.CurrentContext;
189 if (loc_context.IsDefaultContext) {
190 return SimpleTest_remoting_invoke (a, b, c, ref d, ref e, ref f);
192 object loc_datastore = Thread.ResetDataStoreStatus ();
194 // Serialize parameters. This will only serialize LogicalContext data if needed.
195 loc_serialized_array = RemotingServices.SerializeCallData (null);
197 // Get the target domain id and change the domain
198 RealProxy loc_real_proxy = ((TransparentProxy)this).rp;
199 loc_new_domainid = loc_real_proxy->target_domain_id;
201 loc_old_domainid = mono_remoting_set_domain_by_id (loc_new_domainid);
203 /* The following is an indirect call made into the target domain */
204 loc_return = SimpleTest_xdomain_dispatch (rp, ref loc_serialized_array, out loc_serialized_exc, a);
207 mono_remoting_set_domain_by_id (loc_old_domainid);
209 // Restore thread domain data
210 mono_context_set (loc_context);
211 Thread.RestoreDataStoreStatus (loc_datastore);
213 if (loc_serialized_exc != null) {
214 Exception ex = (Exception) RemotingServices.DeserializeCallData (loc_serialized_exc);
215 ex.FixRemotingException ();
219 RemotingServices.DeserializeCallData (loc_serialized_array);
220 return loc_return [2];
224 int SimpleTest_xdomain_dispatch (RealProxy rp, ref byte[] loc_call_data, out byte[] loc_exc_data, int a)
228 // Deserialize parameters
230 // Clean the call context
231 CallContext.SetCurrentCallContext (null);
233 // Deserialize call data
234 if (loc_call_data != null) {
235 loc_call_data = mono_marshal_xdomain_copy_value (loc_call_data);
236 RemotingServices.DeserializeCallData (loc_call_data);
239 // Get the target object
240 object target = rp.GetAppDomainTarget ();
242 // Make the call to the real object
243 loc_return = target.Test (a);
245 loc_call_data = RemotingServices.SerializeCallData (loc_Array);
248 catch (Exception ex) {
249 loc_exc_data = RemotingServices.SerializeExceptionData (ex);