hqlstack.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include "jlib.hpp"
  16. #include "eclhelper.hpp"
  17. #include "eclrtl.hpp"
  18. #include "eclrtl_imp.hpp"
  19. #include "rtlfield.hpp"
  20. #include "rtlds_imp.hpp"
  21. #include "rtlrecord.hpp"
  22. #include "rtldynfield.hpp"
  23. #include "hqlstack.hpp"
  24. #include "hqlir.hpp"
  25. #include "hqlutil.hpp"
  26. FuncCallStack::FuncCallStack(bool _hasMeta, int size)
  27. {
  28. hasMeta = _hasMeta;
  29. if(size < DEFAULTSTACKSIZE)
  30. size = DEFAULTSTACKSIZE;
  31. sp = 0;
  32. tos = size;
  33. stackbuf = (char*) malloc(tos);
  34. numToFree = 0;
  35. #ifdef MAXFPREGS
  36. numFpRegs = 0;
  37. for (unsigned i=0;i<MAXFPREGS;i++)
  38. {
  39. #ifdef FPREG_FIXEDSIZE
  40. fpRegs[i] = 0.0;
  41. #else
  42. fpRegs[i].d = 0.0;
  43. fpSizes[i] = 8;
  44. #endif
  45. }
  46. #endif
  47. }
  48. FuncCallStack::~FuncCallStack() {
  49. if(stackbuf) {
  50. free(stackbuf);
  51. }
  52. // Free memory used by string/data parameters
  53. for(int i = 0; i < numToFree; i++) {
  54. free(toFree[i]);
  55. }
  56. }
  57. unsigned FuncCallStack::align(unsigned size)
  58. {
  59. #ifdef ALIGN_USES_ELEMENTSIZE
  60. unsigned boundary = (size < ALIGNMENT) ? ALIGNMENT : size;
  61. #else
  62. unsigned boundary = ALIGNMENT;
  63. #endif
  64. return ((size + boundary - 1) & ~(boundary-1));
  65. }
  66. unsigned FuncCallStack::getSp(){
  67. return sp;
  68. }
  69. char* FuncCallStack::getMem() {
  70. return stackbuf;
  71. }
  72. int FuncCallStack::push(unsigned len, const void * data)
  73. {
  74. int incsize = len;
  75. int inclen = align(incsize);
  76. assure(inclen);
  77. memcpy(stackbuf + sp, data, incsize);
  78. memset(stackbuf+sp+incsize, 0, inclen - incsize);
  79. sp += inclen;
  80. return sp;
  81. }
  82. int FuncCallStack::push(ITypeInfo* argType, IHqlExpression* curParam)
  83. {
  84. unsigned len = 0;
  85. char* str;
  86. int incsize;
  87. int inclen;
  88. IValue * paramValue = curParam->queryValue();
  89. Owned<IValue> castParam;
  90. if (paramValue) // Not all constants have a paramValue - null, all, constant records etc
  91. {
  92. castParam.setown(paramValue->castTo(argType));
  93. if(!castParam)
  94. {
  95. IERRLOG("Failed to cast paramValue to argType in FuncCallStack::push");
  96. return -1;
  97. }
  98. }
  99. switch (argType->getTypeCode())
  100. {
  101. case type_string:
  102. case type_data:
  103. getStringFromIValue(len, str, castParam);
  104. // For STRINGn, len doesn't need to be passed in.
  105. if(argType->getSize() == UNKNOWN_LENGTH) {
  106. push(sizeof(unsigned), &len);
  107. }
  108. push(sizeof(char *), &str);
  109. if(numToFree < MAXARGS) {
  110. toFree[numToFree++] = str;
  111. }
  112. break;
  113. case type_varstring:
  114. getStringFromIValue(len, str, castParam);
  115. push(sizeof(char *), &str);
  116. if(numToFree < MAXARGS) {
  117. toFree[numToFree++] = str;
  118. }
  119. break;
  120. case type_qstring:
  121. case type_unicode:
  122. case type_utf8:
  123. {
  124. unsigned argSize = castParam->getSize();
  125. const void * text = castParam->queryValue();
  126. str = (char *)malloc(argSize);
  127. memcpy(str, text, argSize);
  128. // For STRINGn, len doens't need to be passed in.
  129. if(argType->getSize() == UNKNOWN_LENGTH)
  130. {
  131. len = castParam->queryType()->getStringLen();
  132. push(sizeof(unsigned), &len);
  133. }
  134. push(sizeof(char *), &str);
  135. if(numToFree < MAXARGS) {
  136. toFree[numToFree++] = str;
  137. }
  138. }
  139. break;
  140. case type_varunicode:
  141. UNIMPLEMENTED;
  142. case type_real:
  143. #ifdef MAXFPREGS
  144. if (numFpRegs==MAXFPREGS) {
  145. IERRLOG("Too many floating point registers needed in FuncCallStack::push");
  146. return -1;
  147. }
  148. char tempbuf[sizeof(double)];
  149. castParam->toMem(tempbuf);
  150. #ifdef FPREG_FIXEDSIZE
  151. if (argType->getSize()<=4)
  152. fpRegs[numFpRegs++] = *(float *)&tempbuf;
  153. else
  154. fpRegs[numFpRegs++] = *(double *)&tempbuf;
  155. #else
  156. // Variable size FP registers as on arm/x64
  157. if (argType->getSize()<=4)
  158. fpRegs[numFpRegs].f = *(float *)&tempbuf;
  159. else
  160. fpRegs[numFpRegs].d = *(double *)&tempbuf;
  161. fpSizes[numFpRegs++] = argType->getSize();
  162. #endif
  163. break;
  164. #else
  165. // fall through if no hw regs used for params
  166. #endif
  167. case type_boolean:
  168. case type_int:
  169. case type_decimal:
  170. case type_date:
  171. case type_char:
  172. case type_enumerated:
  173. case type_swapint:
  174. case type_packedint:
  175. incsize = argType->getSize();
  176. inclen = align(incsize);
  177. assure(inclen);
  178. castParam->toMem(stackbuf+sp);
  179. memset(stackbuf+sp+incsize, 0, inclen - incsize);
  180. sp += inclen;
  181. break;
  182. case type_row:
  183. {
  184. if (hasMeta)
  185. {
  186. try
  187. {
  188. pushMeta(curParam->queryRecordType());
  189. }
  190. catch (IException *E)
  191. {
  192. ::Release(E);
  193. return -1;
  194. }
  195. }
  196. if (curParam->getOperator()==no_null)
  197. {
  198. // MORE - check type matches
  199. MemoryBuffer out;
  200. createConstantNullRow(out, curParam->queryRecord());
  201. str = (char *) out.detach();
  202. push(sizeof(char *), &str);
  203. if(numToFree < MAXARGS)
  204. toFree[numToFree++] = str;
  205. }
  206. else
  207. return -1;
  208. break;
  209. }
  210. case type_record:
  211. {
  212. try
  213. {
  214. pushMeta(curParam->queryRecordType());
  215. }
  216. catch (IException *E)
  217. {
  218. ::Release(E);
  219. return -1;
  220. }
  221. break;
  222. }
  223. default:
  224. EclIR::dump_ir(curParam);
  225. //code isn't here to pass sets/datasets to external functions....
  226. return -1;
  227. }
  228. return sp;
  229. }
  230. int FuncCallStack::pushMeta(ITypeInfo *type)
  231. {
  232. if (!deserializer)
  233. deserializer.setown(createRtlFieldTypeDeserializer());
  234. const RtlTypeInfo *typeInfo = buildRtlType(*deserializer.get(), type);
  235. CDynamicOutputMetaData * meta = new CDynamicOutputMetaData(* static_cast<const RtlRecordTypeInfo *>(typeInfo));
  236. metas.append(*meta);
  237. return pushPtr(meta);
  238. }
  239. int FuncCallStack::pushPtr(void * val)
  240. {
  241. return push(sizeof(void *), &val);
  242. }
  243. int FuncCallStack::push(char* & val) {
  244. return push(sizeof(char *), &val);
  245. }
  246. int FuncCallStack::pushRef(unsigned& val) {
  247. unsigned* valRef = &val;
  248. return push(sizeof(unsigned *), &valRef);
  249. }
  250. int FuncCallStack::pushRef(char*& val) {
  251. char** valRef = &val;
  252. return push(sizeof(char **), &valRef);
  253. }
  254. void FuncCallStack::assure(int inclen) {
  255. if(sp + inclen >= tos) {
  256. tos += INCREMENTALSIZE;
  257. stackbuf = (char *)realloc(stackbuf, tos);
  258. }
  259. }