aboutsummaryrefslogtreecommitdiffstats
path: root/src/module.c
diff options
context:
space:
mode:
authorAurélien Aptel2015-11-16 00:47:04 +0100
committerTed Zlatanov2015-11-18 14:24:19 -0500
commit307e76c79979736c109cfa6de07b1567700231f3 (patch)
tree02105101ce7cad65e199c32cb902167687a73066 /src/module.c
parentf69cd6bfa114ea02f3d10ddb2fe809a26eafb9a4 (diff)
downloademacs-307e76c79979736c109cfa6de07b1567700231f3.tar.gz
emacs-307e76c79979736c109cfa6de07b1567700231f3.zip
Add dynamic module module support
* configure.ac: Add '--with-modules' option. Conditionally add dynlib.o and module.o to the list of objects. Add any system specific flags to the linker flags to support dynamic libraries. * m4/ax_gcc_var_attribute.m4: Add autoconf extension to test gcc attributes. * src/Makefile.in: Conditionally add module objects and linker flags. * src/alloc.c (garbage_collect_1): protect module local values from GC. * src/lisp.h: Add 'module_init' and 'syms_of_module' prototypes. * src/emacs_module.h: New header file included by modules. Public module API. * src/module.c: New module implementation file. Co-authored-by: Philipp Stephani <phst@google.com>
Diffstat (limited to 'src/module.c')
-rw-r--r--src/module.c1185
1 files changed, 1185 insertions, 0 deletions
diff --git a/src/module.c b/src/module.c
new file mode 100644
index 00000000000..125fd7fed26
--- /dev/null
+++ b/src/module.c
@@ -0,0 +1,1185 @@
1/*
2 module.c - Module loading and runtime implementation
3 Copyright (C) 2015 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include <stdbool.h>
22#include <stddef.h>
23#include <stdint.h>
24#include <stdio.h>
25
26#include <config.h>
27#include "lisp.h"
28#include "emacs_module.h"
29#include "dynlib.h"
30#include "coding.h"
31#include "verify.h"
32
33
34/* Feature tests */
35
36enum {
37 /* 1 if we have __attribute__((cleanup(...))), 0 otherwise */
38 module_has_cleanup =
39#ifdef HAVE_VAR_ATTRIBUTE_CLEANUP
40 1
41#else
42 0
43#endif
44};
45
46/* Handle to the main thread. Used to verify that modules call us in
47 the right thread. */
48#if defined(HAVE_THREADS_H)
49#include <threads.h>
50static thrd_t main_thread;
51#elif defined(HAVE_PTHREAD)
52#include <pthread.h>
53static pthread_t main_thread;
54#elif defined(WINDOWSNT)
55#include <windows.h>
56/* On Windows, we store a handle to the main thread instead of the
57 thread ID because the latter can be reused when a thread terminates. */
58static HANDLE main_thread;
59#endif
60
61
62/* Implementation of runtime and environment functions */
63
64static emacs_env* module_get_environment (struct emacs_runtime *ert);
65
66static emacs_value module_make_global_ref (emacs_env *env,
67 emacs_value ref);
68static void module_free_global_ref (emacs_env *env,
69 emacs_value ref);
70static enum emacs_funcall_exit module_non_local_exit_check (emacs_env *env);
71static void module_non_local_exit_clear (emacs_env *env);
72static enum emacs_funcall_exit module_non_local_exit_get (emacs_env *env, emacs_value *sym, emacs_value *data);
73static void module_non_local_exit_signal (emacs_env *env, emacs_value sym, emacs_value data);
74static void module_non_local_exit_throw (emacs_env *env, emacs_value tag, emacs_value value);
75static emacs_value module_make_function (emacs_env *env,
76 int min_arity,
77 int max_arity,
78 emacs_subr subr,
79 const char *documentation,
80 void *data);
81static emacs_value module_funcall (emacs_env *env,
82 emacs_value fun,
83 int nargs,
84 emacs_value args[]);
85static emacs_value module_intern (emacs_env *env, const char *name);
86static emacs_value module_type_of (emacs_env *env, emacs_value value);
87static bool module_is_not_nil (emacs_env *env, emacs_value value);
88static bool module_eq (emacs_env *env, emacs_value a, emacs_value b);
89static int64_t module_extract_integer (emacs_env *env, emacs_value n);
90static emacs_value module_make_integer (emacs_env *env, int64_t n);
91static emacs_value module_make_float (emacs_env *env, double d);
92static double module_extract_float (emacs_env *env, emacs_value f);
93static bool module_copy_string_contents (emacs_env *env,
94 emacs_value value,
95 char *buffer,
96 size_t* length);
97static emacs_value module_make_string (emacs_env *env, const char *str, size_t lenght);
98static emacs_value module_make_user_ptr (emacs_env *env,
99 emacs_finalizer_function fin,
100 void *ptr);
101static void* module_get_user_ptr (emacs_env *env, emacs_value uptr);
102static void module_set_user_ptr (emacs_env *env, emacs_value uptr, void *ptr);
103static emacs_finalizer_function module_get_user_finalizer (emacs_env *env, emacs_value uptr);
104static void module_set_user_finalizer (emacs_env *env,
105 emacs_value uptr,
106 emacs_finalizer_function fin);
107
108
109/* Helper functions */
110
111/* If checking is enabled, abort if the current thread is not the
112 Emacs main thread. */
113static void check_main_thread (void);
114
115/* Internal versions of `module_non_local_exit_signal' and `module_non_local_exit_throw'. */
116static void module_non_local_exit_signal_1 (emacs_env *env, Lisp_Object sym, Lisp_Object data);
117static void module_non_local_exit_throw_1 (emacs_env *env, Lisp_Object tag, Lisp_Object value);
118
119/* Module version of `wrong_type_argument'. */
120static void module_wrong_type (emacs_env *env, Lisp_Object predicate, Lisp_Object value);
121
122/* Signal an out-of-memory condition to the caller. */
123static void module_out_of_memory (emacs_env *env);
124
125/* Signal arguments are out of range. */
126static void module_args_out_of_range (emacs_env *env, Lisp_Object a1, Lisp_Object a2);
127
128
129/* Value conversion */
130
131/* Converts an `emacs_value' to the corresponding internal object.
132 Never fails. */
133static Lisp_Object value_to_lisp (emacs_value v);
134
135/* Converts an internal object to an `emacs_value'. Allocates storage
136 from the environment; returns NULL if allocation fails. */
137static emacs_value lisp_to_value (emacs_env *env, Lisp_Object o);
138
139
140/* Memory management */
141
142/* An `emacs_value' is just a pointer to a structure holding an
143 internal Lisp object. */
144struct emacs_value_tag { Lisp_Object v; };
145
146/* Local value objects use a simple fixed-sized block allocation
147 scheme without explicit deallocation. All local values are
148 deallocated when the lifetime of their environment ends. We keep
149 track of a current frame from which new values are allocated,
150 appending further dynamically-allocated frames if necessary. */
151
152enum { value_frame_size = 512 };
153
154/* A block from which `emacs_value' object can be allocated. */
155struct emacs_value_frame {
156 /* Storage for values */
157 struct emacs_value_tag objects[value_frame_size];
158
159 /* Index of the next free value in `objects' */
160 size_t offset;
161
162 /* Pointer to next frame, if any */
163 struct emacs_value_frame *next;
164};
165
166/* Must be called for each frame before it can be used for
167 allocation. */
168static void initialize_frame (struct emacs_value_frame *frame);
169
170/* A structure that holds an initial frame (so that the first local
171 values require no dynamic allocation) and keeps track of the
172 current frame. */
173static struct emacs_value_storage {
174 struct emacs_value_frame initial;
175 struct emacs_value_frame *current;
176} global_storage;
177
178/* Must be called for any storage object before it can be used for
179 allocation. */
180static void initialize_storage (struct emacs_value_storage *storage);
181
182/* Must be called for any initialized storage object before its
183 lifetime ends. Frees all dynamically-allocated frames. */
184static void finalize_storage (struct emacs_value_storage *storage);
185
186/* Allocates a new value from STORAGE and stores OBJ in it. Returns
187 NULL if allocations fails and uses ENV for non local exit reporting. */
188static emacs_value allocate_emacs_value (emacs_env *env, struct emacs_value_storage *storage,
189 Lisp_Object obj);
190
191
192/* Private runtime and environment members */
193
194/* The private part of an environment stores the current non local exit state
195 and holds the `emacs_value' objects allocated during the lifetime
196 of the environment. */
197struct emacs_env_private {
198 enum emacs_funcall_exit pending_non_local_exit;
199
200 /* Dedicated storage for non-local exit symbol and data so that we always
201 have storage available for them, even in an out-of-memory
202 situation. */
203 struct emacs_value_tag non_local_exit_symbol, non_local_exit_data;
204
205 struct emacs_value_storage storage;
206};
207
208/* Combines public and private parts in one structure. This structure
209 is used whenever an environment is created. */
210struct env_storage {
211 emacs_env pub;
212 struct emacs_env_private priv;
213};
214
215/* Must be called before the environment can be used. */
216static void initialize_environment (struct env_storage *env);
217
218/* Must be called before the lifetime of the environment object
219 ends. */
220static void finalize_environment (struct env_storage *env);
221
222/* The private parts of an `emacs_runtime' object contain the initial
223 environment. */
224struct emacs_runtime_private {
225 struct env_storage environment;
226};
227
228
229/* Convenience macros for non-local exit handling */
230
231/* Emacs uses setjmp(3) and longjmp(3) for non-local exits, but we
232 can't allow module frames to be skipped because they are in general
233 not prepared for long jumps (e.g. the behavior in C++ is undefined
234 if objects with nontrivial destructors would be skipped).
235 Therefore we catch all non-local exits. There are two kinds of
236 non-local exits: `signal' and `throw'. The macros in this section
237 can be used to catch both. We use macros so that we don't have to
238 write lots of additional variants of `internal_condition_case'
239 etc. and don't have to worry about passing information to the
240 handler functions. */
241
242/* Called on `signal'. ERR will be a cons cell (SYMBOL . DATA), which
243 gets stored in the environment. Sets the pending non-local exit flag. */
244static void module_handle_signal (emacs_env *env, Lisp_Object err);
245
246/* Called on `throw'. TAG_VAL will be a cons cell (TAG . VALUE),
247 which gets stored in the environment. Sets the pending non-local exit
248 flag. */
249static void module_handle_throw (emacs_env *env, Lisp_Object tag_val);
250
251/* Must be called after setting up a handler immediately before
252 returning from the function. See the comments in lisp.h and the
253 code in eval.c for details. The macros below arrange for this
254 function to be called automatically. DUMMY is ignored. */
255static void module_reset_handlerlist (const int *dummy);
256
257/* Place this macro at the beginning of a function returning a number
258 or a pointer to handle signals. The function must have an ENV
259 parameter. The function will return 0 (or NULL) if a signal is
260 caught. */
261#define MODULE_HANDLE_SIGNALS MODULE_HANDLE_SIGNALS_RETURN(0)
262
263/* Place this macro at the beginning of a function returning void to
264 handle signals. The function must have an ENV parameter. */
265#define MODULE_HANDLE_SIGNALS_VOID MODULE_HANDLE_SIGNALS_RETURN()
266
267#define MODULE_HANDLE_SIGNALS_RETURN(retval) \
268 MODULE_SETJMP(CONDITION_CASE, module_handle_signal, retval)
269
270/* Place this macro at the beginning of a function returning a pointer
271 to handle non-local exits via `throw'. The function must have an
272 ENV parameter. The function will return NULL if a `throw' is
273 caught. */
274#define MODULE_HANDLE_THROW \
275 MODULE_SETJMP(CATCHER_ALL, module_handle_throw, NULL)
276
277#define MODULE_SETJMP(handlertype, handlerfunc, retval) \
278 MODULE_SETJMP_1(handlertype, handlerfunc, retval, \
279 internal_handler_##handlertype, \
280 internal_cleanup_##handlertype)
281
282#define MODULE_SETJMP_1(handlertype, handlerfunc, retval, c, dummy) \
283 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return); \
284 struct handler *c; \
285 /* It is very important that pushing the handler doesn't itself raise a \
286 signal. */ \
287 if (!push_handler_nosignal(&c, Qt, handlertype)) { \
288 module_out_of_memory(env); \
289 return retval; \
290 } \
291 verify(module_has_cleanup); \
292 /* We can install the cleanup only after the handler has been pushed. Use \
293 __attribute__((cleanup)) to avoid non-local-exit-prone manual cleanup. */ \
294 const int dummy __attribute__((cleanup(module_reset_handlerlist))); \
295 if (sys_setjmp(c->jmp)) { \
296 (handlerfunc)(env, c->val); \
297 return retval; \
298 } \
299 /* Force the macro to be followed by a semicolon. */ \
300 do { \
301 } while (0)
302
303
304/* Function environments */
305
306/* A function environment is an auxiliary structure used by
307 `module_make_function' to store information about a module
308 function. It is stored in a save pointer and retrieved by
309 `module-call'. Its members correspond to the arguments given to
310 `module_make_function'. */
311
312struct module_fun_env
313{
314 int min_arity, max_arity;
315 emacs_subr subr;
316 void *data;
317};
318
319/* Returns a string object that contains a user-friendly
320 representation of the function environment. */
321static Lisp_Object module_format_fun_env (const struct module_fun_env *env);
322
323/* Holds the function definition of `module-call'. `module-call' is
324 uninterned because user code couldn't meaningfully use it, so we
325 have to keep its definition around somewhere else. */
326static Lisp_Object module_call_func;
327
328
329/* Implementation of runtime and environment functions */
330
331/* We catch signals and throws only if the code can actually signal or
332 throw. */
333
334static emacs_env* module_get_environment (struct emacs_runtime *ert)
335{
336 check_main_thread ();
337 return &ert->private_members->environment.pub;
338}
339
340/*
341 * To make global refs (GC-protected global values) we keep a hash
342 * that maps global Lisp objects to reference counts.
343 */
344
345static emacs_value module_make_global_ref (emacs_env *env,
346 emacs_value ref)
347{
348 check_main_thread ();
349 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
350 MODULE_HANDLE_SIGNALS;
351 eassert (HASH_TABLE_P (Vmodule_refs_hash));
352 struct Lisp_Hash_Table *h = XHASH_TABLE (Vmodule_refs_hash);
353 Lisp_Object new_obj = value_to_lisp (ref);
354 EMACS_UINT hashcode;
355 ptrdiff_t i = hash_lookup (h, new_obj, &hashcode);
356
357 if (i >= 0)
358 {
359 Lisp_Object value = HASH_VALUE (h, i);
360 eassert (NATNUMP (value));
361 const EMACS_UINT refcount = XFASTINT (value);
362 if (refcount >= MOST_POSITIVE_FIXNUM)
363 {
364 module_non_local_exit_signal_1 (env, Qoverflow_error, Qnil);
365 return NULL;
366 }
367 XSETFASTINT (value, refcount + 1);
368 set_hash_value_slot (h, i, value);
369 }
370 else
371 {
372 hash_put (h, new_obj, make_natnum (1), hashcode);
373 }
374
375 return allocate_emacs_value (env, &global_storage, new_obj);
376}
377
378static void module_free_global_ref (emacs_env *env,
379 emacs_value ref)
380{
381 check_main_thread ();
382 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
383 /* TODO: This probably never signals. */
384 MODULE_HANDLE_SIGNALS_VOID;
385 eassert (HASH_TABLE_P (Vmodule_refs_hash));
386 struct Lisp_Hash_Table *h = XHASH_TABLE (Vmodule_refs_hash);
387 Lisp_Object obj = value_to_lisp (ref);
388 EMACS_UINT hashcode;
389 ptrdiff_t i = hash_lookup (h, obj, &hashcode);
390
391 if (i >= 0)
392 {
393 Lisp_Object value = HASH_VALUE (h, i);
394 eassert (NATNUMP (value));
395 const EMACS_UINT refcount = XFASTINT (value);
396 eassert (refcount > 0);
397 if (refcount > 1)
398 {
399 XSETFASTINT (value, refcount - 1);
400 set_hash_value_slot (h, i, value);
401 }
402 else
403 {
404 hash_remove_from_table (h, value);
405 }
406 }
407}
408
409static enum emacs_funcall_exit module_non_local_exit_check (emacs_env *env)
410{
411 check_main_thread ();
412 return env->private_members->pending_non_local_exit;
413}
414
415static void module_non_local_exit_clear (emacs_env *env)
416{
417 check_main_thread ();
418 env->private_members->pending_non_local_exit = emacs_funcall_exit_return;
419}
420
421static enum emacs_funcall_exit module_non_local_exit_get (emacs_env *env, emacs_value *sym, emacs_value *data)
422{
423 check_main_thread ();
424 struct emacs_env_private *const p = env->private_members;
425 if (p->pending_non_local_exit != emacs_funcall_exit_return)
426 {
427 *sym = &p->non_local_exit_symbol;
428 *data = &p->non_local_exit_data;
429 }
430 return p->pending_non_local_exit;
431}
432
433/*
434 * Like for `signal', DATA must be a list
435 */
436static void module_non_local_exit_signal (emacs_env *env, emacs_value sym, emacs_value data)
437{
438 check_main_thread ();
439 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
440 module_non_local_exit_signal_1 (env, value_to_lisp (sym), value_to_lisp (data));
441}
442
443static void module_non_local_exit_throw (emacs_env *env, emacs_value tag, emacs_value value)
444{
445 check_main_thread ();
446 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
447 module_non_local_exit_throw_1 (env, value_to_lisp (tag), value_to_lisp (value));
448}
449
450/*
451 * A module function is lambda function that calls `module-call',
452 * passing the function pointer of the module function along with the
453 * module emacs_env pointer as arguments.
454 *
455 * (function
456 * (lambda
457 * (&rest arglist)
458 * (module-call
459 * envobj
460 * arglist)))
461 *
462 */
463static emacs_value module_make_function (emacs_env *env,
464 int min_arity,
465 int max_arity,
466 emacs_subr subr,
467 const char *const documentation,
468 void *data)
469{
470 check_main_thread ();
471 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
472 MODULE_HANDLE_SIGNALS;
473
474 if (min_arity > MOST_POSITIVE_FIXNUM || max_arity > MOST_POSITIVE_FIXNUM)
475 xsignal0 (Qoverflow_error);
476
477 if (min_arity < 0 ||
478 (max_arity >= 0 && max_arity < min_arity) ||
479 (max_arity < 0 && max_arity != emacs_variadic_function))
480 xsignal2 (Qinvalid_arity, make_number (min_arity), make_number (max_arity));
481
482 Lisp_Object envobj;
483
484 /* XXX: This should need to be freed when envobj is GC'd */
485 struct module_fun_env *envptr = xzalloc (sizeof (*envptr));
486 envptr->min_arity = min_arity;
487 envptr->max_arity = max_arity;
488 envptr->subr = subr;
489 envptr->data = data;
490 envobj = make_save_ptr (envptr);
491
492 Lisp_Object ret = list4 (Qlambda,
493 list2 (Qand_rest, Qargs),
494 documentation ? build_string (documentation) : Qnil,
495 list3 (module_call_func,
496 envobj,
497 Qargs));
498
499 return lisp_to_value (env, ret);
500}
501
502static emacs_value module_funcall (emacs_env *env,
503 emacs_value fun,
504 int nargs,
505 emacs_value args[])
506{
507 check_main_thread ();
508 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
509 MODULE_HANDLE_SIGNALS;
510 MODULE_HANDLE_THROW;
511
512 /*
513 * Make a new Lisp_Object array starting with the function as the
514 * first arg, because that's what Ffuncall takes
515 */
516 Lisp_Object newargs[nargs + 1];
517 newargs[0] = value_to_lisp (fun);
518 for (int i = 0; i < nargs; i++)
519 newargs[1 + i] = value_to_lisp (args[i]);
520 return lisp_to_value (env, Ffuncall (nargs + 1, newargs));
521}
522
523static emacs_value module_intern (emacs_env *env, const char *name)
524{
525 check_main_thread ();
526 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
527 MODULE_HANDLE_SIGNALS;
528 return lisp_to_value (env, intern (name));
529}
530
531static emacs_value module_type_of (emacs_env *env, emacs_value value)
532{
533 check_main_thread ();
534 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
535 return lisp_to_value (env, Ftype_of (value_to_lisp (value)));
536}
537
538static bool module_is_not_nil (emacs_env *env, emacs_value value)
539{
540 check_main_thread ();
541 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
542 return ! NILP (value_to_lisp (value));
543}
544
545static bool module_eq (emacs_env *env, emacs_value a, emacs_value b)
546{
547 check_main_thread ();
548 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
549 return EQ (value_to_lisp (a), value_to_lisp (b));
550}
551
552static int64_t module_extract_integer (emacs_env *env, emacs_value n)
553{
554 verify (INT64_MIN <= MOST_NEGATIVE_FIXNUM);
555 verify (INT64_MAX >= MOST_POSITIVE_FIXNUM);
556 check_main_thread ();
557 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
558 const Lisp_Object l = value_to_lisp (n);
559 if (! INTEGERP (l))
560 {
561 module_wrong_type (env, Qintegerp, l);
562 return 0;
563 }
564 return XINT (l);
565}
566
567static emacs_value module_make_integer (emacs_env *env, int64_t n)
568{
569 check_main_thread ();
570 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
571 if (n < MOST_NEGATIVE_FIXNUM)
572 {
573 module_non_local_exit_signal_1 (env, Qunderflow_error, Qnil);
574 return NULL;
575 }
576 if (n > MOST_POSITIVE_FIXNUM)
577 {
578 module_non_local_exit_signal_1 (env, Qoverflow_error, Qnil);
579 return NULL;
580 }
581 return lisp_to_value (env, make_number (n));
582}
583
584static double module_extract_float (emacs_env *env, emacs_value f)
585{
586 check_main_thread ();
587 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
588 const Lisp_Object lisp = value_to_lisp (f);
589 if (! FLOATP (lisp))
590 {
591 module_wrong_type (env, Qfloatp, lisp);
592 return 0;
593 }
594 return XFLOAT_DATA (lisp);
595}
596
597static emacs_value module_make_float (emacs_env *env, double d)
598{
599 check_main_thread ();
600 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
601 MODULE_HANDLE_SIGNALS;
602 return lisp_to_value (env, make_float (d));
603}
604
605static bool module_copy_string_contents (emacs_env *env,
606 emacs_value value,
607 char *buffer,
608 size_t* length)
609{
610 check_main_thread ();
611 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
612 MODULE_HANDLE_SIGNALS;
613 Lisp_Object lisp_str = value_to_lisp (value);
614 if (! STRINGP (lisp_str))
615 {
616 module_wrong_type (env, Qstringp, lisp_str);
617 return false;
618 }
619
620 size_t raw_size = SBYTES (lisp_str);
621
622 /*
623 * Emacs internal encoding is more-or-less UTF8, let's assume utf8
624 * encoded emacs string are the same byte size.
625 */
626
627 if (!buffer || length == 0 || *length-1 < raw_size)
628 {
629 *length = raw_size + 1;
630 return false;
631 }
632
633 Lisp_Object lisp_str_utf8 = ENCODE_UTF_8 (lisp_str);
634 eassert (raw_size == SBYTES (lisp_str_utf8));
635 *length = raw_size + 1;
636 memcpy (buffer, SDATA (lisp_str_utf8), SBYTES (lisp_str_utf8));
637 buffer[raw_size] = 0;
638
639 return true;
640}
641
642static emacs_value module_make_string (emacs_env *env, const char *str, size_t length)
643{
644 check_main_thread ();
645 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
646 MODULE_HANDLE_SIGNALS;
647 if (length > PTRDIFF_MAX)
648 {
649 module_non_local_exit_signal_1 (env, Qoverflow_error, Qnil);
650 return NULL;
651 }
652 /* Assume STR is utf8 encoded */
653 return lisp_to_value (env, make_string (str, length));
654}
655
656static emacs_value module_make_user_ptr (emacs_env *env,
657 emacs_finalizer_function fin,
658 void *ptr)
659{
660 check_main_thread ();
661 return lisp_to_value (env, make_user_ptr (fin, ptr));
662}
663
664static void* module_get_user_ptr (emacs_env *env, emacs_value uptr)
665{
666 check_main_thread ();
667 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
668 const Lisp_Object lisp = value_to_lisp (uptr);
669 if (! USER_PTRP (lisp))
670 {
671 module_wrong_type (env, Quser_ptr, lisp);
672 return NULL;
673 }
674 return XUSER_PTR (lisp)->p;
675}
676
677static void module_set_user_ptr (emacs_env *env, emacs_value uptr, void *ptr)
678{
679 check_main_thread ();
680 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
681 const Lisp_Object lisp = value_to_lisp (uptr);
682 if (! USER_PTRP (lisp)) module_wrong_type (env, Quser_ptr, lisp);
683 XUSER_PTR (lisp)->p = ptr;
684}
685
686static emacs_finalizer_function module_get_user_finalizer (emacs_env *env, emacs_value uptr)
687{
688 check_main_thread ();
689 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
690 const Lisp_Object lisp = value_to_lisp (uptr);
691 if (! USER_PTRP (lisp))
692 {
693 module_wrong_type (env, Quser_ptr, lisp);
694 return NULL;
695 }
696 return XUSER_PTR (lisp)->finalizer;
697}
698
699static void module_set_user_finalizer (emacs_env *env,
700 emacs_value uptr,
701 emacs_finalizer_function fin)
702{
703 check_main_thread ();
704 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
705 const Lisp_Object lisp = value_to_lisp (uptr);
706 if (! USER_PTRP (lisp)) module_wrong_type (env, Quser_ptr, lisp);
707 XUSER_PTR (lisp)->finalizer = fin;
708}
709
710static void module_vec_set (emacs_env *env,
711 emacs_value vec,
712 size_t i,
713 emacs_value val)
714{
715 check_main_thread ();
716 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
717 if (i > MOST_POSITIVE_FIXNUM)
718 {
719 module_non_local_exit_signal_1 (env, Qoverflow_error, Qnil);
720 return;
721 }
722 Lisp_Object lvec = value_to_lisp (vec);
723 if (! VECTORP (lvec))
724 {
725 module_wrong_type (env, Qvectorp, lvec);
726 return;
727 }
728 if (i >= ASIZE (lvec))
729 {
730 module_args_out_of_range (env, lvec, make_number (i));
731 return;
732 }
733 ASET (lvec, i, value_to_lisp (val));
734}
735
736static emacs_value module_vec_get (emacs_env *env,
737 emacs_value vec,
738 size_t i)
739{
740 /* Type of ASIZE (lvec) is ptrdiff_t, make sure it fits */
741 verify (PTRDIFF_MAX <= SIZE_MAX);
742 check_main_thread ();
743 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
744 if (i > MOST_POSITIVE_FIXNUM)
745 {
746 module_non_local_exit_signal_1 (env, Qoverflow_error, Qnil);
747 return NULL;
748 }
749 Lisp_Object lvec = value_to_lisp (vec);
750 if (! VECTORP (lvec))
751 {
752 module_wrong_type (env, Qvectorp, lvec);
753 return NULL;
754 }
755 /* Prevent error-prone comparison between types of different signedness. */
756 const size_t size = ASIZE (lvec);
757 eassert (size >= 0);
758 if (i >= size)
759 {
760 if (i > MOST_POSITIVE_FIXNUM) i = MOST_POSITIVE_FIXNUM;
761 module_args_out_of_range (env, lvec, make_number (i));
762 return NULL;
763 }
764 return lisp_to_value (env, AREF (lvec, i));
765}
766
767static size_t module_vec_size (emacs_env *env,
768 emacs_value vec)
769{
770 /* Type of ASIZE (lvec) is ptrdiff_t, make sure it fits */
771 verify (PTRDIFF_MAX <= SIZE_MAX);
772 check_main_thread ();
773 eassert (module_non_local_exit_check (env) == emacs_funcall_exit_return);
774 Lisp_Object lvec = value_to_lisp (vec);
775 if (! VECTORP (lvec))
776 {
777 module_wrong_type (env, Qvectorp, lvec);
778 return 0;
779 }
780 eassert (ASIZE (lvec) >= 0);
781 return ASIZE (lvec);
782}
783
784
785/* Subroutines */
786
787DEFUN ("module-load", Fmodule_load, Smodule_load, 1, 1, 0,
788 doc: /* Load module FILE. */)
789 (Lisp_Object file)
790{
791 dynlib_handle_ptr handle;
792 emacs_init_function module_init;
793 void *gpl_sym;
794 Lisp_Object doc_name, args[2];
795
796 CHECK_STRING (file);
797 handle = dynlib_open (SDATA (file));
798 if (!handle)
799 error ("Cannot load file %s: %s", SDATA (file), dynlib_error ());
800
801 gpl_sym = dynlib_sym (handle, "plugin_is_GPL_compatible");
802 if (!gpl_sym)
803 error ("Module %s is not GPL compatible", SDATA (file));
804
805 module_init = (emacs_init_function) dynlib_sym (handle, "emacs_module_init");
806 if (!module_init)
807 error ("Module %s does not have an init function.", SDATA (file));
808
809 struct {
810 struct emacs_runtime pub;
811 struct emacs_runtime_private priv;
812 } runtime = {
813 .pub = {
814 .size = sizeof runtime.pub,
815 .get_environment = module_get_environment,
816 .private_members = &runtime.priv
817 }
818 };
819 initialize_environment (&runtime.priv.environment);
820 int r = module_init (&runtime.pub);
821 finalize_environment (&runtime.priv.environment);
822
823 if (r != 0)
824 {
825 if (r < MOST_NEGATIVE_FIXNUM)
826 xsignal0 (Qunderflow_error);
827 if (r > MOST_POSITIVE_FIXNUM)
828 xsignal0 (Qoverflow_error);
829 xsignal2 (Qmodule_load_failed, file, make_number (r));
830 }
831
832 return Qt;
833}
834
835DEFUN ("module-call", Fmodule_call, Smodule_call, 2, 2, 0,
836 doc: /* Internal function to call a module function.
837ENVOBJ is a save pointer to a module_fun_env structure.
838ARGLIST is a list of arguments passed to SUBRPTR. */)
839 (Lisp_Object envobj, Lisp_Object arglist)
840{
841 const struct module_fun_env *const envptr =
842 (const struct module_fun_env *) XSAVE_POINTER (envobj, 0);
843 const EMACS_INT len = XINT (Flength (arglist));
844 eassert (len >= 0);
845 if (len > MOST_POSITIVE_FIXNUM)
846 xsignal0 (Qoverflow_error);
847 if (len > INT_MAX || len < envptr->min_arity || (envptr->max_arity >= 0 && len > envptr->max_arity))
848 xsignal2 (Qwrong_number_of_arguments, module_format_fun_env (envptr), make_number (len));
849
850 struct env_storage env;
851 initialize_environment (&env);
852
853 emacs_value *args = xzalloc (len * sizeof (*args));
854 int i;
855
856 for (i = 0; i < len; i++)
857 {
858 args[i] = lisp_to_value (&env.pub, XCAR (arglist));
859 if (! args[i]) memory_full (sizeof *args[i]);
860 arglist = XCDR (arglist);
861 }
862
863 emacs_value ret = envptr->subr (&env.pub, len, args, envptr->data);
864 xfree (args);
865
866 switch (env.priv.pending_non_local_exit)
867 {
868 case emacs_funcall_exit_return:
869 finalize_environment (&env);
870 if (ret == NULL) xsignal1 (Qinvalid_module_call, module_format_fun_env (envptr));
871 return value_to_lisp (ret);
872 case emacs_funcall_exit_signal:
873 {
874 const Lisp_Object symbol = value_to_lisp (&env.priv.non_local_exit_symbol);
875 const Lisp_Object data = value_to_lisp (&env.priv.non_local_exit_data);
876 finalize_environment (&env);
877 xsignal (symbol, data);
878 }
879 case emacs_funcall_exit_throw:
880 {
881 const Lisp_Object tag = value_to_lisp (&env.priv.non_local_exit_symbol);
882 const Lisp_Object value = value_to_lisp (&env.priv.non_local_exit_data);
883 finalize_environment (&env);
884 Fthrow (tag, value);
885 }
886 }
887}
888
889
890/* Helper functions */
891
892static void check_main_thread (void)
893{
894#if defined(HAVE_THREADS_H)
895 eassert (thrd_equal (thdr_current (), main_thread);
896#elif defined(HAVE_PTHREAD)
897 eassert (pthread_equal (pthread_self (), main_thread));
898#elif defined(WINDOWSNT)
899 /* CompareObjectHandles would be perfect, but is only available in
900 Windows 10. Also check whether the thread is still running to
901 protect against thread identifier reuse. */
902 eassert (GetCurrentThreadID () == GetThreadID (main_thread) &&
903 WaitForSingleObject (main_thread, 0) == WAIT_TIMEOUT);
904#endif
905}
906
907static void module_non_local_exit_signal_1 (emacs_env *env, Lisp_Object sym, Lisp_Object data)
908{
909 struct emacs_env_private *const p = env->private_members;
910 eassert (p->pending_non_local_exit == emacs_funcall_exit_return);
911 p->pending_non_local_exit = emacs_funcall_exit_signal;
912 p->non_local_exit_symbol.v = sym;
913 p->non_local_exit_data.v = data;
914}
915
916static void module_non_local_exit_throw_1 (emacs_env *env, Lisp_Object tag, Lisp_Object value)
917{
918 struct emacs_env_private *const p = env->private_members;
919 eassert (p->pending_non_local_exit == emacs_funcall_exit_return);
920 p->pending_non_local_exit = emacs_funcall_exit_throw;
921 p->non_local_exit_symbol.v = tag;
922 p->non_local_exit_data.v = value;
923}
924
925static void module_wrong_type (emacs_env *env, Lisp_Object predicate, Lisp_Object value)
926{
927 module_non_local_exit_signal_1 (env, Qwrong_type_argument, list2 (predicate, value));
928}
929
930static void module_out_of_memory (emacs_env *env)
931{
932 // TODO: Reimplement this so it works even if memory-signal-data has been modified.
933 module_non_local_exit_signal_1 (env, XCAR (Vmemory_signal_data), XCDR (Vmemory_signal_data));
934}
935
936static void module_args_out_of_range (emacs_env *env, Lisp_Object a1, Lisp_Object a2)
937{
938 module_non_local_exit_signal_1 (env, Qargs_out_of_range, list2 (a1, a2));
939}
940
941
942/* Value conversion */
943
944static Lisp_Object value_to_lisp (emacs_value v)
945{
946 return v->v;
947}
948
949static emacs_value lisp_to_value (emacs_env *env, Lisp_Object o)
950{
951 struct emacs_env_private *const p = env->private_members;
952 if (p->pending_non_local_exit != emacs_funcall_exit_return) return NULL;
953 return allocate_emacs_value (env, &p->storage, o);
954}
955
956
957/* Memory management */
958
959static void initialize_frame (struct emacs_value_frame *frame)
960{
961 frame->offset = 0;
962 frame->next = NULL;
963}
964
965static void initialize_storage (struct emacs_value_storage *storage)
966{
967 initialize_frame (&storage->initial);
968 storage->current = &storage->initial;
969}
970
971static void finalize_storage (struct emacs_value_storage *storage)
972{
973 struct emacs_value_frame *next = storage->initial.next;
974 while (next != NULL)
975 {
976 struct emacs_value_frame *const current = next;
977 next = current->next;
978 free (current);
979 }
980}
981
982static emacs_value allocate_emacs_value (emacs_env *env, struct emacs_value_storage *storage,
983 Lisp_Object obj)
984{
985 eassert (storage->current);
986 eassert (storage->current->offset < value_frame_size);
987 eassert (! storage->current->next);
988 if (storage->current->offset == value_frame_size - 1)
989 {
990 storage->current->next = malloc (sizeof *storage->current->next);
991 if (! storage->current->next)
992 {
993 module_out_of_memory (env);
994 return NULL;
995 }
996 initialize_frame (storage->current->next);
997 storage->current = storage->current->next;
998 }
999 const emacs_value value = storage->current->objects + storage->current->offset;
1000 value->v = obj;
1001 ++storage->current->offset;
1002 return value;
1003}
1004
1005/* Mark all objects allocated from local environments so that they
1006 don't get garbage-collected. */
1007void mark_modules (void)
1008{
1009 for (Lisp_Object tem = Vmodule_environments; CONSP (tem); tem = XCDR (tem))
1010 {
1011 const struct env_storage *const env = XSAVE_POINTER (tem, 0);
1012 for (const struct emacs_value_frame *frame = &env->priv.storage.initial; frame != NULL; frame = frame->next)
1013 for (size_t i = 0; i < frame->offset; ++i)
1014 mark_object (frame->objects[i].v);
1015 }
1016}
1017
1018
1019/* Environment lifetime management */
1020
1021static void initialize_environment (struct env_storage *env)
1022{
1023 env->priv.pending_non_local_exit = emacs_funcall_exit_return;
1024 initialize_storage (&env->priv.storage);
1025 env->pub.size = sizeof env->pub;
1026 env->pub.private_members = &env->priv;
1027 env->pub.make_global_ref = module_make_global_ref;
1028 env->pub.free_global_ref = module_free_global_ref;
1029 env->pub.non_local_exit_check = module_non_local_exit_check;
1030 env->pub.non_local_exit_clear = module_non_local_exit_clear;
1031 env->pub.non_local_exit_get = module_non_local_exit_get;
1032 env->pub.non_local_exit_signal = module_non_local_exit_signal;
1033 env->pub.non_local_exit_throw = module_non_local_exit_throw;
1034 env->pub.make_function = module_make_function;
1035 env->pub.funcall = module_funcall;
1036 env->pub.intern = module_intern;
1037 env->pub.type_of = module_type_of;
1038 env->pub.is_not_nil = module_is_not_nil;
1039 env->pub.eq = module_eq;
1040 env->pub.extract_integer = module_extract_integer;
1041 env->pub.make_integer = module_make_integer;
1042 env->pub.extract_float = module_extract_float;
1043 env->pub.make_float = module_make_float;
1044 env->pub.copy_string_contents = module_copy_string_contents;
1045 env->pub.make_string = module_make_string;
1046 env->pub.make_user_ptr = module_make_user_ptr;
1047 env->pub.get_user_ptr = module_get_user_ptr;
1048 env->pub.set_user_ptr = module_set_user_ptr;
1049 env->pub.get_user_finalizer = module_get_user_finalizer;
1050 env->pub.set_user_finalizer = module_set_user_finalizer;
1051 env->pub.vec_set = module_vec_set;
1052 env->pub.vec_get = module_vec_get;
1053 env->pub.vec_size = module_vec_size;
1054 Vmodule_environments = Fcons (make_save_ptr (env), Vmodule_environments);
1055}
1056
1057static void finalize_environment (struct env_storage *env)
1058{
1059 finalize_storage (&env->priv.storage);
1060 Vmodule_environments = XCDR (Vmodule_environments);
1061}
1062
1063
1064/* Non-local exit handling */
1065
1066static void module_reset_handlerlist(const int *dummy)
1067{
1068 handlerlist = handlerlist->next;
1069}
1070
1071static void module_handle_signal (emacs_env *const env, const Lisp_Object err)
1072{
1073 module_non_local_exit_signal_1 (env, XCAR (err), XCDR (err));
1074}
1075
1076static void module_handle_throw (emacs_env *const env, const Lisp_Object tag_val)
1077{
1078 module_non_local_exit_throw_1 (env, XCAR (tag_val), XCDR (tag_val));
1079}
1080
1081
1082/* Function environments */
1083
1084static Lisp_Object module_format_fun_env (const struct module_fun_env *const env)
1085{
1086 /* Try to print a function name if possible. */
1087 const char *path, *sym;
1088 if (dynlib_addr (env->subr, &path, &sym))
1089 {
1090 const char *const format = "#<module function %s from %s>";
1091 const int size = snprintf (NULL, 0, format, sym, path);
1092 eassert (size > 0);
1093 char buffer[size + 1];
1094 snprintf (buffer, sizeof buffer, format, sym, path);
1095 return make_unibyte_string (buffer, size);
1096 }
1097 else
1098 {
1099 const char *const format = "#<module function at %p>";
1100 const void *const subr = env->subr;
1101 const int size = snprintf (NULL, 0, format, subr);
1102 eassert (size > 0);
1103 char buffer[size + 1];
1104 snprintf (buffer, sizeof buffer, format, subr);
1105 return make_unibyte_string (buffer, size);
1106 }
1107}
1108
1109
1110/* Segment initializer */
1111
1112void syms_of_module (void)
1113{
1114 DEFSYM (Qmodule_refs_hash, "module-refs-hash");
1115 DEFVAR_LISP ("module-refs-hash", Vmodule_refs_hash,
1116 doc: /* Module global referrence table. */);
1117
1118 Vmodule_refs_hash = make_hash_table (hashtest_eq, make_number (DEFAULT_HASH_SIZE),
1119 make_float (DEFAULT_REHASH_SIZE),
1120 make_float (DEFAULT_REHASH_THRESHOLD),
1121 Qnil);
1122 Funintern (Qmodule_refs_hash, Qnil);
1123
1124 DEFSYM (Qmodule_environments, "module-environments");
1125 DEFVAR_LISP ("module-environments", Vmodule_environments,
1126 doc: /* List of active module environments. */);
1127 Vmodule_environments = Qnil;
1128 /* Unintern `module-environments' because it is only used
1129 internally. */
1130 Funintern (Qmodule_environments, Qnil);
1131
1132 DEFSYM (Qmodule_load_failed, "module-load-failed");
1133 Fput (Qmodule_load_failed, Qerror_conditions,
1134 listn (CONSTYPE_PURE, 2, Qmodule_load_failed, Qerror));
1135 Fput (Qmodule_load_failed, Qerror_message,
1136 build_pure_c_string ("Module load failed"));
1137
1138 DEFSYM (Qinvalid_module_call, "invalid-module-call");
1139 Fput (Qinvalid_module_call, Qerror_conditions,
1140 listn (CONSTYPE_PURE, 2, Qinvalid_module_call, Qerror));
1141 Fput (Qinvalid_module_call, Qerror_message,
1142 build_pure_c_string ("Invalid module call"));
1143
1144 DEFSYM (Qinvalid_arity, "invalid-arity");
1145 Fput (Qinvalid_arity, Qerror_conditions,
1146 listn (CONSTYPE_PURE, 2, Qinvalid_arity, Qerror));
1147 Fput (Qinvalid_arity, Qerror_message,
1148 build_pure_c_string ("Invalid function arity"));
1149
1150 initialize_storage (&global_storage);
1151
1152 /* Unintern `module-refs-hash' because it is internal-only and Lisp
1153 code or modules should not access it. */
1154 Funintern (Qmodule_refs_hash, Qnil);
1155
1156 defsubr (&Smodule_load);
1157
1158 /* Don't call defsubr on `module-call' because that would intern it,
1159 but `module-call' is an internal function that users cannot
1160 meaningfully use. Instead, assign its definition to a private
1161 variable. */
1162 XSETPVECTYPE (&Smodule_call, PVEC_SUBR);
1163 XSETSUBR (module_call_func, &Smodule_call);
1164}
1165
1166/* Unlike syms_of_module, this initializer is called even from an
1167 * initialized (dumped) Emacs. */
1168
1169void module_init (void)
1170{
1171 /* It is not guaranteed that dynamic initializers run in the main thread,
1172 therefore we detect the main thread here. */
1173#if defined(HAVE_THREADS_H)
1174 main_thread = thrd_current ();
1175#elif defined(HAVE_PTHREAD)
1176 main_thread = pthread_self ();
1177#elif defined(WINDOWSNT)
1178 /* GetCurrentProcess returns a pseudohandle, which we have to duplicate. */
1179 if (! DuplicateHandle (GetCurrentProcess(), GetCurrentThread(),
1180 GetCurrentProcess(), &main_thread,
1181 SYNCHRONIZE | THREAD_QUERY_LIMITED_INFORMATION,
1182 FALSE, 0))
1183 emacs_abort ();
1184#endif
1185}