0f77776d117b96ec9d1bfe8ede92bbffd42be725
[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       if(entry->getContainer()->isForElement()) {
271         str << "  CMI_ZC_MSGTYPE((char *)UsrToEnv(impl_msg)) = CMK_ZC_P2P_SEND_MSG;\n";
272       } else { // Mark a Ncpy Bcast message to intercept it in the send code path
273         str << "  CMI_ZC_MSGTYPE((char *)UsrToEnv(impl_msg)) = CMK_ZC_BCAST_SEND_MSG;\n";
274       }
275       str << "#else\n";
276       if (!hasArrays) str << "  char *impl_buf=impl_msg->msgBuf+impl_arrstart;\n";
277       callEach(&Parameter::marshallRdmaArrayData, str);
278       str << "#endif\n";
279     }
280   }
281 }
282
283 void Parameter::check() {
284   Type* dt = type->deref();
285   checkPointer(dt);
286 }
287
288 void Parameter::checkPointer(Type* dt) {
289   if (dt->isPointer())
290     XLAT_ERROR_NOCOL(
291         "can't pass pointers across processors--\n"
292         "Indicate the array length with []'s, or pass a reference",
293         line);
294 }
295
296 void Parameter::marshallArraySizes(XStr& str, Type* dt) {
297   str << "  int impl_off_" << name << ", impl_cnt_" << name << ";\n";
298   str << "  impl_off_" << name << "=impl_off=CK_ALIGN(impl_off,sizeof(" << dt << "));\n";
299   str << "  impl_off+=(impl_cnt_" << name << "=sizeof(" << dt << ")*(" << arrLen
300       << "));\n";
301 }
302
303 void Parameter::marshallRegArraySizes(XStr& str) {
304   Type* dt = type->deref();
305   if (isArray()) marshallArraySizes(str, dt);
306 }
307
308 void Parameter::marshallRdmaParameters(XStr& str, bool genRdma) {
309   if (isRdma()) {
310     Type* dt = type->deref();  // Type, without &
311     if (genRdma) {
312       str << "  impl_num_rdma_fields++;\n";
313       str << "  ncpyBuffer_" << name << ".cnt=sizeof(" << dt << ")*(" << arrLen
314           << ");\n";
315       str << "  ncpyBuffer_" << name << ".registerMem()" << ";\n";
316     } else {
317       marshallArraySizes(str, dt);
318     }
319   }
320 }
321
322 void Parameter::pupRdma(XStr& str, bool genRdma) {
323   if (isRdma()) {
324     if (genRdma)
325       str << "    implP|ncpyBuffer_" << name << ";\n";
326     else
327       pupArray(str);
328   }
329 }
330
331 void Parameter::pupArray(XStr& str) {
332   str << "    implP|impl_off_" << name << ";\n";
333   str << "    implP|impl_cnt_" << name << ";\n";
334 }
335
336 void Parameter::pup(XStr& str) {
337   if (isArray()) {
338     pupArray(str);
339   } else if (!conditional) {
340     if (byReference) {
341       str << "    //Have to cast away const-ness to get pup routine\n";
342       str << "    implP|(typename std::remove_cv<typename std::remove_reference<" << type << ">::type>::type &)" << name << ";\n";
343     } else if (!isRdma())
344       str << "    implP|" << name << ";\n";
345   }
346 }
347
348 void Parameter::marshallRdmaArrayData(XStr& str) {
349   if (isRdma()) {
350     str << "  memcpy(impl_buf+impl_off_" << name << ","
351         << "ncpyBuffer_" << name << ".ptr"
352         << ",impl_cnt_" << name << ");\n";
353     str << "  ncpyBuffer_" << name << ".cb.send("
354         << "sizeof(CkNcpyBuffer)"
355         << ","
356         << "&ncpyBuffer_" << name
357         << ");\n";
358   }
359 }
360
361 void Parameter::marshallArrayData(XStr& str) {
362   if (isArray())
363     str << "  memcpy(impl_buf+impl_off_" << name << "," << name << ",impl_cnt_" << name
364         << ");\n";
365 }
366
367 void Parameter::copyPtr(XStr& str) {
368   if (isConditional()) {
369     str << "    impl_msg->" << name << "=" << name << ";\n";
370   }
371 }
372
373 void ParamList::beginRednWrapperUnmarshall(XStr& str, bool needsClosure) {
374   if (needsClosure) {
375     str << *entry->genClosureTypeNameProxyTemp << "*"
376         << " genClosure = new " << *entry->genClosureTypeNameProxyTemp << "()"
377         << ";\n";
378   }
379
380   if (isMarshalled()) {
381     str << "  /*Unmarshall pup'd fields: ";
382     print(str, 0);
383     str << "*/\n";
384     str << "  PUP::fromMem implP(impl_buf);\n";
385     if (next != NULL && next->next == NULL) {
386       // 2 argument case - special cases for an array and its length, in either order
387       if (isArray() && !next->isArray()) {
388         if (!needsClosure) {
389           Type* dtLen = next->param->type->deref();
390           str << "  PUP::detail::TemporaryObjectHolder<" << dtLen << "> "
391               << next->param->name << "; " << next->param->name << ".t = "
392               << "((CkReductionMsg*)impl_msg)->getLength() / sizeof("
393               << param->type->deref() << ");\n";
394           Type* dt = param->type->deref();
395           str << "  " << dt << "* " << param->name << "; " << param->name << " = (" << dt
396               << "*)impl_buf;\n";
397         } else {
398           str << "  genClosure->" << next->param->name << " = "
399               << "((CkReductionMsg*)impl_msg)->getLength() / sizeof("
400               << param->type->deref() << ");\n";
401           Type* dt = param->type->deref();
402           str << "  genClosure->" << param->name << " = (" << dt << "*)impl_buf;\n";
403         }
404       } else if (!isArray() && next->isArray()) {
405         if (!needsClosure) {
406           Type* dt = param->type->deref();
407           str << "  PUP::detail::TemporaryObjectHolder<" << dt << "> " << param->name
408               << "; " << param->name << ".t = "
409               << "((CkReductionMsg*)impl_msg)->getLength() / sizeof("
410               << next->param->type->deref() << ");\n";
411           dt = next->param->type->deref();
412           str << "  " << dt << "* " << next->param->name << "; " << next->param->name
413               << " = (" << dt << "*)impl_buf;\n";
414         } else {
415           str << "  genClosure->" << param->name << " = "
416               << "((CkReductionMsg*)impl_msg)->getLength() / sizeof("
417               << next->param->type->deref() << ");\n";
418           Type* dt = next->param->type->deref();
419           str << "  genClosure->" << next->param->name << " = (" << dt << "*)impl_buf;\n";
420         }
421       } else {
422         if (!needsClosure) {
423           if (hasRdma()) {
424             str << "#if CMK_ONESIDED_IMPL\n";
425             str << "  char *impl_buf_begin = impl_buf;\n";
426             str << "  CkUnpackRdmaPtrs(impl_buf_begin);\n";
427             str << "  int impl_num_rdma_fields; implP|impl_num_rdma_fields;\n";
428             callEach(&Parameter::beginUnmarshallRdma, str, true);
429             str << "#else\n";
430             callEach(&Parameter::beginUnmarshallRdma, str, false);
431             str << "#endif\n";
432           }
433           callEach(&Parameter::beginUnmarshall, str);
434         } else {
435           if (hasRdma()) {
436             str << "#if CMK_ONESIDED_IMPL\n";
437             str << "  char *impl_buf_begin = impl_buf;\n";
438             str << "  CkUnpackRdmaPtrs(impl_buf_begin);\n";
439             callEach(&Parameter::beginUnmarshallSDAGCallRdma, str, true);
440             str << "#else\n";
441             callEach(&Parameter::beginUnmarshallSDAGCallRdma, str, false);
442             str << "#endif\n";
443           }
444           callEach(&Parameter::beginUnmarshallSDAGCall, str);
445         }
446       }
447     } else if (next == NULL && isArray()) {
448       // 1 argument case - special case for a standalone array
449       Type* dt = param->type->deref();
450       if (!needsClosure) {
451         str << "  " << dt << "* " << param->name << "; " << param->name << " = (" << dt
452             << "*)impl_buf;\n";
453       } else {
454         str << "  genClosure->" << param->name << " = (" << dt << "*)impl_buf;\n";
455       }
456     } else {
457       str << "  /* non two-param case */\n";
458       if (!needsClosure) {
459         if (hasRdma()) {
460           str << "#if CMK_ONESIDED_IMPL\n";
461           str << "  char *impl_buf_begin = impl_buf;\n";
462           str << "  CkUnpackRdmaPtrs(impl_buf_begin);\n";
463           str << "  int impl_num_rdma_fields; implP|impl_num_rdma_fields;\n";
464           callEach(&Parameter::beginUnmarshallRdma, str, true);
465           str << "#else\n";
466           callEach(&Parameter::beginUnmarshallRdma, str, false);
467           str << "#endif\n";
468         }
469         callEach(&Parameter::beginUnmarshall, str);
470       } else
471         callEach(&Parameter::beginUnmarshallSDAGCall, str);
472       str << "  impl_buf+=CK_ALIGN(implP.size(),16);\n";
473       str << "  /*Unmarshall arrays:*/\n";
474       if (!needsClosure)
475         callEach(&Parameter::unmarshallRegArrayData, str);
476       else
477         callEach(&Parameter::unmarshallRegArrayDataSDAGCall, str);
478     }
479   }
480   if (needsClosure) {
481     str << "  genClosure->setRefnum(CkGetRefNum((CkReductionMsg*)impl_msg));\n";
482   }
483 }
484
485 /** unmarshalling: unpack fields from flat buffer **/
486 void ParamList::beginUnmarshall(XStr& str) {
487   if (isMarshalled()) {
488     str << "  /*Unmarshall pup'd fields: ";
489     print(str, 0);
490     str << "*/\n";
491     str << "  PUP::fromMem implP(impl_buf);\n";
492     if (hasRdma()) {
493       str << "#if CMK_ONESIDED_IMPL\n";
494       str << "  char *impl_buf_begin = impl_buf;\n";
495       str << "  CkUnpackRdmaPtrs(impl_buf_begin);\n";
496       str << "  int impl_num_rdma_fields; implP|impl_num_rdma_fields; \n";
497       callEach(&Parameter::beginUnmarshallRdma, str, true);
498       str << "#else\n";
499       callEach(&Parameter::beginUnmarshallRdma, str, false);
500       str << "#endif\n";
501     }
502     callEach(&Parameter::beginUnmarshall, str);
503     str << "  impl_buf+=CK_ALIGN(implP.size(),16);\n";
504     str << "  /*Unmarshall arrays:*/\n";
505     callEach(&Parameter::unmarshallRegArrayData, str);
506     if (hasRdma()) {
507       str << "#if !CMK_ONESIDED_IMPL\n";
508       callEach(&Parameter::unmarshallRdmaArrayData, str, true);
509       str << "#endif\n";
510     }
511   }
512 }
513
514 void Parameter::beginUnmarshallArray(XStr& str) {
515   str << "  int impl_off_" << name << ", impl_cnt_" << name << ";\n";
516   str << "  implP|impl_off_" << name << ";\n";
517   str << "  implP|impl_cnt_" << name << ";\n";
518 }
519
520 void Parameter::beginUnmarshallRdma(XStr& str,
521                                     bool genRdma) {  // First pass: unpack pup'd entries
522   Type* dt = type->deref();                          // Type, without &
523   if (isRdma()) {
524     if (genRdma) {
525       str << "  CkNcpyBuffer ncpyBuffer_" << name << ";\n";
526       str << "  implP|ncpyBuffer_" << name << ";\n";
527     } else
528       beginUnmarshallArray(str);
529   }
530 }
531
532 void Parameter::beginUnmarshall(XStr& str) {  // First pass: unpack pup'd entries
533   Type* dt = type->deref();                   // Type, without &
534   if (isArray())
535     beginUnmarshallArray(str);
536   else if (isConditional())
537     str << "  " << dt << " *" << name << "=impl_msg_typed->" << name << ";\n";
538   else if (!isRdma())
539     str << "  PUP::detail::TemporaryObjectHolder<" << dt << "> " << name << ";\n"
540         << "  "
541         << "implP|" << name << ";\n";
542 }
543
544 void Parameter::beginUnmarshallSDAGCallRdma(XStr& str, bool genRdma) {
545   if (isRdma()) {
546     if (genRdma) {
547       if (isFirstRdma()) {
548         str << "  implP|genClosure->num_rdma_fields;\n";
549       }
550       str << "  implP|genClosure->ncpyBuffer_" << name << ";\n";
551     } else {
552       beginUnmarshallArray(str);
553     }
554   }
555 }
556
557 void Parameter::beginUnmarshallSDAGCall(XStr& str) {
558   Type* dt = type->deref();
559   if (isArray()) {
560     beginUnmarshallArray(str);
561   } else if (isRdma()) {
562     // unmarshalled before regular parameters
563   } else {
564     str << "  implP|" << (podType ? "" : "*") << "genClosure->" << name << ";\n";
565   }
566 }
567
568 /** unmarshalling: unpack fields from flat buffer **/
569 void ParamList::beginUnmarshallSDAGCall(XStr& str, bool usesImplBuf) {
570   bool hasArray = false;
571   for (ParamList* pl = this; pl != NULL; pl = pl->next) {
572     hasArray = hasArray || pl->param->isArray();
573   }
574
575   if (isMarshalled()) {
576     str << "  PUP::fromMem implP(impl_buf);\n";
577     str << "  " << *entry->genClosureTypeNameProxyTemp << "*"
578         << " genClosure = new " << *entry->genClosureTypeNameProxyTemp << "()"
579         << ";\n";
580     if (hasRdma()) {
581       str << "#if CMK_ONESIDED_IMPL\n";
582       str << "  char *impl_buf_begin = impl_buf;\n";
583       str << "  CkUnpackRdmaPtrs(impl_buf_begin);\n";
584       callEach(&Parameter::beginUnmarshallSDAGCallRdma, str, true);
585       str << "#else\n";
586       callEach(&Parameter::beginUnmarshallSDAGCallRdma, str, false);
587       str << "#endif\n";
588     }
589     callEach(&Parameter::beginUnmarshallSDAGCall, str);
590     str << "  impl_buf+=CK_ALIGN(implP.size(),16);\n";
591     if (hasRdma()) str << "#if !CMK_ONESIDED_IMPL\n";
592     callEach(&Parameter::unmarshallRdmaArrayDataSDAGCall, str);
593     if (hasRdma()) str << "#endif\n";
594     callEach(&Parameter::unmarshallRegArrayDataSDAGCall, str);
595     if (hasArray || hasRdma()) {
596       if (!usesImplBuf) {
597         str << "  genClosure->_impl_marshall = impl_msg_typed;\n";
598         str << "  CmiReference(UsrToEnv(genClosure->_impl_marshall));\n";
599       } else {
600         if (hasRdma() && !hasArray) str << "#if !CMK_ONESIDED_IMPL\n";
601         str << "  genClosure->_impl_buf_in = impl_buf;\n";
602         str << "  genClosure->_impl_buf_size = implP.size();\n";
603         if (hasRdma() && !hasArray) str << "#endif\n";
604       }
605     }
606   }
607 }
608 void ParamList::beginUnmarshallSDAG(XStr& str) {
609   if (isMarshalled()) {
610     str << "          PUP::fromMem implP(impl_buf);\n";
611     if (hasRdma()) {
612       str << "#if CMK_ONESIDED_IMPL\n";
613       /* Before migration of the closure structure, Rdmawrapper pointers
614        * store the offset to the actual buffer from the msgBuf
615        * After migration, the Rdmawrapper pointer needs to be adjusted
616        * to point to the msgBuf + offset. As the actual buffer is within
617        * the message, the adjusting should happen after the message is
618        * unpacked. (see code in Entry::genClosure)
619        */
620       callEach(&Parameter::adjustUnmarshalledRdmaPtrsSDAG, str);
621       str << "  implP|num_rdma_fields;\n";
622       callEach(&Parameter::beginUnmarshallRdma, str, true);
623       str << "#else\n";
624       callEach(&Parameter::beginUnmarshallRdma, str, false);
625       str << "#endif\n";
626     }
627     callEach(&Parameter::beginUnmarshall, str);
628     str << "          impl_buf+=CK_ALIGN(implP.size(),16);\n";
629     // If there's no rdma support, unmarshall as a regular array
630     str << "#if !CMK_ONESIDED_IMPL\n";
631     callEach(&Parameter::unmarshallRdmaArrayDataSDAG, str);
632     str << "#endif\n";
633     callEach(&Parameter::unmarshallRegArrayDataSDAG, str);
634   }
635 }
636
637 void Parameter::unmarshallRegArrayDataSDAG(XStr& str) {
638   if (isArray()) {
639     Type* dt = type->deref();  // Type, without &
640     str << "          " << name << " = (" << dt << " *)(impl_buf+impl_off_" << name
641         << ");\n";
642   }
643 }
644
645 void Parameter::adjustUnmarshalledRdmaPtrsSDAG(XStr& str) {
646   if (isRdma()) {
647     str << "  ncpyBuffer_" << name << ".ptr = ";
648     str << "(void *)(impl_buf + (size_t)(ncpyBuffer_" << name << ".ptr));\n";
649   }
650 }
651
652 void Parameter::unmarshallRdmaArrayDataSDAG(XStr& str) {
653   if (isRdma()) {
654     Type* dt = type->deref();  // Type, without &
655     str << "          " << name << " = (" << dt << " *)(impl_buf+impl_off_" << name
656         << ");\n";
657   }
658 }
659
660 void Parameter::unmarshallRegArrayDataSDAGCall(XStr& str) {
661   if (isArray()) {
662     Type* dt = type->deref();  // Type, without &
663     str << "  genClosure->" << name << " = (" << dt << " *)(impl_buf+impl_off_" << name
664         << ");\n";
665   }
666 }
667
668 void Parameter::unmarshallRdmaArrayDataSDAGCall(XStr& str) {
669   if (isRdma()) {
670     Type* dt = type->deref();  // Type, without &
671     str << "  genClosure->" << name << " = (" << dt << " *)(impl_buf+impl_off_" << name
672         << ");\n";
673   }
674 }
675
676 void ParamList::unmarshallSDAGCall(XStr& str, int isFirst) {
677   if (isFirst && isMessage())
678     str << "(" << param->type << ")impl_msg";
679   else if (!isVoid()) {
680     str << "genClosure->";
681     str << param->getName();
682     if (next) {
683       str << ", ";
684       next->unmarshallSDAGCall(str, 0);
685     }
686   }
687 }
688
689 void Parameter::unmarshallArrayData(XStr& str) {
690   Type* dt = type->deref();  // Type, without &
691   str << "  " << dt << " *" << name << "=(" << dt << " *)(impl_buf+impl_off_" << name
692       << ");\n";
693 }
694
695 void Parameter::unmarshallRdmaArrayData(XStr& str, bool genRegArray) {
696   if (isRdma() && genRegArray) unmarshallArrayData(str);
697 }
698
699 void Parameter::unmarshallRegArrayData(
700     XStr& str) {  // Second pass: unpack pointed-to arrays
701   if (isArray()) unmarshallArrayData(str);
702 }
703
704 void ParamList::unmarshall(XStr& str, bool isInline, bool isFirst)  // Pass-by-value
705 {
706   if (isFirst && isMessage())
707     str << "(" << param->type << ")impl_msg";
708   else if (!isVoid()) {
709     if (param->isRdma()) {
710       str << "\n#if CMK_ONESIDED_IMPL\n";
711       str << "(" << (param->getType())->deref() << " *)";
712       str << "ncpyBuffer_" << param->getName() << ".ptr";
713       str << "\n#else\n";
714       str << param->getName();
715       str << "\n#endif\n";
716     } else if (param->isArray() || isInline) {
717       str << param->getName();
718     } else {
719       str << "std::move(" << param->getName() << ".t)";
720     }
721
722     if (next) {
723       str << ", ";
724       next->unmarshall(str, isInline, false);
725     }
726   }
727 }
728
729 // Do forwarding for rvalue references, used for inline and local entry methods
730 void ParamList::unmarshallForward(XStr& str,
731                                   bool isInline,
732                                   bool isFirst,
733                                   int fwdNum)
734 {
735   if (!isInline)
736     unmarshall(str, isInline, isFirst);
737   if (isReference()) {
738     str << "std::forward<Fwd" << fwdNum++ << ">(" << param->getName() << ")";
739     if (next) {
740       str << ", ";
741       next->unmarshallForward(str, isInline, false, fwdNum);
742     }
743   } else {
744     unmarshall(str, isInline, isFirst);
745   }
746 }
747
748 void ParamList::unmarshallAddress(XStr& str,
749                                   int isFirst)  // Pass-by-reference, for Fortran
750 {
751   if (isFirst && isMessage())
752     str << "(" << param->type << ")impl_msg";
753   else if (!isVoid()) {
754     //@TODO : Case for RDMA
755     if (param->isArray())
756       str << param->getName();  // Arrays are already pointers
757     else
758       str << "& " << param->getName() << ".t";  // Take address of simple types and structs
759     if (next) {
760       str << ", ";
761       next->unmarshallAddress(str, 0);
762     }
763   }
764 }
765
766 void ParamList::pupAllValues(XStr& str) {
767   if (isMarshalled()) callEach(&Parameter::pupAllValues, str);
768 }
769
770 void Parameter::pupAllValues(XStr& str) {
771   str << "  if (implDestP.hasComments()) implDestP.comment(\"" << name << "\");\n";
772   if (isArray()) {
773     str << "  implDestP.synchronize(PUP::sync_begin_array);\n"
774            "  for (int impl_i=0;impl_i*(sizeof(*"
775         << name << "))<impl_cnt_" << name
776         << ";impl_i++) {\n"
777            "    implDestP.synchronize(PUP::sync_item);\n"
778            "    implDestP|"
779         << name
780         << "[impl_i];\n"
781            "  }\n"
782            "  implDestP.synchronize(PUP::sync_end_array);\n";
783   } else if (isRdma()) {
784     str << "#if CMK_ONESIDED_IMPL\n";
785     str << "  implDestP|ncpyBuffer_" << name << ";\n";
786     str << "#else\n";
787     str << "  implDestP.synchronize(PUP::sync_begin_array);\n"
788            "  { for (int impl_i=0;impl_i*(sizeof(*"
789         << name << "))<impl_cnt_" << name
790         << ";impl_i++) { \n"
791            "      implDestP.synchronize(PUP::sync_item);\n"
792            "      implDestP|"
793         << name
794         << "[impl_i];\n"
795            "  } } \n"
796            "  implDestP.synchronize(PUP::sync_end_array);\n";
797     str << "#endif\n";
798   } else /* not an array */ {
799     if (isConditional())
800       str << "  pup_pointer(&implDestP, (void**)&" << name << ");\n";
801     else
802       str << "  implDestP|" << name << ";\n";
803   }
804 }
805
806 void ParamList::endUnmarshall(XStr&) {
807   /* Marshalled entry points now have the "SNOKEEP" attribute...
808   if (isMarshalled()) {
809           str<<"  delete (CkMarshallMsg *)impl_msg;\n";
810   }
811   */
812 }
813
814 void ParamList::printMsg(XStr& str) {
815   ParamList* pl;
816   param->printMsg(str);
817   pl = next;
818   while (pl != NULL) {
819     str << ", ";
820     pl->param->printMsg(str);
821     pl = pl->next;
822   }
823 }
824
825 void Parameter::printMsg(XStr& str) {
826   type->print(str);
827   if (given_name != 0) str << given_name;
828 }
829
830 int Parameter::isMessage(void) const { return type->isMessage(); }
831 int Parameter::isVoid(void) const { return type->isVoid(); }
832 int Parameter::isCkArgMsgPtr(void) const { return type->isCkArgMsgPtr(); }
833 int Parameter::isCkMigMsgPtr(void) const { return type->isCkMigMsgPtr(); }
834 int Parameter::isArray(void) const { return (arrLen != NULL && !isRdma()); }
835 int Parameter::isConditional(void) const { return conditional; }
836 int Parameter::isRdma(void) const { return rdma; }
837 int Parameter::isFirstRdma(void) const { return firstRdma; }
838
839 int Parameter::operator==(const Parameter& parm) const { return *type == *parm.type; }
840
841 void Parameter::setConditional(int c) {
842   conditional = c;
843   if (c) byReference = false;
844 }
845
846 void Parameter::setRdma(bool r) { rdma = r; }
847
848 void Parameter::setFirstRdma(bool fr) { firstRdma = fr; }
849
850 void Parameter::setAccelBufferType(int abt) {
851   accelBufferType = ((abt < ACCEL_BUFFER_TYPE_MIN || abt > ACCEL_BUFFER_TYPE_MAX)
852                          ? (ACCEL_BUFFER_TYPE_UNKNOWN)
853                          : (abt));
854 }
855
856 int Parameter::getAccelBufferType() { return accelBufferType; }
857 void Parameter::setAccelInstName(XStr* ain) { accelInstName = ain; }
858 XStr* Parameter::getAccelInstName(void) { return accelInstName; }
859
860 ParamList::ParamList(Parameter* Nparam, ParamList* Nnext) : param(Nparam), next(Nnext) {
861   manyPointers = false;
862   if (next != NULL && (param->isMessage() || next->isMessage())) {
863     manyPointers = true;
864   }
865 }
866
867 int ParamList::isNamed(void) const { return param->type->isNamed(); }
868 int ParamList::isBuiltin(void) const { return param->type->isBuiltin(); }
869 int ParamList::isMessage(void) const { return (next == NULL) && param->isMessage(); }
870 int ParamList::hasRdma(void) { return orEach(&Parameter::isRdma); }
871 int ParamList::isRdma(void) { return param->isRdma(); }
872 int ParamList::isFirstRdma(void) { return param->isFirstRdma(); }
873 const char* ParamList::getArrayLen(void) const { return param->getArrayLen(); }
874 int ParamList::isArray(void) const { return param->isArray(); }
875 int ParamList::isReference(void) const {
876   return param->type->isReference() || param->byReference;
877 }
878 int ParamList::declaredReference(void) const {
879   return param->type->isReference() || param->declaredReference;
880 }
881 bool ParamList::isConst(void) const { return param->type->isConst() || param->byConst; }
882 int ParamList::isVoid(void) const { return (next == NULL) && param->isVoid(); }
883 int ParamList::isPointer(void) const { return param->type->isPointer(); }
884 const char* ParamList::getGivenName(void) const { return param->getGivenName(); }
885 void ParamList::setGivenName(const char* s) { param->setGivenName(s); }
886 const char* ParamList::getName(void) const { return param->getName(); }
887 int ParamList::isMarshalled(void) const { return !isVoid() && !isMessage(); }
888 int ParamList::isCkArgMsgPtr(void) const {
889   return (next == NULL) && param->isCkArgMsgPtr();
890 }
891 int ParamList::isCkMigMsgPtr(void) const {
892   return (next == NULL) && param->isCkMigMsgPtr();
893 }
894 int ParamList::getNumStars(void) const { return param->type->getNumStars(); }
895 const char* ParamList::getBaseName(void) { return param->type->getBaseName(); }
896 void ParamList::genMsgProxyName(XStr& str) { param->type->genMsgProxyName(str); }
897
898 void ParamList::checkParamList() {
899   if (manyPointers) {
900     XLAT_ERROR_NOCOL(
901         "multiple pointers passed to a non-local entry method\n"
902         "You may pass only a single pointer to it, which should point to a message.",
903         param->line);
904   }
905 }
906
907 int ParamList::operator==(ParamList& plist) {
908   if (!(*param == *(plist.param))) return 0;
909   if (!next && !plist.next) return 1;
910   if (!next || !plist.next) return 0;
911   return *next == *plist.next;
912 }
913
914 }  // namespace xi