hqlstack.cpp 8.5 KB

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