08edf142457d94a5219ae0a71690b0be535153a3
[charm.git] / src / xlat-i / xi-Parameter.C
1 #include "xi-Entry.h"
2 #include "xi-Parameter.h"
3 #include "xi-Type.h"
4 #include "xi-Value.h"
5 #include "xi-Chare.h"
6
7 namespace xi {
8
9 /******************* C/C++ Parameter Marshalling ******************
10 For entry methods like:
11         entry void foo(int nx,double xarr[nx],complex<float> yarr[ny],long ny);
12
13 We generate code on the call-side (in the proxy entry method) to
14 create a message and copy the user's parameters into it.  Scalar
15 fields are PUP'd, arrays are just memcpy'd.
16
17 The message looks like this:
18
19 messagestart>--------- PUP'd data ----------------
20         |  PUP'd nx
21         |  PUP'd offset-to-xarr (from array start, int byte count)
22         |  PUP'd length-of-xarr (in elements)
23         |  PUP'd offset-to-yarr
24         |  PUP'd length-of-yarr (in elements)
25         |  PUP'd ny
26         +-------------------------------------------
27         |  alignment gap (to multiple of 16 bytes)
28 arraystart>------- xarr data ----------
29         | xarr[0]
30         | xarr[1]
31         | ...
32         | xarr[nx-1]
33         +------------------------------
34         |  alignment gap (for yarr-elements)
35         +--------- yarr data ----------
36         | yarr[0]
37         | yarr[1]
38         | ...
39         | yarr[ny-1]
40         +------------------------------
41
42 On the recieve side, all the scalar fields are PUP'd to fresh
43 stack copies, and the arrays are passed to the user as pointers
44 into the message data-- so there's no copy on the receive side.
45
46 The message is freed after the user entry returns.
47 */
48 Parameter::Parameter(int Nline, Type* Ntype, const char* Nname, const char* NarrLen,
49                      Value* Nvalue)
50     : type(Ntype),
51       name(Nname),
52       arrLen(NarrLen),
53       val(Nvalue),
54       line(Nline),
55       byConst(false),
56       conditional(0),
57       given_name(Nname),
58       podType(false),
59       rdma(false),
60       firstRdma(false) {
61   if (isMessage()) {
62     name = "impl_msg";
63   }
64   if (name == NULL && !isVoid()) { /*Fabricate a unique name for this marshalled param.*/
65     static int unnamedCount = 0;
66     name = new char[50];
67     sprintf((char*)name, "impl_noname_%x", unnamedCount++);
68   }
69   byReference = false;
70   declaredReference = false;
71   if ((arrLen == NULL) && (val == NULL)) { /* Consider passing type by reference: */
72     if (type->isNamed()) {                 /* Some user-defined type: pass by reference */
73       byReference = true;
74     }
75     if (type->isReference()) {
76       byReference = true;
77       declaredReference = true;
78       /* Clip off the ampersand--we'll add
79          it back ourselves in Parameter::print. */
80       type = type->deref();
81     }
82     if (type->isConst()) {
83       byConst = true;
84       type = type->deref();
85     }
86   }
87 }
88
89 ParamList::ParamList(ParamList* pl)
90     : manyPointers(false), param(pl->param), next(pl->next) {}
91
92 int ParamList::print(XStr& str, int withDefaultValues, int useConst, int fwdNum) {
93   fwdNum = param->print(str, withDefaultValues, useConst, fwdNum);
94   if (next) {
95     str << ", ";
96     fwdNum = next->print(str, withDefaultValues, useConst, fwdNum);
97   }
98   return fwdNum;
99 }
100
101 void ParamList::printTypes(XStr& str, int withDefaultValues, int useConst) {
102   XStr typeStr;
103   param->getType()->print(typeStr);
104   str << typeStr;
105   if (next) {
106     str << ", ";
107     next->printTypes(str, withDefaultValues, useConst);
108   }
109 }
110
111 int Parameter::print(XStr& str, int withDefaultValues, int useConst, int fwdNum) {
112   if (isRdma()) {
113     str << "CkNcpyBuffer ncpyBuffer_" << name;
114   } else if (arrLen != NULL) {  // Passing arrays by const pointer-reference
115     if (useConst) str << "const ";
116     str << type << " *";
117     if (name != NULL) str << name;
118   } else {
119     if (conditional) {
120       str << type << " *" << name;
121     } else if (byReference) {  // Pass named types by const C++ reference
122       if (fwdNum) {
123         str << "Fwd" << fwdNum++ << " &&";
124       } else {
125         if (useConst || byConst) str << "const ";
126         str << type << " &";
127       }
128       if (name != NULL) str << name;
129     } else {  // Pass everything else by value
130               // @TODO uncommenting this requires that PUP work on const types
131               // if (byConst) str << "const ";
132       //"void" shouldn't be typed in the param list
133       // to have CkEntryOptions as the last argument
134       if (!type->isVoid()) str << type;
135       if (name != NULL) str << " " << name;
136       if (withDefaultValues && val != NULL) {
137         str << " = ";
138         val->print(str);
139       }
140     }
141   }
142   return fwdNum;
143 }
144
145 void ParamList::printAddress(XStr& str) {
146   param->printAddress(str);
147   if (next) {
148     str << ", ";
149     next->printAddress(str);
150   }
151 }
152
153 void Parameter::printAddress(XStr& str) {
154   type->print(str);
155   str << "*";
156   if (name != NULL) str << " " << name;
157 }
158
159 void ParamList::printValue(XStr& str) {
160   param->printValue(str);
161   if (next) {
162     str << ", ";
163     next->printValue(str);
164   }
165 }
166
167 void Parameter::printValue(XStr& str) {
168   if (arrLen == NULL) str << "*";
169   if (name != NULL) str << name;
170 }
171
172 int ParamList::orEach(pred_t f) {
173   ParamList* cur = this;
174   int ret = 0;
175   do {
176     ret |= ((cur->param)->*f)();
177   } while (NULL != (cur = cur->next));
178   return ret;
179 }
180
181 void ParamList::callEach(fn_t f, XStr& str) {
182   ParamList* cur = this;
183   do {
184     ((cur->param)->*f)(str);
185   } while (NULL != (cur = cur->next));
186 }
187
188 void ParamList::callEach(rdmafn_t f, XStr& str, bool isArray) {
189   ParamList* cur = this;
190   do {
191     ((cur->param)->*f)(str, isArray);
192   } while (NULL != (cur = cur->next));
193 }
194
195 int ParamList::hasConditional() { return orEach(&Parameter::isConditional); }
196
197 /** marshalling: pack fields into flat byte buffer **/
198 void ParamList::marshall(XStr& str, XStr& entry_str) {
199   if (isVoid())
200     str << "  void *impl_msg = CkAllocSysMsg(impl_e_opts);\n";
201   else if (isMarshalled()) {
202     str << "  //Marshall: ";
203     print(str, 0);
204     str << "\n";
205     // First pass: find sizes
206     str << "  int impl_off=0;\n";
207     int hasArrays = orEach(&Parameter::isArray);
208     if (hasArrays) {
209       str << "  int impl_arrstart=0;\n";
210       callEach(&Parameter::marshallRegArraySizes, str);
211     }
212     bool hasrdma = hasRdma();
213     if (hasrdma) {
214       str << "#if CMK_ONESIDED_IMPL\n";
215       str << "  int impl_num_rdma_fields = 0; \n";
216       callEach(&Parameter::marshallRdmaParameters, str, true);
217       str << "#else\n";
218       if (!hasArrays) str << "  int impl_arrstart=0;\n";
219       callEach(&Parameter::marshallRdmaParameters, str, false);
220       str << "#endif\n";
221     }
222     str << "  { //Find the size of the PUP'd data\n";
223     str << "    PUP::sizer implP;\n";
224     callEach(&Parameter::pup, str);
225     if (hasrdma) {
226       str << "#if CMK_ONESIDED_IMPL\n";
227       str << "    implP|impl_num_rdma_fields;\n";
228       // All rdma parameters have to be pupped at the start
229       callEach(&Parameter::pupRdma, str, true);
230       str << "#else\n";
231       callEach(&Parameter::pupRdma, str, false);
232       if (!hasArrays) {
233         str << "    impl_arrstart=CK_ALIGN(implP.size(),16);\n";
234         str << "    impl_off+=impl_arrstart;\n";
235       }
236       str << "#endif\n";
237     }
238     if (hasArrays) { /*round up pup'd data length--that's the first array*/
239       str << "    impl_arrstart=CK_ALIGN(implP.size(),16);\n";
240       str << "    impl_off+=impl_arrstart;\n";
241     } else /*No arrays--no padding*/
242       str << "    impl_off+=implP.size();\n";
243     str << "  }\n";
244     // Now that we know the size, allocate the packing buffer
245     if (hasConditional())
246       str << "  MarshallMsg_" << entry_str << " *impl_msg=CkAllocateMarshallMsgT<MarshallMsg_"
247           << entry_str << ">(impl_off,impl_e_opts);\n";
248     else
249       str << "  CkMarshallMsg *impl_msg=CkAllocateMarshallMsg(impl_off,impl_e_opts);\n";
250     // Second pass: write the data
251     str << "  { //Copy over the PUP'd data\n";
252     str << "    PUP::toMem implP((void *)impl_msg->msgBuf);\n";
253     if (hasRdma()) {
254       str << "#if CMK_ONESIDED_IMPL\n";
255       str << "    implP|impl_num_rdma_fields;\n";
256       callEach(&Parameter::pupRdma, str, true);
257       str << "#else\n";
258       callEach(&Parameter::pupRdma, str, false);
259       str << "#endif\n";
260     }
261     callEach(&Parameter::pup, str);
262     callEach(&Parameter::copyPtr, str);
263     str << "  }\n";
264     if (hasArrays) {  // Marshall each array
265       str << "  char *impl_buf=impl_msg->msgBuf+impl_arrstart;\n";
266       callEach(&Parameter::marshallArrayData, str);
267     }
268     if (hasrdma) {
269       str << "#if CMK_ONESIDED_IMPL\n";
270       Chare *container = entry->getContainer();
271       if(container->isChare() || container->isForElement()) {
272         str << "  CMI_ZC_MSGTYPE((char *)UsrToEnv(impl_msg)) = CMK_ZC_P2P_SEND_MSG;\n";
273       } else { // Mark a Ncpy Bcast message to intercept it in the send code path
274         str << "  CMI_ZC_MSGTYPE((char *)UsrToEnv(impl_msg)) = CMK_ZC_BCAST_SEND_MSG;\n";
275       }
276       str << "#else\n";
277       if (!hasArrays) str << "  char *impl_buf=impl_msg->msgBuf+impl_arrstart;\n";
278       callEach(&Parameter::marshallRdmaArrayData, str);
279       str << "#endif\n";
280     }
281   }
282 }
283
284 void Parameter::check() {
285   Type* dt = type->deref();
286   checkPointer(dt);
287 }
288
289 void Parameter::checkPointer(Type* dt) {
290   if (dt->isPointer())
291     XLAT_ERROR_NOCOL(
292         "can't pass pointers across processors--\n"
293         "Indicate the array length with []'s, or pass a reference",
294         line);
295 }
296
297 void Parameter::marshallArraySizes(XStr& str, Type* dt) {
298   str << "  int impl_off_" << name << ", impl_cnt_" << name << ";\n";
299   str << "  impl_off_" << name << "=impl_off=CK_ALIGN(impl_off,sizeof(" << dt << "));\n";
300   str << "  impl_off+=(impl_cnt_" << name << "=sizeof(" << dt << ")*(" << arrLen
301       << "));\n";
302 }
303
304 void Parameter::marshallRegArraySizes(XStr& str) {
305   Type* dt = type->deref();
306   if (isArray()) marshallArraySizes(str, dt);
307 }
308
309 void Parameter::marshallRdmaParameters(XStr& str, bool genRdma) {
310   if (isRdma()) {
311     Type* dt = type->deref();  // Type, without &
312     if (genRdma) {
313       str << "  impl_num_rdma_fields++;\n";
314       str << "  ncpyBuffer_" << name << ".cnt=sizeof(" << dt << ")*(" << arrLen
315           << ");\n";
316       str << "  ncpyBuffer_" << name << ".registerMem()" << ";\n";
317     } else {
318       marshallArraySizes(str, dt);
319     }
320   }
321 }
322
323 void Parameter::pupRdma(XStr& str, bool genRdma) {
324   if (isRdma()) {
325     if (genRdma)
326       str << "    implP|ncpyBuffer_" << name << ";\n";
327     else
328       pupArray(str);
329   }
330 }
331
332 void Parameter::pupArray(XStr& str) {
333   str << "    implP|impl_off_" << name << ";\n";
334   str << "    implP|impl_cnt_" << name << ";\n";
335 }
336
337 void Parameter::pup(XStr& str) {
338   if (isArray()) {
339     pupArray(str);
340   } else if (!conditional) {
341     if (byReference) {
342       str << "    //Have to cast away const-ness to get pup routine\n";
343       str << "    implP|(typename std::remove_cv<typename std::remove_reference<" << type << ">::type>::type &)" << name << ";\n";
344     } else if (!isRdma())
345       str << "    implP|" << name << ";\n";
346   }
347 }
348
349 void Parameter::marshallRdmaArrayData(XStr& str) {
350   if (isRdma()) {
351     str << "  memcpy(impl_buf+impl_off_" << name << ","
352         << "ncpyBuffer_" << name << ".ptr"
353         << ",impl_cnt_" << name << ");\n";
354     str << "  ncpyBuffer_" << name << ".cb.send("
355         << "sizeof(CkNcpyBuffer)"
356         << ","
357         << "&ncpyBuffer_" << name
358         << ");\n";
359   }
360 }
361
362 void Parameter::marshallArrayData(XStr& str) {
363   if (isArray())
364     str << "  memcpy(impl_buf+impl_off_" << name << "," << name << ",impl_cnt_" << name
365         << ");\n";
366 }
367
368 void Parameter::copyPtr(XStr& str) {
369   if (isConditional()) {
370     str << "    impl_msg->" << name << "=" << name << ";\n";
371   }
372 }
373
374 void ParamList::beginRednWrapperUnmarshall(XStr& str, bool needsClosure) {
375   if (needsClosure) {
376     str << *entry->genClosureTypeNameProxyTemp << "*"
377         << " genClosure = new " << *entry->genClosureTypeNameProxyTemp << "()"
378         << ";\n";
379   }
380
381   if (isMarshalled()) {
382     str << "  /*Unmarshall pup'd fields: ";
383     print(str, 0);
384     str << "*/\n";
385     str << "  PUP::fromMem implP(impl_buf);\n";
386     if (next != NULL && next->next == NULL) {
387       // 2 argument case - special cases for an array and its length, in either order
388       if (isArray() && !next->isArray()) {
389         if (!needsClosure) {
390           Type* dtLen = next->param->type->deref();
391           str << "  PUP::detail::TemporaryObjectHolder<" << dtLen << "> "
392               << next->param->name << "; " << next->param->name << ".t = "
393               << "((CkReductionMsg*)impl_msg)->getLength() / sizeof("
394               << param->type->deref() << ");\n";
395           Type* dt = param->type->deref();
396           str << "  " << dt << "* " << param->name << "; " << param->name << " = (" << dt
397               << "*)impl_buf;\n";
398         } else {
399           str << "  genClosure->" << next->param->name << " = "
400               << "((CkReductionMsg*)impl_msg)->getLength() / sizeof("
401               << param->type->deref() << ");\n";
402           Type* dt = param->type->deref();
403           str << "  genClosure->" << param->name << " = (" << dt << "*)impl_buf;\n";
404         }
405       } else if (!isArray() && next->isArray()) {
406         if (!needsClosure) {
407           Type* dt = param->type->deref();
408           str << "  PUP::detail::TemporaryObjectHolder<" << dt << "> " << param->name
409               << "; " << param->name << ".t = "
410               << "((CkReductionMsg*)impl_msg)->getLength() / sizeof("
411               << next->param->type->deref() << ");\n";
412           dt = next->param->type->deref();
413           str << "  " << dt << "* " << next->param->name << "; " << next->param->name
414               << " = (" << dt << "*)impl_buf;\n";
415         } else {
416           str << "  genClosure->" << param->name << " = "
417               << "((CkReductionMsg*)impl_msg)->getLength() / sizeof("
418               << next->param->type->deref() << ");\n";
419           Type* dt = next->param->type->deref();
420           str << "  genClosure->" << next->param->name << " = (" << dt << "*)impl_buf;\n";
421         }
422       } else {
423         if (!needsClosure) {
424           if (hasRdma()) {
425             str << "#if CMK_ONESIDED_IMPL\n";
426             str << "  char *impl_buf_begin = impl_buf;\n";
427             str << "  CkUnpackRdmaPtrs(impl_buf_begin);\n";
428             str << "  int impl_num_rdma_fields; implP|impl_num_rdma_fields;\n";
429             callEach(&Parameter::beginUnmarshallRdma, str, true);
430             str << "#else\n";
431             callEach(&Parameter::beginUnmarshallRdma, str, false);
432             str << "#endif\n";
433           }
434           callEach(&Parameter::beginUnmarshall, str);
435         } else {
436           if (hasRdma()) {
437             str << "#if CMK_ONESIDED_IMPL\n";
438             str << "  char *impl_buf_begin = impl_buf;\n";
439             str << "  CkUnpackRdmaPtrs(impl_buf_begin);\n";
440             callEach(&Parameter::beginUnmarshallSDAGCallRdma, str, true);
441             str << "#else\n";
442             callEach(&Parameter::beginUnmarshallSDAGCallRdma, str, false);
443             str << "#endif\n";
444           }
445           callEach(&Parameter::beginUnmarshallSDAGCall, str);
446         }
447       }
448     } else if (next == NULL && isArray()) {
449       // 1 argument case - special case for a standalone array
450       Type* dt = param->type->deref();
451       if (!needsClosure) {
452         str << "  " << dt << "* " << param->name << "; " << param->name << " = (" << dt
453             << "*)impl_buf;\n";
454       } else {
455         str << "  genClosure->" << param->name << " = (" << dt << "*)impl_buf;\n";
456       }
457     } else {
458       str << "  /* non two-param case */\n";
459       if (!needsClosure) {
460         if (hasRdma()) {
461           str << "#if CMK_ONESIDED_IMPL\n";
462           str << "  char *impl_buf_begin = impl_buf;\n";
463           str << "  CkUnpackRdmaPtrs(impl_buf_begin);\n";
464           str << "  int impl_num_rdma_fields; implP|impl_num_rdma_fields;\n";
465           callEach(&Parameter::beginUnmarshallRdma, str, true);
466           str << "#else\n";
467           callEach(&Parameter::beginUnmarshallRdma, str, false);
468           str << "#endif\n";
469         }
470         callEach(&Parameter::beginUnmarshall, str);
471       } else
472         callEach(&Parameter::beginUnmarshallSDAGCall, str);
473       str << "  impl_buf+=CK_ALIGN(implP.size(),16);\n";
474       str << "  /*Unmarshall arrays:*/\n";
475       if (!needsClosure)
476         callEach(&Parameter::unmarshallRegArrayData, str);
477       else
478         callEach(&Parameter::unmarshallRegArrayDataSDAGCall, str);
479     }
480   }
481   if (needsClosure) {
482     str << "  genClosure->setRefnum(CkGetRefNum((CkReductionMsg*)impl_msg));\n";
483   }
484 }
485
486 /** unmarshalling: unpack fields from flat buffer **/
487 void ParamList::beginUnmarshall(XStr& str) {
488   if (isMarshalled()) {
489     str << "  /*Unmarshall pup'd fields: ";
490     print(str, 0);
491     str << "*/\n";
492     str << "  PUP::fromMem implP(impl_buf);\n";
493     if (hasRdma()) {
494       str << "#if CMK_ONESIDED_IMPL\n";
495       str << "  char *impl_buf_begin = impl_buf;\n";
496       str << "  CkUnpackRdmaPtrs(impl_buf_begin);\n";
497       str << "  int impl_num_rdma_fields; implP|impl_num_rdma_fields; \n";
498       callEach(&Parameter::beginUnmarshallRdma, str, true);
499       str << "#else\n";
500       callEach(&Parameter::beginUnmarshallRdma, str, false);
501       str << "#endif\n";
502     }
503     callEach(&Parameter::beginUnmarshall, str);
504     str << "  impl_buf+=CK_ALIGN(implP.size(),16);\n";
505     str << "  /*Unmarshall arrays:*/\n";
506     callEach(&Parameter::unmarshallRegArrayData, str);
507     if (hasRdma()) {
508       str << "#if !CMK_ONESIDED_IMPL\n";
509       callEach(&Parameter::unmarshallRdmaArrayData, str, true);
510       str << "#endif\n";
511     }
512   }
513 }
514
515 void Parameter::beginUnmarshallArray(XStr& str) {
516   str << "  int impl_off_" << name << ", impl_cnt_" << name << ";\n";
517   str << "  implP|impl_off_" << name << ";\n";
518   str << "  implP|impl_cnt_" << name << ";\n";
519 }
520
521 void Parameter::beginUnmarshallRdma(XStr& str,
522                                     bool genRdma) {  // First pass: unpack pup'd entries
523   Type* dt = type->deref();                          // Type, without &
524   if (isRdma()) {
525     if (genRdma) {
526       str << "  CkNcpyBuffer ncpyBuffer_" << name << ";\n";
527       str << "  implP|ncpyBuffer_" << name << ";\n";
528     } else
529       beginUnmarshallArray(str);
530   }
531 }
532
533 void Parameter::beginUnmarshall(XStr& str) {  // First pass: unpack pup'd entries
534   Type* dt = type->deref();                   // Type, without &
535   if (isArray())
536     beginUnmarshallArray(str);
537   else if (isConditional())
538     str << "  " << dt << " *" << name << "=impl_msg_typed->" << name << ";\n";
539   else if (!isRdma())
540     str << "  PUP::detail::TemporaryObjectHolder<" << dt << "> " << name << ";\n"
541         << "  "
542         << "implP|" << name << ";\n";
543 }
544
545 void Parameter::beginUnmarshallSDAGCallRdma(XStr& str, bool genRdma) {
546   if (isRdma()) {
547     if (genRdma) {
548       if (isFirstRdma()) {
549         str << "  implP|genClosure->num_rdma_fields;\n";
550       }
551       str << "  implP|genClosure->ncpyBuffer_" << name << ";\n";
552     } else {
553       beginUnmarshallArray(str);
554     }
555   }
556 }
557
558 void Parameter::beginUnmarshallSDAGCall(XStr& str) {
559   Type* dt = type->deref();
560   if (isArray()) {
561     beginUnmarshallArray(str);
562   } else if (isRdma()) {
563     // unmarshalled before regular parameters
564   } else {
565     str << "  implP|" << (podType ? "" : "*") << "genClosure->" << name << ";\n";
566   }
567 }
568
569 /** unmarshalling: unpack fields from flat buffer **/
570 void ParamList::beginUnmarshallSDAGCall(XStr& str, bool usesImplBuf) {
571   bool hasArray = false;
572   for (ParamList* pl = this; pl != NULL; pl = pl->next) {
573     hasArray = hasArray || pl->param->isArray();
574   }
575
576   if (isMarshalled()) {
577     str << "  PUP::fromMem implP(impl_buf);\n";
578     str << "  " << *entry->genClosureTypeNameProxyTemp << "*"
579         << " genClosure = new " << *entry->genClosureTypeNameProxyTemp << "()"
580         << ";\n";
581     if (hasRdma()) {
582       str << "#if CMK_ONESIDED_IMPL\n";
583       str << "  char *impl_buf_begin = impl_buf;\n";
584       str << "  CkUnpackRdmaPtrs(impl_buf_begin);\n";
585       callEach(&Parameter::beginUnmarshallSDAGCallRdma, str, true);
586       str << "#else\n";
587       callEach(&Parameter::beginUnmarshallSDAGCallRdma, str, false);
588       str << "#endif\n";
589     }
590     callEach(&Parameter::beginUnmarshallSDAGCall, str);
591     str << "  impl_buf+=CK_ALIGN(implP.size(),16);\n";
592     if (hasRdma()) str << "#if !CMK_ONESIDED_IMPL\n";
593     callEach(&Parameter::unmarshallRdmaArrayDataSDAGCall, str);
594     if (hasRdma()) str << "#endif\n";
595     callEach(&Parameter::unmarshallRegArrayDataSDAGCall, str);
596     if (hasArray || hasRdma()) {
597       if (!usesImplBuf) {
598         str << "  genClosure->_impl_marshall = impl_msg_typed;\n";
599         str << "  CmiReference(UsrToEnv(genClosure->_impl_marshall));\n";
600       } else {
601         if (hasRdma() && !hasArray) str << "#if !CMK_ONESIDED_IMPL\n";
602         str << "  genClosure->_impl_buf_in = impl_buf;\n";
603         str << "  genClosure->_impl_buf_size = implP.size();\n";
604         if (hasRdma() && !hasArray) str << "#endif\n";
605       }
606     }
607   }
608 }
609 void ParamList::beginUnmarshallSDAG(XStr& str) {
610   if (isMarshalled()) {
611     str << "          PUP::fromMem implP(impl_buf);\n";
612     if (hasRdma()) {
613       str << "#if CMK_ONESIDED_IMPL\n";
614       /* Before migration of the closure structure, Rdmawrapper pointers
615        * store the offset to the actual buffer from the msgBuf
616        * After migration, the Rdmawrapper pointer needs to be adjusted
617        * to point to the msgBuf + offset. As the actual buffer is within
618        * the message, the adjusting should happen after the message is
619        * unpacked. (see code in Entry::genClosure)
620        */
621       callEach(&Parameter::adjustUnmarshalledRdmaPtrsSDAG, str);
622       str << "  implP|num_rdma_fields;\n";
623       callEach(&Parameter::beginUnmarshallRdma, str, true);
624       str << "#else\n";
625       callEach(&Parameter::beginUnmarshallRdma, str, false);
626       str << "#endif\n";
627     }
628     callEach(&Parameter::beginUnmarshall, str);
629     str << "          impl_buf+=CK_ALIGN(implP.size(),16);\n";
630     // If there's no rdma support, unmarshall as a regular array
631     str << "#if !CMK_ONESIDED_IMPL\n";
632     callEach(&Parameter::unmarshallRdmaArrayDataSDAG, str);
633     str << "#endif\n";
634     callEach(&Parameter::unmarshallRegArrayDataSDAG, str);
635   }
636 }
637
638 void Parameter::unmarshallRegArrayDataSDAG(XStr& str) {
639   if (isArray()) {
640     Type* dt = type->deref();  // Type, without &
641     str << "          " << name << " = (" << dt << " *)(impl_buf+impl_off_" << name
642         << ");\n";
643   }
644 }
645
646 void Parameter::adjustUnmarshalledRdmaPtrsSDAG(XStr& str) {
647   if (isRdma()) {
648     str << "  ncpyBuffer_" << name << ".ptr = ";
649     str << "(void *)(impl_buf + (size_t)(ncpyBuffer_" << name << ".ptr));\n";
650   }
651 }
652
653 void Parameter::unmarshallRdmaArrayDataSDAG(XStr& str) {
654   if (isRdma()) {
655     Type* dt = type->deref();  // Type, without &
656     str << "          " << name << " = (" << dt << " *)(impl_buf+impl_off_" << name
657         << ");\n";
658   }
659 }
660
661 void Parameter::unmarshallRegArrayDataSDAGCall(XStr& str) {
662   if (isArray()) {
663     Type* dt = type->deref();  // Type, without &
664     str << "  genClosure->" << name << " = (" << dt << " *)(impl_buf+impl_off_" << name
665         << ");\n";
666   }
667 }
668
669 void Parameter::unmarshallRdmaArrayDataSDAGCall(XStr& str) {
670   if (isRdma()) {
671     Type* dt = type->deref();  // Type, without &
672     str << "  genClosure->" << name << " = (" << dt << " *)(impl_buf+impl_off_" << name
673         << ");\n";
674   }
675 }
676
677 void ParamList::unmarshallSDAGCall(XStr& str, int isFirst) {
678   if (isFirst && isMessage())
679     str << "(" << param->type << ")impl_msg";
680   else if (!isVoid()) {
681     str << "genClosure->";
682     str << param->getName();
683     if (next) {
684       str << ", ";
685       next->unmarshallSDAGCall(str, 0);
686     }
687   }
688 }
689
690 void Parameter::unmarshallArrayData(XStr& str) {
691   Type* dt = type->deref();  // Type, without &
692   str << "  " << dt << " *" << name << "=(" << dt << " *)(impl_buf+impl_off_" << name
693       << ");\n";
694 }
695
696 void Parameter::unmarshallRdmaArrayData(XStr& str, bool genRegArray) {
697   if (isRdma() && genRegArray) unmarshallArrayData(str);
698 }
699
700 void Parameter::unmarshallRegArrayData(
701     XStr& str) {  // Second pass: unpack pointed-to arrays
702   if (isArray()) unmarshallArrayData(str);
703 }
704
705 void ParamList::unmarshall(XStr& str, bool isInline, bool isFirst)  // Pass-by-value
706 {
707   if (isFirst && isMessage())
708     str << "(" << param->type << ")impl_msg";
709   else if (!isVoid()) {
710     if (param->isRdma()) {
711       str << "\n#if CMK_ONESIDED_IMPL\n";
712       str << "(" << (param->getType())->deref() << " *)";
713       str << "ncpyBuffer_" << param->getName() << ".ptr";
714       str << "\n#else\n";
715       str << param->getName();
716       str << "\n#endif\n";
717     } else if (param->isArray() || isInline) {
718       str << param->getName();
719     } else {
720       str << "std::move(" << param->getName() << ".t)";
721     }
722
723     if (next) {
724       str << ", ";
725       next->unmarshall(str, isInline, false);
726     }
727   }
728 }
729
730 // Do forwarding for rvalue references, used for inline and local entry methods
731 void ParamList::unmarshallForward(XStr& str,
732                                   bool isInline,
733                                   bool isFirst,
734                                   int fwdNum)
735 {
736   if (!isInline)
737     unmarshall(str, isInline, isFirst);
738   if (isReference()) {
739     str << "std::forward<Fwd" << fwdNum++ << ">(" << param->getName() << ")";
740     if (next) {
741       str << ", ";
742       next->unmarshallForward(str, isInline, false, fwdNum);
743     }
744   } else {
745     unmarshall(str, isInline, isFirst);
746   }
747 }
748
749 void ParamList::unmarshallAddress(XStr& str,
750                                   int isFirst)  // Pass-by-reference, for Fortran
751 {
752   if (isFirst && isMessage())
753     str << "(" << param->type << ")impl_msg";
754   else if (!isVoid()) {
755     //@TODO : Case for RDMA
756     if (param->isArray())
757       str << param->getName();  // Arrays are already pointers
758     else
759       str << "& " << param->getName() << ".t";  // Take address of simple types and structs
760     if (next) {
761       str << ", ";
762       next->unmarshallAddress(str, 0);
763     }
764   }
765 }
766
767 void ParamList::pupAllValues(XStr& str) {
768   if (isMarshalled()) callEach(&Parameter::pupAllValues, str);
769 }
770
771 void Parameter::pupAllValues(XStr& str) {
772   str << "  if (implDestP.hasComments()) implDestP.comment(\"" << name << "\");\n";
773   if (isArray()) {
774     str << "  implDestP.synchronize(PUP::sync_begin_array);\n"
775            "  for (int impl_i=0;impl_i*(sizeof(*"
776         << name << "))<impl_cnt_" << name
777         << ";impl_i++) {\n"
778            "    implDestP.synchronize(PUP::sync_item);\n"
779            "    implDestP|"
780         << name
781         << "[impl_i];\n"
782            "  }\n"
783            "  implDestP.synchronize(PUP::sync_end_array);\n";
784   } else if (isRdma()) {
785     str << "#if CMK_ONESIDED_IMPL\n";
786     str << "  implDestP|ncpyBuffer_" << name << ";\n";
787     str << "#else\n";
788     str << "  implDestP.synchronize(PUP::sync_begin_array);\n"
789            "  { for (int impl_i=0;impl_i*(sizeof(*"
790         << name << "))<impl_cnt_" << name
791         << ";impl_i++) { \n"
792            "      implDestP.synchronize(PUP::sync_item);\n"
793            "      implDestP|"
794         << name
795         << "[impl_i];\n"
796            "  } } \n"
797            "  implDestP.synchronize(PUP::sync_end_array);\n";
798     str << "#endif\n";
799   } else /* not an array */ {
800     if (isConditional())
801       str << "  pup_pointer(&implDestP, (void**)&" << name << ");\n";
802     else
803       str << "  implDestP|" << name << ";\n";
804   }
805 }
806
807 void ParamList::endUnmarshall(XStr&) {
808   /* Marshalled entry points now have the "SNOKEEP" attribute...
809   if (isMarshalled()) {
810           str<<"  delete (CkMarshallMsg *)impl_msg;\n";
811   }
812   */
813 }
814
815 void ParamList::printMsg(XStr& str) {
816   ParamList* pl;
817   param->printMsg(str);
818   pl = next;
819   while (pl != NULL) {
820     str << ", ";
821     pl->param->printMsg(str);
822     pl = pl->next;
823   }
824 }
825
826 void Parameter::printMsg(XStr& str) {
827   type->print(str);
828   if (given_name != 0) str << given_name;
829 }
830
831 int Parameter::isMessage(void) const { return type->isMessage(); }
832 int Parameter::isVoid(void) const { return type->isVoid(); }
833 int Parameter::isCkArgMsgPtr(void) const { return type->isCkArgMsgPtr(); }
834 int Parameter::isCkMigMsgPtr(void) const { return type->isCkMigMsgPtr(); }
835 int Parameter::isArray(void) const { return (arrLen != NULL && !isRdma()); }
836 int Parameter::isConditional(void) const { return conditional; }
837 int Parameter::isRdma(void) const { return rdma; }
838 int Parameter::isFirstRdma(void) const { return firstRdma; }
839
840 int Parameter::operator==(const Parameter& parm) const { return *type == *parm.type; }
841
842 void Parameter::setConditional(int c) {
843   conditional = c;
844   if (c) byReference = false;
845 }
846
847 void Parameter::setRdma(bool r) { rdma = r; }
848
849 void Parameter::setFirstRdma(bool fr) { firstRdma = fr; }
850
851 void Parameter::setAccelBufferType(int abt) {
852   accelBufferType = ((abt < ACCEL_BUFFER_TYPE_MIN || abt > ACCEL_BUFFER_TYPE_MAX)
853                          ? (ACCEL_BUFFER_TYPE_UNKNOWN)
854                          : (abt));
855 }
856
857 int Parameter::getAccelBufferType() { return accelBufferType; }
858 void Parameter::setAccelInstName(XStr* ain) { accelInstName = ain; }
859 XStr* Parameter::getAccelInstName(void) { return accelInstName; }
860
861 ParamList::ParamList(Parameter* Nparam, ParamList* Nnext) : param(Nparam), next(Nnext) {
862   manyPointers = false;
863   if (next != NULL && (param->isMessage() || next->isMessage())) {
864     manyPointers = true;
865   }
866 }
867
868 int ParamList::isNamed(void) const { return param->type->isNamed(); }
869 int ParamList::isBuiltin(void) const { return param->type->isBuiltin(); }
870 int ParamList::isMessage(void) const { return (next == NULL) && param->isMessage(); }
871 int ParamList::hasRdma(void) { return orEach(&Parameter::isRdma); }
872 int ParamList::isRdma(void) { return param->isRdma(); }
873 int ParamList::isFirstRdma(void) { return param->isFirstRdma(); }
874 const char* ParamList::getArrayLen(void) const { return param->getArrayLen(); }
875 int ParamList::isArray(void) const { return param->isArray(); }
876 int ParamList::isReference(void) const {
877   return param->type->isReference() || param->byReference;
878 }
879 int ParamList::declaredReference(void) const {
880   return param->type->isReference() || param->declaredReference;
881 }
882 bool ParamList::isConst(void) const { return param->type->isConst() || param->byConst; }
883 int ParamList::isVoid(void) const { return (next == NULL) && param->isVoid(); }
884 int ParamList::isPointer(void) const { return param->type->isPointer(); }
885 const char* ParamList::getGivenName(void) const { return param->getGivenName(); }
886 void ParamList::setGivenName(const char* s) { param->setGivenName(s); }
887 const char* ParamList::getName(void) const { return param->getName(); }
888 int ParamList::isMarshalled(void) const { return !isVoid() && !isMessage(); }
889 int ParamList::isCkArgMsgPtr(void) const {
890   return (next == NULL) && param->isCkArgMsgPtr();
891 }
892 int ParamList::isCkMigMsgPtr(void) const {
893   return (next == NULL) && param->isCkMigMsgPtr();
894 }
895 int ParamList::getNumStars(void) const { return param->type->getNumStars(); }
896 const char* ParamList::getBaseName(void) { return param->type->getBaseName(); }
897 void ParamList::genMsgProxyName(XStr& str) { param->type->genMsgProxyName(str); }
898
899 void ParamList::checkParamList() {
900   if (manyPointers) {
901     XLAT_ERROR_NOCOL(
902         "multiple pointers passed to a non-local entry method\n"
903         "You may pass only a single pointer to it, which should point to a message.",
904         param->line);
905   }
906 }
907
908 int ParamList::operator==(ParamList& plist) {
909   if (!(*param == *(plist.param))) return 0;
910   if (!next && !plist.next) return 1;
911   if (!next || !plist.next) return 0;
912   return *next == *plist.next;
913 }
914
915 }  // namespace xi