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