emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Dynamic loading progress


From: Daniel Colascione
Subject: Re: Dynamic loading progress
Date: Sun, 4 Oct 2015 02:10:43 -0700
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.2.0

On 10/04/2015 01:57 AM, Philipp Stephani wrote:
> Daniel Colascione <address@hidden <mailto:address@hidden>> schrieb
> am So., 15. Feb. 2015 um 21:21 Uhr:
> 
>     Here's a broad outline of what I have in mind.
> 
> 
> Thanks, that looks really good. Just a few minor issues that I
> encountered over the last couple of weeks.
>  
> 
>     Thread-local environments
>     -------------------------
> 
>     The `get_environment' member lets us do anything else interesting. As
>     in Java, environments are thread-local. We only support one thread for
>     the moment, so this constraint is easy to enforce. (Just abort if we
>     use an emacs_env off the main thread.)
> 
> 
> Would you really abort, or rather use the error handling functions? We
> should be able to make the error values thread-local so that calling a
> function from the wrong thread would be the equivalent of raising a
> signal, giving the caller a chance to react. Otherwise the burden of
> remembering the correct thread would be on the caller's side.

If we abort, thread mismatch is a programming error, and we can omit
optionally the check for performance. If we fail in some recoverable
way, we have to perform the thread check every time, since it's now
contractual.

>  
> 
>       typedef struct emacs_value_tag* emacs_value;
> 
> 
> I think it's important that this is a pointer to a struct (for type
> safety and size correctness) rather than just an arbitrary type.

A typedef is exactly as typesafe. The question of whether to use a
struct or a typedef is aesthetic. I strongly prefer a typedef, just like
pthreads, and I believe that the people who advocate using structs
directly are simply wrong.


>       typedef emacs_value (*emacs_subr)(
>         emacs_env* env,
>         int nargs,
>         emacs_value args[]);
> 
> 
> Could we give this a void* data parameter for storing arbitrary user
> data? This is common for callbacks in C interfaces and allows C++ users
> to store C++ objects in the pointer. This can be implemented using
> another save pointer.

Yes, of course.

>  
> 
> 
>         emacs_value (*funcall)(
>           emacs_env* env,
>           emacs_value function,
>           int nargs,
>           emacs_value args[]);
> 
> 
> Does function have to be a function object, or can it be a symbol? I.e.
> is the user supposed to call symbol-function first?

It'll have the same semantics as Ffuncall, so we'll be able to call a
symbol or a function.

>         int64_t (*fixnum_to_int)(
>           emacs_env* env,
>           emacs_value value);
> 
>         emacs_value (*make_fixnum)(
>           emacs_env* env,
>           int64_t value);
> 
> 
> What's the behavior of these functions if the source would not fit into
> the result? Undefined behavior, abort(), raising a signal?

I think we can do a range check fairly inexpensively, so just failing is
probably fine. Code that ignores the possibility of failure will just
abort later when it tries to misuse the API. If that's too expensive or
error prone, we can just convert to an unspecified value when out of
range (in practice, lopping off the extra bits).

>     Modules can use make_global_reference to allocate a global reference
>     (i.e., a GC root) for any emacs_value; modules must then free these
>     references explicitly.
> 
>     All routines (except make_global_reference) that return emacs_value
>     values return local references.  It's up to modules to register
>     long-lived references explicitly.
> 
> 
> In which cases would global references be necessary?

Any time you want to hold onto a lisp value outside the dynamic extent
of your emacs_env.

>     Like JNI, we can just declare that it's illegal to call all but a few
>     specially-marked functions (like global reference deregistration) with
>     a pending error.
> 
> 
> What's the behavior if other functions are called? abort()?

abort in check mode; unspecified when optimizing for performance.

>  
> 
>     If Lisp signals or throws, `funcall' returns NULL.
> 
> 
> Hmm, with the current implementation emacs_value is just the same as
> Lisp_Object, i.e. not a real pointer, so NULL doesn't have specific
> semantics. Should it return Qnil instead and force the user to use
> check_error?

I thought we make Qnil equal zero. In any case, I *don't* like the idea
of Lisp_Object being emacs_value. I'd much rather emacs_value be a
pointer to a Lisp_Object, solving this problem completely.

>     3) How exactly do we represent catch/throw values?
> 
> 
> I've thought about this a bit, and I think it would be simplest to add a
> new function env->set_throw and have get_error and check_error return an
> enum { normal, signal, throw }. One could come up with something like
> creating a list (error-kind error-tag error-value), but it looks like
> the module implementation would create such lists only for the module
> code to convert them back, so it's simpler to represent the two kinds of
> non-local exits directly in the interface.

I'm fine with a list; keep in mind that we'll need to handle OOM
somehow, so I'd suggest an opaque type.

>     4) Do we need to use int64_t for integers?
> 
> 
> Maybe just intmax_t and a static check that that is larger than an Elisp
> integer?

Why make the behavior vary depending on what intmax_t is? At least
int64_t is nice and explicit.

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]