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