1 /* pvm.h - Poke Virtual Machine.  */
2 
3 /* Copyright (C) 2019, 2020, 2021 Jose E. Marchesi */
4 
5 /* This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <config.h>
20 
21 #include <string.h>
22 #include <assert.h>
23 #include <signal.h>
24 #include <stdarg.h>
25 
26 #include "pkl.h"
27 #include "pkl-asm.h"
28 #include "pvm.h"
29 
30 #include "pvm-alloc.h"
31 #include "pvm-program.h"
32 #include "pvm-vm.h"
33 
34 /* The following struct defines a Poke Virtual Machine.  */
35 
36 #define PVM_STATE_RESULT_VALUE(PVM)                     \
37   ((PVM)->pvm_state.pvm_state_backing.result_value)
38 #define PVM_STATE_EXIT_CODE(PVM)                        \
39   ((PVM)->pvm_state.pvm_state_backing.exit_code)
40 #define PVM_STATE_VM(PVM)                               \
41   ((PVM)->pvm_state.pvm_state_backing.vm)
42 #define PVM_STATE_ENV(PVM)                              \
43   ((PVM)->pvm_state.pvm_state_runtime.env)
44 #define PVM_STATE_ENDIAN(PVM)                           \
45   ((PVM)->pvm_state.pvm_state_runtime.endian)
46 #define PVM_STATE_NENC(PVM)                             \
47   ((PVM)->pvm_state.pvm_state_runtime.nenc)
48 #define PVM_STATE_PRETTY_PRINT(PVM)                     \
49   ((PVM)->pvm_state.pvm_state_runtime.pretty_print)
50 #define PVM_STATE_OMODE(PVM)                            \
51   ((PVM)->pvm_state.pvm_state_runtime.omode)
52 #define PVM_STATE_OBASE(PVM)                            \
53   ((PVM)->pvm_state.pvm_state_runtime.obase)
54 #define PVM_STATE_OMAPS(PVM)                            \
55   ((PVM)->pvm_state.pvm_state_runtime.omaps)
56 #define PVM_STATE_ODEPTH(PVM)                           \
57   ((PVM)->pvm_state.pvm_state_runtime.odepth)
58 #define PVM_STATE_OINDENT(PVM)                          \
59   ((PVM)->pvm_state.pvm_state_runtime.oindent)
60 #define PVM_STATE_OACUTOFF(PVM)                         \
61   ((PVM)->pvm_state.pvm_state_runtime.oacutoff)
62 
63 struct pvm
64 {
65   /* Note that the contents of the struct pvm_state are defined in the
66      state-struct-backing-c and state-struct-runtime-c entries in
67      pvm.jitter.  */
68   struct pvm_state pvm_state;
69 
70   /* If not NULL, this is the compiler to be used when the PVM needs
71      to build programs.  */
72   pkl_compiler compiler;
73 };
74 
75 static void
pvm_initialize_state(pvm apvm,struct pvm_state * state)76 pvm_initialize_state (pvm apvm, struct pvm_state *state)
77 {
78   /* Call the Jitter state initializer.  */
79   pvm_state_initialize (state);
80 
81   /* Register GC roots.  */
82   pvm_alloc_add_gc_roots (&state->pvm_state_runtime.env, 1);
83   pvm_alloc_add_gc_roots
84     (state->pvm_state_backing.jitter_stack_stack_backing.memory,
85      state->pvm_state_backing.jitter_stack_stack_backing.element_no);
86   pvm_alloc_add_gc_roots
87     (state->pvm_state_backing.jitter_stack_returnstack_backing.memory,
88      state->pvm_state_backing.jitter_stack_returnstack_backing.element_no);
89   pvm_alloc_add_gc_roots
90     (state->pvm_state_backing.jitter_stack_exceptionstack_backing.memory,
91      state->pvm_state_backing.jitter_stack_exceptionstack_backing.element_no);
92 
93   /* Initialize the global environment.  Note we do this after
94      registering GC roots, since we are allocating memory.  */
95   state->pvm_state_runtime.env = pvm_env_new (0 /* hint */);
96   state->pvm_state_backing.vm = apvm;
97 }
98 
99 pvm
pvm_init(void)100 pvm_init (void)
101 {
102   pvm apvm = calloc (1, sizeof (struct pvm));
103   if (!apvm)
104     return NULL;
105 
106   /* Initialize the memory allocation subsystem.  */
107   pvm_alloc_initialize ();
108 
109   /* Initialize values.  */
110   pvm_val_initialize ();
111 
112   /* Initialize the VM subsystem.  */
113   pvm_initialize ();
114 
115   /* Initialize the VM state.  */
116   pvm_initialize_state (apvm, &apvm->pvm_state);
117 
118   /* Initialize pvm-program.  */
119   pvm_program_init ();
120 
121   return apvm;
122 }
123 
124 extern jitter_print_context jitter_context; /* pvm-program.c */
125 
126 void
pvm_print_profile(pvm apvm)127 pvm_print_profile (pvm apvm)
128 {
129   struct pvm_profile_runtime *p
130     = pvm_state_profile_runtime (&apvm->pvm_state);
131   pvm_profile_runtime_print_unspecialized (jitter_context, p);
132 }
133 
134 void
pvm_reset_profile(pvm apvm)135 pvm_reset_profile (pvm apvm)
136 {
137   struct pvm_profile_runtime *p
138     = pvm_state_profile_runtime (&apvm->pvm_state);
139   pvm_profile_runtime_clear (p);
140 }
141 
142 pvm_env
pvm_get_env(pvm apvm)143 pvm_get_env (pvm apvm)
144 {
145   return PVM_STATE_ENV (apvm);
146 }
147 
148 enum pvm_exit_code
pvm_run(pvm apvm,pvm_program program,pvm_val * res)149 pvm_run (pvm apvm, pvm_program program, pvm_val *res)
150 {
151   sighandler_t previous_handler;
152   pvm_routine routine = pvm_program_routine (program);
153 
154   PVM_STATE_RESULT_VALUE (apvm) = PVM_NULL;
155   PVM_STATE_EXIT_CODE (apvm) = PVM_EXIT_OK;
156 
157   previous_handler = signal (SIGINT, pvm_handle_signal);
158   pvm_execute_routine (routine, &apvm->pvm_state);
159   signal (SIGINT, previous_handler);
160 
161   if (res != NULL)
162     *res = PVM_STATE_RESULT_VALUE (apvm);
163 
164   return PVM_STATE_EXIT_CODE (apvm);
165 }
166 
167 void
pvm_call_closure(pvm vm,pvm_val cls,...)168 pvm_call_closure (pvm vm, pvm_val cls, ...)
169 {
170   pvm_program program;
171   pkl_asm pasm;
172   va_list valist;
173   pvm_val arg;
174 
175   pasm = pkl_asm_new (NULL /* ast */,
176                       pvm_compiler (vm), 1 /* prologue */);
177 
178   /* Push the arguments to the call.  */
179   va_start (valist, cls);
180   while ((arg = va_arg (valist, pvm_val)) != PVM_NULL)
181     pkl_asm_insn (pasm, PKL_INSN_PUSH, arg);
182   va_end (valist);
183 
184   /* Call the closure.  */
185   pkl_asm_insn (pasm, PKL_INSN_PUSH, cls);
186   pkl_asm_insn (pasm, PKL_INSN_CALL);
187 
188   /* Run the program in the poke VM.  */
189   program = pkl_asm_finish (pasm, 1 /* epilogue */);
190   pvm_program_make_executable (program);
191   (void) pvm_run (vm, program, NULL);
192   pvm_destroy_program (program);
193 
194 }
195 
196 void
pvm_shutdown(pvm apvm)197 pvm_shutdown (pvm apvm)
198 {
199   /* Finalize pvm-program.  */
200   pvm_program_fini ();
201 
202   /* Deregister GC roots.  */
203   pvm_alloc_remove_gc_roots (&PVM_STATE_ENV (apvm), 1);
204   pvm_alloc_remove_gc_roots
205     (apvm->pvm_state.pvm_state_backing.jitter_stack_stack_backing.memory,
206      apvm->pvm_state.pvm_state_backing.jitter_stack_stack_backing.element_no);
207   pvm_alloc_remove_gc_roots
208     (apvm->pvm_state.pvm_state_backing.jitter_stack_returnstack_backing.memory,
209      apvm->pvm_state.pvm_state_backing.jitter_stack_returnstack_backing.element_no);
210   pvm_alloc_remove_gc_roots
211     (apvm->pvm_state.pvm_state_backing.jitter_stack_exceptionstack_backing.memory,
212      apvm->pvm_state.pvm_state_backing.jitter_stack_exceptionstack_backing.element_no);
213 
214   /* Finalize values.  */
215   pvm_val_initialize ();
216 
217   /* Finalize the VM state.  */
218   pvm_state_finalize (&apvm->pvm_state);
219 
220   /* Finalize the VM subsystem.  */
221   pvm_finalize ();
222 
223   free (apvm);
224 
225   /* Finalize the memory allocator.  */
226   pvm_alloc_finalize ();
227 }
228 
229 enum ios_endian
pvm_endian(pvm apvm)230 pvm_endian (pvm apvm)
231 {
232   return PVM_STATE_ENDIAN (apvm);
233 }
234 
235 void
pvm_set_endian(pvm apvm,enum ios_endian endian)236 pvm_set_endian (pvm apvm, enum ios_endian endian)
237 {
238   PVM_STATE_ENDIAN (apvm) = endian;
239 }
240 
241 enum ios_nenc
pvm_nenc(pvm apvm)242 pvm_nenc (pvm apvm)
243 {
244   return PVM_STATE_NENC (apvm);
245 }
246 
247 void
pvm_set_nenc(pvm apvm,enum ios_nenc nenc)248 pvm_set_nenc (pvm apvm, enum ios_nenc nenc)
249 {
250   PVM_STATE_NENC (apvm) = nenc;
251 }
252 
253 int
pvm_pretty_print(pvm apvm)254 pvm_pretty_print (pvm apvm)
255 {
256   return PVM_STATE_PRETTY_PRINT (apvm);
257 }
258 
259 void
pvm_set_pretty_print(pvm apvm,int flag)260 pvm_set_pretty_print (pvm apvm, int flag)
261 {
262   PVM_STATE_PRETTY_PRINT (apvm) = flag;
263 }
264 
265 enum pvm_omode
pvm_omode(pvm apvm)266 pvm_omode (pvm apvm)
267 {
268   return PVM_STATE_OMODE (apvm);
269 }
270 
271 void
pvm_set_omode(pvm apvm,enum pvm_omode omode)272 pvm_set_omode (pvm apvm, enum pvm_omode omode)
273 {
274   PVM_STATE_OMODE (apvm) = omode;
275 }
276 
277 int
pvm_obase(pvm apvm)278 pvm_obase (pvm apvm)
279 {
280   return PVM_STATE_OBASE (apvm);
281 }
282 
283 void
pvm_set_obase(pvm apvm,int obase)284 pvm_set_obase (pvm apvm, int obase)
285 {
286   PVM_STATE_OBASE (apvm) = obase;
287 }
288 
289 int
pvm_omaps(pvm apvm)290 pvm_omaps (pvm apvm)
291 {
292   return PVM_STATE_OMAPS (apvm);
293 }
294 
295 void
pvm_set_omaps(pvm apvm,int omaps)296 pvm_set_omaps (pvm apvm, int omaps)
297 {
298   PVM_STATE_OMAPS (apvm) = omaps;
299 }
300 
301 unsigned int
pvm_oindent(pvm apvm)302 pvm_oindent (pvm apvm)
303 {
304   return PVM_STATE_OINDENT (apvm);
305 }
306 
307 void
pvm_set_oindent(pvm apvm,unsigned int oindent)308 pvm_set_oindent (pvm apvm, unsigned int oindent)
309 {
310   PVM_STATE_OINDENT (apvm) = oindent;
311 }
312 
313 unsigned int
pvm_odepth(pvm apvm)314 pvm_odepth (pvm apvm)
315 {
316   return PVM_STATE_ODEPTH (apvm);
317 }
318 
319 void
pvm_set_odepth(pvm apvm,unsigned int odepth)320 pvm_set_odepth (pvm apvm, unsigned int odepth)
321 {
322   PVM_STATE_ODEPTH (apvm) = odepth;
323 }
324 
325 unsigned int
pvm_oacutoff(pvm apvm)326 pvm_oacutoff (pvm apvm)
327 {
328   return PVM_STATE_OACUTOFF (apvm);
329 }
330 
331 void
pvm_set_oacutoff(pvm apvm,unsigned int cutoff)332 pvm_set_oacutoff (pvm apvm, unsigned int cutoff)
333 {
334   PVM_STATE_OACUTOFF (apvm) = cutoff;
335 }
336 
337 pkl_compiler
pvm_compiler(pvm apvm)338 pvm_compiler (pvm apvm)
339 {
340   return apvm->compiler;
341 }
342 
343 void
pvm_set_compiler(pvm apvm,pkl_compiler compiler)344 pvm_set_compiler (pvm apvm, pkl_compiler compiler)
345 {
346   apvm->compiler = compiler;
347 }
348 
349 void
pvm_assert(int expression)350 pvm_assert (int expression)
351 {
352   assert (expression);
353 }
354