interp.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. /* Declarations 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. #ifndef __KP_INTERP__
  14. #define __KP_INTERP__ 1
  15. #include "defs.hpp"
  16. #include "event.hpp"
  17. KP_DECLS_BEGIN
  18. struct interpreter;
  19. // Valid hook types.
  20. enum
  21. {
  22. HOOK_TYPE_STKMOV,
  23. HOOK_TYPE_FCALL,
  24. HOOK_TYPE_LAST
  25. };
  26. struct interp_hook
  27. {
  28. unsigned int type;
  29. void (*cb) (interpreter *, void *);
  30. void *arg;
  31. interpreter *interp = nullptr;
  32. dlist link;
  33. interp_hook (unsigned int tp,
  34. void (*cb) (interpreter *, void *), void *arg = nullptr) :
  35. type (tp), cb (cb), arg (arg)
  36. {
  37. }
  38. bool attach (interpreter *interp);
  39. bool detach ();
  40. void call (interpreter *interp)
  41. {
  42. this->cb (interp, this->arg);
  43. }
  44. ~interp_hook ()
  45. {
  46. this->detach ();
  47. }
  48. };
  49. // Reference to a GC-visible value.
  50. struct valref
  51. {
  52. dlist link;
  53. object value;
  54. valref () = delete;
  55. valref (const valref&) = delete;
  56. inline valref (interpreter *interp, object val = 0);
  57. inline valref (object val = 0);
  58. valref (valref&& right)
  59. {
  60. this->link = right.link;
  61. this->value = right.value;
  62. right.link.init_head ();
  63. }
  64. object& operator* ()
  65. {
  66. return (this->value);
  67. }
  68. object operator* () const
  69. {
  70. return (this->value);
  71. }
  72. ~valref ()
  73. {
  74. this->link.del ();
  75. }
  76. };
  77. struct sync_event;
  78. struct memmgr;
  79. struct coroutine;
  80. struct stream;
  81. struct io_info;
  82. struct pack_info;
  83. struct comparator;
  84. // Possible interpreter states.
  85. enum
  86. {
  87. INTERP_RUNNING,
  88. INTERP_BLOCKING,
  89. INTERP_SUSPENDED
  90. };
  91. struct stack_allocator
  92. {
  93. char *curr;
  94. uint32_t left = 0;
  95. void init (char *ptr, uint32_t size)
  96. {
  97. this->curr = ptr;
  98. this->left = size;
  99. }
  100. char* alloc (uint32_t size)
  101. {
  102. size = (size + sizeof (std::max_align_t)) &
  103. ~(alignof (std::max_align_t) - 1);
  104. if (size >= this->left)
  105. return (nullptr);
  106. char *ret = this->curr;
  107. this->curr += size;
  108. this->left -= size;
  109. return (ret);
  110. }
  111. void reset (char *ptr)
  112. {
  113. this->left += (uint32_t)(this->curr - ptr);
  114. this->curr = ptr;
  115. }
  116. };
  117. // Temporary buffer.
  118. struct interp_tbuf
  119. {
  120. union
  121. {
  122. interp_tbuf *next;
  123. std::max_align_t align;
  124. };
  125. };
  126. struct interpreter
  127. {
  128. object *stack;
  129. object *stkend;
  130. uint32_t cur_frame;
  131. uint32_t throw_frame;
  132. uint32_t exc_offset;
  133. object thread;
  134. object last_err;
  135. object last_tb;
  136. object stkobj;
  137. object xpkg;
  138. // Interpreter registers.
  139. object retval;
  140. object alval;
  141. object aux;
  142. // Current and saved interpreter state.
  143. int state;
  144. int saved_state;
  145. stack_allocator stk_alloc;
  146. bool evh_active;
  147. bool exc_raised;
  148. #if !defined (__GNUC__)
  149. bool result_errored;
  150. #endif
  151. interp_tbuf *tbuf;
  152. sync_event *evp;
  153. uint32_t rand_seed;
  154. uint32_t call_depth;
  155. uint32_t npendev;
  156. intptr_t pendev_mask[NPENDEV / (sizeof (intptr_t) * 8) +
  157. (NPENDEV % (sizeof (intptr_t) * 8) != 0)];
  158. dlist values;
  159. memmgr *mmgr;
  160. unsigned int num_hooks[HOOK_TYPE_LAST];
  161. dlist hooks;
  162. object *tl_syms;
  163. uintptr_t n_tlsyms;
  164. #ifdef KP_PLATFORM_WINDOWS
  165. void *io_event;
  166. #endif
  167. // Internal constants.
  168. enum
  169. {
  170. frame_size = 5
  171. };
  172. bool init (char *base, uint32_t size);
  173. void reset_exc ()
  174. {
  175. this->throw_frame = 0;
  176. this->exc_raised = false;
  177. this->last_err = this->last_tb = NIL;
  178. }
  179. result<void> growstk (uint32_t off);
  180. result<object*> push (object elem)
  181. {
  182. KP_VTRY (this->growstk (1));
  183. *this->stkend++ = elem;
  184. return (this->stkend - 1);
  185. }
  186. object pop ()
  187. {
  188. return (this->retval = *--this->stkend);
  189. }
  190. uint32_t stklen () const
  191. {
  192. return ((uint32_t)(this->stkend - this->stack));
  193. }
  194. void popn (uint32_t n = 1)
  195. {
  196. this->stkend -= n;
  197. }
  198. object stktop () const
  199. {
  200. return (*(this->stkend - 1));
  201. }
  202. void* talloc (size_t size);
  203. void do_call_hooks (unsigned int type, unsigned int n);
  204. void call_hooks (unsigned int type)
  205. {
  206. unsigned int n = this->num_hooks[type];
  207. if (kp_unlikely (n))
  208. this->do_call_hooks (type, n);
  209. }
  210. #ifdef KP_NO_THREADS
  211. bool lock ()
  212. {
  213. return (false);
  214. }
  215. void unlock (bool = true)
  216. {
  217. }
  218. bool lock_remote (interpreter *)
  219. {
  220. return (false);
  221. }
  222. #else
  223. bool lock ();
  224. void unlock (bool release = true);
  225. bool lock_remote (interpreter *interp);
  226. #endif
  227. result<void> begin_blocking ();
  228. void end_blocking ();
  229. struct lock_guard
  230. {
  231. interpreter *interp;
  232. bool rel;
  233. lock_guard (interpreter *ip) : interp (ip)
  234. {
  235. this->rel = this->interp->lock ();
  236. }
  237. ~lock_guard ()
  238. {
  239. this->interp->unlock (this->rel);
  240. }
  241. };
  242. #ifdef KP_NO_THREADS
  243. # define KP_TLS_INTERP
  244. #elif defined (__clang__) && (defined (__MINGW32__) || defined (__MINGW64__))
  245. # define KP_TLS_INTERP __thread
  246. #else
  247. # define KP_TLS_INTERP thread_local
  248. #endif
  249. static KP_TLS_INTERP interpreter *self_interp;
  250. static interpreter* self () __attribute__ ((const))
  251. {
  252. return (interpreter::self_interp);
  253. }
  254. static void set_self (interpreter *interp)
  255. {
  256. interpreter::self_interp = interp;
  257. }
  258. sync_event*& sync_ev ()
  259. {
  260. return (this->evp);
  261. }
  262. object caller () const;
  263. uint32_t xrand ();
  264. void nargs_msg (char *buf, int size, int min_argc,
  265. int max_argc, int passed);
  266. exception raise (object exception);
  267. exception raise (result<object> exc)
  268. {
  269. if (exc.error_p ())
  270. return (exception ());
  271. return (this->raise (*exc));
  272. }
  273. exception raise (const char *exctype, const char *msg);
  274. exception raise (const char *exctype, object msg);
  275. exception raise (const char *exctype, result<object> msg)
  276. {
  277. if (msg.error_p ())
  278. return (exception ());
  279. return (this->raise (exctype, *msg));
  280. }
  281. exception raise_nargs (object name, int min, int max, int passed);
  282. exception raise_nargs (int min, int max, int passed)
  283. {
  284. return (this->raise_nargs (this->caller (), min, max, passed));
  285. }
  286. exception raise_oob (int idx, int max);
  287. exception raise_const ()
  288. {
  289. return (this->raise ("const-error", "cannot modify read-only object"));
  290. }
  291. result<bool> exc_handle (void);
  292. result<bool> push_frame (object env, int nargs, int off);
  293. result<object> dbind_idx (uintptr_t tl_idx, object value);
  294. result<object> dbind (object sym, object value);
  295. void unbind (uint32_t n);
  296. result<bool> unbind (uint32_t n, coroutine *crp);
  297. result<object> stacktrace (uint32_t frame, uint32_t limit = 0);
  298. void set_ev (unsigned int ev);
  299. result<void> do_handle_evs ();
  300. result<void> handle_evs ()
  301. {
  302. if (kp_unlikely (this->npendev && this->evh_active))
  303. {
  304. lock_guard g (this);
  305. return (this->do_handle_evs ());
  306. }
  307. return (0);
  308. }
  309. #if !defined (__GNUC__)
  310. template <typename T>
  311. T store_result (T&& rx)
  312. {
  313. this->result_errored = error_p (rx);
  314. return (rx);
  315. }
  316. #endif
  317. // User friendly interface for hooks.
  318. struct hook
  319. {
  320. interp_hook base;
  321. virtual void call (interpreter *) = 0;
  322. static void hook_cb (interpreter *interp, void *arg)
  323. {
  324. ((hook *)arg)->call (interp);
  325. }
  326. bool attach (interpreter *interp)
  327. {
  328. return (this->base.attach (interp));
  329. }
  330. bool detach ()
  331. {
  332. return (this->base.detach ());
  333. }
  334. hook (unsigned int tp) : base (tp, hook_cb, this) {}
  335. };
  336. };
  337. struct tmp_allocator
  338. {
  339. interpreter *ip;
  340. interp_tbuf *tbuf;
  341. char *stk_top;
  342. tmp_allocator (interpreter *interp) : ip (interp),
  343. tbuf (interp->tbuf), stk_top (interp->stk_alloc.curr)
  344. {
  345. }
  346. void* slow_alloc (uint32_t size);
  347. void talloc_cleanup ();
  348. void* alloc (uint32_t size)
  349. {
  350. void *ret = this->ip->stk_alloc.alloc (size);
  351. if (kp_unlikely (!ret))
  352. ret = this->slow_alloc (size);
  353. return (ret);
  354. }
  355. ~tmp_allocator ()
  356. {
  357. this->ip->stk_alloc.reset (this->stk_top);
  358. if (kp_unlikely (this->tbuf != this->ip->tbuf))
  359. this->talloc_cleanup ();
  360. }
  361. };
  362. valref::valref (interpreter *interp, object val)
  363. {
  364. this->value = val;
  365. interp->values.add (&this->link);
  366. }
  367. valref::valref (object val) : valref (interpreter::self (), val)
  368. {
  369. }
  370. // For event management.
  371. struct evh_guard
  372. {
  373. bool *swap;
  374. evh_guard (bool *p = nullptr) : swap (p)
  375. {
  376. }
  377. static result<evh_guard>
  378. make (interpreter *interp)
  379. {
  380. evh_guard ret (nullptr);
  381. if (interp->evh_active)
  382. {
  383. *(ret.swap = &interp->evh_active) = false;
  384. KP_VTRY (interp->handle_evs ());
  385. }
  386. return (ret);
  387. }
  388. ~evh_guard ()
  389. {
  390. if (this->swap)
  391. *this->swap = true;
  392. }
  393. };
  394. struct evh_safeguard
  395. {
  396. bool prev;
  397. interpreter *ip;
  398. evh_safeguard (interpreter *interp) : prev (interp->evh_active), ip (interp)
  399. {
  400. interp->evh_active = false;
  401. }
  402. ~evh_safeguard ()
  403. {
  404. this->ip->evh_active = prev;
  405. }
  406. };
  407. // Saves and restores the stack pointer.
  408. struct sp_guard
  409. {
  410. interpreter *interp;
  411. uint32_t sp;
  412. sp_guard (interpreter *interp, uint32_t sp) :
  413. interp (interp), sp (sp)
  414. {
  415. }
  416. sp_guard (interpreter *interp) : sp_guard (interp, interp->stklen ())
  417. {
  418. }
  419. ~sp_guard ()
  420. {
  421. this->interp->stkend = this->interp->stack + this->sp;
  422. }
  423. };
  424. // Saves what's needed in function calls.
  425. struct call_guard : public sp_guard
  426. {
  427. uint32_t cf;
  428. uint32_t eoff;
  429. call_guard (interpreter *interp, uint32_t spadj = 0) :
  430. sp_guard (interp, interp->stklen () - spadj),
  431. cf (interp->cur_frame), eoff (interp->exc_offset)
  432. {
  433. }
  434. ~call_guard ()
  435. {
  436. this->interp->cur_frame = this->cf;
  437. this->interp->exc_offset = this->eoff;
  438. }
  439. };
  440. // Temporarily binds a dynamic symbol.
  441. struct dbinding
  442. {
  443. interpreter *interp;
  444. valref val;
  445. uintptr_t tl_idx;
  446. dbinding (interpreter *ip) : interp (ip), val (ip), tl_idx (0)
  447. {
  448. }
  449. result<void> init (uintptr_t idx, object val);
  450. ~dbinding ();
  451. };
  452. struct wait_point
  453. {
  454. interpreter *interp;
  455. wait_point (interpreter *ip) : interp (ip)
  456. {
  457. }
  458. result<void> begin ()
  459. {
  460. return (this->interp->begin_blocking ());
  461. }
  462. ~wait_point ()
  463. {
  464. this->interp->end_blocking ();
  465. }
  466. };
  467. // Main thread's interpreter.
  468. KP_EXPORT interpreter *main_interp;
  469. KP_DECLS_END
  470. #endif