xref: /netbsd-src/external/gpl3/gcc.old/dist/libcc1/rpc.hh (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
1 /* RPC call and callback templates
2    Copyright (C) 2014-2020 Free Software Foundation, Inc.
3 
4 This file is part of GCC.
5 
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
10 
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  */
19 
20 #ifndef CC1_PLUGIN_RPC_HH
21 #define CC1_PLUGIN_RPC_HH
22 
23 #include "status.hh"
24 #include "connection.hh"
25 
26 namespace cc1_plugin
27 {
28   // The plugin API may contain some "const" method parameters.
29   // However, when unmarshalling we cannot unmarshall into a const
30   // object; and furthermore we want to be able to deallocate pointers
31   // when finished with them.  This wrapper class lets us properly
32   // remove the "const" and handle deallocation from pointer types.
33 
34   template<typename T>
35   class argument_wrapper
36   {
37   public:
38 
argument_wrapper()39     argument_wrapper () { }
~argument_wrapper()40     ~argument_wrapper () { }
41 
operator T() const42     operator T () const { return m_object; }
43 
unmarshall(connection * conn)44     status unmarshall (connection *conn)
45     {
46       return ::cc1_plugin::unmarshall (conn, &m_object);
47     }
48 
49   private:
50 
51     T m_object;
52 
53     // No copying or assignment allowed.
54     argument_wrapper (const argument_wrapper &);
55     argument_wrapper &operator= (const argument_wrapper &);
56   };
57 
58   // Specialization for any kind of pointer.  This is declared but not
59   // defined to avoid bugs if a new pointer type is introduced into
60   // the API.  Instead you will just get a compilation error.
61   template<typename T>
62   class argument_wrapper<const T *>;
63 
64   // Specialization for string types.
65   template<>
66   class argument_wrapper<const char *>
67   {
68   public:
argument_wrapper()69     argument_wrapper () : m_object (NULL) { }
~argument_wrapper()70     ~argument_wrapper ()
71     {
72       delete[] m_object;
73     }
74 
operator const char*() const75     operator const char * () const
76     {
77       return m_object;
78     }
79 
unmarshall(connection * conn)80     status unmarshall (connection *conn)
81     {
82       return ::cc1_plugin::unmarshall (conn, &m_object);
83     }
84 
85   private:
86 
87     char *m_object;
88 
89     // No copying or assignment allowed.
90     argument_wrapper (const argument_wrapper &);
91     argument_wrapper &operator= (const argument_wrapper &);
92   };
93 
94   // Specialization for gcc_type_array.
95   template<>
96   class argument_wrapper<const gcc_type_array *>
97   {
98   public:
argument_wrapper()99     argument_wrapper () : m_object (NULL) { }
~argument_wrapper()100     ~argument_wrapper ()
101     {
102       // It would be nicer if gcc_type_array could have a destructor.
103       // But, it is in code shared with gdb and cannot.
104       if (m_object != NULL)
105 	delete[] m_object->elements;
106       delete m_object;
107     }
108 
operator const gcc_type_array*() const109     operator const gcc_type_array * () const
110     {
111       return m_object;
112     }
113 
unmarshall(connection * conn)114     status unmarshall (connection *conn)
115     {
116       return ::cc1_plugin::unmarshall (conn, &m_object);
117     }
118 
119   private:
120 
121     gcc_type_array *m_object;
122 
123     // No copying or assignment allowed.
124     argument_wrapper (const argument_wrapper &);
125     argument_wrapper &operator= (const argument_wrapper &);
126   };
127 
128 #ifdef GCC_CP_INTERFACE_H
129   // Specialization for gcc_vbase_array.
130   template<>
131   class argument_wrapper<const gcc_vbase_array *>
132   {
133   public:
argument_wrapper()134     argument_wrapper () : m_object (NULL) { }
~argument_wrapper()135     ~argument_wrapper ()
136     {
137       // It would be nicer if gcc_type_array could have a destructor.
138       // But, it is in code shared with gdb and cannot.
139       if (m_object != NULL)
140 	{
141 	  delete[] m_object->flags;
142 	  delete[] m_object->elements;
143 	}
144       delete m_object;
145     }
146 
operator const gcc_vbase_array*() const147     operator const gcc_vbase_array * () const
148     {
149       return m_object;
150     }
151 
unmarshall(connection * conn)152     status unmarshall (connection *conn)
153     {
154       return ::cc1_plugin::unmarshall (conn, &m_object);
155     }
156 
157   private:
158 
159     gcc_vbase_array *m_object;
160 
161     // No copying or assignment allowed.
162     argument_wrapper (const argument_wrapper &);
163     argument_wrapper &operator= (const argument_wrapper &);
164   };
165 
166   // Specialization for gcc_cp_template_args.
167   template<>
168   class argument_wrapper<const gcc_cp_template_args *>
169   {
170   public:
argument_wrapper()171     argument_wrapper () : m_object (NULL) { }
~argument_wrapper()172     ~argument_wrapper ()
173     {
174       // It would be nicer if gcc_type_array could have a destructor.
175       // But, it is in code shared with gdb and cannot.
176       if (m_object != NULL)
177 	{
178 	  delete[] m_object->elements;
179 	  delete[] m_object->kinds;
180 	}
181       delete m_object;
182     }
183 
operator const gcc_cp_template_args*() const184     operator const gcc_cp_template_args * () const
185     {
186       return m_object;
187     }
188 
unmarshall(connection * conn)189     status unmarshall (connection *conn)
190     {
191       return ::cc1_plugin::unmarshall (conn, &m_object);
192     }
193 
194   private:
195 
196     gcc_cp_template_args *m_object;
197 
198     // No copying or assignment allowed.
199     argument_wrapper (const argument_wrapper &);
200     argument_wrapper &operator= (const argument_wrapper &);
201   };
202 
203   // Specialization for gcc_cp_function_args.
204   template<>
205   class argument_wrapper<const gcc_cp_function_args *>
206   {
207   public:
argument_wrapper()208     argument_wrapper () : m_object (NULL) { }
~argument_wrapper()209     ~argument_wrapper ()
210     {
211       // It would be nicer if gcc_type_array could have a destructor.
212       // But, it is in code shared with gdb and cannot.
213       if (m_object != NULL)
214 	{
215 	  delete[] m_object->elements;
216 	}
217       delete m_object;
218     }
219 
operator const gcc_cp_function_args*() const220     operator const gcc_cp_function_args * () const
221     {
222       return m_object;
223     }
224 
unmarshall(connection * conn)225     status unmarshall (connection *conn)
226     {
227       return ::cc1_plugin::unmarshall (conn, &m_object);
228     }
229 
230   private:
231 
232     gcc_cp_function_args *m_object;
233 
234     // No copying or assignment allowed.
235     argument_wrapper (const argument_wrapper &);
236     argument_wrapper &operator= (const argument_wrapper &);
237   };
238 #endif /* GCC_CP_INTERFACE_H */
239 
240   // There are two kinds of template functions here: "call" and
241   // "callback".  They are each repeated multiple times to handle
242   // different numbers of arguments.  (This would be improved with
243   // C++11, though applying a call is still tricky until C++14 can be
244   // used.)
245 
246   // The "call" template is used for making a remote procedure call.
247   // It starts a query ('Q') packet, marshalls its arguments, waits
248   // for a result, and finally reads and returns the result via an
249   // "out" parameter.
250 
251   // The "callback" template is used when receiving a remote procedure
252   // call.  This template function is suitable for use with the
253   // "callbacks" and "connection" classes.  It decodes incoming
254   // arguments, passes them to the wrapped function, and finally
255   // marshalls a reply packet.
256 
257   template<typename R>
258   status
call(connection * conn,const char * method,R * result)259   call (connection *conn, const char *method, R *result)
260   {
261     if (!conn->send ('Q'))
262       return FAIL;
263     if (!marshall (conn, method))
264       return FAIL;
265     if (!marshall (conn, 0))
266       return FAIL;
267     if (!conn->wait_for_result ())
268       return FAIL;
269     if (!unmarshall (conn, result))
270       return FAIL;
271     return OK;
272   }
273 
274   template<typename R, R (*func) (connection *)>
275   status
callback(connection * conn)276   callback (connection *conn)
277   {
278     R result;
279 
280     if (!unmarshall_check (conn, 0))
281       return FAIL;
282     result = func (conn);
283     if (!conn->send ('R'))
284       return FAIL;
285     return marshall (conn, result);
286   }
287 
288   template<typename R, typename A>
289   status
call(connection * conn,const char * method,R * result,A arg)290   call (connection *conn, const char *method, R *result, A arg)
291   {
292     if (!conn->send ('Q'))
293       return FAIL;
294     if (!marshall (conn, method))
295       return FAIL;
296     if (!marshall (conn, 1))
297       return FAIL;
298     if (!marshall (conn, arg))
299       return FAIL;
300     if (!conn->wait_for_result ())
301       return FAIL;
302     if (!unmarshall (conn, result))
303       return FAIL;
304     return OK;
305   }
306 
307   template<typename R, typename A, R (*func) (connection *, A)>
308   status
callback(connection * conn)309   callback (connection *conn)
310   {
311     argument_wrapper<A> arg;
312     R result;
313 
314     if (!unmarshall_check (conn, 1))
315       return FAIL;
316     if (!arg.unmarshall (conn))
317       return FAIL;
318     result = func (conn, arg);
319     if (!conn->send ('R'))
320       return FAIL;
321     return marshall (conn, result);
322   }
323 
324   template<typename R, typename A1, typename A2>
325   status
call(connection * conn,const char * method,R * result,A1 arg1,A2 arg2)326   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2)
327   {
328     if (!conn->send ('Q'))
329       return FAIL;
330     if (!marshall (conn, method))
331       return FAIL;
332     if (!marshall (conn, 2))
333       return FAIL;
334     if (!marshall (conn, arg1))
335       return FAIL;
336     if (!marshall (conn, arg2))
337       return FAIL;
338     if (!conn->wait_for_result ())
339       return FAIL;
340     if (!unmarshall (conn, result))
341       return FAIL;
342     return OK;
343   }
344 
345   template<typename R, typename A1, typename A2, R (*func) (connection *,
346 							    A1, A2)>
347   status
callback(connection * conn)348   callback (connection *conn)
349   {
350     argument_wrapper<A1> arg1;
351     argument_wrapper<A2> arg2;
352     R result;
353 
354     if (!unmarshall_check (conn, 2))
355       return FAIL;
356     if (!arg1.unmarshall (conn))
357       return FAIL;
358     if (!arg2.unmarshall (conn))
359       return FAIL;
360     result = func (conn, arg1, arg2);
361     if (!conn->send ('R'))
362       return FAIL;
363     return marshall (conn, result);
364   }
365 
366   template<typename R, typename A1, typename A2, typename A3>
367   status
call(connection * conn,const char * method,R * result,A1 arg1,A2 arg2,A3 arg3)368   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
369 	A3 arg3)
370   {
371     if (!conn->send ('Q'))
372       return FAIL;
373     if (!marshall (conn, method))
374       return FAIL;
375     if (!marshall (conn, 3))
376       return FAIL;
377     if (!marshall (conn, arg1))
378       return FAIL;
379     if (!marshall (conn, arg2))
380       return FAIL;
381     if (!marshall (conn, arg3))
382       return FAIL;
383     if (!conn->wait_for_result ())
384       return FAIL;
385     if (!unmarshall (conn, result))
386       return FAIL;
387     return OK;
388   }
389 
390   template<typename R, typename A1, typename A2, typename A3,
391 	   R (*func) (connection *, A1, A2, A3)>
392   status
callback(connection * conn)393   callback (connection *conn)
394   {
395     argument_wrapper<A1> arg1;
396     argument_wrapper<A2> arg2;
397     argument_wrapper<A3> arg3;
398     R result;
399 
400     if (!unmarshall_check (conn, 3))
401       return FAIL;
402     if (!arg1.unmarshall (conn))
403       return FAIL;
404     if (!arg2.unmarshall (conn))
405       return FAIL;
406     if (!arg3.unmarshall (conn))
407       return FAIL;
408     result = func (conn, arg1, arg2, arg3);
409     if (!conn->send ('R'))
410       return FAIL;
411     return marshall (conn, result);
412   }
413 
414   template<typename R, typename A1, typename A2, typename A3, typename A4>
415   status
call(connection * conn,const char * method,R * result,A1 arg1,A2 arg2,A3 arg3,A4 arg4)416   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
417 	A3 arg3, A4 arg4)
418   {
419     if (!conn->send ('Q'))
420       return FAIL;
421     if (!marshall (conn, method))
422       return FAIL;
423     if (!marshall (conn, 4))
424       return FAIL;
425     if (!marshall (conn, arg1))
426       return FAIL;
427     if (!marshall (conn, arg2))
428       return FAIL;
429     if (!marshall (conn, arg3))
430       return FAIL;
431     if (!marshall (conn, arg4))
432       return FAIL;
433     if (!conn->wait_for_result ())
434       return FAIL;
435     if (!unmarshall (conn, result))
436       return FAIL;
437     return OK;
438   }
439 
440   template<typename R, typename A1, typename A2, typename A3, typename A4,
441 	   R (*func) (connection *, A1, A2, A3, A4)>
442   status
callback(connection * conn)443   callback (connection *conn)
444   {
445     argument_wrapper<A1> arg1;
446     argument_wrapper<A2> arg2;
447     argument_wrapper<A3> arg3;
448     argument_wrapper<A4> arg4;
449     R result;
450 
451     if (!unmarshall_check (conn, 4))
452       return FAIL;
453     if (!arg1.unmarshall (conn))
454       return FAIL;
455     if (!arg2.unmarshall (conn))
456       return FAIL;
457     if (!arg3.unmarshall (conn))
458       return FAIL;
459     if (!arg4.unmarshall (conn))
460       return FAIL;
461     result = func (conn, arg1, arg2, arg3, arg4);
462     if (!conn->send ('R'))
463       return FAIL;
464     return marshall (conn, result);
465   }
466 
467   template<typename R, typename A1, typename A2, typename A3, typename A4,
468 	   typename A5>
469   status
call(connection * conn,const char * method,R * result,A1 arg1,A2 arg2,A3 arg3,A4 arg4,A5 arg5)470   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
471 	A3 arg3, A4 arg4, A5 arg5)
472   {
473     if (!conn->send ('Q'))
474       return FAIL;
475     if (!marshall (conn, method))
476       return FAIL;
477     if (!marshall (conn, 5))
478       return FAIL;
479     if (!marshall (conn, arg1))
480       return FAIL;
481     if (!marshall (conn, arg2))
482       return FAIL;
483     if (!marshall (conn, arg3))
484       return FAIL;
485     if (!marshall (conn, arg4))
486       return FAIL;
487     if (!marshall (conn, arg5))
488       return FAIL;
489     if (!conn->wait_for_result ())
490       return FAIL;
491     if (!unmarshall (conn, result))
492       return FAIL;
493     return OK;
494   }
495 
496   template<typename R, typename A1, typename A2, typename A3, typename A4,
497 	   typename A5, R (*func) (connection *, A1, A2, A3, A4, A5)>
498   status
callback(connection * conn)499   callback (connection *conn)
500   {
501     argument_wrapper<A1> arg1;
502     argument_wrapper<A2> arg2;
503     argument_wrapper<A3> arg3;
504     argument_wrapper<A4> arg4;
505     argument_wrapper<A5> arg5;
506     R result;
507 
508     if (!unmarshall_check (conn, 5))
509       return FAIL;
510     if (!arg1.unmarshall (conn))
511       return FAIL;
512     if (!arg2.unmarshall (conn))
513       return FAIL;
514     if (!arg3.unmarshall (conn))
515       return FAIL;
516     if (!arg4.unmarshall (conn))
517       return FAIL;
518     if (!arg5.unmarshall (conn))
519       return FAIL;
520     result = func (conn, arg1, arg2, arg3, arg4, arg5);
521     if (!conn->send ('R'))
522       return FAIL;
523     return marshall (conn, result);
524   }
525 
526   template<typename R, typename A1, typename A2, typename A3, typename A4,
527 	   typename A5, typename A6, typename A7>
528   status
call(connection * conn,const char * method,R * result,A1 arg1,A2 arg2,A3 arg3,A4 arg4,A5 arg5,A6 arg6,A7 arg7)529   call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
530 	A3 arg3, A4 arg4, A5 arg5, A6 arg6, A7 arg7)
531   {
532     if (!conn->send ('Q'))
533       return FAIL;
534     if (!marshall (conn, method))
535       return FAIL;
536     if (!marshall (conn, 7))
537       return FAIL;
538     if (!marshall (conn, arg1))
539       return FAIL;
540     if (!marshall (conn, arg2))
541       return FAIL;
542     if (!marshall (conn, arg3))
543       return FAIL;
544     if (!marshall (conn, arg4))
545       return FAIL;
546     if (!marshall (conn, arg5))
547       return FAIL;
548     if (!marshall (conn, arg6))
549       return FAIL;
550     if (!marshall (conn, arg7))
551       return FAIL;
552     if (!conn->wait_for_result ())
553       return FAIL;
554     if (!unmarshall (conn, result))
555       return FAIL;
556     return OK;
557   }
558 
559   template<typename R, typename A1, typename A2, typename A3, typename A4,
560 	   typename A5, typename A6, typename A7,
561 	   R (*func) (connection *, A1, A2, A3, A4, A5, A6, A7)>
562   status
callback(connection * conn)563   callback (connection *conn)
564   {
565     argument_wrapper<A1> arg1;
566     argument_wrapper<A2> arg2;
567     argument_wrapper<A3> arg3;
568     argument_wrapper<A4> arg4;
569     argument_wrapper<A5> arg5;
570     argument_wrapper<A6> arg6;
571     argument_wrapper<A7> arg7;
572     R result;
573 
574     if (!unmarshall_check (conn, 7))
575       return FAIL;
576     if (!arg1.unmarshall (conn))
577       return FAIL;
578     if (!arg2.unmarshall (conn))
579       return FAIL;
580     if (!arg3.unmarshall (conn))
581       return FAIL;
582     if (!arg4.unmarshall (conn))
583       return FAIL;
584     if (!arg5.unmarshall (conn))
585       return FAIL;
586     if (!arg6.unmarshall (conn))
587       return FAIL;
588     if (!arg7.unmarshall (conn))
589       return FAIL;
590     result = func (conn, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
591     if (!conn->send ('R'))
592       return FAIL;
593     return marshall (conn, result);
594   }
595 };
596 
597 #endif // CC1_PLUGIN_RPC_HH
598