123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584 |
- /* Declarations for the runtime interpreter.
- This file is part of khipu.
- khipu is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>. */
- #ifndef __KP_INTERP__
- #define __KP_INTERP__ 1
- #include "defs.hpp"
- #include "event.hpp"
- KP_DECLS_BEGIN
- struct interpreter;
- // Valid hook types.
- enum
- {
- HOOK_TYPE_STKMOV,
- HOOK_TYPE_FCALL,
- HOOK_TYPE_LAST
- };
- struct interp_hook
- {
- unsigned int type;
- void (*cb) (interpreter *, void *);
- void *arg;
- interpreter *interp = nullptr;
- dlist link;
- interp_hook (unsigned int tp,
- void (*cb) (interpreter *, void *), void *arg = nullptr) :
- type (tp), cb (cb), arg (arg)
- {
- }
- bool attach (interpreter *interp);
- bool detach ();
- void call (interpreter *interp)
- {
- this->cb (interp, this->arg);
- }
- ~interp_hook ()
- {
- this->detach ();
- }
- };
- // Reference to a GC-visible value.
- struct valref
- {
- dlist link;
- object value;
- valref () = delete;
- valref (const valref&) = delete;
- inline valref (interpreter *interp, object val = 0);
- inline valref (object val = 0);
- valref (valref&& right)
- {
- this->link = right.link;
- this->value = right.value;
- right.link.init_head ();
- }
- object& operator* ()
- {
- return (this->value);
- }
- object operator* () const
- {
- return (this->value);
- }
- ~valref ()
- {
- this->link.del ();
- }
- };
- struct sync_event;
- struct memmgr;
- struct coroutine;
- struct stream;
- struct io_info;
- struct pack_info;
- struct comparator;
- // Possible interpreter states.
- enum
- {
- INTERP_RUNNING,
- INTERP_BLOCKING,
- INTERP_SUSPENDED
- };
- struct stack_allocator
- {
- char *curr;
- uint32_t left = 0;
- void init (char *ptr, uint32_t size)
- {
- this->curr = ptr;
- this->left = size;
- }
- char* alloc (uint32_t size)
- {
- size = (size + sizeof (std::max_align_t)) &
- ~(alignof (std::max_align_t) - 1);
- if (size >= this->left)
- return (nullptr);
- char *ret = this->curr;
- this->curr += size;
- this->left -= size;
- return (ret);
- }
- void reset (char *ptr)
- {
- this->left += (uint32_t)(this->curr - ptr);
- this->curr = ptr;
- }
- };
- // Temporary buffer.
- struct interp_tbuf
- {
- union
- {
- interp_tbuf *next;
- std::max_align_t align;
- };
- };
- struct interpreter
- {
- object *stack;
- object *stkend;
- uint32_t cur_frame;
- uint32_t throw_frame;
- uint32_t exc_offset;
- object thread;
- object last_err;
- object last_tb;
- object stkobj;
- object xpkg;
- // Interpreter registers.
- object retval;
- object alval;
- object aux;
- // Current and saved interpreter state.
- int state;
- int saved_state;
- stack_allocator stk_alloc;
- bool evh_active;
- bool exc_raised;
- #if !defined (__GNUC__)
- bool result_errored;
- #endif
- interp_tbuf *tbuf;
- sync_event *evp;
- uint32_t rand_seed;
- uint32_t call_depth;
- uint32_t npendev;
- intptr_t pendev_mask[NPENDEV / (sizeof (intptr_t) * 8) +
- (NPENDEV % (sizeof (intptr_t) * 8) != 0)];
- dlist values;
- memmgr *mmgr;
- unsigned int num_hooks[HOOK_TYPE_LAST];
- dlist hooks;
- object *tl_syms;
- uintptr_t n_tlsyms;
- #ifdef KP_PLATFORM_WINDOWS
- void *io_event;
- #endif
- // Internal constants.
- enum
- {
- frame_size = 5
- };
- bool init (char *base, uint32_t size);
- void reset_exc ()
- {
- this->throw_frame = 0;
- this->exc_raised = false;
- this->last_err = this->last_tb = NIL;
- }
- result<void> growstk (uint32_t off);
- result<object*> push (object elem)
- {
- KP_VTRY (this->growstk (1));
- *this->stkend++ = elem;
- return (this->stkend - 1);
- }
- object pop ()
- {
- return (this->retval = *--this->stkend);
- }
- uint32_t stklen () const
- {
- return ((uint32_t)(this->stkend - this->stack));
- }
- void popn (uint32_t n = 1)
- {
- this->stkend -= n;
- }
- object stktop () const
- {
- return (*(this->stkend - 1));
- }
- void* talloc (size_t size);
- void do_call_hooks (unsigned int type, unsigned int n);
- void call_hooks (unsigned int type)
- {
- unsigned int n = this->num_hooks[type];
- if (kp_unlikely (n))
- this->do_call_hooks (type, n);
- }
- #ifdef KP_NO_THREADS
- bool lock ()
- {
- return (false);
- }
- void unlock (bool = true)
- {
- }
- bool lock_remote (interpreter *)
- {
- return (false);
- }
- #else
- bool lock ();
- void unlock (bool release = true);
- bool lock_remote (interpreter *interp);
- #endif
- result<void> begin_blocking ();
- void end_blocking ();
- struct lock_guard
- {
- interpreter *interp;
- bool rel;
- lock_guard (interpreter *ip) : interp (ip)
- {
- this->rel = this->interp->lock ();
- }
- ~lock_guard ()
- {
- this->interp->unlock (this->rel);
- }
- };
- #ifdef KP_NO_THREADS
- # define KP_TLS_INTERP
- #elif defined (__clang__) && (defined (__MINGW32__) || defined (__MINGW64__))
- # define KP_TLS_INTERP __thread
- #else
- # define KP_TLS_INTERP thread_local
- #endif
- static KP_TLS_INTERP interpreter *self_interp;
- static interpreter* self () __attribute__ ((const))
- {
- return (interpreter::self_interp);
- }
- static void set_self (interpreter *interp)
- {
- interpreter::self_interp = interp;
- }
- sync_event*& sync_ev ()
- {
- return (this->evp);
- }
- object caller () const;
- uint32_t xrand ();
- void nargs_msg (char *buf, int size, int min_argc,
- int max_argc, int passed);
- exception raise (object exception);
- exception raise (result<object> exc)
- {
- if (exc.error_p ())
- return (exception ());
- return (this->raise (*exc));
- }
- exception raise (const char *exctype, const char *msg);
- exception raise (const char *exctype, object msg);
- exception raise (const char *exctype, result<object> msg)
- {
- if (msg.error_p ())
- return (exception ());
- return (this->raise (exctype, *msg));
- }
- exception raise_nargs (object name, int min, int max, int passed);
- exception raise_nargs (int min, int max, int passed)
- {
- return (this->raise_nargs (this->caller (), min, max, passed));
- }
- exception raise_oob (int idx, int max);
- exception raise_const ()
- {
- return (this->raise ("const-error", "cannot modify read-only object"));
- }
- result<bool> exc_handle (void);
- result<bool> push_frame (object env, int nargs, int off);
- result<object> dbind_idx (uintptr_t tl_idx, object value);
- result<object> dbind (object sym, object value);
- void unbind (uint32_t n);
- result<bool> unbind (uint32_t n, coroutine *crp);
- result<object> stacktrace (uint32_t frame, uint32_t limit = 0);
- void set_ev (unsigned int ev);
- result<void> do_handle_evs ();
- result<void> handle_evs ()
- {
- if (kp_unlikely (this->npendev && this->evh_active))
- {
- lock_guard g (this);
- return (this->do_handle_evs ());
- }
- return (0);
- }
- #if !defined (__GNUC__)
- template <typename T>
- T store_result (T&& rx)
- {
- this->result_errored = error_p (rx);
- return (rx);
- }
- #endif
- // User friendly interface for hooks.
- struct hook
- {
- interp_hook base;
- virtual void call (interpreter *) = 0;
- static void hook_cb (interpreter *interp, void *arg)
- {
- ((hook *)arg)->call (interp);
- }
- bool attach (interpreter *interp)
- {
- return (this->base.attach (interp));
- }
- bool detach ()
- {
- return (this->base.detach ());
- }
- hook (unsigned int tp) : base (tp, hook_cb, this) {}
- };
- };
- struct tmp_allocator
- {
- interpreter *ip;
- interp_tbuf *tbuf;
- char *stk_top;
- tmp_allocator (interpreter *interp) : ip (interp),
- tbuf (interp->tbuf), stk_top (interp->stk_alloc.curr)
- {
- }
- void* slow_alloc (uint32_t size);
- void talloc_cleanup ();
- void* alloc (uint32_t size)
- {
- void *ret = this->ip->stk_alloc.alloc (size);
- if (kp_unlikely (!ret))
- ret = this->slow_alloc (size);
- return (ret);
- }
- ~tmp_allocator ()
- {
- this->ip->stk_alloc.reset (this->stk_top);
- if (kp_unlikely (this->tbuf != this->ip->tbuf))
- this->talloc_cleanup ();
- }
- };
- valref::valref (interpreter *interp, object val)
- {
- this->value = val;
- interp->values.add (&this->link);
- }
- valref::valref (object val) : valref (interpreter::self (), val)
- {
- }
- // For event management.
- struct evh_guard
- {
- bool *swap;
- evh_guard (bool *p = nullptr) : swap (p)
- {
- }
- static result<evh_guard>
- make (interpreter *interp)
- {
- evh_guard ret (nullptr);
- if (interp->evh_active)
- {
- *(ret.swap = &interp->evh_active) = false;
- KP_VTRY (interp->handle_evs ());
- }
- return (ret);
- }
- ~evh_guard ()
- {
- if (this->swap)
- *this->swap = true;
- }
- };
- struct evh_safeguard
- {
- bool prev;
- interpreter *ip;
- evh_safeguard (interpreter *interp) : prev (interp->evh_active), ip (interp)
- {
- interp->evh_active = false;
- }
- ~evh_safeguard ()
- {
- this->ip->evh_active = prev;
- }
- };
- // Saves and restores the stack pointer.
- struct sp_guard
- {
- interpreter *interp;
- uint32_t sp;
- sp_guard (interpreter *interp, uint32_t sp) :
- interp (interp), sp (sp)
- {
- }
- sp_guard (interpreter *interp) : sp_guard (interp, interp->stklen ())
- {
- }
- ~sp_guard ()
- {
- this->interp->stkend = this->interp->stack + this->sp;
- }
- };
- // Saves what's needed in function calls.
- struct call_guard : public sp_guard
- {
- uint32_t cf;
- uint32_t eoff;
- call_guard (interpreter *interp, uint32_t spadj = 0) :
- sp_guard (interp, interp->stklen () - spadj),
- cf (interp->cur_frame), eoff (interp->exc_offset)
- {
- }
- ~call_guard ()
- {
- this->interp->cur_frame = this->cf;
- this->interp->exc_offset = this->eoff;
- }
- };
- // Temporarily binds a dynamic symbol.
- struct dbinding
- {
- interpreter *interp;
- valref val;
- uintptr_t tl_idx;
- dbinding (interpreter *ip) : interp (ip), val (ip), tl_idx (0)
- {
- }
- result<void> init (uintptr_t idx, object val);
- ~dbinding ();
- };
- struct wait_point
- {
- interpreter *interp;
- wait_point (interpreter *ip) : interp (ip)
- {
- }
- result<void> begin ()
- {
- return (this->interp->begin_blocking ());
- }
- ~wait_point ()
- {
- this->interp->end_blocking ();
- }
- };
- // Main thread's interpreter.
- KP_EXPORT interpreter *main_interp;
- KP_DECLS_END
- #endif
|