1 /*  Abstract Machine for the Small compiler
2  *
3  *  Copyright (c) ITB CompuPhase, 1997-2003
4  *  Portions Copyright (c) Carsten Haitzler, 2004-2010 <raster@rasterman.com>
5  *
6  *  This software is provided "as-is", without any express or implied warranty.
7  *  In no event will the authors be held liable for any damages arising from
8  *  the use of this software.
9  *
10  *  Permission is granted to anyone to use this software for any purpose,
11  *  including commercial applications, and to alter it and redistribute it
12  *  freely, subject to the following restrictions:
13  *
14  *  1.  The origin of this software must not be misrepresented; you must not
15  *      claim that you wrote the original software. If you use this software in
16  *      a product, an acknowledgment in the product documentation would be
17  *      appreciated but is not required.
18  *  2.  Altered source versions must be plainly marked as such, and must not be
19  *      misrepresented as being the original software.
20  *  3.  This notice may not be removed or altered from any source distribution.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26 
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 
31 #include <Eina.h>
32 
33 #include "Embryo.h"
34 #include "embryo_private.h"
35 
36 #define JUMPABS(base, ip) ((Embryo_Cell *)(code + (*ip)))
37 
38 #ifdef WORDS_BIGENDIAN
39 static void _embryo_byte_swap_16(unsigned short *v);
40 static void _embryo_byte_swap_32(unsigned int *v);
41 #endif
42 static int  _embryo_native_call(Embryo_Program *ep, Embryo_Cell idx, Embryo_Cell *result, Embryo_Cell *params);
43 static int  _embryo_func_get(Embryo_Program *ep, int idx, char *funcname);
44 static int  _embryo_var_get(Embryo_Program *ep, int idx, char *varname, Embryo_Cell *ep_addr);
45 static int  _embryo_program_init(Embryo_Program *ep, void *code);
46 
47 #ifdef WORDS_BIGENDIAN
48 static void
_embryo_byte_swap_16(unsigned short * v)49 _embryo_byte_swap_16(unsigned short *v)
50 {
51    unsigned char *s, t;
52 
53    s = (unsigned char *)v;
54    t = s[0]; s[0] = s[1]; s[1] = t;
55 }
56 
57 static void
_embryo_byte_swap_32(unsigned int * v)58 _embryo_byte_swap_32(unsigned int *v)
59 {
60    unsigned char *s, t;
61 
62    s = (unsigned char *)v;
63    t = s[0]; s[0] = s[3]; s[3] = t;
64    t = s[1]; s[1] = s[2]; s[2] = t;
65 }
66 
67 #endif
68 
69 static int
_embryo_native_call(Embryo_Program * ep,Embryo_Cell idx,Embryo_Cell * result,Embryo_Cell * params)70 _embryo_native_call(Embryo_Program *ep, Embryo_Cell idx, Embryo_Cell *result, Embryo_Cell *params)
71 {
72    Embryo_Header *hdr;
73    Embryo_Func_Stub *func_entry;
74    Embryo_Native f;
75 
76    hdr = (Embryo_Header *)ep->base;
77    func_entry = GETENTRY(hdr, natives, idx);
78    if ((func_entry->address <= 0) ||
79        (func_entry->address > ep->native_calls_size))
80      {
81         ep->error = EMBRYO_ERROR_CALLBACK;
82         return ep->error;
83      }
84    f = ep->native_calls[func_entry->address - 1];
85    if (!f)
86      {
87         ep->error = EMBRYO_ERROR_CALLBACK;
88         return ep->error;
89      }
90    ep->error = EMBRYO_ERROR_NONE;
91    *result = f(ep, params);
92    return ep->error;
93 }
94 
95 static int
_embryo_func_get(Embryo_Program * ep,int idx,char * funcname)96 _embryo_func_get(Embryo_Program *ep, int idx, char *funcname)
97 {
98    Embryo_Header *hdr;
99    Embryo_Func_Stub *func;
100 
101    hdr = (Embryo_Header *)ep->code;
102    if (idx >= (Embryo_Cell)NUMENTRIES(hdr, publics, natives))
103      return EMBRYO_ERROR_INDEX;
104 
105    func = GETENTRY(hdr, publics, idx);
106    strcpy(funcname, GETENTRYNAME(hdr, func));
107    return EMBRYO_ERROR_NONE;
108 }
109 
110 static int
_embryo_var_get(Embryo_Program * ep,int idx,char * varname,Embryo_Cell * ep_addr)111 _embryo_var_get(Embryo_Program *ep, int idx, char *varname, Embryo_Cell *ep_addr)
112 {
113    Embryo_Header *hdr;
114    Embryo_Func_Stub *var;
115 
116    hdr = (Embryo_Header *)ep->base;
117    if (idx >= (Embryo_Cell)NUMENTRIES(hdr, pubvars, tags))
118      return EMBRYO_ERROR_INDEX;
119 
120    var = GETENTRY(hdr, pubvars, idx);
121    strcpy(varname, GETENTRYNAME(hdr, var));
122    *ep_addr = var->address;
123    return EMBRYO_ERROR_NONE;
124 }
125 
126 static int
_embryo_program_init(Embryo_Program * ep,void * code)127 _embryo_program_init(Embryo_Program *ep, void *code)
128 {
129    Embryo_Header *hdr;
130 
131    if ((ep->flags & EMBRYO_FLAG_RELOC)) return 1;
132    ep->code = (unsigned char *)code;
133    hdr = (Embryo_Header *)ep->code;
134 #ifdef WORDS_BIGENDIAN
135    embryo_swap_32((unsigned int *)&hdr->size);
136    embryo_swap_16((unsigned short *)&hdr->magic);
137    embryo_swap_16((unsigned short *)&hdr->flags);
138    embryo_swap_16((unsigned short *)&hdr->defsize);
139    embryo_swap_32((unsigned int *)&hdr->cod);
140    embryo_swap_32((unsigned int *)&hdr->dat);
141    embryo_swap_32((unsigned int *)&hdr->hea);
142    embryo_swap_32((unsigned int *)&hdr->stp);
143    embryo_swap_32((unsigned int *)&hdr->cip);
144    embryo_swap_32((unsigned int *)&hdr->publics);
145    embryo_swap_32((unsigned int *)&hdr->natives);
146    embryo_swap_32((unsigned int *)&hdr->libraries);
147    embryo_swap_32((unsigned int *)&hdr->pubvars);
148    embryo_swap_32((unsigned int *)&hdr->tags);
149    embryo_swap_32((unsigned int *)&hdr->nametable);
150 #endif
151 
152    if (hdr->magic != EMBRYO_MAGIC) return 0;
153    if ((hdr->file_version < MIN_FILE_VERSION) ||
154        (hdr->ep_version > CUR_FILE_VERSION)) return 0;
155    if ((hdr->defsize != sizeof(Embryo_Func_Stub)) &&
156        (hdr->defsize != (2 * sizeof(unsigned int)))) return 0;
157    if (hdr->defsize == (2 * sizeof(unsigned int)))
158      {
159         unsigned short *len;
160 
161         len = (unsigned short *)((unsigned char *)ep->code + hdr->nametable);
162 #ifdef WORDS_BIGENDIAN
163         embryo_swap_16((unsigned short *)len);
164 #endif
165         if (*len > sNAMEMAX) return 0;
166      }
167    if (hdr->stp <= 0) return 0;
168    if ((hdr->flags & EMBRYO_FLAG_COMPACT)) return 0;
169 
170 #ifdef WORDS_BIGENDIAN
171    {
172       Embryo_Func_Stub *fs;
173       int i, num;
174 
175       /* also align all addresses in the public function, public variable and */
176       /* public tag tables */
177       fs = GETENTRY(hdr, publics, 0);
178       num = NUMENTRIES(hdr, publics, natives);
179       for (i = 0; i < num; i++)
180         {
181            embryo_swap_32(&(fs->address));
182            fs = (Embryo_Func_Stub *)((unsigned char *)fs + hdr->defsize);
183         }
184 
185       fs = GETENTRY(hdr, pubvars, 0);
186       num = NUMENTRIES(hdr, pubvars, tags);
187       for (i = 0; i < num; i++)
188         {
189            embryo_swap_32(&(fs->address));
190            fs = (Embryo_Func_Stub *)((unsigned char *)fs + hdr->defsize);
191         }
192 
193       fs = GETENTRY(hdr, tags, 0);
194       num = NUMENTRIES(hdr, tags, nametable);
195       for (i = 0; i < num; i++)
196         {
197            embryo_swap_32(&(fs->address));
198            fs = (Embryo_Func_Stub *)((unsigned char *)fs + hdr->defsize);
199         }
200    }
201 #endif
202    ep->flags = EMBRYO_FLAG_RELOC;
203 
204 #ifdef WORDS_BIGENDIAN
205 /* until we do more... this is only used for bigendian */
206    {
207       Embryo_Cell cip, code_size, cip_end;
208       Embryo_Cell *code;
209 
210       code_size = hdr->dat - hdr->cod;
211       code = (Embryo_Cell *)((unsigned char *)ep->code + (int)hdr->cod);
212       cip_end = code_size / sizeof(Embryo_Cell);
213       for (cip = 0; cip < cip_end; cip++)
214         {
215 /* move this here - later we probably want something that verifies opcodes
216  * are valid and ok...
217  */
218 #ifdef WORDS_BIGENDIAN
219            embryo_swap_32(&(code[cip]));
220 #endif
221         }
222    }
223 #endif
224 
225    /* init native api for handling floating point - default in embryo */
226    _embryo_args_init(ep);
227    _embryo_fp_init(ep);
228    _embryo_rand_init(ep);
229    _embryo_str_init(ep);
230    _embryo_time_init(ep);
231    return 1;
232 }
233 
234 /*** EXPORTED CALLS ***/
235 
236 EAPI Embryo_Program *
embryo_program_new(void * data,int size)237 embryo_program_new(void *data, int size)
238 {
239    Embryo_Program *ep;
240    void *code_data;
241 
242    if (size < (int)sizeof(Embryo_Header)) return NULL;
243 
244    ep = calloc(1, sizeof(Embryo_Program));
245    if (!ep) return NULL;
246 
247    code_data = malloc(size);
248    if (!code_data)
249      {
250         free(ep);
251         return NULL;
252      }
253    memcpy(code_data, data, size);
254    if (_embryo_program_init(ep, code_data)) return ep;
255    free(code_data);
256    free(ep);
257    return NULL;
258 }
259 
260 EAPI Embryo_Program *
embryo_program_const_new(void * data,int size)261 embryo_program_const_new(void *data, int size)
262 {
263    Embryo_Program *ep;
264 
265    if (size < (int)sizeof(Embryo_Header)) return NULL;
266 
267    ep = calloc(1, sizeof(Embryo_Program));
268    if (!ep) return NULL;
269 
270    if (_embryo_program_init(ep, data))
271      {
272         ep->dont_free_code = 1;
273         return ep;
274      }
275    free(ep);
276    return NULL;
277 }
278 
279 EAPI Embryo_Program *
embryo_program_load(const char * file)280 embryo_program_load(const char *file)
281 {
282    Embryo_Program *ep;
283    Embryo_Header hdr;
284    FILE *f;
285    void *program = NULL;
286    int program_size = 0;
287 
288    f = fopen(file, "rb");
289    if (!f) return NULL;
290    fseek(f, 0, SEEK_END);
291    program_size = ftell(f);
292    fseek(f, 0L, SEEK_SET);
293    if (program_size < (int)sizeof(Embryo_Header))
294      {
295         fclose(f);
296         return NULL;
297      }
298    if (fread(&hdr, sizeof(Embryo_Header), 1, f) != 1)
299      {
300         fclose(f);
301         return NULL;
302      }
303    fseek(f, 0L, SEEK_SET);
304 #ifdef WORDS_BIGENDIAN
305    embryo_swap_32((unsigned int *)(&hdr.size));
306 #endif
307    if ((int)hdr.size < program_size) program_size = hdr.size;
308    program = malloc(program_size);
309    if (!program)
310      {
311         fclose(f);
312         return NULL;
313      }
314    if (fread(program, program_size, 1, f) != 1)
315      {
316         free(program);
317         fclose(f);
318         return NULL;
319      }
320    ep = embryo_program_new(program, program_size);
321    free(program);
322    fclose(f);
323    return ep;
324 }
325 
326 EAPI void
embryo_program_free(Embryo_Program * ep)327 embryo_program_free(Embryo_Program *ep)
328 {
329    int i;
330 
331    if (ep->base) free(ep->base);
332    if ((!ep->dont_free_code) && (ep->code)) free(ep->code);
333    if (ep->native_calls) free(ep->native_calls);
334    for (i = 0; i < ep->params_size; i++)
335      {
336         if (ep->params[i].string) free(ep->params[i].string);
337         if (ep->params[i].cell_array) free(ep->params[i].cell_array);
338      }
339    if (ep->params) free(ep->params);
340    free(ep);
341 }
342 
343 EAPI void
embryo_program_native_call_add(Embryo_Program * ep,const char * name,Embryo_Cell (* func)(Embryo_Program * ep,Embryo_Cell * params))344 embryo_program_native_call_add(Embryo_Program *ep, const char *name, Embryo_Cell (*func)(Embryo_Program *ep, Embryo_Cell *params))
345 {
346    Embryo_Func_Stub *func_entry;
347    Embryo_Header *hdr;
348    int i, num;
349 
350    if ((!ep) || (!name) || (!func)) return;
351    if (strlen(name) > sNAMEMAX) return;
352 
353    hdr = (Embryo_Header *)ep->code;
354    if (hdr->defsize < 1) return;
355    num = NUMENTRIES(hdr, natives, libraries);
356    if (num <= 0) return;
357 
358    ep->native_calls_size++;
359    if (ep->native_calls_size > ep->native_calls_alloc)
360      {
361         Embryo_Native *calls;
362 
363         ep->native_calls_alloc += 32;
364         calls = realloc(ep->native_calls,
365                         ep->native_calls_alloc * sizeof(Embryo_Native));
366         if (!calls)
367           {
368              ep->native_calls_size--;
369              ep->native_calls_alloc -= 32;
370              return;
371           }
372         ep->native_calls = calls;
373      }
374    ep->native_calls[ep->native_calls_size - 1] = func;
375 
376    func_entry = GETENTRY(hdr, natives, 0);
377    for (i = 0; i < num; i++)
378      {
379         if (func_entry->address == 0)
380           {
381              char *entry_name;
382 
383              entry_name = GETENTRYNAME(hdr, func_entry);
384              if ((entry_name) && (!strcmp(entry_name, name)))
385                {
386                   func_entry->address = ep->native_calls_size;
387                   /* FIXME: embryo_cc is putting in multiple native */
388                   /* function call entries - so we need to fill in all */
389                   /* of them!!! */
390                   /* return; */
391                }
392           }
393         func_entry =
394           (Embryo_Func_Stub *)((unsigned char *)func_entry + hdr->defsize);
395      }
396 }
397 
398 EAPI void
embryo_program_vm_reset(Embryo_Program * ep)399 embryo_program_vm_reset(Embryo_Program *ep)
400 {
401    Embryo_Header *hdr;
402 
403    if ((!ep) || (!ep->base)) return;
404    hdr = (Embryo_Header *)ep->code;
405    memcpy(ep->base, hdr, hdr->size);
406    *(Embryo_Cell *)(ep->base + (int)hdr->stp - sizeof(Embryo_Cell)) = 0;
407 
408    ep->hlw = hdr->hea - hdr->dat; /* stack and heap relative to data segment */
409    ep->stp = hdr->stp - hdr->dat - sizeof(Embryo_Cell);
410    ep->hea = ep->hlw;
411    ep->stk = ep->stp;
412 }
413 
414 EAPI void
embryo_program_vm_push(Embryo_Program * ep)415 embryo_program_vm_push(Embryo_Program *ep)
416 {
417    Embryo_Header *hdr;
418 
419    if (!ep) return;
420    ep->pushes++;
421    if (ep->pushes > 1)
422      {
423         embryo_program_vm_reset(ep);
424         return;
425      }
426    hdr = (Embryo_Header *)ep->code;
427    ep->base = calloc(1, hdr->stp);
428    if (!ep->base)
429      {
430         ep->pushes = 0;
431         return;
432      }
433    embryo_program_vm_reset(ep);
434 }
435 
436 EAPI void
embryo_program_vm_pop(Embryo_Program * ep)437 embryo_program_vm_pop(Embryo_Program *ep)
438 {
439    if ((!ep) || (!ep->base)) return;
440    ep->pushes--;
441    if (ep->pushes >= 1) return;
442    free(ep->base);
443    ep->base = NULL;
444 }
445 
446 EAPI void
embryo_swap_16(unsigned short * v EINA_UNUSED)447 embryo_swap_16(unsigned short *v
448 #ifndef WORDS_BIGENDIAN
449                EINA_UNUSED
450 #endif
451                )
452 {
453 #ifdef WORDS_BIGENDIAN
454    _embryo_byte_swap_16(v);
455 #endif
456 }
457 
458 EAPI void
embryo_swap_32(unsigned int * v EINA_UNUSED)459 embryo_swap_32(unsigned int *v
460 #ifndef WORDS_BIGENDIAN
461                EINA_UNUSED
462 #endif
463                )
464 {
465 #ifdef WORDS_BIGENDIAN
466    _embryo_byte_swap_32(v);
467 #endif
468 }
469 
470 EAPI Embryo_Function
embryo_program_function_find(Embryo_Program * ep,const char * name)471 embryo_program_function_find(Embryo_Program *ep, const char *name)
472 {
473    int first, last, mid, result;
474    char pname[sNAMEMAX + 1];
475    Embryo_Header *hdr;
476 
477    if (!ep) return EMBRYO_FUNCTION_NONE;
478    hdr = (Embryo_Header *)ep->code;
479    last = NUMENTRIES(hdr, publics, natives) - 1;
480    first = 0;
481    /* binary search */
482    while (first <= last)
483      {
484         mid = (first + last) / 2;
485         if (_embryo_func_get(ep, mid, pname) == EMBRYO_ERROR_NONE)
486           result = strcmp(pname, name);
487         else
488           return EMBRYO_FUNCTION_NONE;
489 /*	  result = -1;*/
490         if (result > 0) last = mid - 1;
491         else if (result < 0)
492           first = mid + 1;
493         else return mid;
494      }
495    return EMBRYO_FUNCTION_NONE;
496 }
497 
498 EAPI Embryo_Cell
embryo_program_variable_find(Embryo_Program * ep,const char * name)499 embryo_program_variable_find(Embryo_Program *ep, const char *name)
500 {
501    int first, last, mid, result;
502    char pname[sNAMEMAX + 1];
503    Embryo_Cell paddr;
504    Embryo_Header *hdr;
505 
506    if (!ep) return EMBRYO_CELL_NONE;
507    if (!ep->base) return EMBRYO_CELL_NONE;
508    hdr = (Embryo_Header *)ep->base;
509    last = NUMENTRIES(hdr, pubvars, tags) - 1;
510    first = 0;
511    /* binary search */
512    while (first <= last)
513      {
514         mid = (first + last) / 2;
515         if (_embryo_var_get(ep, mid, pname, &paddr) == EMBRYO_ERROR_NONE)
516           result = strcmp(pname, name);
517         else
518           return EMBRYO_CELL_NONE;
519 /*	  result = -1;*/
520         if (result > 0) last = mid - 1;
521         else if (result < 0)
522           first = mid + 1;
523         else return paddr;
524      }
525    return EMBRYO_CELL_NONE;
526 }
527 
528 EAPI int
embryo_program_variable_count_get(Embryo_Program * ep)529 embryo_program_variable_count_get(Embryo_Program *ep)
530 {
531    Embryo_Header *hdr;
532 
533    if (!ep) return 0;
534    if (!ep->base) return 0;
535    hdr = (Embryo_Header *)ep->base;
536    return NUMENTRIES(hdr, pubvars, tags);
537 }
538 
539 EAPI Embryo_Cell
embryo_program_variable_get(Embryo_Program * ep,int num)540 embryo_program_variable_get(Embryo_Program *ep, int num)
541 {
542    Embryo_Cell paddr;
543    char pname[sNAMEMAX + 1];
544 
545    if (!ep) return EMBRYO_CELL_NONE;
546    if (!ep->base) return EMBRYO_CELL_NONE;
547    if (_embryo_var_get(ep, num, pname, &paddr) == EMBRYO_ERROR_NONE)
548      return paddr;
549    return EMBRYO_CELL_NONE;
550 }
551 
552 EAPI void
embryo_program_error_set(Embryo_Program * ep,Embryo_Error error)553 embryo_program_error_set(Embryo_Program *ep, Embryo_Error error)
554 {
555    if (!ep) return;
556    ep->error = error;
557 }
558 
559 EAPI Embryo_Error
embryo_program_error_get(Embryo_Program * ep)560 embryo_program_error_get(Embryo_Program *ep)
561 {
562    if (!ep) return EMBRYO_ERROR_NONE;
563    return ep->error;
564 }
565 
566 EAPI void
embryo_program_data_set(Embryo_Program * ep,void * data)567 embryo_program_data_set(Embryo_Program *ep, void *data)
568 {
569    if (!ep) return;
570    ep->data = data;
571 }
572 
573 EAPI void *
embryo_program_data_get(Embryo_Program * ep)574 embryo_program_data_get(Embryo_Program *ep)
575 {
576    if (!ep) return NULL;
577    return ep->data;
578 }
579 
580 EAPI const char *
embryo_error_string_get(Embryo_Error error)581 embryo_error_string_get(Embryo_Error error)
582 {
583    const char *messages[] =
584    {
585       /* EMBRYO_ERROR_NONE      */
586       "(none)",
587       /* EMBRYO_ERROR_EXIT      */ "Forced exit",
588       /* EMBRYO_ERROR_ASSERT    */ "Assertion failed",
589       /* EMBRYO_ERROR_STACKERR  */ "Stack/heap collision (insufficient stack size)",
590       /* EMBRYO_ERROR_BOUNDS    */ "Array index out of bounds",
591       /* EMBRYO_ERROR_MEMACCESS */ "Invalid memory access",
592       /* EMBRYO_ERROR_INVINSTR  */ "Invalid instruction",
593       /* EMBRYO_ERROR_STACKLOW  */ "Stack underflow",
594       /* EMBRYO_ERROR_HEAPLOW   */ "Heap underflow",
595       /* EMBRYO_ERROR_CALLBACK  */ "No (valid) native function callback",
596       /* EMBRYO_ERROR_NATIVE    */ "Native function failed",
597       /* EMBRYO_ERROR_DIVIDE    */ "Divide by zero",
598       /* EMBRYO_ERROR_SLEEP     */ "(sleep mode)",
599       /* 13 */ "(reserved)",
600       /* 14 */ "(reserved)",
601       /* 15 */ "(reserved)",
602       /* EMBRYO_ERROR_MEMORY    */ "Out of memory",
603       /* EMBRYO_ERROR_FORMAT    */ "Invalid/unsupported P-code file format",
604       /* EMBRYO_ERROR_VERSION   */ "File is for a newer version of the Embryo_Program",
605       /* EMBRYO_ERROR_NOTFOUND  */ "Native/Public function is not found",
606       /* EMBRYO_ERROR_INDEX     */ "Invalid index parameter (bad entry point)",
607       /* EMBRYO_ERROR_DEBUG     */ "Debugger cannot run",
608       /* EMBRYO_ERROR_INIT      */ "Embryo_Program not initialized (or doubly initialized)",
609       /* EMBRYO_ERROR_USERDATA  */ "Unable to set user data field (table full)",
610       /* EMBRYO_ERROR_INIT_JIT  */ "Cannot initialize the JIT",
611       /* EMBRYO_ERROR_PARAMS    */ "Parameter error",
612    };
613    if (((int)error < 0) ||
614        ((int)error >= (int)(sizeof(messages) / sizeof(messages[0]))))
615      return (const char *)"(unknown)";
616    return messages[error];
617 }
618 
619 EAPI int
embryo_data_string_length_get(Embryo_Program * ep,Embryo_Cell * str_cell)620 embryo_data_string_length_get(Embryo_Program *ep, Embryo_Cell *str_cell)
621 {
622    int len;
623    Embryo_Header *hdr;
624 
625    if ((!ep) || (!ep->base)) return 0;
626    hdr = (Embryo_Header *)ep->base;
627    if ((!str_cell) ||
628        ((void *)str_cell >= (void *)(ep->base + hdr->stp)) ||
629        ((void *)str_cell < (void *)ep->base))
630      return 0;
631    for (len = 0; str_cell[len] != 0; len++) ;
632    return len;
633 }
634 
635 EAPI void
embryo_data_string_get(Embryo_Program * ep,Embryo_Cell * str_cell,char * dst)636 embryo_data_string_get(Embryo_Program *ep, Embryo_Cell *str_cell, char *dst)
637 {
638    int i;
639    Embryo_Header *hdr;
640 
641    if (!dst) return;
642    if ((!ep) || (!ep->base))
643      {
644         dst[0] = 0;
645         return;
646      }
647    hdr = (Embryo_Header *)ep->base;
648    if ((!str_cell) ||
649        ((void *)str_cell >= (void *)(ep->base + hdr->stp)) ||
650        ((void *)str_cell < (void *)ep->base))
651      {
652         dst[0] = 0;
653         return;
654      }
655    for (i = 0; str_cell[i] != 0; i++)
656      {
657 #ifdef WORDS_BIGENDIAN
658         {
659            Embryo_Cell tmp;
660 
661            tmp = str_cell[i];
662            _embryo_byte_swap_32(&tmp);
663            dst[i] = tmp;
664         }
665 #else
666         dst[i] = str_cell[i];
667 #endif
668      }
669    dst[i] = 0;
670 }
671 
672 EAPI void
embryo_data_string_set(Embryo_Program * ep,const char * src,Embryo_Cell * str_cell)673 embryo_data_string_set(Embryo_Program *ep, const char *src, Embryo_Cell *str_cell)
674 {
675    int i;
676    Embryo_Header *hdr;
677 
678    if (!ep) return;
679    if (!ep->base) return;
680    hdr = (Embryo_Header *)ep->base;
681    if ((!str_cell) ||
682        ((void *)str_cell >= (void *)(ep->base + hdr->stp)) ||
683        ((void *)str_cell < (void *)ep->base))
684      return;
685    if (!src)
686      {
687         str_cell[0] = 0;
688         return;
689      }
690    for (i = 0; src[i] != 0; i++)
691      {
692         if ((void *)(&(str_cell[i])) >= (void *)(ep->base + hdr->stp)) return;
693         else if ((void *)(&(str_cell[i])) == (void *)(ep->base + hdr->stp - 1))
694           {
695              str_cell[i] = 0;
696              return;
697           }
698 #ifdef WORDS_BIGENDIAN
699         {
700            Embryo_Cell tmp;
701 
702            tmp = src[i];
703            _embryo_byte_swap_32(&tmp);
704            str_cell[i] = tmp;
705         }
706 #else
707         str_cell[i] = src[i];
708 #endif
709      }
710    str_cell[i] = 0;
711 }
712 
713 EAPI Embryo_Cell *
embryo_data_address_get(Embryo_Program * ep,Embryo_Cell addr)714 embryo_data_address_get(Embryo_Program *ep, Embryo_Cell addr)
715 {
716    Embryo_Header *hdr;
717    unsigned char *data;
718 
719    if ((!ep) || (!ep->base)) return NULL;
720    hdr = (Embryo_Header *)ep->base;
721    data = ep->base + (int)hdr->dat;
722    if ((addr < 0) || (addr >= hdr->stp)) return NULL;
723    return (Embryo_Cell *)(data + (int)addr);
724 }
725 
726 EAPI Embryo_Cell
embryo_data_heap_push(Embryo_Program * ep,int cells)727 embryo_data_heap_push(Embryo_Program *ep, int cells)
728 {
729    Embryo_Cell addr;
730 
731    if ((!ep) || (!ep->base)) return EMBRYO_CELL_NONE;
732    if (ep->stk - ep->hea - (cells * sizeof(Embryo_Cell)) < STKMARGIN)
733      return EMBRYO_CELL_NONE;
734    addr = ep->hea;
735    ep->hea += (cells * sizeof(Embryo_Cell));
736    return addr;
737 }
738 
739 EAPI void
embryo_data_heap_pop(Embryo_Program * ep,Embryo_Cell down_to)740 embryo_data_heap_pop(Embryo_Program *ep, Embryo_Cell down_to)
741 {
742    if (!ep) return;
743    if (down_to < 0) down_to = 0;
744    if (ep->hea > down_to) ep->hea = down_to;
745 }
746 
747 EAPI int
embryo_program_recursion_get(Embryo_Program * ep)748 embryo_program_recursion_get(Embryo_Program *ep)
749 {
750    return ep->run_count;
751 }
752 
753 #ifdef __GNUC__
754 #if 1
755 #define EMBRYO_EXEC_JUMPTABLE
756 #endif
757 #endif
758 
759 /* jump table optimization - only works for gcc though */
760 #ifdef EMBRYO_EXEC_JUMPTABLE
761 #define SWITCH(x) while (1) { goto *switchtable[x];
762 #define SWITCHEND break; }
763 #define CASE(x)   SWITCHTABLE_##x :
764 #define BREAK     break;
765 #else
766 #define SWITCH(x) switch (x) {
767 #define SWITCHEND }
768 
769 #define CASE(x)   case x:
770 #define BREAK     break
771 #endif
772 
773 EAPI Embryo_Status
embryo_program_run(Embryo_Program * ep,Embryo_Function fn)774 embryo_program_run(Embryo_Program *ep, Embryo_Function fn)
775 {
776    Embryo_Header *hdr;
777    Embryo_Func_Stub *func;
778    unsigned char *code, *data;
779    Embryo_Cell pri, alt, stk, frm, hea, hea_start;
780    Embryo_Cell reset_stk, reset_hea, *cip;
781    Embryo_UCell codesize;
782    int i;
783    unsigned char op;
784    Embryo_Cell offs;
785    int num;
786    int max_run_cycles;
787    int cycle_count;
788 #ifdef EMBRYO_EXEC_JUMPTABLE
789    /* we limit the jumptable to 256 elements. why? above we forced "op" to be
790     * a unsigned char - that means 256 max values. we limit opcode overflow
791     * here, so eliminating crashes on table lookups with bad/corrupt bytecode.
792     * no need to atuall do compares, branches etc. the datatype does the work
793     * for us. so that means EXCESS elements are all declared as OP_NONE to
794     * keep them innocuous.
795     */
796    static const void *switchtable[256] =
797    {
798       && SWITCHTABLE_EMBRYO_OP_NONE,
799       && SWITCHTABLE_EMBRYO_OP_LOAD_PRI,
800       && SWITCHTABLE_EMBRYO_OP_LOAD_ALT,
801       && SWITCHTABLE_EMBRYO_OP_LOAD_S_PRI,
802       && SWITCHTABLE_EMBRYO_OP_LOAD_S_ALT,
803       && SWITCHTABLE_EMBRYO_OP_LREF_PRI,
804       && SWITCHTABLE_EMBRYO_OP_LREF_ALT,
805       && SWITCHTABLE_EMBRYO_OP_LREF_S_PRI,
806       && SWITCHTABLE_EMBRYO_OP_LREF_S_ALT,
807       && SWITCHTABLE_EMBRYO_OP_LOAD_I,
808       && SWITCHTABLE_EMBRYO_OP_LODB_I,
809       && SWITCHTABLE_EMBRYO_OP_CONST_PRI,
810       && SWITCHTABLE_EMBRYO_OP_CONST_ALT,
811       && SWITCHTABLE_EMBRYO_OP_ADDR_PRI,
812       && SWITCHTABLE_EMBRYO_OP_ADDR_ALT,
813       && SWITCHTABLE_EMBRYO_OP_STOR_PRI,
814       && SWITCHTABLE_EMBRYO_OP_STOR_ALT,
815       && SWITCHTABLE_EMBRYO_OP_STOR_S_PRI,
816       && SWITCHTABLE_EMBRYO_OP_STOR_S_ALT,
817       && SWITCHTABLE_EMBRYO_OP_SREF_PRI,
818       && SWITCHTABLE_EMBRYO_OP_SREF_ALT,
819       && SWITCHTABLE_EMBRYO_OP_SREF_S_PRI,
820       && SWITCHTABLE_EMBRYO_OP_SREF_S_ALT,
821       && SWITCHTABLE_EMBRYO_OP_STOR_I,
822       && SWITCHTABLE_EMBRYO_OP_STRB_I,
823       && SWITCHTABLE_EMBRYO_OP_LIDX,
824       && SWITCHTABLE_EMBRYO_OP_LIDX_B,
825       && SWITCHTABLE_EMBRYO_OP_IDXADDR,
826       && SWITCHTABLE_EMBRYO_OP_IDXADDR_B,
827       && SWITCHTABLE_EMBRYO_OP_ALIGN_PRI,
828       && SWITCHTABLE_EMBRYO_OP_ALIGN_ALT,
829       && SWITCHTABLE_EMBRYO_OP_LCTRL,
830       && SWITCHTABLE_EMBRYO_OP_SCTRL,
831       && SWITCHTABLE_EMBRYO_OP_MOVE_PRI,
832       && SWITCHTABLE_EMBRYO_OP_MOVE_ALT,
833       && SWITCHTABLE_EMBRYO_OP_XCHG,
834       && SWITCHTABLE_EMBRYO_OP_PUSH_PRI,
835       && SWITCHTABLE_EMBRYO_OP_PUSH_ALT,
836       && SWITCHTABLE_EMBRYO_OP_PUSH_R,
837       && SWITCHTABLE_EMBRYO_OP_PUSH_C,
838       && SWITCHTABLE_EMBRYO_OP_PUSH,
839       && SWITCHTABLE_EMBRYO_OP_PUSH_S,
840       && SWITCHTABLE_EMBRYO_OP_POP_PRI,
841       && SWITCHTABLE_EMBRYO_OP_POP_ALT,
842       && SWITCHTABLE_EMBRYO_OP_STACK,
843       && SWITCHTABLE_EMBRYO_OP_HEAP,
844       && SWITCHTABLE_EMBRYO_OP_PROC,
845       && SWITCHTABLE_EMBRYO_OP_RET,
846       && SWITCHTABLE_EMBRYO_OP_RETN,
847       && SWITCHTABLE_EMBRYO_OP_CALL,
848       && SWITCHTABLE_EMBRYO_OP_CALL_PRI,
849       && SWITCHTABLE_EMBRYO_OP_JUMP,
850       && SWITCHTABLE_EMBRYO_OP_JREL,
851       && SWITCHTABLE_EMBRYO_OP_JZER,
852       && SWITCHTABLE_EMBRYO_OP_JNZ,
853       && SWITCHTABLE_EMBRYO_OP_JEQ,
854       && SWITCHTABLE_EMBRYO_OP_JNEQ,
855       && SWITCHTABLE_EMBRYO_OP_JLESS,
856       && SWITCHTABLE_EMBRYO_OP_JLEQ,
857       && SWITCHTABLE_EMBRYO_OP_JGRTR,
858       && SWITCHTABLE_EMBRYO_OP_JGEQ,
859       && SWITCHTABLE_EMBRYO_OP_JSLESS,
860       && SWITCHTABLE_EMBRYO_OP_JSLEQ,
861       && SWITCHTABLE_EMBRYO_OP_JSGRTR,
862       && SWITCHTABLE_EMBRYO_OP_JSGEQ,
863       && SWITCHTABLE_EMBRYO_OP_SHL,
864       && SWITCHTABLE_EMBRYO_OP_SHR,
865       && SWITCHTABLE_EMBRYO_OP_SSHR,
866       && SWITCHTABLE_EMBRYO_OP_SHL_C_PRI,
867       && SWITCHTABLE_EMBRYO_OP_SHL_C_ALT,
868       && SWITCHTABLE_EMBRYO_OP_SHR_C_PRI,
869       && SWITCHTABLE_EMBRYO_OP_SHR_C_ALT,
870       && SWITCHTABLE_EMBRYO_OP_SMUL,
871       && SWITCHTABLE_EMBRYO_OP_SDIV,
872       && SWITCHTABLE_EMBRYO_OP_SDIV_ALT,
873       && SWITCHTABLE_EMBRYO_OP_UMUL,
874       && SWITCHTABLE_EMBRYO_OP_UDIV,
875       && SWITCHTABLE_EMBRYO_OP_UDIV_ALT,
876       && SWITCHTABLE_EMBRYO_OP_ADD,
877       && SWITCHTABLE_EMBRYO_OP_SUB,
878       && SWITCHTABLE_EMBRYO_OP_SUB_ALT,
879       && SWITCHTABLE_EMBRYO_OP_AND,
880       && SWITCHTABLE_EMBRYO_OP_OR,
881       && SWITCHTABLE_EMBRYO_OP_XOR,
882       && SWITCHTABLE_EMBRYO_OP_NOT,
883       && SWITCHTABLE_EMBRYO_OP_NEG,
884       && SWITCHTABLE_EMBRYO_OP_INVERT,
885       && SWITCHTABLE_EMBRYO_OP_ADD_C,
886       && SWITCHTABLE_EMBRYO_OP_SMUL_C,
887       && SWITCHTABLE_EMBRYO_OP_ZERO_PRI,
888       && SWITCHTABLE_EMBRYO_OP_ZERO_ALT,
889       && SWITCHTABLE_EMBRYO_OP_ZERO,
890       && SWITCHTABLE_EMBRYO_OP_ZERO_S,
891       && SWITCHTABLE_EMBRYO_OP_SIGN_PRI,
892       && SWITCHTABLE_EMBRYO_OP_SIGN_ALT,
893       && SWITCHTABLE_EMBRYO_OP_EQ,
894       && SWITCHTABLE_EMBRYO_OP_NEQ,
895       && SWITCHTABLE_EMBRYO_OP_LESS,
896       && SWITCHTABLE_EMBRYO_OP_LEQ,
897       && SWITCHTABLE_EMBRYO_OP_GRTR,
898       && SWITCHTABLE_EMBRYO_OP_GEQ,
899       && SWITCHTABLE_EMBRYO_OP_SLESS,
900       && SWITCHTABLE_EMBRYO_OP_SLEQ,
901       && SWITCHTABLE_EMBRYO_OP_SGRTR,
902       && SWITCHTABLE_EMBRYO_OP_SGEQ,
903       && SWITCHTABLE_EMBRYO_OP_EQ_C_PRI,
904       && SWITCHTABLE_EMBRYO_OP_EQ_C_ALT,
905       && SWITCHTABLE_EMBRYO_OP_INC_PRI,
906       && SWITCHTABLE_EMBRYO_OP_INC_ALT,
907       && SWITCHTABLE_EMBRYO_OP_INC,
908       && SWITCHTABLE_EMBRYO_OP_INC_S,
909       && SWITCHTABLE_EMBRYO_OP_INC_I,
910       && SWITCHTABLE_EMBRYO_OP_DEC_PRI,
911       && SWITCHTABLE_EMBRYO_OP_DEC_ALT,
912       && SWITCHTABLE_EMBRYO_OP_DEC,
913       && SWITCHTABLE_EMBRYO_OP_DEC_S,
914       && SWITCHTABLE_EMBRYO_OP_DEC_I,
915       && SWITCHTABLE_EMBRYO_OP_MOVS,
916       && SWITCHTABLE_EMBRYO_OP_CMPS,
917       && SWITCHTABLE_EMBRYO_OP_FILL,
918       && SWITCHTABLE_EMBRYO_OP_HALT,
919       && SWITCHTABLE_EMBRYO_OP_BOUNDS,
920       && SWITCHTABLE_EMBRYO_OP_SYSREQ_PRI,
921       && SWITCHTABLE_EMBRYO_OP_SYSREQ_C,
922       && SWITCHTABLE_EMBRYO_OP_FILE,
923       && SWITCHTABLE_EMBRYO_OP_LINE,
924       && SWITCHTABLE_EMBRYO_OP_SYMBOL,
925       && SWITCHTABLE_EMBRYO_OP_SRANGE,
926       && SWITCHTABLE_EMBRYO_OP_JUMP_PRI,
927       && SWITCHTABLE_EMBRYO_OP_SWITCH,
928       && SWITCHTABLE_EMBRYO_OP_CASETBL,
929       && SWITCHTABLE_EMBRYO_OP_SWAP_PRI,
930       && SWITCHTABLE_EMBRYO_OP_SWAP_ALT,
931       && SWITCHTABLE_EMBRYO_OP_PUSHADDR,
932       && SWITCHTABLE_EMBRYO_OP_NOP,
933       && SWITCHTABLE_EMBRYO_OP_SYSREQ_D,
934       && SWITCHTABLE_EMBRYO_OP_SYMTAG,
935       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
936       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
937       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
938       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
939       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
940       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
941       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
942       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
943       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
944       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
945       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
946       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
947       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
948       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
949       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
950       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
951       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
952       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
953       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
954       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
955       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
956       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
957       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE,
958       && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE, && SWITCHTABLE_EMBRYO_OP_NONE
959    };
960 #endif
961    if (!ep) return EMBRYO_PROGRAM_FAIL;
962    if (!(ep->flags & EMBRYO_FLAG_RELOC))
963      {
964         ep->error = EMBRYO_ERROR_INIT;
965         return EMBRYO_PROGRAM_FAIL;
966      }
967    if (!ep->base)
968      {
969         ep->error = EMBRYO_ERROR_INIT;
970         return EMBRYO_PROGRAM_FAIL;
971      }
972    if (ep->run_count > 0)
973      {
974         /* return EMBRYO_PROGRAM_BUSY; */
975         /* FIXME: test C->vm->C->vm recursion more fully */
976         /* it seems to work... just fine!!! - strange! */
977      }
978 
979    /* set up the registers */
980    hdr = (Embryo_Header *)ep->base;
981    codesize = (Embryo_UCell)(hdr->dat - hdr->cod);
982    code = ep->base + (int)hdr->cod;
983    data = ep->base + (int)hdr->dat;
984    hea_start = hea = ep->hea;
985    stk = ep->stk;
986    reset_stk = stk;
987    reset_hea = hea;
988    frm = alt = pri = 0;
989 
990    /* get the start address */
991    if (fn == EMBRYO_FUNCTION_MAIN)
992      {
993         if (hdr->cip < 0)
994           {
995              ep->error = EMBRYO_ERROR_INDEX;
996              return EMBRYO_PROGRAM_FAIL;
997           }
998         cip = (Embryo_Cell *)(code + (int)hdr->cip);
999      }
1000    else if (fn == EMBRYO_FUNCTION_CONT)
1001      {
1002         /* all registers: pri, alt, frm, cip, hea, stk, reset_stk, reset_hea */
1003         frm = ep->frm;
1004         stk = ep->stk;
1005         hea = ep->hea;
1006         pri = ep->pri;
1007         alt = ep->alt;
1008         reset_stk = ep->reset_stk;
1009         reset_hea = ep->reset_hea;
1010         cip = (Embryo_Cell *)(code + (int)ep->cip);
1011      }
1012    else if (fn < 0)
1013      {
1014         ep->error = EMBRYO_ERROR_INDEX;
1015         return EMBRYO_PROGRAM_FAIL;
1016      }
1017    else
1018      {
1019         if (fn >= (Embryo_Cell)NUMENTRIES(hdr, publics, natives))
1020           {
1021              ep->error = EMBRYO_ERROR_INDEX;
1022              return EMBRYO_PROGRAM_FAIL;
1023           }
1024         func = GETENTRY(hdr, publics, fn);
1025         cip = (Embryo_Cell *)(code + (int)func->address);
1026      }
1027    /* check values just copied */
1028    CHKSTACK();
1029    CHKHEAP();
1030 
1031    if (fn != EMBRYO_FUNCTION_CONT)
1032      {
1033         int j;
1034 
1035         for (j = ep->params_size - 1; j >= 0; j--)
1036           {
1037              Embryo_Param *pr;
1038 
1039              pr = &(ep->params[j]);
1040              if (pr->string)
1041                {
1042                   int len;
1043                   Embryo_Cell ep_addr, *addr;
1044 
1045                   len = strlen(pr->string);
1046                   ep_addr = embryo_data_heap_push(ep, len + 1);
1047                   if (ep_addr == EMBRYO_CELL_NONE)
1048                     {
1049                        ep->error = EMBRYO_ERROR_HEAPLOW;
1050                        return EMBRYO_PROGRAM_FAIL;
1051                     }
1052                   addr = embryo_data_address_get(ep, ep_addr);
1053                   if (addr)
1054                     embryo_data_string_set(ep, pr->string, addr);
1055                   else
1056                     {
1057                        ep->error = EMBRYO_ERROR_HEAPLOW;
1058                        return EMBRYO_PROGRAM_FAIL;
1059                     }
1060                   PUSH(ep_addr);
1061                   free(pr->string);
1062                }
1063              else if (pr->cell_array)
1064                {
1065                   int len;
1066                   Embryo_Cell ep_addr, *addr;
1067 
1068                   len = pr->cell_array_size;
1069                   ep_addr = embryo_data_heap_push(ep, len + 1);
1070                   if (ep_addr == EMBRYO_CELL_NONE)
1071                     {
1072                        ep->error = EMBRYO_ERROR_HEAPLOW;
1073                        return EMBRYO_PROGRAM_FAIL;
1074                     }
1075                   addr = embryo_data_address_get(ep, ep_addr);
1076                   if (addr)
1077                     memcpy(addr, pr->cell_array,
1078                            pr->cell_array_size * sizeof(Embryo_Cell));
1079                   else
1080                     {
1081                        ep->error = EMBRYO_ERROR_HEAPLOW;
1082                        return EMBRYO_PROGRAM_FAIL;
1083                     }
1084                   PUSH(ep_addr);
1085                   free(pr->cell_array);
1086                }
1087              else
1088                {
1089                   PUSH(pr->cell);
1090                }
1091           }
1092         PUSH(ep->params_size * sizeof(Embryo_Cell));
1093         PUSH(0);
1094         if (ep->params)
1095           {
1096              free(ep->params);
1097              ep->params = NULL;
1098           }
1099         ep->params_size = ep->params_alloc = 0;
1100      }
1101    /* check stack/heap before starting to run */
1102    CHKMARGIN();
1103 
1104    /* track recursion depth */
1105    ep->run_count++;
1106 
1107    max_run_cycles = ep->max_run_cycles;
1108    /* start running */
1109    for (cycle_count = 0;; )
1110      {
1111         if (max_run_cycles > 0)
1112           {
1113              if (cycle_count >= max_run_cycles)
1114                {
1115                   TOOLONG(ep);
1116                }
1117              cycle_count++;
1118           }
1119         op = (Embryo_Opcode) * cip++;
1120         SWITCH(op);
1121         CASE(EMBRYO_OP_LOAD_PRI);
1122         GETPARAM(offs);
1123         pri = *(Embryo_Cell *)(data + (int)offs);
1124         BREAK;
1125         CASE(EMBRYO_OP_LOAD_ALT);
1126         GETPARAM(offs);
1127         alt = *(Embryo_Cell *)(data + (int)offs);
1128         BREAK;
1129         CASE(EMBRYO_OP_LOAD_S_PRI);
1130         GETPARAM(offs);
1131         pri = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1132         BREAK;
1133         CASE(EMBRYO_OP_LOAD_S_ALT);
1134         GETPARAM(offs);
1135         alt = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1136         BREAK;
1137         CASE(EMBRYO_OP_LREF_PRI);
1138         GETPARAM(offs);
1139         offs = *(Embryo_Cell *)(data + (int)offs);
1140         pri = *(Embryo_Cell *)(data + (int)offs);
1141         BREAK;
1142         CASE(EMBRYO_OP_LREF_ALT);
1143         GETPARAM(offs);
1144         offs = *(Embryo_Cell *)(data + (int)offs);
1145         alt = *(Embryo_Cell *)(data + (int)offs);
1146         BREAK;
1147         CASE(EMBRYO_OP_LREF_S_PRI);
1148         GETPARAM(offs);
1149         offs = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1150         pri = *(Embryo_Cell *)(data + (int)offs);
1151         BREAK;
1152         CASE(EMBRYO_OP_LREF_S_ALT);
1153         GETPARAM(offs);
1154         offs = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1155         alt = *(Embryo_Cell *)(data + (int)offs);
1156         BREAK;
1157         CASE(EMBRYO_OP_LOAD_I);
1158         CHKMEM(pri);
1159         pri = *(Embryo_Cell *)(data + (int)pri);
1160         BREAK;
1161         CASE(EMBRYO_OP_LODB_I);
1162         GETPARAM(offs);
1163         CHKMEM(pri);
1164         switch (offs)
1165           {
1166            case 1:
1167              pri = *(data + (int)pri);
1168              break;
1169 
1170            case 2:
1171              pri = *(unsigned short *)(data + (int)pri);
1172              break;
1173 
1174            case 4:
1175              pri = *(unsigned int *)(data + (int)pri);
1176              break;
1177 
1178            default:
1179              ABORT(ep, EMBRYO_ERROR_INVINSTR);
1180              break;
1181           }
1182         BREAK;
1183         CASE(EMBRYO_OP_CONST_PRI);
1184         GETPARAM(pri);
1185         BREAK;
1186         CASE(EMBRYO_OP_CONST_ALT);
1187         GETPARAM(alt);
1188         BREAK;
1189         CASE(EMBRYO_OP_ADDR_PRI);
1190         GETPARAM(pri);
1191         pri += frm;
1192         BREAK;
1193         CASE(EMBRYO_OP_ADDR_ALT);
1194         GETPARAM(alt);
1195         alt += frm;
1196         BREAK;
1197         CASE(EMBRYO_OP_STOR_PRI);
1198         GETPARAM(offs);
1199         *(Embryo_Cell *)(data + (int)offs) = pri;
1200         BREAK;
1201         CASE(EMBRYO_OP_STOR_ALT);
1202         GETPARAM(offs);
1203         *(Embryo_Cell *)(data + (int)offs) = alt;
1204         BREAK;
1205         CASE(EMBRYO_OP_STOR_S_PRI);
1206         GETPARAM(offs);
1207         *(Embryo_Cell *)(data + (int)frm + (int)offs) = pri;
1208         BREAK;
1209         CASE(EMBRYO_OP_STOR_S_ALT);
1210         GETPARAM(offs);
1211         *(Embryo_Cell *)(data + (int)frm + (int)offs) = alt;
1212         BREAK;
1213         CASE(EMBRYO_OP_SREF_PRI);
1214         GETPARAM(offs);
1215         offs = *(Embryo_Cell *)(data + (int)offs);
1216         *(Embryo_Cell *)(data + (int)offs) = pri;
1217         BREAK;
1218         CASE(EMBRYO_OP_SREF_ALT);
1219         GETPARAM(offs);
1220         offs = *(Embryo_Cell *)(data + (int)offs);
1221         *(Embryo_Cell *)(data + (int)offs) = alt;
1222         BREAK;
1223         CASE(EMBRYO_OP_SREF_S_PRI);
1224         GETPARAM(offs);
1225         offs = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1226         *(Embryo_Cell *)(data + (int)offs) = pri;
1227         BREAK;
1228         CASE(EMBRYO_OP_SREF_S_ALT);
1229         GETPARAM(offs);
1230         offs = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1231         *(Embryo_Cell *)(data + (int)offs) = alt;
1232         BREAK;
1233         CASE(EMBRYO_OP_STOR_I);
1234         CHKMEM(alt);
1235         *(Embryo_Cell *)(data + (int)alt) = pri;
1236         BREAK;
1237         CASE(EMBRYO_OP_STRB_I);
1238         GETPARAM(offs);
1239         CHKMEM(alt);
1240         switch (offs)
1241           {
1242            case 1:
1243              *(data + (int)alt) = (unsigned char)pri;
1244              break;
1245 
1246            case 2:
1247              *(unsigned short *)(data + (int)alt) = (unsigned short)pri;
1248              break;
1249 
1250            case 4:
1251              *(unsigned int *)(data + (int)alt) = (unsigned int)pri;
1252              break;
1253 
1254            default:
1255              ABORT(ep, EMBRYO_ERROR_INVINSTR);
1256              break;
1257           }
1258         BREAK;
1259         CASE(EMBRYO_OP_LIDX);
1260         offs = (pri * sizeof(Embryo_Cell)) + alt;
1261         CHKMEM(offs);
1262         pri = *(Embryo_Cell *)(data + (int)offs);
1263         BREAK;
1264         CASE(EMBRYO_OP_LIDX_B);
1265         GETPARAM(offs);
1266         offs = (pri << (int)offs) + alt;
1267         CHKMEM(offs);
1268         pri = *(Embryo_Cell *)(data + (int)offs);
1269         BREAK;
1270         CASE(EMBRYO_OP_IDXADDR);
1271         pri = (pri * sizeof(Embryo_Cell)) + alt;
1272         BREAK;
1273         CASE(EMBRYO_OP_IDXADDR_B);
1274         GETPARAM(offs);
1275         pri = (pri << (int)offs) + alt;
1276         BREAK;
1277         CASE(EMBRYO_OP_ALIGN_PRI);
1278         GETPARAM(offs);
1279 #ifdef WORDS_BIGENDIAN
1280         if ((size_t)offs < sizeof(Embryo_Cell))
1281           pri ^= sizeof(Embryo_Cell) - offs;
1282 #endif
1283         BREAK;
1284         CASE(EMBRYO_OP_ALIGN_ALT);
1285         GETPARAM(offs);
1286 #ifdef WORDS_BIGENDIAN
1287         if ((size_t)offs < sizeof(Embryo_Cell))
1288           alt ^= sizeof(Embryo_Cell) - offs;
1289 #endif
1290         BREAK;
1291         CASE(EMBRYO_OP_LCTRL);
1292         GETPARAM(offs);
1293         switch (offs)
1294           {
1295            case 0:
1296              pri = hdr->cod;
1297              break;
1298 
1299            case 1:
1300              pri = hdr->dat;
1301              break;
1302 
1303            case 2:
1304              pri = hea;
1305              break;
1306 
1307            case 3:
1308              pri = ep->stp;
1309              break;
1310 
1311            case 4:
1312              pri = stk;
1313              break;
1314 
1315            case 5:
1316              pri = frm;
1317              break;
1318 
1319            case 6:
1320              pri = (Embryo_Cell)((unsigned char *)cip - code);
1321              break;
1322 
1323            default:
1324              ABORT(ep, EMBRYO_ERROR_INVINSTR);
1325              break;
1326           }
1327         BREAK;
1328         CASE(EMBRYO_OP_SCTRL);
1329         GETPARAM(offs);
1330         switch (offs)
1331           {
1332            case 0:
1333            case 1:
1334            case 2:
1335              hea = pri;
1336              break;
1337 
1338            case 3:
1339              /* cannot change these parameters */
1340              break;
1341 
1342            case 4:
1343              stk = pri;
1344              break;
1345 
1346            case 5:
1347              frm = pri;
1348              break;
1349 
1350            case 6:
1351              cip = (Embryo_Cell *)(code + (int)pri);
1352              break;
1353 
1354            default:
1355              ABORT(ep, EMBRYO_ERROR_INVINSTR);
1356              break;
1357           }
1358         BREAK;
1359         CASE(EMBRYO_OP_MOVE_PRI);
1360         pri = alt;
1361         BREAK;
1362         CASE(EMBRYO_OP_MOVE_ALT);
1363         alt = pri;
1364         BREAK;
1365         CASE(EMBRYO_OP_XCHG);
1366         offs = pri; /* offs is a temporary variable */
1367         pri = alt;
1368         alt = offs;
1369         BREAK;
1370         CASE(EMBRYO_OP_PUSH_PRI);
1371         PUSH(pri);
1372         BREAK;
1373         CASE(EMBRYO_OP_PUSH_ALT);
1374         PUSH(alt);
1375         BREAK;
1376         CASE(EMBRYO_OP_PUSH_C);
1377         GETPARAM(offs);
1378         PUSH(offs);
1379         BREAK;
1380         CASE(EMBRYO_OP_PUSH_R);
1381         GETPARAM(offs);
1382         while (offs--)
1383           PUSH(pri);
1384         BREAK;
1385         CASE(EMBRYO_OP_PUSH);
1386         GETPARAM(offs);
1387         PUSH(*(Embryo_Cell *)(data + (int)offs));
1388         BREAK;
1389         CASE(EMBRYO_OP_PUSH_S);
1390         GETPARAM(offs);
1391         PUSH(*(Embryo_Cell *)(data + (int)frm + (int)offs));
1392         BREAK;
1393         CASE(EMBRYO_OP_POP_PRI);
1394         POP(pri);
1395         BREAK;
1396         CASE(EMBRYO_OP_POP_ALT);
1397         POP(alt);
1398         BREAK;
1399         CASE(EMBRYO_OP_STACK);
1400         GETPARAM(offs);
1401         alt = stk;
1402         stk += offs;
1403         CHKMARGIN();
1404         CHKSTACK();
1405         BREAK;
1406         CASE(EMBRYO_OP_HEAP);
1407         GETPARAM(offs);
1408         alt = hea;
1409         hea += offs;
1410         CHKMARGIN();
1411         CHKHEAP();
1412         BREAK;
1413         CASE(EMBRYO_OP_PROC);
1414         PUSH(frm);
1415         frm = stk;
1416         CHKMARGIN();
1417         BREAK;
1418         CASE(EMBRYO_OP_RET);
1419         POP(frm);
1420         POP(offs);
1421         if ((Embryo_UCell)offs >= codesize)
1422           ABORT(ep, EMBRYO_ERROR_MEMACCESS);
1423         cip = (Embryo_Cell *)(code + (int)offs);
1424         BREAK;
1425         CASE(EMBRYO_OP_RETN);
1426         POP(frm);
1427         POP(offs);
1428         if ((Embryo_UCell)offs >= codesize)
1429           ABORT(ep, EMBRYO_ERROR_MEMACCESS);
1430         cip = (Embryo_Cell *)(code + (int)offs);
1431         stk += *(Embryo_Cell *)(data + (int)stk) + sizeof(Embryo_Cell); /* remove parameters from the stack */
1432         ep->stk = stk;
1433         BREAK;
1434         CASE(EMBRYO_OP_CALL);
1435         PUSH(((unsigned char *)cip - code) + sizeof(Embryo_Cell)); /* skip address */
1436         cip = JUMPABS(code, cip); /* jump to the address */
1437         BREAK;
1438         CASE(EMBRYO_OP_CALL_PRI);
1439         PUSH((unsigned char *)cip - code);
1440         cip = (Embryo_Cell *)(code + (int)pri);
1441         BREAK;
1442         CASE(EMBRYO_OP_JUMP);
1443         /* since the GETPARAM() macro modifies cip, you cannot
1444          * do GETPARAM(cip) directly */
1445         cip = JUMPABS(code, cip);
1446         BREAK;
1447         CASE(EMBRYO_OP_JREL);
1448         offs = *cip;
1449         cip = (Embryo_Cell *)((unsigned char *)cip + (int)offs + sizeof(Embryo_Cell));
1450         BREAK;
1451         CASE(EMBRYO_OP_JZER);
1452         if (pri == 0)
1453           cip = JUMPABS(code, cip);
1454         else
1455           cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1456         BREAK;
1457         CASE(EMBRYO_OP_JNZ);
1458         if (pri != 0)
1459           cip = JUMPABS(code, cip);
1460         else
1461           cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1462         BREAK;
1463         CASE(EMBRYO_OP_JEQ);
1464         if (pri == alt)
1465           cip = JUMPABS(code, cip);
1466         else
1467           cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1468         BREAK;
1469         CASE(EMBRYO_OP_JNEQ);
1470         if (pri != alt)
1471           cip = JUMPABS(code, cip);
1472         else
1473           cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1474         BREAK;
1475         CASE(EMBRYO_OP_JLESS);
1476         if ((Embryo_UCell)pri < (Embryo_UCell)alt)
1477           cip = JUMPABS(code, cip);
1478         else
1479           cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1480         BREAK;
1481         CASE(EMBRYO_OP_JLEQ);
1482         if ((Embryo_UCell)pri <= (Embryo_UCell)alt)
1483           cip = JUMPABS(code, cip);
1484         else
1485           cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1486         BREAK;
1487         CASE(EMBRYO_OP_JGRTR);
1488         if ((Embryo_UCell)pri > (Embryo_UCell)alt)
1489           cip = JUMPABS(code, cip);
1490         else
1491           cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1492         BREAK;
1493         CASE(EMBRYO_OP_JGEQ);
1494         if ((Embryo_UCell)pri >= (Embryo_UCell)alt)
1495           cip = JUMPABS(code, cip);
1496         else
1497           cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1498         BREAK;
1499         CASE(EMBRYO_OP_JSLESS);
1500         if (pri < alt)
1501           cip = JUMPABS(code, cip);
1502         else
1503           cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1504         BREAK;
1505         CASE(EMBRYO_OP_JSLEQ);
1506         if (pri <= alt)
1507           cip = JUMPABS(code, cip);
1508         else
1509           cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1510         BREAK;
1511         CASE(EMBRYO_OP_JSGRTR);
1512         if (pri > alt)
1513           cip = JUMPABS(code, cip);
1514         else
1515           cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1516         BREAK;
1517         CASE(EMBRYO_OP_JSGEQ);
1518         if (pri >= alt)
1519           cip = JUMPABS(code, cip);
1520         else
1521           cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1522         BREAK;
1523         CASE(EMBRYO_OP_SHL);
1524         pri <<= alt;
1525         BREAK;
1526         CASE(EMBRYO_OP_SHR);
1527         pri = (Embryo_UCell)pri >> (int)alt;
1528         BREAK;
1529         CASE(EMBRYO_OP_SSHR);
1530         pri >>= alt;
1531         BREAK;
1532         CASE(EMBRYO_OP_SHL_C_PRI);
1533         GETPARAM(offs);
1534         pri <<= offs;
1535         BREAK;
1536         CASE(EMBRYO_OP_SHL_C_ALT);
1537         GETPARAM(offs);
1538         alt <<= offs;
1539         BREAK;
1540         CASE(EMBRYO_OP_SHR_C_PRI);
1541         GETPARAM(offs);
1542         pri = (Embryo_UCell)pri >> (int)offs;
1543         BREAK;
1544         CASE(EMBRYO_OP_SHR_C_ALT);
1545         GETPARAM(offs);
1546         alt = (Embryo_UCell)alt >> (int)offs;
1547         BREAK;
1548         CASE(EMBRYO_OP_SMUL);
1549         pri *= alt;
1550         BREAK;
1551         CASE(EMBRYO_OP_SDIV);
1552         if (alt == 0) ABORT(ep, EMBRYO_ERROR_DIVIDE);
1553         /* divide must always round down; this is a bit
1554          * involved to do in a machine-independent way.
1555          */
1556         offs = ((pri % alt) + alt) % alt; /* true modulus */
1557         pri = (pri - offs) / alt; /* division result */
1558         alt = offs;
1559         BREAK;
1560         CASE(EMBRYO_OP_SDIV_ALT);
1561         if (pri == 0) ABORT(ep, EMBRYO_ERROR_DIVIDE);
1562         /* divide must always round down; this is a bit
1563          * involved to do in a machine-independent way.
1564          */
1565         offs = ((alt % pri) + pri) % pri; /* true modulus */
1566         pri = (alt - offs) / pri; /* division result */
1567         alt = offs;
1568         BREAK;
1569         CASE(EMBRYO_OP_UMUL);
1570         pri = (Embryo_UCell)pri * (Embryo_UCell)alt;
1571         BREAK;
1572         CASE(EMBRYO_OP_UDIV);
1573         if (alt == 0) ABORT(ep, EMBRYO_ERROR_DIVIDE);
1574         offs = (Embryo_UCell)pri % (Embryo_UCell)alt; /* temporary storage */
1575         pri = (Embryo_UCell)pri / (Embryo_UCell)alt;
1576         alt = offs;
1577         BREAK;
1578         CASE(EMBRYO_OP_UDIV_ALT);
1579         if (pri == 0) ABORT(ep, EMBRYO_ERROR_DIVIDE);
1580         offs = (Embryo_UCell)alt % (Embryo_UCell)pri; /* temporary storage */
1581         pri = (Embryo_UCell)alt / (Embryo_UCell)pri;
1582         alt = offs;
1583         BREAK;
1584         CASE(EMBRYO_OP_ADD);
1585         pri += alt;
1586         BREAK;
1587         CASE(EMBRYO_OP_SUB);
1588         pri -= alt;
1589         BREAK;
1590         CASE(EMBRYO_OP_SUB_ALT);
1591         pri = alt - pri;
1592         BREAK;
1593         CASE(EMBRYO_OP_AND);
1594         pri &= alt;
1595         BREAK;
1596         CASE(EMBRYO_OP_OR);
1597         pri |= alt;
1598         BREAK;
1599         CASE(EMBRYO_OP_XOR);
1600         pri ^= alt;
1601         BREAK;
1602         CASE(EMBRYO_OP_NOT);
1603         pri = !pri;
1604         BREAK;
1605         CASE(EMBRYO_OP_NEG);
1606         pri = -pri;
1607         BREAK;
1608         CASE(EMBRYO_OP_INVERT);
1609         pri = ~pri;
1610         BREAK;
1611         CASE(EMBRYO_OP_ADD_C);
1612         GETPARAM(offs);
1613         pri += offs;
1614         BREAK;
1615         CASE(EMBRYO_OP_SMUL_C);
1616         GETPARAM(offs);
1617         pri *= offs;
1618         BREAK;
1619         CASE(EMBRYO_OP_ZERO_PRI);
1620         pri = 0;
1621         BREAK;
1622         CASE(EMBRYO_OP_ZERO_ALT);
1623         alt = 0;
1624         BREAK;
1625         CASE(EMBRYO_OP_ZERO);
1626         GETPARAM(offs);
1627         *(Embryo_Cell *)(data + (int)offs) = 0;
1628         BREAK;
1629         CASE(EMBRYO_OP_ZERO_S);
1630         GETPARAM(offs);
1631         *(Embryo_Cell *)(data + (int)frm + (int)offs) = 0;
1632         BREAK;
1633         CASE(EMBRYO_OP_SIGN_PRI);
1634         if ((pri & 0xff) >= 0x80) pri |= ~(Embryo_UCell)0xff;
1635         BREAK;
1636         CASE(EMBRYO_OP_SIGN_ALT);
1637         if ((alt & 0xff) >= 0x80) alt |= ~(Embryo_UCell)0xff;
1638         BREAK;
1639         CASE(EMBRYO_OP_EQ);
1640         pri = (pri == alt) ? 1 : 0;
1641         BREAK;
1642         CASE(EMBRYO_OP_NEQ);
1643         pri = (pri != alt) ? 1 : 0;
1644         BREAK;
1645         CASE(EMBRYO_OP_LESS);
1646         pri = ((Embryo_UCell)pri < (Embryo_UCell)alt) ? 1 : 0;
1647         BREAK;
1648         CASE(EMBRYO_OP_LEQ);
1649         pri = ((Embryo_UCell)pri <= (Embryo_UCell)alt) ? 1 : 0;
1650         BREAK;
1651         CASE(EMBRYO_OP_GRTR);
1652         pri = ((Embryo_UCell)pri > (Embryo_UCell)alt) ? 1 : 0;
1653         BREAK;
1654         CASE(EMBRYO_OP_GEQ);
1655         pri = ((Embryo_UCell)pri >= (Embryo_UCell)alt) ? 1 : 0;
1656         BREAK;
1657         CASE(EMBRYO_OP_SLESS);
1658         pri = (pri < alt) ? 1 : 0;
1659         BREAK;
1660         CASE(EMBRYO_OP_SLEQ);
1661         pri = (pri <= alt) ? 1 : 0;
1662         BREAK;
1663         CASE(EMBRYO_OP_SGRTR);
1664         pri = (pri > alt) ? 1 : 0;
1665         BREAK;
1666         CASE(EMBRYO_OP_SGEQ);
1667         pri = (pri >= alt) ? 1 : 0;
1668         BREAK;
1669         CASE(EMBRYO_OP_EQ_C_PRI);
1670         GETPARAM(offs);
1671         pri = (pri == offs) ? 1 : 0;
1672         BREAK;
1673         CASE(EMBRYO_OP_EQ_C_ALT);
1674         GETPARAM(offs);
1675         pri = (alt == offs) ? 1 : 0;
1676         BREAK;
1677         CASE(EMBRYO_OP_INC_PRI);
1678         pri++;
1679         BREAK;
1680         CASE(EMBRYO_OP_INC_ALT);
1681         alt++;
1682         BREAK;
1683         CASE(EMBRYO_OP_INC);
1684         GETPARAM(offs);
1685         *(Embryo_Cell *)(data + (int)offs) += 1;
1686         BREAK;
1687         CASE(EMBRYO_OP_INC_S);
1688         GETPARAM(offs);
1689         *(Embryo_Cell *)(data + (int)frm + (int)offs) += 1;
1690         BREAK;
1691         CASE(EMBRYO_OP_INC_I);
1692         *(Embryo_Cell *)(data + (int)pri) += 1;
1693         BREAK;
1694         CASE(EMBRYO_OP_DEC_PRI);
1695         pri--;
1696         BREAK;
1697         CASE(EMBRYO_OP_DEC_ALT);
1698         alt--;
1699         BREAK;
1700         CASE(EMBRYO_OP_DEC);
1701         GETPARAM(offs);
1702         *(Embryo_Cell *)(data + (int)offs) -= 1;
1703         BREAK;
1704         CASE(EMBRYO_OP_DEC_S);
1705         GETPARAM(offs);
1706         *(Embryo_Cell *)(data + (int)frm + (int)offs) -= 1;
1707         BREAK;
1708         CASE(EMBRYO_OP_DEC_I);
1709         *(Embryo_Cell *)(data + (int)pri) -= 1;
1710         BREAK;
1711         CASE(EMBRYO_OP_MOVS);
1712         GETPARAM(offs);
1713         CHKMEM(pri);
1714         CHKMEM(pri + offs);
1715         CHKMEM(alt);
1716         CHKMEM(alt + offs);
1717         memcpy(data + (int)alt, data + (int)pri, (int)offs);
1718         BREAK;
1719         CASE(EMBRYO_OP_CMPS);
1720         GETPARAM(offs);
1721         CHKMEM(pri);
1722         CHKMEM(pri + offs);
1723         CHKMEM(alt);
1724         CHKMEM(alt + offs);
1725         pri = memcmp(data + (int)alt, data + (int)pri, (int)offs);
1726         BREAK;
1727         CASE(EMBRYO_OP_FILL);
1728         GETPARAM(offs);
1729         CHKMEM(alt);
1730         CHKMEM(alt + offs);
1731         for (i = (int)alt;
1732              (size_t)offs >= sizeof(Embryo_Cell);
1733              i += sizeof(Embryo_Cell), offs -= sizeof(Embryo_Cell))
1734           *(Embryo_Cell *)(data + i) = pri;
1735         BREAK;
1736         CASE(EMBRYO_OP_HALT);
1737         GETPARAM(offs);
1738         ep->retval = pri;
1739         /* store complete status */
1740         ep->frm = frm;
1741         ep->stk = stk;
1742         ep->hea = hea;
1743         ep->pri = pri;
1744         ep->alt = alt;
1745         ep->cip = (Embryo_Cell)((unsigned char *)cip - code);
1746         if (offs == EMBRYO_ERROR_SLEEP)
1747           {
1748              ep->reset_stk = reset_stk;
1749              ep->reset_hea = reset_hea;
1750              ep->run_count--;
1751              return EMBRYO_PROGRAM_SLEEP;
1752           }
1753         OK(ep, (int)offs);
1754         CASE(EMBRYO_OP_BOUNDS);
1755         GETPARAM(offs);
1756         if ((Embryo_UCell)pri > (Embryo_UCell)offs)
1757           ABORT(ep, EMBRYO_ERROR_BOUNDS);
1758         BREAK;
1759         CASE(EMBRYO_OP_SYSREQ_PRI);
1760         /* save a few registers */
1761         ep->cip = (Embryo_Cell)((unsigned char *)cip - code);
1762         ep->hea = hea;
1763         ep->frm = frm;
1764         ep->stk = stk;
1765         num = _embryo_native_call(ep, pri, &pri, (Embryo_Cell *)(data + (int)stk));
1766         if (num != EMBRYO_ERROR_NONE)
1767           {
1768              if (num == EMBRYO_ERROR_SLEEP)
1769                {
1770                   ep->pri = pri;
1771                   ep->alt = alt;
1772                   ep->reset_stk = reset_stk;
1773                   ep->reset_hea = reset_hea;
1774                   ep->run_count--;
1775                   return EMBRYO_PROGRAM_SLEEP;
1776                }
1777              ABORT(ep, num);
1778           }
1779         BREAK;
1780         CASE(EMBRYO_OP_SYSREQ_C);
1781         GETPARAM(offs);
1782         /* save a few registers */
1783         ep->cip = (Embryo_Cell)((unsigned char *)cip - code);
1784         ep->hea = hea;
1785         ep->frm = frm;
1786         ep->stk = stk;
1787         num = _embryo_native_call(ep, offs, &pri, (Embryo_Cell *)(data + (int)stk));
1788         if (num != EMBRYO_ERROR_NONE)
1789           {
1790              if (num == EMBRYO_ERROR_SLEEP)
1791                {
1792                   ep->pri = pri;
1793                   ep->alt = alt;
1794                   ep->reset_stk = reset_stk;
1795                   ep->reset_hea = reset_hea;
1796                   ep->run_count--;
1797                   return EMBRYO_PROGRAM_SLEEP;
1798                }
1799              {
1800                 Embryo_Header *hdr2;
1801                 int j, num2;
1802                 Embryo_Func_Stub *func_entry;
1803 
1804                 hdr2 = (Embryo_Header *)ep->code;
1805                 num2 = NUMENTRIES(hdr2, natives, libraries);
1806                 func_entry = GETENTRY(hdr2, natives, 0);
1807                 for (j = 0; j < num2; j++)
1808                   {
1809                      char *entry_name;
1810 
1811                      entry_name = GETENTRYNAME(hdr2, func_entry);
1812                      if (j == offs)
1813                        printf("EMBRYO: CALL [%i] %s() non-existent!\n", j, entry_name);
1814                      func_entry =
1815                        (Embryo_Func_Stub *)((unsigned char *)func_entry + hdr2->defsize);
1816                   }
1817              }
1818              ABORT(ep, num);
1819           }
1820         BREAK;
1821         CASE(EMBRYO_OP_SYSREQ_D);
1822         GETPARAM(offs);
1823         /* save a few registers */
1824         ep->cip = (Embryo_Cell)((unsigned char *)cip - code);
1825         ep->hea = hea;
1826         ep->frm = frm;
1827         ep->stk = stk;
1828         num = _embryo_native_call(ep, offs, &pri, (Embryo_Cell *)(data + (int)stk));
1829         if (num != EMBRYO_ERROR_NONE)
1830           {
1831              if (num == EMBRYO_ERROR_SLEEP)
1832                {
1833                   ep->pri = pri;
1834                   ep->alt = alt;
1835                   ep->reset_stk = reset_stk;
1836                   ep->reset_hea = reset_hea;
1837                   ep->run_count--;
1838                   return EMBRYO_PROGRAM_SLEEP;
1839                }
1840              ABORT(ep, ep->error);
1841           }
1842         BREAK;
1843         CASE(EMBRYO_OP_JUMP_PRI);
1844         cip = (Embryo_Cell *)(code + (int)pri);
1845         BREAK;
1846         CASE(EMBRYO_OP_SWITCH);
1847         {
1848            Embryo_Cell *cptr;
1849 
1850            /* +1, to skip the "casetbl" opcode */
1851            cptr = (Embryo_Cell *)(code + (*cip)) + 1;
1852            /* number of records in the case table */
1853            num = (int)(*cptr);
1854            /* preset to "none-matched" case */
1855            cip = (Embryo_Cell *)(code + *(cptr + 1));
1856            for (cptr += 2;
1857                 (num > 0) && (*cptr != pri);
1858                 num--, cptr += 2) ;
1859            /* case found */
1860            if (num > 0)
1861              cip = (Embryo_Cell *)(code + *(cptr + 1));
1862         }
1863         BREAK;
1864         CASE(EMBRYO_OP_SWAP_PRI);
1865         offs = *(Embryo_Cell *)(data + (int)stk);
1866         *(Embryo_Cell *)(data + (int)stk) = pri;
1867         pri = offs;
1868         BREAK;
1869         CASE(EMBRYO_OP_SWAP_ALT);
1870         offs = *(Embryo_Cell *)(data + (int)stk);
1871         *(Embryo_Cell *)(data + (int)stk) = alt;
1872         alt = offs;
1873         BREAK;
1874         CASE(EMBRYO_OP_PUSHADDR);
1875         GETPARAM(offs);
1876         PUSH(frm + offs);
1877         BREAK;
1878         CASE(EMBRYO_OP_NOP);
1879         BREAK;
1880         CASE(EMBRYO_OP_NONE);
1881         CASE(EMBRYO_OP_FILE);
1882         CASE(EMBRYO_OP_LINE);
1883         CASE(EMBRYO_OP_SYMBOL);
1884         CASE(EMBRYO_OP_SRANGE);
1885         CASE(EMBRYO_OP_CASETBL);
1886         CASE(EMBRYO_OP_SYMTAG);
1887         BREAK;
1888 
1889 #ifndef EMBRYO_EXEC_JUMPTABLE
1890       default:
1891         ABORT(ep, EMBRYO_ERROR_INVINSTR);
1892 #endif
1893         SWITCHEND;
1894      }
1895    ep->max_run_cycles = max_run_cycles;
1896    ep->run_count--;
1897    ep->hea = hea_start;
1898    return EMBRYO_PROGRAM_OK;
1899 }
1900 
1901 EAPI Embryo_Cell
embryo_program_return_value_get(Embryo_Program * ep)1902 embryo_program_return_value_get(Embryo_Program *ep)
1903 {
1904    if (!ep) return 0;
1905    return ep->retval;
1906 }
1907 
1908 EAPI void
embryo_program_max_cycle_run_set(Embryo_Program * ep,int max)1909 embryo_program_max_cycle_run_set(Embryo_Program *ep, int max)
1910 {
1911    if (!ep) return;
1912    if (max < 0) max = 0;
1913    ep->max_run_cycles = max;
1914 }
1915 
1916 EAPI int
embryo_program_max_cycle_run_get(Embryo_Program * ep)1917 embryo_program_max_cycle_run_get(Embryo_Program *ep)
1918 {
1919    if (!ep) return 0;
1920    return ep->max_run_cycles;
1921 }
1922 
1923 EAPI int
embryo_parameter_cell_push(Embryo_Program * ep,Embryo_Cell cell)1924 embryo_parameter_cell_push(Embryo_Program *ep, Embryo_Cell cell)
1925 {
1926    Embryo_Param *pr;
1927 
1928    ep->params_size++;
1929    if (ep->params_size > ep->params_alloc)
1930      {
1931         ep->params_alloc += 8;
1932         pr = realloc(ep->params, ep->params_alloc * sizeof(Embryo_Param));
1933         if (!pr) return 0;
1934         ep->params = pr;
1935      }
1936    pr = &(ep->params[ep->params_size - 1]);
1937    pr->string = NULL;
1938    pr->cell_array = NULL;
1939    pr->cell_array_size = 0;
1940    pr->cell = cell;
1941    return 1;
1942 }
1943 
1944 EAPI int
embryo_parameter_string_push(Embryo_Program * ep,const char * str)1945 embryo_parameter_string_push(Embryo_Program *ep, const char *str)
1946 {
1947    Embryo_Param *pr;
1948    char *str_dup;
1949 
1950    if (!str)
1951      return embryo_parameter_string_push(ep, "");
1952    str_dup = strdup(str);
1953    if (!str_dup) return 0;
1954    ep->params_size++;
1955    if (ep->params_size > ep->params_alloc)
1956      {
1957         ep->params_alloc += 8;
1958         pr = realloc(ep->params, ep->params_alloc * sizeof(Embryo_Param));
1959         if (!pr)
1960           {
1961              free(str_dup);
1962              return 0;
1963           }
1964         ep->params = pr;
1965      }
1966    pr = &(ep->params[ep->params_size - 1]);
1967    pr->string = str_dup;
1968    pr->cell_array = NULL;
1969    pr->cell_array_size = 0;
1970    pr->cell = 0;
1971    return 1;
1972 }
1973 
1974 EAPI int
embryo_parameter_cell_array_push(Embryo_Program * ep,Embryo_Cell * cells,int num)1975 embryo_parameter_cell_array_push(Embryo_Program *ep, Embryo_Cell *cells, int num)
1976 {
1977    Embryo_Param *pr;
1978    Embryo_Cell *cell_array;
1979 
1980    if ((!cells) || (num <= 0))
1981      return embryo_parameter_cell_push(ep, 0);
1982    cell_array = malloc(num * sizeof(Embryo_Cell));
1983    ep->params_size++;
1984    if (ep->params_size > ep->params_alloc)
1985      {
1986         ep->params_alloc += 8;
1987         pr = realloc(ep->params, ep->params_alloc * sizeof(Embryo_Param));
1988         if (!pr)
1989           {
1990              free(cell_array);
1991              return 0;
1992           }
1993         ep->params = pr;
1994      }
1995    pr = &(ep->params[ep->params_size - 1]);
1996    pr->string = NULL;
1997    pr->cell = 0;
1998    pr->cell_array = cell_array;
1999    pr->cell_array_size = num;
2000    memcpy(pr->cell_array, cells, num * sizeof(Embryo_Cell));
2001    return 1;
2002 }
2003 
2004