NCDInterpProcess.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /**
  2. * @file NCDInterpProcess.c
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the author nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #include <stdint.h>
  30. #include <limits.h>
  31. #include <string.h>
  32. #include <stdlib.h>
  33. #include <misc/balloc.h>
  34. #include <misc/maxalign.h>
  35. #include <misc/strdup.h>
  36. #include <base/BLog.h>
  37. #include <ncd/make_name_indices.h>
  38. #include "NCDInterpProcess.h"
  39. #include <generated/blog_channel_ncd.h>
  40. struct NCDInterpProcess__stmt {
  41. NCD_string_id_t name;
  42. NCD_string_id_t cmdname;
  43. NCD_string_id_t *objnames;
  44. size_t num_objnames;
  45. union {
  46. const struct NCDInterpModule *simple_module;
  47. int method_name_id;
  48. } binding;
  49. NCDEvaluatorExpr arg_expr;
  50. int alloc_size;
  51. int prealloc_offset;
  52. int hash_next;
  53. };
  54. static int compute_prealloc (NCDInterpProcess *o)
  55. {
  56. int size = 0;
  57. for (int i = 0; i < o->num_stmts; i++) {
  58. int mod = size % BMAX_ALIGN;
  59. int align_size = (mod == 0 ? 0 : BMAX_ALIGN - mod);
  60. if (align_size + o->stmts[i].alloc_size > INT_MAX - size) {
  61. return 0;
  62. }
  63. o->stmts[i].prealloc_offset = size + align_size;
  64. size += align_size + o->stmts[i].alloc_size;
  65. }
  66. ASSERT(size >= 0)
  67. o->prealloc_size = size;
  68. return 1;
  69. }
  70. int NCDInterpProcess_Init (NCDInterpProcess *o, NCDProcess *process, NCDStringIndex *string_index, NCDEvaluator *eval, NCDModuleIndex *module_index)
  71. {
  72. ASSERT(process)
  73. ASSERT(string_index)
  74. ASSERT(eval)
  75. ASSERT(module_index)
  76. NCDBlock *block = NCDProcess_Block(process);
  77. if (NCDBlock_NumStatements(block) > INT_MAX) {
  78. BLog(BLOG_ERROR, "too many statements");
  79. goto fail0;
  80. }
  81. int num_stmts = NCDBlock_NumStatements(block);
  82. if (!(o->stmts = BAllocArray(num_stmts, sizeof(o->stmts[0])))) {
  83. BLog(BLOG_ERROR, "BAllocArray failed");
  84. goto fail0;
  85. }
  86. o->num_hash_buckets = num_stmts;
  87. if (!(o->hash_buckets = BAllocArray(o->num_hash_buckets, sizeof(o->hash_buckets[0])))) {
  88. BLog(BLOG_ERROR, "BAllocArray failed");
  89. goto fail1;
  90. }
  91. for (size_t i = 0; i < o->num_hash_buckets; i++) {
  92. o->hash_buckets[i] = -1;
  93. }
  94. if (!(o->name = b_strdup(NCDProcess_Name(process)))) {
  95. BLog(BLOG_ERROR, "b_strdup failed");
  96. goto fail2;
  97. }
  98. o->num_stmts = 0;
  99. o->prealloc_size = -1;
  100. o->is_template = NCDProcess_IsTemplate(process);
  101. o->cache = NULL;
  102. for (NCDStatement *s = NCDBlock_FirstStatement(block); s; s = NCDBlock_NextStatement(block, s)) {
  103. ASSERT(NCDStatement_Type(s) == NCDSTATEMENT_REG)
  104. struct NCDInterpProcess__stmt *e = &o->stmts[o->num_stmts];
  105. e->name = -1;
  106. e->objnames = NULL;
  107. e->num_objnames = 0;
  108. e->alloc_size = 0;
  109. if (NCDStatement_Name(s)) {
  110. e->name = NCDStringIndex_Get(string_index, NCDStatement_Name(s));
  111. if (e->name < 0) {
  112. BLog(BLOG_ERROR, "NCDStringIndex_Get failed");
  113. goto loop_fail0;
  114. }
  115. }
  116. e->cmdname = NCDStringIndex_Get(string_index, NCDStatement_RegCmdName(s));
  117. if (e->cmdname < 0) {
  118. BLog(BLOG_ERROR, "NCDStringIndex_Get failed");
  119. goto loop_fail0;
  120. }
  121. if (!NCDEvaluatorExpr_Init(&e->arg_expr, eval, NCDStatement_RegArgs(s))) {
  122. BLog(BLOG_ERROR, "NCDEvaluatorExpr_Init failed");
  123. goto loop_fail0;
  124. }
  125. if (NCDStatement_RegObjName(s)) {
  126. if (!ncd_make_name_indices(string_index, NCDStatement_RegObjName(s), &e->objnames, &e->num_objnames)) {
  127. BLog(BLOG_ERROR, "ncd_make_name_indices failed");
  128. goto loop_fail1;
  129. }
  130. e->binding.method_name_id = NCDModuleIndex_GetMethodNameId(module_index, NCDStatement_RegCmdName(s));
  131. if (e->binding.method_name_id == -1) {
  132. BLog(BLOG_ERROR, "NCDModuleIndex_GetMethodNameId failed");
  133. goto loop_fail2;
  134. }
  135. } else {
  136. e->binding.simple_module = NCDModuleIndex_FindModule(module_index, NCDStatement_RegCmdName(s));
  137. }
  138. if (e->name >= 0) {
  139. size_t bucket_idx = e->name % o->num_hash_buckets;
  140. e->hash_next = o->hash_buckets[bucket_idx];
  141. o->hash_buckets[bucket_idx] = o->num_stmts;
  142. }
  143. o->num_stmts++;
  144. continue;
  145. loop_fail2:
  146. BFree(e->objnames);
  147. loop_fail1:
  148. NCDEvaluatorExpr_Free(&e->arg_expr);
  149. loop_fail0:
  150. goto fail3;
  151. }
  152. ASSERT(o->num_stmts == num_stmts)
  153. DebugObject_Init(&o->d_obj);
  154. return 1;
  155. fail3:
  156. while (o->num_stmts-- > 0) {
  157. struct NCDInterpProcess__stmt *e = &o->stmts[o->num_stmts];
  158. BFree(e->objnames);
  159. NCDEvaluatorExpr_Free(&e->arg_expr);
  160. }
  161. free(o->name);
  162. fail2:
  163. BFree(o->hash_buckets);
  164. fail1:
  165. BFree(o->stmts);
  166. fail0:
  167. return 0;
  168. }
  169. void NCDInterpProcess_Free (NCDInterpProcess *o)
  170. {
  171. DebugObject_Free(&o->d_obj);
  172. while (o->num_stmts-- > 0) {
  173. struct NCDInterpProcess__stmt *e = &o->stmts[o->num_stmts];
  174. BFree(e->objnames);
  175. NCDEvaluatorExpr_Free(&e->arg_expr);
  176. }
  177. free(o->name);
  178. BFree(o->hash_buckets);
  179. BFree(o->stmts);
  180. }
  181. int NCDInterpProcess_FindStatement (NCDInterpProcess *o, int from_index, NCD_string_id_t name)
  182. {
  183. DebugObject_Access(&o->d_obj);
  184. ASSERT(from_index >= 0)
  185. ASSERT(from_index <= o->num_stmts)
  186. size_t bucket_idx = name % o->num_hash_buckets;
  187. int stmt_idx = o->hash_buckets[bucket_idx];
  188. ASSERT(stmt_idx >= -1)
  189. ASSERT(stmt_idx < o->num_stmts)
  190. while (stmt_idx >= 0) {
  191. if (stmt_idx < from_index && o->stmts[stmt_idx].name == name) {
  192. return stmt_idx;
  193. }
  194. stmt_idx = o->stmts[stmt_idx].hash_next;
  195. ASSERT(stmt_idx >= -1)
  196. ASSERT(stmt_idx < o->num_stmts)
  197. }
  198. return -1;
  199. }
  200. const char * NCDInterpProcess_StatementCmdName (NCDInterpProcess *o, int i, NCDStringIndex *string_index)
  201. {
  202. DebugObject_Access(&o->d_obj);
  203. ASSERT(i >= 0)
  204. ASSERT(i < o->num_stmts)
  205. ASSERT(string_index)
  206. return NCDStringIndex_Value(string_index, o->stmts[i].cmdname);
  207. }
  208. void NCDInterpProcess_StatementObjNames (NCDInterpProcess *o, int i, const NCD_string_id_t **out_objnames, size_t *out_num_objnames)
  209. {
  210. DebugObject_Access(&o->d_obj);
  211. ASSERT(i >= 0)
  212. ASSERT(i < o->num_stmts)
  213. ASSERT(out_objnames)
  214. ASSERT(out_num_objnames)
  215. *out_objnames = o->stmts[i].objnames;
  216. *out_num_objnames = o->stmts[i].num_objnames;
  217. }
  218. const struct NCDInterpModule * NCDInterpProcess_StatementGetSimpleModule (NCDInterpProcess *o, int i, NCDStringIndex *string_index, NCDModuleIndex *module_index)
  219. {
  220. DebugObject_Access(&o->d_obj);
  221. ASSERT(i >= 0)
  222. ASSERT(i < o->num_stmts)
  223. ASSERT(!o->stmts[i].objnames)
  224. struct NCDInterpProcess__stmt *e = &o->stmts[i];
  225. if (!e->binding.simple_module) {
  226. const char *cmdname = NCDStringIndex_Value(string_index, e->cmdname);
  227. e->binding.simple_module = NCDModuleIndex_FindModule(module_index, cmdname);
  228. }
  229. return e->binding.simple_module;
  230. }
  231. const struct NCDInterpModule * NCDInterpProcess_StatementGetMethodModule (NCDInterpProcess *o, int i, NCD_string_id_t obj_type, NCDModuleIndex *module_index)
  232. {
  233. DebugObject_Access(&o->d_obj);
  234. ASSERT(i >= 0)
  235. ASSERT(i < o->num_stmts)
  236. ASSERT(o->stmts[i].objnames)
  237. ASSERT(obj_type >= 0)
  238. ASSERT(module_index)
  239. return NCDModuleIndex_GetMethodModule(module_index, obj_type, o->stmts[i].binding.method_name_id);
  240. }
  241. NCDEvaluatorExpr * NCDInterpProcess_GetStatementArgsExpr (NCDInterpProcess *o, int i)
  242. {
  243. DebugObject_Access(&o->d_obj);
  244. ASSERT(i >= 0)
  245. ASSERT(i < o->num_stmts)
  246. struct NCDInterpProcess__stmt *e = &o->stmts[i];
  247. return &e->arg_expr;
  248. }
  249. void NCDInterpProcess_StatementBumpAllocSize (NCDInterpProcess *o, int i, int alloc_size)
  250. {
  251. DebugObject_Access(&o->d_obj);
  252. ASSERT(i >= 0)
  253. ASSERT(i < o->num_stmts)
  254. ASSERT(alloc_size >= 0)
  255. if (alloc_size > o->stmts[i].alloc_size) {
  256. o->stmts[i].alloc_size = alloc_size;
  257. o->prealloc_size = -1;
  258. }
  259. }
  260. int NCDInterpProcess_PreallocSize (NCDInterpProcess *o)
  261. {
  262. DebugObject_Access(&o->d_obj);
  263. ASSERT(o->prealloc_size == -1 || o->prealloc_size >= 0)
  264. if (o->prealloc_size < 0 && !compute_prealloc(o)) {
  265. return -1;
  266. }
  267. return o->prealloc_size;
  268. }
  269. int NCDInterpProcess_StatementPreallocSize (NCDInterpProcess *o, int i)
  270. {
  271. DebugObject_Access(&o->d_obj);
  272. ASSERT(i >= 0)
  273. ASSERT(i < o->num_stmts)
  274. ASSERT(o->prealloc_size >= 0)
  275. return o->stmts[i].alloc_size;
  276. }
  277. int NCDInterpProcess_StatementPreallocOffset (NCDInterpProcess *o, int i)
  278. {
  279. DebugObject_Access(&o->d_obj);
  280. ASSERT(i >= 0)
  281. ASSERT(i < o->num_stmts)
  282. ASSERT(o->prealloc_size >= 0)
  283. return o->stmts[i].prealloc_offset;
  284. }
  285. const char * NCDInterpProcess_Name (NCDInterpProcess *o)
  286. {
  287. DebugObject_Access(&o->d_obj);
  288. return o->name;
  289. }
  290. int NCDInterpProcess_IsTemplate (NCDInterpProcess *o)
  291. {
  292. DebugObject_Access(&o->d_obj);
  293. return o->is_template;
  294. }
  295. int NCDInterpProcess_NumStatements (NCDInterpProcess *o)
  296. {
  297. DebugObject_Access(&o->d_obj);
  298. return o->num_stmts;
  299. }
  300. int NCDInterpProcess_CachePush (NCDInterpProcess *o, void *elem)
  301. {
  302. DebugObject_Access(&o->d_obj);
  303. ASSERT(elem)
  304. if (o->cache) {
  305. return 0;
  306. }
  307. o->cache = elem;
  308. return 1;
  309. }
  310. void * NCDInterpProcess_CachePull (NCDInterpProcess *o)
  311. {
  312. DebugObject_Access(&o->d_obj);
  313. void *elem = o->cache;
  314. o->cache = NULL;
  315. return elem;
  316. }