hqlstack.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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. /**
  27. * class CDynamicOutputMetaData
  28. *
  29. * An implementation of IOutputMetaData for use with a dynamically-created record type info structure
  30. *
  31. */
  32. class CDynamicOutputMetaData : public COutputMetaData
  33. {
  34. public:
  35. CDynamicOutputMetaData(const RtlRecordTypeInfo & fields) : typeInfo(fields)
  36. {
  37. }
  38. virtual const RtlTypeInfo * queryTypeInfo() const { return &typeInfo; }
  39. virtual size32_t getRecordSize(const void * row)
  40. {
  41. //Allocate a temporary offset array on the stack to avoid runtime overhead.
  42. const RtlRecord *offsetInformation = queryRecordAccessor(true);
  43. unsigned numOffsets = offsetInformation->getNumVarFields() + 1;
  44. size_t * variableOffsets = (size_t *)alloca(numOffsets * sizeof(size_t));
  45. RtlRow offsetCalculator(*offsetInformation, row, numOffsets, variableOffsets);
  46. return offsetCalculator.getRecordSize();
  47. }
  48. virtual size32_t getFixedSize() const
  49. {
  50. return queryRecordAccessor(true)->getFixedSize();
  51. }
  52. // returns 0 for variable row size
  53. virtual size32_t getMinRecordSize() const
  54. {
  55. return queryRecordAccessor(true)->getMinRecordSize();
  56. }
  57. virtual IOutputRowDeserializer * createDiskDeserializer(ICodeContext * ctx, unsigned activityId) { throwUnexpected(); }
  58. protected:
  59. const RtlTypeInfo &typeInfo;
  60. };
  61. FuncCallStack::FuncCallStack(bool _hasMeta, int size)
  62. {
  63. hasMeta = _hasMeta;
  64. if(size < DEFAULTSTACKSIZE)
  65. size = DEFAULTSTACKSIZE;
  66. sp = 0;
  67. tos = size;
  68. stackbuf = (char*) malloc(tos);
  69. numToFree = 0;
  70. #ifdef MAXFPREGS
  71. numFpRegs = 0;
  72. for (unsigned i=0;i<MAXFPREGS;i++)
  73. {
  74. #ifdef FPREG_FIXEDSIZE
  75. fpRegs[i] = 0.0;
  76. #else
  77. fpRegs[i].d = 0.0;
  78. fpSizes[i] = 8;
  79. #endif
  80. }
  81. #endif
  82. }
  83. FuncCallStack::~FuncCallStack() {
  84. if(stackbuf) {
  85. free(stackbuf);
  86. }
  87. // Free memory used by string/data parameters
  88. for(int i = 0; i < numToFree; i++) {
  89. free(toFree[i]);
  90. }
  91. }
  92. unsigned FuncCallStack::align(unsigned size)
  93. {
  94. #ifdef ALIGN_USES_ELEMENTSIZE
  95. unsigned boundary = (size < ALIGNMENT) ? ALIGNMENT : size;
  96. #else
  97. unsigned boundary = ALIGNMENT;
  98. #endif
  99. return ((size + boundary - 1) & ~(boundary-1));
  100. }
  101. unsigned FuncCallStack::getSp(){
  102. return sp;
  103. }
  104. char* FuncCallStack::getMem() {
  105. return stackbuf;
  106. }
  107. int FuncCallStack::push(unsigned len, const void * data)
  108. {
  109. int incsize = len;
  110. int inclen = align(incsize);
  111. assure(inclen);
  112. memcpy(stackbuf + sp, data, incsize);
  113. memset(stackbuf+sp+incsize, 0, inclen - incsize);
  114. sp += inclen;
  115. return sp;
  116. }
  117. int FuncCallStack::push(ITypeInfo* argType, IHqlExpression* curParam)
  118. {
  119. unsigned len = 0;
  120. char* str;
  121. int incsize;
  122. int inclen;
  123. IValue * paramValue = curParam->queryValue();
  124. Owned<IValue> castParam;
  125. if (paramValue) // Not all constants have a paramValue - null, all, constant records etc
  126. {
  127. castParam.setown(paramValue->castTo(argType));
  128. if(!castParam)
  129. {
  130. PrintLog("Failed to cast paramValue to argType in FuncCallStack::push");
  131. return -1;
  132. }
  133. }
  134. switch (argType->getTypeCode())
  135. {
  136. case type_string:
  137. case type_data:
  138. getStringFromIValue(len, str, castParam);
  139. // For STRINGn, len doesn't need to be passed in.
  140. if(argType->getSize() == UNKNOWN_LENGTH) {
  141. push(sizeof(unsigned), &len);
  142. }
  143. push(sizeof(char *), &str);
  144. if(numToFree < MAXARGS) {
  145. toFree[numToFree++] = str;
  146. }
  147. break;
  148. case type_varstring:
  149. getStringFromIValue(len, str, castParam);
  150. push(sizeof(char *), &str);
  151. if(numToFree < MAXARGS) {
  152. toFree[numToFree++] = str;
  153. }
  154. break;
  155. case type_qstring:
  156. case type_unicode:
  157. case type_utf8:
  158. {
  159. unsigned argSize = castParam->getSize();
  160. const void * text = castParam->queryValue();
  161. str = (char *)malloc(argSize);
  162. memcpy(str, text, argSize);
  163. // For STRINGn, len doens't need to be passed in.
  164. if(argType->getSize() == UNKNOWN_LENGTH)
  165. {
  166. len = castParam->queryType()->getStringLen();
  167. push(sizeof(unsigned), &len);
  168. }
  169. push(sizeof(char *), &str);
  170. if(numToFree < MAXARGS) {
  171. toFree[numToFree++] = str;
  172. }
  173. }
  174. break;
  175. case type_varunicode:
  176. UNIMPLEMENTED;
  177. case type_real:
  178. #ifdef MAXFPREGS
  179. if (numFpRegs==MAXFPREGS) {
  180. PrintLog("Too many floating point registers needed in FuncCallStack::push");
  181. return -1;
  182. }
  183. char tempbuf[sizeof(double)];
  184. castParam->toMem(tempbuf);
  185. #ifdef FPREG_FIXEDSIZE
  186. if (argType->getSize()<=4)
  187. fpRegs[numFpRegs++] = *(float *)&tempbuf;
  188. else
  189. fpRegs[numFpRegs++] = *(double *)&tempbuf;
  190. #else
  191. // Variable size FP registers as on arm/x64
  192. if (argType->getSize()<=4)
  193. fpRegs[numFpRegs].f = *(float *)&tempbuf;
  194. else
  195. fpRegs[numFpRegs].d = *(double *)&tempbuf;
  196. fpSizes[numFpRegs++] = argType->getSize();
  197. #endif
  198. break;
  199. #else
  200. // fall through if no hw regs used for params
  201. #endif
  202. case type_boolean:
  203. case type_int:
  204. case type_decimal:
  205. case type_date:
  206. case type_char:
  207. case type_enumerated:
  208. case type_swapint:
  209. case type_packedint:
  210. incsize = argType->getSize();
  211. inclen = align(incsize);
  212. assure(inclen);
  213. castParam->toMem(stackbuf+sp);
  214. memset(stackbuf+sp+incsize, 0, inclen - incsize);
  215. sp += inclen;
  216. break;
  217. case type_row:
  218. {
  219. if (hasMeta)
  220. {
  221. try
  222. {
  223. pushMeta(curParam->queryRecordType());
  224. }
  225. catch (IException *E)
  226. {
  227. ::Release(E);
  228. return -1;
  229. }
  230. }
  231. if (curParam->getOperator()==no_null)
  232. {
  233. // MORE - check type matches
  234. MemoryBuffer out;
  235. createConstantNullRow(out, curParam->queryRecord());
  236. str = (char *) out.detach();
  237. push(sizeof(char *), &str);
  238. if(numToFree < MAXARGS)
  239. toFree[numToFree++] = str;
  240. }
  241. else
  242. return -1;
  243. break;
  244. }
  245. case type_record:
  246. {
  247. try
  248. {
  249. pushMeta(curParam->queryRecordType());
  250. }
  251. catch (IException *E)
  252. {
  253. ::Release(E);
  254. return -1;
  255. }
  256. break;
  257. }
  258. default:
  259. EclIR::dump_ir(curParam);
  260. //code isn't here to pass sets/datasets to external functions....
  261. return -1;
  262. }
  263. return sp;
  264. }
  265. int FuncCallStack::pushMeta(ITypeInfo *type)
  266. {
  267. if (!deserializer)
  268. deserializer.setown(createRtlFieldTypeDeserializer());
  269. const RtlTypeInfo *typeInfo = buildRtlType(*deserializer.get(), type);
  270. CDynamicOutputMetaData * meta = new CDynamicOutputMetaData(* static_cast<const RtlRecordTypeInfo *>(typeInfo));
  271. metas.append(*meta);
  272. return pushPtr(meta);
  273. }
  274. int FuncCallStack::pushPtr(void * val)
  275. {
  276. return push(sizeof(void *), &val);
  277. }
  278. int FuncCallStack::push(char* & val) {
  279. return push(sizeof(char *), &val);
  280. }
  281. int FuncCallStack::pushRef(unsigned& val) {
  282. unsigned* valRef = &val;
  283. return push(sizeof(unsigned *), &valRef);
  284. }
  285. int FuncCallStack::pushRef(char*& val) {
  286. char** valRef = &val;
  287. return push(sizeof(char **), &valRef);
  288. }
  289. void FuncCallStack::assure(int inclen) {
  290. if(sp + inclen >= tos) {
  291. tos += INCREMENTALSIZE;
  292. stackbuf = (char *)realloc(stackbuf, tos);
  293. }
  294. }