interp.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. /* Definitions for the runtime interpreter.
  2. This file is part of khipu.
  3. khipu is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. #include <cstdio>
  14. #include "khipu.hpp"
  15. KP_DECLS_BEGIN
  16. bool interp_hook::attach (interpreter *ip)
  17. {
  18. if (this->interp)
  19. return (false);
  20. this->interp = ip;
  21. ++this->interp->num_hooks[this->type];
  22. this->interp->hooks.add (&this->link);
  23. return (true);
  24. }
  25. bool interp_hook::detach ()
  26. {
  27. if (!this->interp)
  28. return (false);
  29. --this->interp->num_hooks[this->type];
  30. this->link.del ();
  31. return (true);
  32. }
  33. bool interpreter::init (char *base, uint32_t size)
  34. {
  35. // Initialization order is important for bootstrapping.
  36. this->values.init_head ();
  37. this->hooks.init_head ();
  38. this->mmgr = memmgr_alloc ();
  39. {
  40. auto stk = alloc_array (this, 64);
  41. if (stk.error_p ())
  42. return (false);
  43. this->stkobj = deref (stk);
  44. }
  45. this->stack = this->stkend = &xaref(this->stkobj, 0);
  46. this->cur_frame = this->throw_frame = this->exc_offset = 0;
  47. this->last_err = this->last_tb = NIL;
  48. this->retval = this->alval = this->aux = UNBOUND;
  49. this->state = this->saved_state = INTERP_RUNNING;
  50. this->tbuf = nullptr;
  51. this->evp = nullptr;
  52. this->call_depth = 0;
  53. this->stk_alloc.init (base, size);
  54. double dvt = monotonic_time ();
  55. this->rand_seed = hashbuf (&dvt, sizeof (dvt));
  56. memset (this->pendev_mask, 0, sizeof (this->pendev_mask));
  57. this->npendev = 0;
  58. this->evh_active = true;
  59. this->exc_raised = false;
  60. this->n_tlsyms = 0;
  61. for (size_t i = 0; i < KP_NELEM (this->num_hooks); ++i)
  62. this->num_hooks[i] = 0;
  63. return (true);
  64. }
  65. uint32_t interpreter::xrand ()
  66. {
  67. uint32_t next = this->rand_seed;
  68. next = next * 1103515245 + 12345;
  69. this->rand_seed = next;
  70. return (next >> 16);
  71. }
  72. result<void> interpreter::growstk (uint32_t n)
  73. {
  74. uint32_t sp = this->stklen (), size = sp + n;
  75. if (kp_likely (size < len_a (this->stkobj)))
  76. return (0);
  77. object ns = KP_TRY_IP (this,
  78. alloc_array (this, size = upsize (size), UNBOUND));
  79. memcpy (&xaref(ns, 0), this->stack, sp * sizeof (object));
  80. this->stkobj = ns;
  81. this->stack = &xaref(ns, 0);
  82. this->stkend = this->stack + sp;
  83. this->call_hooks (HOOK_TYPE_STKMOV);
  84. return (0);
  85. }
  86. void interpreter::do_call_hooks (unsigned int type, unsigned int n)
  87. {
  88. for (auto i = this->hooks.iterator (&interp_hook::link); n > 0; ++i)
  89. if (i->type == type)
  90. {
  91. i->call (this);
  92. --n;
  93. }
  94. }
  95. KP_TLS_INTERP interpreter *interpreter::self_interp;
  96. #ifndef KP_NO_THREADS
  97. /* We cannot use the internal lightweight locks here, because it may
  98. * cause a deadlock when contending against the gc-triggering thread.
  99. * Instead, we use a simple spinlock, since we shouldn't hold this
  100. * lock for too many instructions, anyway. */
  101. bool interpreter::lock_remote (interpreter *interp)
  102. {
  103. intptr_t val = (intptr_t)interp;
  104. auto *ilp = &as_thread(this->thread)->ilock;
  105. if (*ilp == val)
  106. return (false);
  107. while (true)
  108. {
  109. if (atomic_cas_bool (ilp, 0, val))
  110. return (true);
  111. int nspins = 100; // An arbitrary value.
  112. while (*ilp != 0 && --nspins > 0)
  113. atomic_spin_nop ();
  114. }
  115. }
  116. bool interpreter::lock ()
  117. {
  118. return (this->lock_remote (this));
  119. }
  120. void interpreter::unlock (bool release)
  121. {
  122. if (!release)
  123. return;
  124. as_thread(this->thread)->ilock = 0;
  125. atomic_mfence_rel ();
  126. }
  127. #endif
  128. result<void> interpreter::begin_blocking ()
  129. {
  130. lock_guard g (this);
  131. if (kp_unlikely (this->npendev && this->evh_active))
  132. KP_VTRY (this->do_handle_evs ());
  133. this->state = INTERP_BLOCKING;
  134. return (0);
  135. }
  136. void interpreter::end_blocking ()
  137. {
  138. while (true)
  139. {
  140. this->lock ();
  141. if (this->state != INTERP_SUSPENDED)
  142. break;
  143. /* Someone suspended us while we were blocking.
  144. * We now need to wait on the event they set up for us. */
  145. this->unlock ();
  146. this->sync_ev()->wait (this);
  147. }
  148. this->state = INTERP_RUNNING;
  149. this->unlock ();
  150. }
  151. object interpreter::caller () const
  152. {
  153. if (this->cur_frame == 0)
  154. return (NIL);
  155. int nargs = as_int (this->stack[this->cur_frame - 3]);
  156. return (this->stack[this->cur_frame - nargs - frame_size - 1]);
  157. }
  158. exception interpreter::raise (object exc)
  159. {
  160. this->throw_frame = this->cur_frame;
  161. this->exc_raised = true;
  162. this->last_err = exc;
  163. return (exception ());
  164. }
  165. exception interpreter::raise (const char *exctp, object str)
  166. {
  167. auto name = string::make (this, exctp);
  168. if (name.error_p ())
  169. return (exception ());
  170. object mkexc = find_sym (this, "%mkexc", 6);
  171. if (symbol_p (mkexc) && fct_p (this->retval = symval (mkexc)))
  172. {
  173. if (this->growstk(3).error_p ())
  174. return (exception ());
  175. *this->stkend++ = this->retval;
  176. *this->stkend++ = *name;
  177. *this->stkend++ = str;
  178. if (call_n(this, 2).error_p ())
  179. return (exception ());
  180. }
  181. else if (cons::make(this, *name, str).error_p ())
  182. return (exception ());
  183. return (this->raise (this->retval));
  184. }
  185. exception interpreter::raise (const char *exctp, const char *msg)
  186. {
  187. auto tmp = string::make (this, msg);
  188. if (tmp.error_p ())
  189. return (exception ());
  190. valref str (this, *tmp);
  191. return (this->raise (exctp, *str));
  192. }
  193. void interpreter::nargs_msg (char *bp, int sz, int min,
  194. int max, int passed)
  195. {
  196. const char FMT[] = "wrong number of arguments for %Q (expected ";
  197. memcpy (bp, FMT, sizeof (FMT) - 1);
  198. int n = (int)sizeof (FMT) - 1;
  199. bp += n, sz -= n;
  200. if (min == max)
  201. n = snprintf (bp, sz, "%d", min);
  202. else if (max == -1)
  203. n = snprintf (bp, sz, "%d or more", min);
  204. else
  205. n = snprintf (bp, sz, "%d to %d", min, max);
  206. bp += n, sz -= n;
  207. snprintf (bp, sz, ", got %d)", passed);
  208. }
  209. exception interpreter::raise_nargs (object name, int min, int max, int passed)
  210. {
  211. local_varobj<string> sn;
  212. if (!symbol_p (name))
  213. {
  214. sn.local_init ("#:fct", 5);
  215. name = sn.as_obj ();
  216. }
  217. char buf[128];
  218. this->nargs_msg (buf, sizeof (buf) - 1, min, max, passed);
  219. auto msg = KP_SPRINTF (this, buf, name);
  220. return (msg.error_p () ? exception () : this->raise ("arg-error", *msg));
  221. }
  222. exception interpreter::raise_oob (int idx, int nmax)
  223. {
  224. char buf[128];
  225. const char FMT[] = "index out of bounds";
  226. memcpy (buf, FMT, sizeof (FMT) - 1);
  227. int n = (int)sizeof (FMT) - 1;
  228. if (nmax >= 0)
  229. snprintf (&buf[n], sizeof (buf) - n - 1,
  230. " (got %d, length is %d)", idx, nmax);
  231. else
  232. buf[n] = 0;
  233. return (this->raise ("index-error", buf));
  234. }
  235. result<bool> interpreter::push_frame (object env, int nargs, int off)
  236. {
  237. KP_VTRY (this->growstk (frame_size));
  238. *this->stkend++ = env;
  239. *this->stkend++ = fixint (this->cur_frame);
  240. *this->stkend++ = fixint (nargs);
  241. *this->stkend++ = fixint (off);
  242. *this->stkend++ = fixint (0); // Thread-local binding index.
  243. this->cur_frame = this->stklen ();
  244. return (true);
  245. }
  246. static result<object>
  247. trace_frame (interpreter *interp, uint32_t frame, object acc)
  248. {
  249. int size = as_int (interp->stack[frame - 3]) + 1;
  250. int bp = frame - interpreter::frame_size - size;
  251. object caller = interp->stack[bp];
  252. if (fct_p (caller) && as_fct(caller)->flagged_p (function::artificial_flag))
  253. return (acc);
  254. object vec = KP_TRY (alloc_array (interp, size, NIL));
  255. for (int i = 0; i < size; ++i)
  256. {
  257. object elem = interp->stack[bp + i];
  258. xaref(vec, i) = elem == UNBOUND ? NIL :
  259. (xcons_p (elem) && (xcdr (elem) & EXTRA_BIT) ? xcar (elem) : elem);
  260. }
  261. return (cons::make (interp, vec, acc));
  262. }
  263. result<bool> interpreter::exc_handle ()
  264. {
  265. if (!this->exc_raised || this->exc_offset == 0)
  266. return (false);
  267. uint32_t nsp = this->exc_offset;
  268. this->exc_offset = as_int (this->stack[nsp]);
  269. this->aux = fixint (this->stack[nsp + 1]);
  270. for (this->last_tb = NIL; this->cur_frame > nsp; )
  271. {
  272. this->last_tb = KP_TRY_IP (this, trace_frame (this, this->cur_frame,
  273. this->last_tb));
  274. this->unbind (~0u);
  275. this->cur_frame = as_int (this->stack[this->cur_frame - 4]);
  276. }
  277. this->stkend = this->stack + nsp;
  278. this->exc_raised = false;
  279. return (true);
  280. }
  281. result<object> interpreter::dbind_idx (uintptr_t tl_idx, object val)
  282. {
  283. if (tl_idx == 0)
  284. return (this->raise ("runtime-error", "cannot bind a non-dynamic symbol"));
  285. else if (tl_idx > this->n_tlsyms)
  286. {
  287. auto ntl = upsize (tl_idx);
  288. this->tl_syms = (object *)xrealloc (this->tl_syms,
  289. ntl * sizeof (*this->tl_syms));
  290. for (auto i = this->n_tlsyms; i < ntl; ++i)
  291. this->tl_syms[i] = UNBOUND;
  292. this->n_tlsyms = ntl;
  293. }
  294. object prev = this->tl_syms[tl_idx - 1];
  295. this->tl_syms[tl_idx - 1] = val;
  296. return (this->retval = prev);
  297. }
  298. result<object> interpreter::dbind (object sym, object val)
  299. {
  300. return (this->dbind_idx (symtlidx (sym), val));
  301. }
  302. void interpreter::unbind (uint32_t n)
  303. {
  304. uint32_t start = as_int (this->stack[this->cur_frame - 1]);
  305. for (; start && n; --n)
  306. {
  307. uint32_t idx = this->cur_frame + start;
  308. for (int i = 0, j = 1; i < as_int (this->stack[idx]); ++i, j += 2)
  309. {
  310. object sym = this->stack[idx + j + 1];
  311. this->tl_syms[symtlidx (sym) - 1] = this->stack[idx + j];
  312. }
  313. start = as_int (this->stack[this->cur_frame + start - 1]);
  314. }
  315. this->stack[this->cur_frame - 1] = fixint (start);
  316. }
  317. result<bool> interpreter::unbind (uint32_t n, coroutine *crp)
  318. {
  319. if (!crp)
  320. {
  321. this->unbind (n);
  322. return (0);
  323. }
  324. uint32_t start = as_int (this->stack[this->cur_frame - 1]), last_off = 0;
  325. uint32_t size = 0;
  326. while (start)
  327. {
  328. uint32_t idx = this->cur_frame + start;
  329. size += as_int (this->stack[idx]);
  330. start = as_int (this->stack[this->cur_frame + start - 1]);
  331. if (--n == 0)
  332. last_off = start;
  333. }
  334. if (!array_p (crp->dbinds) || len_a (crp->dbinds) < size * 2)
  335. { crp->dbinds = KP_TRY_IP (this, alloc_array (this, size * 2)); }
  336. for (size = 0, start = as_int (this->stack[this->cur_frame - 1]); start; )
  337. {
  338. uint32_t idx = this->cur_frame + start;
  339. for (int i = 0, j = 1; i < as_int (this->stack[idx]); ++i, j += 2)
  340. {
  341. object sym = this->stack[idx + j + 1];
  342. xaref(crp->dbinds, size++) = sym;
  343. xaref(crp->dbinds, size++) = this->tl_syms[symtlidx (sym) - 1];
  344. this->tl_syms[symtlidx (sym) - 1] = this->stack[idx + j];
  345. }
  346. start = as_int (this->stack[this->cur_frame + start - 1]);
  347. }
  348. this->stack[this->cur_frame - 1] = fixint (last_off);
  349. return (0);
  350. }
  351. result<object> interpreter::stacktrace (uint32_t frame, uint32_t limit)
  352. {
  353. valref ret (this, NIL);
  354. while (frame > limit)
  355. {
  356. *ret = KP_TRY_IP (this, trace_frame (this, frame, *ret));
  357. frame = as_int (this->stack[frame - 4]);
  358. }
  359. object argv[] = { *ret, this->last_tb };
  360. this->last_tb = KP_TRY_IP (this, nconcat (this, argv, 2));
  361. return (this->retval);
  362. }
  363. // Event management.
  364. static const int EVMASK_BITS = sizeof (atomic_t) * 8;
  365. void interpreter::set_ev (unsigned int evno)
  366. {
  367. if (--evno >= NPENDEV)
  368. return;
  369. auto bit = (uintptr_t)1 << (evno % EVMASK_BITS);
  370. bool rel = this->lock ();
  371. if (!(this->pendev_mask[evno / EVMASK_BITS] & bit))
  372. {
  373. this->pendev_mask[evno / EVMASK_BITS] |= bit;
  374. ++this->npendev;
  375. }
  376. this->unlock (rel);
  377. }
  378. result<void> interpreter::do_handle_evs ()
  379. {
  380. KP_VTRY (this->growstk (2));
  381. for (uintptr_t i = 0 ; ; ++i)
  382. {
  383. uintptr_t bit = (uintptr_t)1 << (i % EVMASK_BITS);
  384. if (!(this->pendev_mask[i / EVMASK_BITS] & bit))
  385. continue;
  386. this->pendev_mask[i / EVMASK_BITS] &= ~bit;
  387. --this->npendev;
  388. object fn = get_evhandler (this, i + 1);
  389. if (fn != UNBOUND)
  390. {
  391. *this->stkend++ = fn;
  392. *this->stkend++ = fixint (i + 1);
  393. KP_VTRY (call_n (this, 1));
  394. }
  395. if (!this->npendev)
  396. break;
  397. }
  398. return (0);
  399. }
  400. void* tmp_allocator::slow_alloc (uint32_t size)
  401. {
  402. auto tp = (interp_tbuf *)xmalloc (sizeof (interp_tbuf) + size);
  403. tp->next = this->ip->tbuf;
  404. this->ip->tbuf = tp;
  405. return ((char *)tp + sizeof (*tp));
  406. }
  407. void tmp_allocator::talloc_cleanup ()
  408. {
  409. do
  410. {
  411. auto curr = this->ip->tbuf;
  412. this->ip->tbuf = curr->next;
  413. xfree (curr);
  414. }
  415. while (this->ip->tbuf != this->tbuf);
  416. }
  417. result<void> dbinding::init (uintptr_t idx, object val)
  418. {
  419. *this->val = KP_TRY (this->interp->dbind_idx (idx, val));
  420. this->tl_idx = idx;
  421. return (0);
  422. }
  423. dbinding::~dbinding ()
  424. {
  425. if (this->tl_idx)
  426. this->interp->tl_syms[this->tl_idx - 1] = *this->val;
  427. }
  428. KP_DECLS_END