1 /* JitterLisp: interpreter: naïve C version.
2 
3    Copyright (C) 2017, 2018, 2020 Luca Saiu
4    Written by Luca Saiu
5 
6    This file is part of the JitterLisp language implementation, distributed as
7    an example along with Jitter under the same license.
8 
9    Jitter is free software: you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation, either version 3 of the License, or
12    (at your option) any later version.
13 
14    Jitter is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with Jitter.  If not, see <http://www.gnu.org/licenses/>. */
21 
22 
23 #include "jitterlisp-eval-interpreter.h"
24 #include "jitterlisp-eval-vm.h"
25 
26 #include "jitterlisp.h"
27 
28 
29 
30 
31 /* Non-Jittery interpreter: AST evaluation helpers for primitives and closures.
32  * ************************************************************************** */
33 
34 /* Return the evaluation of the given primitive on the given (of course still
35    unevaluated) operand ASTs.  Assume that the rator argument is an encoded
36    primitive, and that rand_asts is a C array of operand_no elements.
37    The noinline attribute is important here: this function invokes a primitive C
38    function in what would syntactically look like a tail context, but passing it
39    a pointer to local storage as argument; that prevents GCC from compiling the
40    call as a sibling call optimization, which in itself is a very minor loss.
41    However having the body of this function inlined in
42    jitterlisp_eval_interpreter_ast , which in its turn also inlines
43    jitterlisp_eval_interpreter_ast_call , would prevent sibling call compilation
44    in the case of *closure* tail calls, thus leaking stack space for tail calls.
45    Tested with a GCC 8 snapshot from early October 2017. */
46 __attribute__ ((noinline))
47 static jitterlisp_object
jitterlisp_eval_interpreter_ast_primitive(jitterlisp_object rator,const jitterlisp_object * rand_asts,size_t rand_no,jitterlisp_object env)48 jitterlisp_eval_interpreter_ast_primitive (jitterlisp_object rator,
49                                            const jitterlisp_object *rand_asts,
50                                            size_t rand_no,
51                                            jitterlisp_object env)
52 {
53   /* FIXME: this, and likely this C function signature as well, will need to
54      change with an exact-pointer-finding GC.
55      Evaluate primitive actuals into a temporary array which is large enough for
56      the actuals of any primitive.  Don't bother initializing the elements we
57      don't actually use.  If the AST has been built correctly the primitive
58      in-arity is correct, so we don't need to check it now at run time. */
59   jitterlisp_object values [JITTERLISP_PRIMITIVE_MAX_IN_ARITY];
60   int i;
61   for (i = 0; i < rand_no; i ++)
62     values [i] = jitterlisp_eval_interpreter_ast (rand_asts [i], env);
63 
64   /* FIXME: does GCC guarantee that this will not be compiled as a sibling
65      call?  It is important that the current stack frame is not popped until
66      the callee returns. */
67   return JITTERLISP_PRIMITIVE_DECODE(rator)->function (values);
68 }
69 
70 /* Return the result of the given call in the given environment.  The operator
71    is an AST, still to evaluate, and the operands are tagged ASTs in the given
72    number; the operator comes first in the array.  If the operator doesn't
73    evaluate to a closure this function errors out cleanly. */
74 static inline jitterlisp_object
jitterlisp_eval_interpreter_ast_call(const jitterlisp_object * rator_and_rand_asts,size_t rator_and_rand_no,jitterlisp_object env)75 jitterlisp_eval_interpreter_ast_call
76    (const jitterlisp_object *rator_and_rand_asts,
77     size_t rator_and_rand_no,
78     jitterlisp_object env)
79 {
80   /* First evaluate the operator. */
81   jitterlisp_object rator_value
82     = jitterlisp_eval_interpreter_ast (rator_and_rand_asts [0], env);
83   if (! JITTERLISP_IS_CLOSURE(rator_value))
84     {
85       jitterlisp_print_error_char_star ("About "); // FIXME: add to the error message
86       jitterlisp_print_error (rator_value);
87       jitterlisp_print_error_char_star (":\n");
88       jitterlisp_error_cloned ("call: non-closure operator");
89     }
90 
91   /* If we arrived here the operator is a closure.  Is it compiled or
92      interpreted? */
93   struct jitterlisp_closure *c = JITTERLISP_CLOSURE_DECODE(rator_value);
94 
95   // FIXME: shall I check the arity *before* evaluating actuals or after, as
96   // the code does now?
97   // In either case compiled code must have the same semantics.  Do whatever
98   // is faster on compiled code.  There is another identical case above
99   // and one more below.
100 
101   /* If the closure is compiled tail-call the helper function and ignore the
102      rest of this. */
103   if (__builtin_expect ((c->kind == jitterlisp_closure_type_compiled),
104                         false))
105     return jitterlisp_call_compiled (rator_value,
106                                      rator_and_rand_asts + 1,
107                                      rator_and_rand_no - 1,
108                                      env);
109 
110   /* The closure is interpreted.  Evaluate actuals binding them to the closure
111      formals, in order, starting from the closure environment.  Unfortunately we
112      have to check the arity at run time, differently from the primitive
113      case. */
114   struct jitterlisp_interpreted_closure *ic = & c->interpreted;
115   jitterlisp_object formals = ic->formals;
116   jitterlisp_object body_env = ic->environment;
117   int i;
118   // FIXME: shall I check the arity *before* evaluating actuals or after, as
119   // the code does now?
120   // In either case compiled code must have the same semantics.  Do whatever
121   // is faster on compiled code.  There are two other identical cases above.
122   for (i = 1; i < rator_and_rand_no; i ++)
123     {
124       if (JITTERLISP_IS_EMPTY_LIST(formals))
125         {
126           jitterlisp_print_error_char_star ("About a call to "); // FIXME: add to the error message
127           jitterlisp_print_error (rator_value);
128           jitterlisp_print_error_char_star (":\n");
129           jitterlisp_error_cloned ("call: too many actuals");
130         }
131 
132       jitterlisp_object rand_value =
133         jitterlisp_eval_interpreter_ast (rator_and_rand_asts [i], env);
134       jitterlisp_object formal = JITTERLISP_EXP_C_A_CAR(formals);
135       body_env = jitterlisp_environment_bind (body_env, formal, rand_value);
136 
137       formals = JITTERLISP_EXP_C_A_CDR(formals);
138     }
139   if (! JITTERLISP_IS_EMPTY_LIST(formals))
140     {
141       jitterlisp_print_error_char_star ("About a call to "); // FIXME: add to the error message
142       jitterlisp_print_error (rator_value);
143       jitterlisp_print_error_char_star (":\n");
144       jitterlisp_error_cloned ("call: not enough actuals");
145     }
146 
147   /* Return the evaluation of the closure body in the extended closure
148      environment. */
149   jitterlisp_object body_ast = ic->body;
150   return jitterlisp_eval_interpreter_ast (body_ast, body_env);
151 }
152 
153 
154 
155 
156 /* Non-Jittery interpreter: AST evaluation.
157  * ************************************************************************** */
158 
159 /* This is the main function for AST interpretation. */
160 jitterlisp_object
jitterlisp_eval_interpreter_ast(jitterlisp_object o,jitterlisp_object env)161 jitterlisp_eval_interpreter_ast (jitterlisp_object o,
162                                  jitterlisp_object env)
163 {
164   /* No need to validate o: if it comes from macroexpansion it's definitely an
165      encoded AST, and its subs are well-formed as well.  No need to validate
166      env for the same reason. */
167   const struct jitterlisp_ast *ast = JITTERLISP_AST_DECODE(o);
168   const jitter_uint sub_no = ast->sub_no;
169   const jitterlisp_object * const subs = ast->subs;
170   switch (ast->case_)
171     {
172     case jitterlisp_ast_case_literal:
173       return subs [0];
174 
175     case jitterlisp_ast_case_variable:
176       return jitterlisp_environment_lookup (env, subs [0]);
177 
178     case jitterlisp_ast_case_define:
179       {
180         jitterlisp_object defined_value
181           = jitterlisp_eval_interpreter_ast (subs [1], env);
182         jitterlisp_define (subs [0], defined_value);
183         return JITTERLISP_NOTHING;
184       }
185 
186     case jitterlisp_ast_case_if:
187       {
188         jitterlisp_object condition_result
189           = jitterlisp_eval_interpreter_ast (subs [0], env);
190         jitterlisp_object branch
191           = (JITTERLISP_IS_FALSE(condition_result)
192              ? subs [2]
193              : subs [1]);
194         return jitterlisp_eval_interpreter_ast (branch, env);
195       }
196 
197     case jitterlisp_ast_case_setb:
198       {
199         jitterlisp_object bound_value
200           = jitterlisp_eval_interpreter_ast (subs [1], env);
201         jitterlisp_environment_setb (env, subs [0], bound_value);
202         return JITTERLISP_NOTHING;
203       }
204 
205     case jitterlisp_ast_case_while:
206       {
207         const jitterlisp_object guard = subs [0];
208         const jitterlisp_object body = subs [1];
209         while (! JITTERLISP_IS_FALSE(jitterlisp_eval_interpreter_ast (guard,
210                                                                       env)))
211           jitterlisp_eval_interpreter_ast (body, env);
212         return JITTERLISP_NOTHING;
213       }
214 
215     case jitterlisp_ast_case_primitive:
216       return jitterlisp_eval_interpreter_ast_primitive (subs [0],
217                                                         subs + 1,
218                                                         sub_no - 1,
219                                                         env);
220 
221     case jitterlisp_ast_case_call:
222       return jitterlisp_eval_interpreter_ast_call (subs, sub_no, env);
223 
224     case jitterlisp_ast_case_lambda:
225       {
226         /* Notice that the lambda formals are already stored as a list of
227            symbols in the AST, differently from other AST cases; that is an
228            optimization to make this closure initialization faster. */
229         jitterlisp_object res;
230         JITTERLISP_CLOSURE_(res, env, subs [0], subs [1]);
231         return res;
232       }
233 
234     case jitterlisp_ast_case_let:
235       {
236         /* Evaluate the bound form in env, then bind its result to the bound
237            variable in the current environment. */
238         jitterlisp_object bound_value
239           = jitterlisp_eval_interpreter_ast (subs [1], env);
240         env = jitterlisp_environment_bind (env, subs [0], bound_value);
241 
242         /* Evaluate the body in the extended environment. */
243         return jitterlisp_eval_interpreter_ast (subs [2], env);
244       }
245 
246     case jitterlisp_ast_case_sequence:
247       jitterlisp_eval_interpreter_ast (subs [0], env);
248       return jitterlisp_eval_interpreter_ast (subs [1], env);
249 
250     default:
251       jitterlisp_print_error_char_star ("About "); // FIXME: add to the error message
252       jitterlisp_print_error (o);
253       jitterlisp_print_error_char_star (":\n");
254       jitterlisp_error_cloned ("eval: invalid or unimplemented AST case");
255     }
256 }
257 
258 
259 
260 
261 /* Non-Jittery interpreter: user API.
262  * ************************************************************************** */
263 
264 jitterlisp_object
jitterlisp_eval_globally_interpreter(jitterlisp_object unexpanded_form)265 jitterlisp_eval_globally_interpreter (jitterlisp_object unexpanded_form)
266 {
267   return jitterlisp_eval_interpreter (unexpanded_form,
268                                       jitterlisp_empty_environment);
269 }
270 
271 jitterlisp_object
jitterlisp_eval_interpreter(jitterlisp_object unexpanded_form,jitterlisp_object env)272 jitterlisp_eval_interpreter (jitterlisp_object unexpanded_form,
273                              jitterlisp_object env)
274 {
275   if (jitterlisp_settings.verbose)
276     {
277       jitterlisp_log_char_star ("Macroexpanding ");
278       jitterlisp_log (unexpanded_form);
279       jitterlisp_log_char_star ("...\n");
280     }
281   jitterlisp_object ast = jitterlisp_macroexpand (unexpanded_form, env);
282   if (jitterlisp_settings.verbose)
283     {
284       jitterlisp_log_char_star ("...into ");
285       jitterlisp_log (ast);
286       jitterlisp_log_char_star ("\n");
287     }
288   return jitterlisp_eval_interpreter_ast (ast, env);
289 }
290 
291 
292 
293 
294 /* Non-Jittery interpreter: apply.
295  * ************************************************************************** */
296 
297 /* Differently from what happens in simple meta-circual interpreters here eval
298    and apply are not mutually recursive: eval doesn't evaluate a procedure call
299    operands into a temporary list, for efficiency reasons.  However this is
300    convenient to have, particularly to be called from Lisp (with additional type
301    checking done by the primimitive function), when the operands are already a
302    list. */
303 
304 /* Unfortunately this is difficult to factor with
305    jitterlisp_eval_interpreter_ast_call without introducing unnecessary
306    allocation, and here performance is important. */
307 jitterlisp_object
jitterlisp_apply_interpreter(jitterlisp_object closure_value,jitterlisp_object operands_as_list)308 jitterlisp_apply_interpreter (jitterlisp_object closure_value,
309                               jitterlisp_object operands_as_list)
310 {
311   /* Decode the closure.  No need to check that it's actually a closure, but
312      here we don't know if it's compiled or interpreted. */
313   struct jitterlisp_closure *c = JITTERLISP_CLOSURE_DECODE(closure_value);
314 
315   /* If the closure is compiled tail-call another function which does the
316      job of calling the VM, checking for in-arity mismatches. */
317   if (__builtin_expect ((c->kind == jitterlisp_closure_type_compiled),
318                         false))
319     return jitterlisp_apply_compiled (closure_value, operands_as_list);
320 
321   /* The closure is interpreted, so it's the interpreter's job to evaluate
322      the call.  Keep fields in automatic C variables. */
323   struct jitterlisp_interpreted_closure *ic = & c->interpreted;
324   jitterlisp_object formals = ic->formals;
325   jitterlisp_object body_env = ic->environment;
326 
327   /* Bind operands to formals in the closure environment. */
328   while (! JITTERLISP_IS_EMPTY_LIST (operands_as_list))
329     {
330       if (JITTERLISP_IS_EMPTY_LIST(formals))
331         {
332           jitterlisp_print_error_char_star ("About a call to "); // FIXME: add to the error message
333           jitterlisp_print_error (closure_value);
334           jitterlisp_print_error_char_star ("\n");
335           jitterlisp_error_cloned ("apply: too many actuals");
336         }
337       /* If this were a safe C function I would check whether operands_as_list
338          is a cons; but this has been already checked out of this function when
339          we get here thru a primitive call. */
340 
341       /* Extend the environment with one formal/operand binding. */
342       jitterlisp_object formal = JITTERLISP_EXP_C_A_CAR(formals);
343       jitterlisp_object rand_value = JITTERLISP_EXP_C_A_CAR(operands_as_list);
344       body_env = jitterlisp_environment_bind (body_env, formal, rand_value);
345 
346       /* Advance the two lists. */
347       formals = JITTERLISP_EXP_C_A_CDR(formals);
348       operands_as_list = JITTERLISP_EXP_C_A_CDR(operands_as_list);
349     }
350   if (! JITTERLISP_IS_EMPTY_LIST(formals))
351     {
352       jitterlisp_print_error_char_star ("About a call to "); // FIXME: add to the error message
353       jitterlisp_print_error (closure_value);
354       jitterlisp_print_error_char_star ("\n");
355       jitterlisp_error_cloned ("apply: not enough actuals");
356     }
357 
358   /* Return the evaluation of the closure body in the extended closure
359      environment. */
360   jitterlisp_object body_ast = ic->body;
361   return jitterlisp_eval_interpreter_ast (body_ast, body_env);
362 }
363 
364 
365 
366 
367 /* Call into interpreted code.
368  * ************************************************************************** */
369 
370 jitterlisp_object
jitterlisp_call_interpreted(const struct jitterlisp_interpreted_closure * ic,jitterlisp_object * actual_values,jitter_uint actual_value_no)371 jitterlisp_call_interpreted (const struct jitterlisp_interpreted_closure *ic,
372                              jitterlisp_object *actual_values,
373                              jitter_uint actual_value_no)
374 {
375   /* Keep fields in automatic C variables. */
376   jitterlisp_object formals = ic->formals;
377   jitterlisp_object body_env = ic->environment;
378 
379   /* Bind operands to formals in the closure environment.  No need for arity
380      checking. */
381   int i;
382   for (i = 0; i < actual_value_no; i ++)
383     {
384       /* Extend the environment with one formal/operand binding. */
385       jitterlisp_object formal = JITTERLISP_EXP_C_A_CAR(formals);
386       jitterlisp_object rand_value = actual_values [i];
387       body_env = jitterlisp_environment_bind (body_env, formal, rand_value);
388 
389       /* Advance the formal list. */
390       formals = JITTERLISP_EXP_C_A_CDR(formals);
391     }
392 
393   /* Return the evaluation of the closure body in the extended closure
394      environment. */
395   jitterlisp_object body_ast = ic->body;
396   return jitterlisp_eval_interpreter_ast (body_ast, body_env);
397 }
398